From 6b3cf63bf568cab4f8e05ea483ad97d5ea0e2eec Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 22 May 2020 14:45:51 +0200 Subject: Fix dogfood fallout --- clippy_lints/src/methods/mod.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 810a226b50d..32b3b7f7947 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1496,17 +1496,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { if let ty::Opaque(def_id, _) = ret_ty.kind { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { - match predicate.0.kind() { - ty::PredicateKind::Projection(poly_projection_predicate) => { - let binder = poly_projection_predicate.ty(); - let associated_type = binder.skip_binder(); - - // walk the associated type and check for Self - if contains_self_ty(associated_type) { - return; - } - }, - _ => {}, + if let ty::PredicateKind::Projection(poly_projection_predicate) = predicate.0.kind() { + let binder = poly_projection_predicate.ty(); + let associated_type = binder.skip_binder(); + + // walk the associated type and check for Self + if contains_self_ty(associated_type) { + return; + } } } } -- cgit 1.4.1-3-g733a5 From 566377f6272b0a3b9fa65dabe1f39ee82be80d4e Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Wed, 21 Aug 2019 21:19:28 +0200 Subject: Ignore calls to 'len' --- clippy_lints/src/methods/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 32b3b7f7947..c82cf57a4b1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1614,6 +1614,21 @@ fn lint_or_fun_call<'a, 'tcx>( or_has_args: bool, span: Span, ) { + if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.node { + if path.ident.as_str() == "len" { + let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); + + match ty.sty { + ty::Slice(_) | ty::Array(_, _) => return, + _ => (), + } + + if match_type(cx, ty, &paths::VEC) { + return; + } + } + } + // (path, fn_has_argument, methods, suffix) let know_types: &[(&[_], _, &[_], _)] = &[ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), -- cgit 1.4.1-3-g733a5 From bcfeb4de1589c19a7b21f04fec284e6045c0aa7a Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Mon, 25 May 2020 21:23:39 +0200 Subject: Fix build --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c82cf57a4b1..52ca962e7ef 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1614,11 +1614,11 @@ fn lint_or_fun_call<'a, 'tcx>( or_has_args: bool, span: Span, ) { - if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.node { + if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.kind { if path.ident.as_str() == "len" { let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); - match ty.sty { + match ty.kind { ty::Slice(_) | ty::Array(_, _) => return, _ => (), } -- cgit 1.4.1-3-g733a5 From 32fde0b5116b3a1115d11c49a9bf2af2ebdd5773 Mon Sep 17 00:00:00 2001 From: Ericko Samudera Date: Mon, 25 May 2020 23:22:01 +0700 Subject: New lint: iter_next_slice --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/loops.rs | 26 +++++------ clippy_lints/src/methods/mod.rs | 84 ++++++++++++++++++++++++++++++++++- clippy_lints/src/needless_continue.rs | 2 +- src/lintlist/mod.rs | 7 +++ tests/ui/into_iter_on_ref.fixed | 2 + tests/ui/into_iter_on_ref.rs | 2 + tests/ui/into_iter_on_ref.stderr | 8 +++- tests/ui/iter_next_slice.fixed | 24 ++++++++++ tests/ui/iter_next_slice.rs | 24 ++++++++++ tests/ui/iter_next_slice.stderr | 28 ++++++++++++ tests/ui/needless_collect.fixed | 2 +- tests/ui/needless_collect.stderr | 16 +++---- 14 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 tests/ui/iter_next_slice.fixed create mode 100644 tests/ui/iter_next_slice.rs create mode 100644 tests/ui/iter_next_slice.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac9057199f..714e25a32ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1401,6 +1401,7 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 057d39d4c82..7c16dbd8f26 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -669,6 +669,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::INTO_ITER_ON_REF, &methods::ITERATOR_STEP_BY_ZERO, &methods::ITER_CLONED_COLLECT, + &methods::ITER_NEXT_SLICE, &methods::ITER_NTH, &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, @@ -1303,6 +1304,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), @@ -1483,6 +1485,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 38a5829b3f7..dbe41823a9c 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -27,7 +27,7 @@ use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::symbol::Symbol; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; use std::iter::{once, Iterator}; use std::mem; @@ -2381,32 +2381,32 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' match_type(cx, ty, &paths::BTREEMAP) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { if method.ident.name == sym!(len) { - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(collect)); span_lint_and_sugg( cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, "replace with", - ".count()".to_string(), + "count()".to_string(), Applicability::MachineApplicable, ); } if method.ident.name == sym!(is_empty) { - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(iter)); span_lint_and_sugg( cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, "replace with", - ".next().is_none()".to_string(), + "get(0).is_none()".to_string(), Applicability::MachineApplicable, ); } if method.ident.name == sym!(contains) { let contains_arg = snippet(cx, args[1].span, "??"); - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(collect)); span_lint_and_then( cx, NEEDLESS_COLLECT, @@ -2422,7 +2422,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' span, "replace with", format!( - ".any(|{}| x == {})", + "any(|{}| x == {})", arg, pred ), Applicability::MachineApplicable, @@ -2435,13 +2435,13 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' } } -fn shorten_needless_collect_span(expr: &Expr<'_>) -> Span { - if_chain! { - if let ExprKind::MethodCall(_, _, ref args) = expr.kind; - if let ExprKind::MethodCall(_, ref span, _) = args[0].kind; - then { - return expr.span.with_lo(span.lo() - BytePos(1)); +fn shorten_span(expr: &Expr<'_>, target_fn_name: Symbol) -> Span { + let mut current_expr = expr; + while let ExprKind::MethodCall(ref path, ref span, ref args) = current_expr.kind { + if path.ident.name == target_fn_name { + return expr.span.with_lo(span.lo()); } + current_expr = &args[0]; } unreachable!() } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 32b3b7f7947..7cb04d4d81c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -26,7 +26,7 @@ use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, + get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_applicability, @@ -1242,6 +1242,32 @@ declare_clippy_lint! { "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array + /// + /// **Why is this bad?** These can be shortened into `.get()` + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # let a = [1, 2, 3]; + /// # let b = vec![1, 2, 3]; + /// a[2..].iter().next(); + /// b.iter().next(); + /// ``` + /// should be written as: + /// ```rust + /// # let a = [1, 2, 3]; + /// # let b = vec![1, 2, 3]; + /// a.get(2); + /// b.get(0); + /// ``` + pub ITER_NEXT_SLICE, + style, + "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1273,6 +1299,7 @@ declare_lint_pass!(Methods => [ FIND_MAP, MAP_FLATTEN, ITERATOR_STEP_BY_ZERO, + ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, ITER_SKIP_NEXT, @@ -1320,6 +1347,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), + ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]), @@ -2184,6 +2212,60 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args } } +fn lint_iter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { + let caller_expr = &iter_args[0]; + + // Skip lint if the `iter().next()` expression is a for loop argument, + // since it is already covered by `&loops::ITER_NEXT_LOOP` + let mut parent_expr_opt = get_parent_expr(cx, expr); + while let Some(parent_expr) = parent_expr_opt { + if higher::for_loop(parent_expr).is_some() { + return; + } + parent_expr_opt = get_parent_expr(cx, parent_expr); + } + + if derefs_to_slice(cx, caller_expr, cx.tables.expr_ty(caller_expr)).is_some() { + // caller is a Slice + if_chain! { + if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind; + if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) + = higher::range(cx, index_expr); + if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; + if let ast::LitKind::Int(start_idx, _) = start_lit.node; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "Using `.iter().next()` on a Slice without end index.", + "try calling", + format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), + applicability, + ); + } + } + } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(caller_expr), sym!(vec_type)) + || matches!(&walk_ptrs_ty(cx.tables.expr_ty(caller_expr)).kind, ty::Array(_, _)) + { + // caller is a Vec or an Array + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "Using `.iter().next()` on an array", + "try calling", + format!( + "{}.get(0)", + snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability) + ), + applicability, + ); + } +} + fn lint_iter_nth<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 28183810df4..a971d041ca6 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -424,7 +424,7 @@ fn erode_from_back(s: &str) -> String { } fn span_of_first_expr_in_block(block: &ast::Block) -> Option { - block.stmts.iter().next().map(|stmt| stmt.span) + block.stmts.get(0).map(|stmt| stmt.span) } #[cfg(test)] diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8211a57b564..79da1f3702e 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -934,6 +934,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "loops", }, + Lint { + name: "iter_next_slice", + group: "style", + desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`", + deprecation: None, + module: "methods", + }, Lint { name: "iter_nth", group: "perf", diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index c30d23de3f8..7f92d0dbdc9 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -40,4 +40,6 @@ fn main() { let _ = (&HashSet::::new()).iter(); //~ WARN equivalent to .iter() let _ = std::path::Path::new("12/34").iter(); //~ WARN equivalent to .iter() let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR equivalent to .iter() + + let _ = (&[1, 2, 3]).iter().next(); //~ WARN equivalent to .iter() } diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 94bc1689619..416056d3fdb 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -40,4 +40,6 @@ fn main() { let _ = (&HashSet::::new()).into_iter(); //~ WARN equivalent to .iter() let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() + + let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() } diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 80e2d104f82..1cd6400b019 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -156,5 +156,11 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not move the LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 26 previous errors +error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` + --> $DIR/into_iter_on_ref.rs:44:26 + | +LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() + | ^^^^^^^^^ help: call directly: `iter` + +error: aborting due to 27 previous errors diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed new file mode 100644 index 00000000000..79c1db87ac3 --- /dev/null +++ b/tests/ui/iter_next_slice.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::iter_next_slice)] + +fn main() { + // test code goes here + let s = [1, 2, 3]; + let v = vec![1, 2, 3]; + + s.get(0); + // Should be replaced by s.get(0) + + s.get(2); + // Should be replaced by s.get(2) + + v.get(5); + // Should be replaced by v.get(5) + + v.get(0); + // Should be replaced by v.get(0) + + let o = Some(5); + o.iter().next(); + // Shouldn't be linted since this is not a Slice or an Array +} diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs new file mode 100644 index 00000000000..ef9a55f3d99 --- /dev/null +++ b/tests/ui/iter_next_slice.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::iter_next_slice)] + +fn main() { + // test code goes here + let s = [1, 2, 3]; + let v = vec![1, 2, 3]; + + s.iter().next(); + // Should be replaced by s.get(0) + + s[2..].iter().next(); + // Should be replaced by s.get(2) + + v[5..].iter().next(); + // Should be replaced by v.get(5) + + v.iter().next(); + // Should be replaced by v.get(0) + + let o = Some(5); + o.iter().next(); + // Shouldn't be linted since this is not a Slice or an Array +} diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr new file mode 100644 index 00000000000..bbf61df0cda --- /dev/null +++ b/tests/ui/iter_next_slice.stderr @@ -0,0 +1,28 @@ +error: Using `.iter().next()` on an array + --> $DIR/iter_next_slice.rs:9:5 + | +LL | s.iter().next(); + | ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)` + | + = note: `-D clippy::iter-next-slice` implied by `-D warnings` + +error: Using `.iter().next()` on a Slice without end index. + --> $DIR/iter_next_slice.rs:12:5 + | +LL | s[2..].iter().next(); + | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` + +error: Using `.iter().next()` on a Slice without end index. + --> $DIR/iter_next_slice.rs:15:5 + | +LL | v[5..].iter().next(); + | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` + +error: Using `.iter().next()` on an array + --> $DIR/iter_next_slice.rs:18:5 + | +LL | v.iter().next(); + | ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index b4227eaf2f8..be37dc16b9a 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -9,7 +9,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; fn main() { let sample = [1; 5]; let len = sample.iter().count(); - if sample.iter().next().is_none() { + if sample.get(0).is_none() { // Empty } sample.iter().cloned().any(|x| x == 1); diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 8884c8e1612..9113aad90dd 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -1,28 +1,28 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:11:28 + --> $DIR/needless_collect.rs:11:29 | LL | let len = sample.iter().collect::>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` | = note: `-D clippy::needless-collect` implied by `-D warnings` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:12:21 + --> $DIR/needless_collect.rs:12:15 | LL | if sample.iter().collect::>().is_empty() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get(0).is_none()` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:15:27 + --> $DIR/needless_collect.rs:15:28 | LL | sample.iter().cloned().collect::>().contains(&1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|x| x == 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:16:34 + --> $DIR/needless_collect.rs:16:35 | LL | sample.iter().map(|x| (x, x)).collect::>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 9893254dff38c2644612c8465ae9abfa553f4ea3 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 31 May 2020 12:08:41 +0200 Subject: Add more corrected code for doc --- clippy_lints/src/methods/mod.rs | 65 ++++++++++++++++++++++++++-------- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/vec.rs | 10 ++++-- clippy_lints/src/verbose_file_reads.rs | 1 + clippy_lints/src/wildcard_imports.rs | 12 +++++-- clippy_lints/src/write.rs | 22 ++++++++++-- clippy_lints/src/zero_div_zero.rs | 6 +++- src/lintlist/mod.rs | 2 +- 8 files changed, 95 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 52ca962e7ef..fbc29efdeb2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -218,7 +218,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let x = Ok::<_, ()>(()); - /// x.ok().expect("why did I do this again?") + /// + /// // Bad + /// x.ok().expect("why did I do this again?"); + /// + /// // Good + /// x.expect("why did I do this again?"); /// ``` pub OK_EXPECT, style, @@ -273,8 +278,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let opt = Some(1); - /// opt.map_or(None, |a| Some(a + 1)) - /// # ; + /// + /// // Bad + /// opt.map_or(None, |a| Some(a + 1)); + /// + /// // Good + /// opt.and_then(|a| Some(a + 1)); /// ``` pub OPTION_MAP_OR_NONE, style, @@ -390,14 +399,19 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, /// /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// single method call using `_.flat_map(_)` /// /// **Known problems:** /// /// **Example:** /// ```rust /// let vec = vec![vec![1]]; + /// + /// // Bad /// vec.iter().map(|x| x.iter()).flatten(); + /// + /// // Good + /// vec.iter().flat_map(|x| x.iter()); /// ``` pub MAP_FLATTEN, pedantic, @@ -417,7 +431,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let vec = vec![1]; + /// + /// // Bad /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2); + /// + /// // Good + /// vec.iter().filter_map(|x| Some(*x * 2)); /// ``` pub FILTER_MAP, pedantic, @@ -634,7 +653,12 @@ declare_clippy_lint! { /// ```rust /// # use std::rc::Rc; /// let x = Rc::new(1); + /// + /// // Bad /// x.clone(); + /// + /// // Good + /// Rc::clone(&x); /// ``` pub CLONE_ON_REF_PTR, restriction, @@ -741,7 +765,12 @@ declare_clippy_lint! { /// **Known problems:** Does not catch multi-byte unicode characters. /// /// **Example:** - /// `_.split("x")` could be `_.split('x')` + /// ```rust,ignore + /// // Bad + /// _.split("x"); + /// + /// // Good + /// _.split('x'); pub SINGLE_CHAR_PATTERN, perf, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" @@ -964,8 +993,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.chars().last()` or - /// `.chars().next_back()` on a `str` to check if it ends with a given char. + /// **What it does:** Checks for usage of `_.chars().last()` or + /// `_.chars().next_back()` on a `str` to check if it ends with a given char. /// /// **Why is this bad?** Readability, this can be written more concisely as /// `_.ends_with(_)`. @@ -975,8 +1004,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let name = "_"; - /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-') - /// # ; + /// + /// // Bad + /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); + /// + /// // Good + /// name.ends_with('_') || name.ends_with('-'); /// ``` pub CHARS_LAST_CMP, style, @@ -1044,17 +1077,15 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); - /// ``` - /// As there is no transformation of the argument this could be written as: - /// ```rust + /// + /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).filter(|&x| x > 2); /// ``` /// /// ```rust /// let _ = (0..4).filter_map(|x| Some(x + 1)); - /// ``` - /// As there is no conditional check on the argument this could be written as: - /// ```rust + /// + /// // As there is no conditional check on the argument this could be written as: /// let _ = (0..4).map(|x| x + 1); /// ``` pub UNNECESSARY_FILTER_MAP, @@ -1075,7 +1106,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let _ = (&vec![3, 4, 5]).into_iter(); + /// + /// // Good + /// let _ = (&vec![3, 4, 5]).iter(); /// ``` pub INTO_ITER_ON_REF, style, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a3b7134a376..51282ab93ef 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -93,7 +93,7 @@ declare_clippy_lint! { /// ```rust /// let x = 1.2331f64; /// let y = 1.2332f64; - /// + /// /// // Bad /// if y == 1.23f64 { } /// if y != x {} // where both are floats diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 1174f421577..a8d4c7620b1 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -17,8 +17,14 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust,ignore - /// foo(&vec![1, 2]) + /// ```rust + /// # fn foo(my_vec: &[u8]) {} + /// + /// // Bad + /// foo(&vec![1, 2]); + /// + /// // Good + /// foo(&[1, 2]); /// ``` pub USELESS_VEC, perf, diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 4d8d4438d88..7247518e19b 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -9,6 +9,7 @@ declare_clippy_lint! { /// /// **Why is this bad?** `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + /// /// **Known problems:** None. /// /// **Example:** diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 32d9a45c37d..b637253bd02 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -19,8 +19,14 @@ declare_clippy_lint! { /// still around. /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// use std::cmp::Ordering::*; + /// foo(Less); + /// + /// // Good + /// use std::cmp::Ordering; + /// foo(Ordering::Less) /// ``` pub ENUM_GLOB_USE, pedantic, @@ -60,15 +66,15 @@ declare_clippy_lint! { /// /// **Example:** /// - /// Bad: /// ```rust,ignore + /// // Bad /// use crate1::*; /// /// foo(); /// ``` /// - /// Good: /// ```rust,ignore + /// // Good /// use crate1::foo; /// /// foo(); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 5f794598052..22ce484b24e 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -23,7 +23,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// println!(""); + /// + /// // Good + /// println!(); /// ``` pub PRINTLN_EMPTY_STRING, style, @@ -32,8 +36,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** This lint warns when you use `print!()` with a format - /// string that - /// ends in a newline. + /// string that ends in a newline. /// /// **Why is this bad?** You should use `println!()` instead, which appends the /// newline. @@ -125,7 +128,12 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); + /// + /// // Bad /// writeln!(buf, ""); + /// + /// // Good + /// writeln!(buf); /// ``` pub WRITELN_EMPTY_STRING, style, @@ -147,7 +155,12 @@ declare_clippy_lint! { /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; + /// + /// // Bad /// write!(buf, "Hello {}!\n", name); + /// + /// // Good + /// writeln!(buf, "Hello {}!", name); /// ``` pub WRITE_WITH_NEWLINE, style, @@ -168,7 +181,12 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); + /// + /// // Bad /// writeln!(buf, "{}", "foo"); + /// + /// // Good + /// writeln!(buf, "foo"); /// ``` pub WRITE_LITERAL, style, diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index fb4700d8743..0820385e01b 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -14,7 +14,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// 0.0f32 / 0.0; + /// // Bad + /// let nan = 0.0f32 / 0.0; + /// + /// // Good + /// let nan = f32::NAN; /// ``` pub ZERO_DIVIDED_BY_ZERO, complexity, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index ab9542a7b9c..6b6e2c7324c 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1735,7 +1735,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "pub_enum_variant_names", group: "pedantic", - desc: "enums where all variants share a prefix/postfix", + desc: "public enums where all variants share a prefix/postfix", deprecation: None, module: "enum_variants", }, -- cgit 1.4.1-3-g733a5 From 137a3b4d3242cfe331f8f9b87c51ac0c431fe160 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 1 Jun 2020 10:16:01 +0200 Subject: Corrected doc PR fixes --- clippy_lints/src/drop_bounds.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 7 +++++-- clippy_lints/src/fallible_impl_from.rs | 12 ++++++++++-- clippy_lints/src/functions.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++++- 6 files changed, 23 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/drop_bounds.rs b/clippy_lints/src/drop_bounds.rs index 4ef963ac314..5a7f759486e 100644 --- a/clippy_lints/src/drop_bounds.rs +++ b/clippy_lints/src/drop_bounds.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// ``` /// Could be written as: /// ```rust - /// fn foo() {} + /// fn foo() {} /// ``` pub DROP_BOUNDS, correctness, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 5f0cd1ec72c..d093025fd3d 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// xs.map(|x| foo(x)) /// /// // Good - /// foo(xs) + /// xs.map(foo) /// ``` /// where `foo(_)` is a plain function that takes the exact argument type of /// `x`. diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 37e24ff34f7..74144fb299d 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -30,8 +30,11 @@ declare_clippy_lint! { /// // Unclear whether a is 1 or 2. /// /// // Good - /// x = 1; - /// let a = 1 + x; + /// let tmp = { + /// x = 1; + /// 1 + /// }; + /// let a = tmp + x; /// ``` pub EVAL_ORDER_DEPENDENCE, complexity, diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 575462f25e6..92812816461 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust,ignore + /// ```rust /// struct Foo(i32); /// /// // Bad @@ -27,13 +27,21 @@ declare_clippy_lint! { /// Foo(s.parse().unwrap()) /// } /// } + /// ``` /// + /// ```rust /// // Good + /// struct Foo(i32); + /// /// use std::convert::TryFrom; /// impl TryFrom for Foo { /// type Error = (); /// fn try_from(s: String) -> Result { - /// s.parse() + /// if let Ok(parsed) = s.parse() { + /// Ok(Foo(parsed)) + /// } else { + /// Err(()) + /// } /// } /// } /// ``` diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 9b5f1dee7f4..325b6cf32a3 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -52,7 +52,7 @@ declare_clippy_lint! { /// ```rust /// fn im_too_long() { /// println!(""); - /// // ... 100 more LoC + /// // ... 100 more LoC /// println!(""); /// } /// ``` diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fbc29efdeb2..a8d5c10d5da 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -436,7 +436,11 @@ declare_clippy_lint! { /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2); /// /// // Good - /// vec.iter().filter_map(|x| Some(*x * 2)); + /// vec.iter().filter_map(|x| if *x == 0 { + /// Some(*x * 2) + /// } else { + /// None + /// }); /// ``` pub FILTER_MAP, pedantic, -- cgit 1.4.1-3-g733a5 From 623faac84ec56fa545163ab81d7e3b759a392353 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sat, 6 Jun 2020 11:50:59 +0200 Subject: Cleanup: Use rustc's `same_types` instead of our `same_tys` --- clippy_lints/src/copies.rs | 14 +++++--------- clippy_lints/src/loops.rs | 8 ++++---- clippy_lints/src/methods/mod.rs | 12 ++++++------ clippy_lints/src/new_without_default.rs | 6 +++--- clippy_lints/src/types.rs | 6 +++--- clippy_lints/src/useless_conversion.rs | 14 +++++++------- clippy_lints/src/utils/mod.rs | 16 +--------------- 7 files changed, 29 insertions(+), 47 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 66722786eab..b6d50bdfa14 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,9 +1,9 @@ -use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_note, span_lint_and_then}; +use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then}; use crate::utils::{SpanlessEq, SpanlessHash}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; use std::collections::hash_map::Entry; @@ -242,15 +242,11 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) { /// Implementation of `MATCH_SAME_ARMS`. fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr<'_>) { - fn same_bindings<'tcx>( - cx: &LateContext<'_, 'tcx>, - lhs: &FxHashMap>, - rhs: &FxHashMap>, - ) -> bool { + fn same_bindings<'tcx>(lhs: &FxHashMap>, rhs: &FxHashMap>) -> bool { lhs.len() == rhs.len() && lhs .iter() - .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| same_tys(cx, l_ty, r_ty))) + .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| TyS::same_type(l_ty, r_ty))) } if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind { @@ -269,7 +265,7 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr<'_>) { (min_index..=max_index).all(|index| arms[index].guard.is_none()) && SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && // all patterns should have the same bindings - same_bindings(cx, &bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat)) + same_bindings(&bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat)) }; let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index dbe41823a9c..57c62d73964 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -8,7 +8,7 @@ use crate::utils::{ multispan_sugg, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, SpanlessEq, }; -use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sugg}; +use crate::utils::{is_type_diagnostic_item, qpath_res, sugg}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -24,7 +24,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::region; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -1256,7 +1256,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) { let receiver_ty = cx.tables.expr_ty(&args[0]); let receiver_ty_adjusted = cx.tables.expr_ty_adjusted(&args[0]); - if same_tys(cx, receiver_ty, receiver_ty_adjusted) { + if TyS::same_type(receiver_ty, receiver_ty_adjusted) { let mut applicability = Applicability::MachineApplicable; let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); span_lint_and_sugg( @@ -1277,7 +1277,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e mutbl: Mutability::Not, }, ); - if same_tys(cx, receiver_ty_adjusted, ref_receiver_ty) { + if TyS::same_type(receiver_ty_adjusted, ref_receiver_ty) { lint_iter_method(cx, args, arg, method_name) } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a9c0ff24fa6..78d69690c2d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -29,9 +29,9 @@ use crate::utils::{ get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, - remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, + remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, + walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1548,7 +1548,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { let contains_self_ty = |ty: Ty<'tcx>| { ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => same_tys(cx, self_ty, inner_ty), + GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) @@ -1575,7 +1575,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { } } - if name == "new" && !same_tys(cx, ret_ty, self_ty) { + if name == "new" && !TyS::same_type(ret_ty, self_ty) { span_lint( cx, NEW_RET_NO_SELF, diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index e556e5d59c1..dd236535c18 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,13 +1,13 @@ use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, return_ty, same_tys, span_lint_hir_and_then}; +use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -93,7 +93,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); let self_ty = cx.tcx.type_of(self_def_id); if_chain! { - if same_tys(cx, self_ty, return_ty(cx, id)); + if TyS::same_type(self_ty, return_ty(cx, id)); if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); then { if self.impling_types.is_none() { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 5ca30d598eb..bc5fe44b30f 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TypeckTables}; +use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckTables}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::Span; @@ -31,7 +31,7 @@ use crate::utils::paths; use crate::utils::{ clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, same_tys, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, + qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; @@ -2556,7 +2556,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind; if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; then { - if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) { + if !TyS::same_type(self.target.ty(), self.body.expr_ty(e)) { return; } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 7fa97b24699..141035a980a 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,12 +1,12 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, + is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -65,7 +65,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" { let a = cx.tables.expr_ty(e); let b = cx.tables.expr_ty(&args[0]); - if same_tys(cx, a, b) { + if TyS::same_type(a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); span_lint_and_sugg( cx, @@ -81,7 +81,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" { let a = cx.tables.expr_ty(e); let b = cx.tables.expr_ty(&args[0]); - if same_tys(cx, a, b) { + if TyS::same_type(a, b) { let sugg = snippet(cx, args[0].span, "").into_owned(); span_lint_and_sugg( cx, @@ -101,7 +101,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym!(result_type)); if let ty::Adt(_, substs) = a.kind; if let Some(a_type) = substs.types().next(); - if same_tys(cx, a_type, b); + if TyS::same_type(a_type, b); then { span_lint_and_help( @@ -131,7 +131,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym!(result_type)); if let ty::Adt(_, substs) = a.kind; if let Some(a_type) = substs.types().next(); - if same_tys(cx, a_type, b); + if TyS::same_type(a_type, b); then { let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); @@ -148,7 +148,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if_chain! { if match_def_path(cx, def_id, &paths::FROM_FROM); - if same_tys(cx, a, b); + if TyS::same_type(a, b); then { let sugg = snippet(cx, args[0].span.source_callsite(), "").into_owned(); diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 2cdb6486fcb..9a6750c51ab 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -40,7 +40,7 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::symbol::{self, kw, Symbol}; @@ -879,20 +879,6 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: hir::HirId) -> T cx.tcx.erase_late_bound_regions(&ret_ty) } -/// Checks if two types are the same. -/// -/// This discards any lifetime annotations, too. -// -// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == -// `for <'b> Foo<'b>`, but not for type parameters). -pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - let a = cx.tcx.erase_late_bound_regions(&Binder::bind(a)); - let b = cx.tcx.erase_late_bound_regions(&Binder::bind(b)); - cx.tcx - .infer_ctxt() - .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok()) -} - /// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind { -- cgit 1.4.1-3-g733a5 From 78f158e80e3a2ec8022e6cd6b2f62b17b3e96b57 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 28 Mar 2020 11:45:13 +0100 Subject: dogfood unnested_or_patterns --- clippy_lints/src/formatting.rs | 8 +--- .../src/methods/manual_saturating_arithmetic.rs | 2 +- clippy_lints/src/methods/mod.rs | 13 ++---- clippy_lints/src/misc.rs | 19 ++++----- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 6 +-- clippy_lints/src/transmute.rs | 47 ++++++++++------------ clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/utils/mod.rs | 9 ++--- 9 files changed, 44 insertions(+), 64 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index eb4b7a826f2..156246fb8bb 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -112,12 +112,8 @@ declare_lint_pass!(Formatting => [ impl EarlyLintPass for Formatting { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { for w in block.stmts.windows(2) { - match (&w[0].kind, &w[1].kind) { - (&StmtKind::Expr(ref first), &StmtKind::Expr(ref second)) - | (&StmtKind::Expr(ref first), &StmtKind::Semi(ref second)) => { - check_missing_else(cx, first, second); - }, - _ => (), + if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&w[0].kind, &w[1].kind) { + check_missing_else(cx, first, second); } } } diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index aaed6d75048..4f5c06e785c 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -57,7 +57,7 @@ pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr< ); } else { match (mm, arith) { - (MinMax::Max, "add") | (MinMax::Max, "mul") | (MinMax::Min, "sub") => (), + (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (), _ => return, } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 78d69690c2d..214cf0c130f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1403,9 +1403,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), - ["as_ptr", "unwrap"] | ["as_ptr", "expect"] => { - lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]) - }, + ["as_ptr", "unwrap" | "expect"] => lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), @@ -1418,12 +1416,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), - ["unwrap_or", arith @ "checked_add"] - | ["unwrap_or", arith @ "checked_sub"] - | ["unwrap_or", arith @ "checked_mul"] => { + ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) }, - ["add"] | ["offset"] | ["sub"] | ["wrapping_offset"] | ["wrapping_add"] | ["wrapping_sub"] => { + ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { check_pointer_offset(cx, expr, arg_lists[0]) }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), @@ -1829,8 +1825,7 @@ fn lint_expect_fun_call( hir::ExprKind::Call(fun, _) => { if let hir::ExprKind::Path(ref p) = fun.kind { match cx.tables.qpath_res(p, fun.hir_id) { - hir::def::Res::Def(hir::def::DefKind::Fn, def_id) - | hir::def::Res::Def(hir::def::DefKind::AssocFn, def_id) => matches!( + hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( cx.tcx.fn_sig(def_id).output().skip_binder().kind, ty::Ref(ty::ReStatic, ..) ), diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 51282ab93ef..f513161bbbc 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -275,17 +275,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints { return; } for arg in iter_input_pats(decl, body) { - match arg.pat.kind { - PatKind::Binding(BindingAnnotation::Ref, ..) | PatKind::Binding(BindingAnnotation::RefMut, ..) => { - span_lint( - cx, - TOPLEVEL_REF_ARG, - arg.pat.span, - "`ref` directly on a function argument is ignored. Consider using a reference type \ - instead.", - ); - }, - _ => {}, + if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind { + span_lint( + cx, + TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. \ + Consider using a reference type instead.", + ); } } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index b8bfa676a16..2eacd3c80c4 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -147,7 +147,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option if let ExprKind::Path(ref qpath) = callee.kind { let res = qpath_res(cx, qpath, callee.hir_id); match res { - Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(..), _) + Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) if !has_drop(cx, cx.tables.expr_ty(expr)) => { Some(args.iter().collect()) diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index f1e223d9a48..a9e6fa329c0 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -71,8 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl { if let hir::Node::Expr(e) = cx.tcx.hir().get(parent_expr) { match e.kind { hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::UnNot, _) - | hir::ExprKind::Unary(hir::UnOp::UnNeg, _) + | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _) | hir::ExprKind::AssignOp(..) => return, _ => {}, } @@ -191,8 +190,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { match expr.kind { hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::UnNot, _) - | hir::ExprKind::Unary(hir::UnOp::UnNeg, _) + | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _) | hir::ExprKind::AssignOp(..) => self.in_binary_expr = true, _ => {}, } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index e24d2c4f495..1869638f6ff 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { e.span, &format!("transmute from a type (`{}`) to itself", from_ty), ), - (&ty::Ref(_, rty, rty_mutbl), &ty::RawPtr(ptr_ty)) => span_lint_and_then( + (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => span_lint_and_then( cx, USELESS_TRANSMUTE, e.span, @@ -321,10 +321,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { let rty_and_mut = ty::TypeAndMut { ty: rty, - mutbl: rty_mutbl, + mutbl: *rty_mutbl, }; - let sugg = if ptr_ty == rty_and_mut { + let sugg = if *ptr_ty == rty_and_mut { arg.as_ty(to_ty) } else { arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty) @@ -334,7 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } }, ), - (&ty::Int(_), &ty::RawPtr(_)) | (&ty::Uint(_), &ty::RawPtr(_)) => span_lint_and_then( + (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => span_lint_and_then( cx, USELESS_TRANSMUTE, e.span, @@ -350,16 +350,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } }, ), - (&ty::Float(_), &ty::Ref(..)) - | (&ty::Float(_), &ty::RawPtr(_)) - | (&ty::Char, &ty::Ref(..)) - | (&ty::Char, &ty::RawPtr(_)) => span_lint( + (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_)) => span_lint( cx, WRONG_TRANSMUTE, e.span, &format!("transmute from a `{}` to a pointer", from_ty), ), - (&ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint( + (ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint( cx, CROSSPOINTER_TRANSMUTE, e.span, @@ -368,7 +365,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { from_ty, to_ty ), ), - (_, &ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint( + (_, ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint( cx, CROSSPOINTER_TRANSMUTE, e.span, @@ -377,7 +374,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { from_ty, to_ty ), ), - (&ty::RawPtr(from_pty), &ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then( + (ty::RawPtr(from_pty), ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then( cx, TRANSMUTE_PTR_TO_REF, e.span, @@ -388,13 +385,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ), |diag| { let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let (deref, cast) = if mutbl == Mutability::Mut { + let (deref, cast) = if *mutbl == Mutability::Mut { ("&mut *", "*mut") } else { ("&*", "*const") }; - let arg = if from_pty.ty == to_ref_ty { + let arg = if from_pty.ty == *to_ref_ty { arg } else { arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty))) @@ -408,7 +405,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), - (&ty::Int(ast::IntTy::I32), &ty::Char) | (&ty::Uint(ast::UintTy::U32), &ty::Char) => { + (ty::Int(ast::IntTy::I32) | ty::Uint(ast::UintTy::U32), &ty::Char) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_CHAR, @@ -430,13 +427,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { }, ) }, - (&ty::Ref(_, ty_from, from_mutbl), &ty::Ref(_, ty_to, to_mutbl)) => { + (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => { if_chain! { if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind); if let ty::Uint(ast::UintTy::U8) = slice_ty.kind; if from_mutbl == to_mutbl; then { - let postfix = if from_mutbl == Mutability::Mut { + let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" @@ -465,13 +462,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, - mutbl: from_mutbl + mutbl: *from_mutbl }; - let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl }; + let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl }; let sugg_paren = arg .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); - let sugg = if to_mutbl == Mutability::Mut { + let sugg = if *to_mutbl == Mutability::Mut { sugg_paren.mut_addr_deref() } else { sugg_paren.addr_deref() @@ -488,19 +485,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } } }, - (&ty::RawPtr(_), &ty::RawPtr(to_ty)) => span_lint_and_then( + (ty::RawPtr(_), ty::RawPtr(to_ty)) => span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, e.span, "transmute from a pointer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { - let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty)); + let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty)); diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified); } }, ), - (&ty::Int(ast::IntTy::I8), &ty::Bool) | (&ty::Uint(ast::UintTy::U8), &ty::Bool) => { + (ty::Int(ast::IntTy::I8) | ty::Uint(ast::UintTy::U8), ty::Bool) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_BOOL, @@ -518,7 +515,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { }, ) }, - (&ty::Int(_), &ty::Float(_)) | (&ty::Uint(_), &ty::Float(_)) => span_lint_and_then( + (ty::Int(_) | ty::Uint(_), ty::Float(_)) => span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, e.span, @@ -541,7 +538,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), - (&ty::Float(float_ty), &ty::Int(_)) | (&ty::Float(float_ty), &ty::Uint(_)) => span_lint_and_then( + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, e.span, @@ -585,7 +582,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), - (&ty::Adt(ref from_adt, ref from_substs), &ty::Adt(ref to_adt, ref to_substs)) => { + (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => { if from_adt.did != to_adt.did || !COLLECTIONS.iter().any(|path| match_def_path(cx, to_adt.did, path)) { return; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 8b971e7064b..036dd16a224 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -101,7 +101,7 @@ fn collect_unwrap_info<'a, 'tcx>( if let ExprKind::Binary(op, left, right) = &expr.kind { match (invert, op.node) { - (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => { + (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => { let mut unwrap_info = collect_unwrap_info(cx, left, branch, invert); unwrap_info.append(&mut collect_unwrap_info(cx, right, branch, invert)); return unwrap_info; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 8f8aff622f4..7c823810265 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,6 +1,7 @@ #[macro_use] pub mod sym; +#[allow(clippy::module_name_repetitions)] pub mod ast_utils; pub mod attrs; pub mod author; @@ -73,7 +74,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { let parent_id = cx.tcx.hir().get_parent_item(id); match cx.tcx.hir().get(parent_id) { Node::Item(&Item { - kind: ItemKind::Const(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), .. }) | Node::TraitItem(&TraitItem { @@ -84,11 +85,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { kind: ImplItemKind::Const(..), .. }) - | Node::AnonConst(_) - | Node::Item(&Item { - kind: ItemKind::Static(..), - .. - }) => true, + | Node::AnonConst(_) => true, Node::Item(&Item { kind: ItemKind::Fn(ref sig, ..), .. -- cgit 1.4.1-3-g733a5 From 6bf5434e19ce6d2a501589d1fcbc0d1748c531a6 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Wed, 24 Jun 2020 01:01:23 +0200 Subject: copy_on_clone - add machine applicability --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/clone_on_copy.fixed | 40 +++++++++++++++++++++++++++ tests/ui/clone_on_copy.rs | 40 +++++++++++++++++++++++++++ tests/ui/clone_on_copy.stderr | 34 +++++++++++++++++++++++ tests/ui/unnecessary_clone.rs | 25 ----------------- tests/ui/unnecessary_clone.stderr | 58 ++++++++++----------------------------- 6 files changed, 129 insertions(+), 70 deletions(-) create mode 100644 tests/ui/clone_on_copy.fixed create mode 100644 tests/ui/clone_on_copy.rs create mode 100644 tests/ui/clone_on_copy.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 214cf0c130f..74fefa65612 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2041,7 +2041,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir: } span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| { if let Some((text, snip)) = snip { - diag.span_suggestion(expr.span, text, snip, Applicability::Unspecified); + diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); } }); } diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed new file mode 100644 index 00000000000..1f0ca101757 --- /dev/null +++ b/tests/ui/clone_on_copy.fixed @@ -0,0 +1,40 @@ +// run-rustfix + +#![allow( + unused, + clippy::redundant_clone, + clippy::deref_addrof, + clippy::no_effect, + clippy::unnecessary_operation +)] + +use std::cell::RefCell; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} + +fn is_ascii(ch: char) -> bool { + ch.is_ascii() +} + +fn clone_on_copy() { + 42; + + vec![1].clone(); // ok, not a Copy type + Some(vec![1]).clone(); // ok, not a Copy type + *(&42); + + let rc = RefCell::new(0); + *rc.borrow(); + + // Issue #4348 + let mut x = 43; + let _ = &x.clone(); // ok, getting a ref + 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate + is_ascii('z'); + + // Issue #5436 + let mut vec = Vec::new(); + vec.push(42); +} diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs new file mode 100644 index 00000000000..ca39a654b4f --- /dev/null +++ b/tests/ui/clone_on_copy.rs @@ -0,0 +1,40 @@ +// run-rustfix + +#![allow( + unused, + clippy::redundant_clone, + clippy::deref_addrof, + clippy::no_effect, + clippy::unnecessary_operation +)] + +use std::cell::RefCell; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} + +fn is_ascii(ch: char) -> bool { + ch.is_ascii() +} + +fn clone_on_copy() { + 42.clone(); + + vec![1].clone(); // ok, not a Copy type + Some(vec![1]).clone(); // ok, not a Copy type + (&42).clone(); + + let rc = RefCell::new(0); + rc.borrow().clone(); + + // Issue #4348 + let mut x = 43; + let _ = &x.clone(); // ok, getting a ref + 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate + is_ascii('z'.clone()); + + // Issue #5436 + let mut vec = Vec::new(); + vec.push(42.clone()); +} diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr new file mode 100644 index 00000000000..ec2faf4ab40 --- /dev/null +++ b/tests/ui/clone_on_copy.stderr @@ -0,0 +1,34 @@ +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:22:5 + | +LL | 42.clone(); + | ^^^^^^^^^^ help: try removing the `clone` call: `42` + | + = note: `-D clippy::clone-on-copy` implied by `-D warnings` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:26:5 + | +LL | (&42).clone(); + | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:29:5 + | +LL | rc.borrow().clone(); + | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:35:14 + | +LL | is_ascii('z'.clone()); + | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` + +error: using `clone` on a `Copy` type + --> $DIR/clone_on_copy.rs:39:14 + | +LL | vec.push(42.clone()); + | ^^^^^^^^^^ help: try removing the `clone` call: `42` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index f1cc5b564c1..2c9d4d39e6c 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -13,31 +13,6 @@ impl SomeTrait for SomeImpl {} fn main() {} -fn is_ascii(ch: char) -> bool { - ch.is_ascii() -} - -fn clone_on_copy() { - 42.clone(); - - vec![1].clone(); // ok, not a Copy type - Some(vec![1]).clone(); // ok, not a Copy type - (&42).clone(); - - let rc = RefCell::new(0); - rc.borrow().clone(); - - // Issue #4348 - let mut x = 43; - let _ = &x.clone(); // ok, getting a ref - 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate - is_ascii('z'.clone()); - - // Issue #5436 - let mut vec = Vec::new(); - vec.push(42.clone()); -} - fn clone_on_ref_ptr() { let rc = Rc::new(true); let arc = Arc::new(true); diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 6176a2bc464..113fab69009 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -1,37 +1,5 @@ -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:21:5 - | -LL | 42.clone(); - | ^^^^^^^^^^ help: try removing the `clone` call: `42` - | - = note: `-D clippy::clone-on-copy` implied by `-D warnings` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:25:5 - | -LL | (&42).clone(); - | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:28:5 - | -LL | rc.borrow().clone(); - | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:34:14 - | -LL | is_ascii('z'.clone()); - | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` - -error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:38:14 - | -LL | vec.push(42.clone()); - | ^^^^^^^^^^ help: try removing the `clone` call: `42` - error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:48:5 + --> $DIR/unnecessary_clone.rs:23:5 | LL | rc.clone(); | ^^^^^^^^^^ help: try this: `Rc::::clone(&rc)` @@ -39,43 +7,45 @@ LL | rc.clone(); = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:51:5 + --> $DIR/unnecessary_clone.rs:26:5 | LL | arc.clone(); | ^^^^^^^^^^^ help: try this: `Arc::::clone(&arc)` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:54:5 + --> $DIR/unnecessary_clone.rs:29:5 | LL | rcweak.clone(); | ^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&rcweak)` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:57:5 + --> $DIR/unnecessary_clone.rs:32:5 | LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:61:33 + --> $DIR/unnecessary_clone.rs:36:33 | LL | let _: Arc = x.clone(); | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:65:5 + --> $DIR/unnecessary_clone.rs:40:5 | LL | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` + | + = note: `-D clippy::clone-on-copy` implied by `-D warnings` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:67:5 + --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:73:22 + --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); | ^^^^^^^^^ @@ -91,13 +61,13 @@ LL | let z: &Vec<_> = <&std::vec::Vec>::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:109:20 + --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:114:22 + --> $DIR/unnecessary_clone.rs:89:22 | LL | let _ = &mut encoded.clone(); | ^^^^^^^^^^^^^^^ @@ -112,7 +82,7 @@ LL | let _ = &mut <&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:115:18 + --> $DIR/unnecessary_clone.rs:90:18 | LL | let _ = &encoded.clone(); | ^^^^^^^^^^^^^^^ @@ -126,5 +96,5 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let _ = &<&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From 5150277a4f765bb113e163adc7eb495dcbb57129 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sun, 31 May 2020 15:37:21 -0700 Subject: Used clippy to clean itself --- clippy_lints/src/attrs.rs | 14 ++------ clippy_lints/src/if_let_mutex.rs | 8 ++--- clippy_lints/src/len_zero.rs | 8 ++--- clippy_lints/src/literal_representation.rs | 7 ++-- clippy_lints/src/loops.rs | 26 +++----------- clippy_lints/src/methods/mod.rs | 6 +--- clippy_lints/src/methods/unnecessary_filter_map.rs | 6 +--- clippy_lints/src/minmax.rs | 21 +++++++----- clippy_lints/src/misc.rs | 8 ++--- clippy_lints/src/option_if_let_else.rs | 4 ++- clippy_lints/src/returns.rs | 9 ++--- clippy_lints/src/shadow.rs | 10 ++---- clippy_lints/src/types.rs | 12 +++---- clippy_lints/src/use_self.rs | 8 ++--- clippy_lints/src/utils/attrs.rs | 14 ++++---- clippy_lints/src/utils/mod.rs | 40 +++++----------------- clippy_lints/src/utils/numeric_literal.rs | 6 ++-- clippy_lints/src/utils/sugg.rs | 8 ++--- clippy_lints/src/write.rs | 6 ++-- 19 files changed, 67 insertions(+), 154 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2d0855f6895..cfad9d79f2b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -481,15 +481,11 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { } fn is_relevant_block(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, block: &Block<'_>) -> bool { - if let Some(stmt) = block.stmts.first() { - match &stmt.kind { + block.stmts.first().map_or(block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)), |stmt| match &stmt.kind { StmtKind::Local(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, tables, expr), _ => false, - } - } else { - block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)) - } + }) } fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: &Expr<'_>) -> bool { @@ -499,11 +495,7 @@ fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: & ExprKind::Ret(None) | ExprKind::Break(_, None) => false, ExprKind::Call(path_expr, _) => { if let ExprKind::Path(qpath) = &path_expr.kind { - if let Some(fun_id) = tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() { - !match_def_path(cx, fun_id, &paths::BEGIN_PANIC) - } else { - true - } + tables.qpath_res(qpath, path_expr.hir_id).opt_def_id().map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)) } else { true } diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index f911cb68ea5..7e44618e90e 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -135,13 +135,9 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { } } -impl<'tcx> ArmVisitor<'_, 'tcx> { +impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool { - if let Some(arm_mutex) = self.found_mutex { - SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex) - } else { - false - } + self.found_mutex.map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)) } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 26d96428771..f57fa830adc 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -303,14 +303,10 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr)); match ty.kind { ty::Dynamic(ref tt, ..) => { - if let Some(principal) = tt.principal() { - cx.tcx + tt.principal().map_or(false, |principal| cx.tcx .associated_items(principal.def_id()) .in_definition_order() - .any(|item| is_is_empty(cx, &item)) - } else { - false - } + .any(|item| is_is_empty(cx, &item))) }, ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), ty::Adt(id, _) => has_is_empty_impl(cx, id.did), diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7ba43562d7d..ea2e23bd3a1 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -264,10 +264,11 @@ impl LiteralDigitGrouping { let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent { (exponent, &["32", "64"][..], 'f') - } else if let Some(fraction) = &mut num_lit.fraction { - (fraction, &["32", "64"][..], 'f') } else { - (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i') + num_lit.fraction.as_mut().map_or( + (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), + |fraction| (fraction, &["32", "64"][..], 'f') + ) }; let mut split = part.rsplit('_'); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index d821b513484..8d48f39a045 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -687,11 +687,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { } }, ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => { - if let Some(ref e) = *e { - combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak) - } else { - NeverLoopResult::AlwaysBreak - } + e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)) }, ExprKind::InlineAsm(ref asm) => asm .operands @@ -1882,11 +1878,7 @@ fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.kind { ty::Array(_, n) => { - if let Some(val) = n.try_eval_usize(cx.tcx, cx.param_env) { - (0..=32).contains(&val) - } else { - false - } + n.try_eval_usize(cx.tcx, cx.param_env).map_or(false, |val| (0..=32).contains(&val)) }, _ => false, } @@ -1899,11 +1891,7 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr< return None; } if let StmtKind::Local(ref local) = block.stmts[0].kind { - if let Some(expr) = local.init { - Some(expr) - } else { - None - } + local.init.map(|expr| expr) } else { None } @@ -2023,15 +2011,11 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if let PatKind::Binding(.., ident, _) = local.pat.kind { self.name = Some(ident.name); - self.state = if let Some(ref init) = local.init { - if is_integer_const(&self.cx, init, 0) { + self.state = local.init.as_ref().map_or(VarState::Declared, |init| if is_integer_const(&self.cx, init, 0) { VarState::Warn } else { VarState::Declared - } - } else { - VarState::Declared - } + }) } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 160304865c5..ddad16e163e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2461,11 +2461,7 @@ fn derefs_to_slice<'tcx>( ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)), ty::Array(_, size) => { - if let Some(size) = size.try_eval_usize(cx.tcx, cx.param_env) { - size < 32 - } else { - false - } + size.try_eval_usize(cx.tcx, cx.param_env).map_or(false, |size| size < 32) }, ty::Ref(_, inner, _) => may_slice(cx, inner), _ => false, diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index fdcba110542..97909c97fc7 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -78,11 +78,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc (true, true) }, hir::ExprKind::Block(ref block, _) => { - if let Some(expr) = &block.expr { - check_expression(cx, arg_id, &expr) - } else { - (false, false) - } + block.expr.as_ref().map_or((false, false), |expr| check_expression(cx, arg_id, &expr)) }, hir::ExprKind::Match(_, arms, _) => { let mut found_mapping = false; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 0a2d577396a..a3d1a500aa7 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -86,16 +86,19 @@ fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Opt if args.len() != 2 { return None; } - if let Some(c) = constant_simple(cx, cx.tables(), &args[0]) { - if constant_simple(cx, cx.tables(), &args[1]).is_none() { - // otherwise ignore - Some((m, c, &args[1])) + constant_simple(cx, cx.tables, &args[0]).map_or_else( + || if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) { + Some((m, c, &args[0])) } else { None + }, + |c| { + if constant_simple(cx, cx.tables, &args[1]).is_none() { + // otherwise ignore + Some((c, &args[1])) + } else { + None + } } - } else if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) { - Some((m, c, &args[0])) - } else { - None - } + ).map(|(c, arg)| (m, c, arg)) } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 6a256627bd1..5b0f9d6e3ec 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -682,16 +682,12 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: /// `unused_variables`'s idea /// of what it means for an expression to be "used". fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(parent) = get_parent_expr(cx, expr) { - match parent.kind { + get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind { ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => { SpanlessEq::new(cx).eq_expr(rhs, expr) }, _ => is_used(cx, parent), - } - } else { - true - } + }) } /// Tests whether an expression is in a macro expansion (e.g., something diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index be0c44cae34..b6d08b8ae17 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -37,6 +37,7 @@ declare_clippy_lint! { /// /// ```rust /// # let optional: Option = Some(0); + /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = if let Some(foo) = optional { /// foo /// } else { @@ -54,9 +55,10 @@ declare_clippy_lint! { /// /// ```rust /// # let optional: Option = Some(0); + /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = optional.map_or(5, |foo| foo); /// let _ = optional.map_or_else(||{ - /// let y = do_complicated_function; + /// let y = do_complicated_function(); /// y*y /// }, |foo| foo); /// ``` diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 3c939744173..4d54e3117fa 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -259,15 +259,10 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - if let Some(rpos) = fn_source.rfind("->") { - #[allow(clippy::cast_possible_truncation)] - ( + fn_source.rfind("->").map_or((ty.span, Applicability::MaybeIncorrect), |rpos| ( ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), Applicability::MachineApplicable, - ) - } else { - (ty.span, Applicability::MaybeIncorrect) - } + )) } else { (ty.span, Applicability::MaybeIncorrect) }; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 7da47ee4ff9..de94fb87147 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -164,15 +164,11 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & } fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { - let var_ty = cx.tables().node_type_opt(pat_id); - if let Some(var_ty) = var_ty { - match var_ty.kind { + let var_ty = cx.tables.node_type_opt(pat_id); + var_ty.map_or(false, |var_ty| match var_ty.kind { ty::Adt(..) => false, _ => true, - } - } else { - false - } + }) } fn check_pat<'tcx>( diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index b1345f0de5e..df87c1b9802 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1205,16 +1205,14 @@ fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast // has parens on the outside, they are no longer needed. let mut applicability = Applicability::MachineApplicable; let opt = snippet_opt(cx, op.span); - let sugg = if let Some(ref snip) = opt { - if should_strip_parens(op, snip) { + let sugg = opt.as_ref().map_or_else(|| { + applicability = Applicability::HasPlaceholders; + ".." + }, |snip| if should_strip_parens(op, snip) { &snip[1..snip.len() - 1] } else { snip.as_str() - } - } else { - applicability = Applicability::HasPlaceholders; - ".." - }; + }); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f85db1e2006..eac7ae2358e 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -167,14 +167,10 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind; then { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; - let should_check = if let Some(ref params) = *parameters { - !params.parenthesized && !params.args.iter().any(|arg| match arg { + let should_check = parameters.as_ref().map_or(true, |params| !params.parenthesized && !params.args.iter().any(|arg| match arg { GenericArg::Lifetime(_) => true, _ => false, - }) - } else { - true - }; + })); if should_check { let visitor = &mut UseSelfVisitor { diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index 4dcf6c105ec..2d72f9c3fe1 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -65,8 +65,7 @@ pub fn get_attr<'a>( }; let attr_segments = &attr.path.segments; if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" { - if let Some(deprecation_status) = - BUILTIN_ATTRIBUTES + BUILTIN_ATTRIBUTES .iter() .find_map(|(builtin_name, deprecation_status)| { if *builtin_name == attr_segments[1].ident.to_string() { @@ -74,8 +73,10 @@ pub fn get_attr<'a>( } else { None } - }) - { + }).map_or_else(|| { + sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); + false + }, |deprecation_status| { let mut diag = sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute"); match *deprecation_status { DeprecationStatus::Deprecated => { @@ -97,10 +98,7 @@ pub fn get_attr<'a>( attr_segments[1].ident.to_string() == name }, } - } else { - sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); - false - } + }) } else { false } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 99ba7d64331..6f23e968006 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -153,11 +153,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap(); let trt_id = cx.tcx.trait_of_item(def_id); - if let Some(trt_id) = trt_id { - match_def_path(cx, trt_id, path) - } else { - false - } + trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } /// Checks if an expression references a variable of the given name. @@ -600,21 +596,13 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>( /// // ^^^^^^^^^^ /// ``` pub fn first_line_of_span(cx: &T, span: Span) -> Span { - if let Some(first_char_pos) = first_char_in_first_line(cx, span) { - span.with_lo(first_char_pos) - } else { - span - } + first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) } fn first_char_in_first_line(cx: &T, span: Span) -> Option { let line_span = line_span(cx, span); - if let Some(snip) = snippet_opt(cx, line_span) { - snip.find(|c: char| !c.is_whitespace()) - .map(|pos| line_span.lo() + BytePos::from_usize(pos)) - } else { - None - } + snippet_opt(cx, line_span).and_then(|snip| snip.find(|c: char| !c.is_whitespace()) + .map(|pos| line_span.lo() + BytePos::from_usize(pos))) } /// Returns the indentation of the line of a span @@ -626,11 +614,7 @@ fn first_char_in_first_line(cx: &T, span: Span) -> Option(cx: &T, span: Span) -> Option { - if let Some(snip) = snippet_opt(cx, line_span(cx, span)) { - snip.find(|c: char| !c.is_whitespace()) - } else { - None - } + snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } /// Extends the span to the beginning of the spans line, incl. whitespaces. @@ -738,8 +722,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio let enclosing_node = map .get_enclosing_scope(hir_id) .and_then(|enclosing_id| map.find(enclosing_id)); - if let Some(node) = enclosing_node { - match node { + enclosing_node.and_then(|node| match node { Node::Block(block) => Some(block), Node::Item(&Item { kind: ItemKind::Fn(_, _, eid), @@ -753,10 +736,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio _ => None, }, _ => None, - } - } else { - None - } + }) } /// Returns the base type for HIR references and pointers. @@ -1328,11 +1308,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - if let Some(did) = did { - must_use_attr(&cx.tcx.get_attrs(did)).is_some() - } else { - false - } + did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some()) } pub fn is_no_std_crate(krate: &Crate<'_>) -> bool { diff --git a/clippy_lints/src/utils/numeric_literal.rs b/clippy_lints/src/utils/numeric_literal.rs index 99413153d49..7a79741b30b 100644 --- a/clippy_lints/src/utils/numeric_literal.rs +++ b/clippy_lints/src/utils/numeric_literal.rs @@ -200,12 +200,10 @@ impl<'a> NumericLiteral<'a> { fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) { debug_assert!(lit_kind.is_numeric()); - if let Some(suffix_length) = lit_suffix_length(lit_kind) { + lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| { let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length); (unsuffixed, Some(suffix)) - } else { - (src, None) - } + }) } fn lit_suffix_length(lit_kind: &LitKind) -> Option { diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 8fc97f2fd64..20bea3cbabe 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -492,8 +492,7 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { /// before it on its line. fn indentation(cx: &T, span: Span) -> Option { let lo = cx.sess().source_map().lookup_char_pos(span.lo()); - if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) { - if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { + lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */).and_then(|line| if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { // We can mix char and byte positions here because we only consider `[ \t]`. if lo.col == CharPos(pos) { Some(line[..pos].into()) @@ -502,10 +501,7 @@ fn indentation(cx: &T, span: Span) -> Option { } } else { None - } - } else { - None - } + }) } /// Convenience extension trait for `DiagnosticBuilder`. diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 732f4b28e06..3b10b7b82a0 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -297,12 +297,10 @@ impl EarlyLintPass for Write { if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) { if fmt_str.symbol == Symbol::intern("") { let mut applicability = Applicability::MachineApplicable; - let suggestion = if let Some(e) = expr { - snippet_with_applicability(cx, e.span, "v", &mut applicability) - } else { + let suggestion = expr.map_or_else(|| { applicability = Applicability::HasPlaceholders; Cow::Borrowed("v") - }; + }, |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable)); span_lint_and_sugg( cx, -- cgit 1.4.1-3-g733a5 From 6ce981225b73d6c3514b0abb759a5282521a17d9 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Thu, 25 Jun 2020 11:58:47 -0700 Subject: Clean existing lint code to match new lint --- clippy_lints/src/attrs.rs | 14 +++-- clippy_lints/src/if_let_mutex.rs | 5 +- clippy_lints/src/len_zero.rs | 12 ++-- clippy_lints/src/literal_representation.rs | 10 ++-- clippy_lints/src/loops.rs | 20 ++++--- clippy_lints/src/methods/mod.rs | 6 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 7 ++- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 8 +-- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/returns.rs | 18 +++--- clippy_lints/src/shadow.rs | 6 +- clippy_lints/src/types.rs | 21 ++++--- clippy_lints/src/use_self.rs | 7 ++- clippy_lints/src/utils/attrs.rs | 65 ++++++++++++---------- clippy_lints/src/utils/mod.rs | 32 ++++++----- clippy_lints/src/utils/sugg.rs | 16 ++++-- clippy_lints/src/write.rs | 11 ++-- 18 files changed, 147 insertions(+), 115 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index cfad9d79f2b..c4397560d7d 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -480,12 +480,15 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { } } -fn is_relevant_block(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, block: &Block<'_>) -> bool { - block.stmts.first().map_or(block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)), |stmt| match &stmt.kind { +fn is_relevant_block(cx: &LateContext<'_, '_>, tables: &ty::TypeckTables<'_>, block: &Block<'_>) -> bool { + block.stmts.first().map_or( + block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)), + |stmt| match &stmt.kind { StmtKind::Local(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, tables, expr), _ => false, - }) + }, + ) } fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: &Expr<'_>) -> bool { @@ -495,7 +498,10 @@ fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: & ExprKind::Ret(None) | ExprKind::Break(_, None) => false, ExprKind::Call(path_expr, _) => { if let ExprKind::Path(qpath) = &path_expr.kind { - tables.qpath_res(qpath, path_expr.hir_id).opt_def_id().map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)) + tables + .qpath_res(qpath, path_expr.hir_id) + .opt_def_id() + .map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)) } else { true } diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 7e44618e90e..5426e14ead5 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -136,8 +136,9 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { } impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { - fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool { - self.found_mutex.map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)) + fn same_mutex(&self, cx: &LateContext<'_, '_>, op_mutex: &Expr<'_>) -> bool { + self.found_mutex + .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)) } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index f57fa830adc..1b09328ceab 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -302,12 +302,12 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr)); match ty.kind { - ty::Dynamic(ref tt, ..) => { - tt.principal().map_or(false, |principal| cx.tcx - .associated_items(principal.def_id()) - .in_definition_order() - .any(|item| is_is_empty(cx, &item))) - }, + ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { + cx.tcx + .associated_items(principal.def_id()) + .in_definition_order() + .any(|item| is_is_empty(cx, &item)) + }), ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), ty::Adt(id, _) => has_is_empty_impl(cx, id.did), ty::Array(..) | ty::Slice(..) | ty::Str => true, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index ea2e23bd3a1..a36fdca5d5d 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -265,10 +265,12 @@ impl LiteralDigitGrouping { let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent { (exponent, &["32", "64"][..], 'f') } else { - num_lit.fraction.as_mut().map_or( - (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), - |fraction| (fraction, &["32", "64"][..], 'f') - ) + num_lit + .fraction + .as_mut() + .map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| { + (fraction, &["32", "64"][..], 'f') + }) }; let mut split = part.rsplit('_'); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 8d48f39a045..b803d753b6d 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -686,9 +686,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { NeverLoopResult::AlwaysBreak } }, - ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => { - e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)) - }, + ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| { + combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak) + }), ExprKind::InlineAsm(ref asm) => asm .operands .iter() @@ -1877,9 +1877,9 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.kind { - ty::Array(_, n) => { - n.try_eval_usize(cx.tcx, cx.param_env).map_or(false, |val| (0..=32).contains(&val)) - }, + ty::Array(_, n) => n + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |val| (0..=32).contains(&val)), _ => false, } } @@ -1891,7 +1891,7 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr< return None; } if let StmtKind::Local(ref local) = block.stmts[0].kind { - local.init.map(|expr| expr) + local.init //.map(|expr| expr) } else { None } @@ -2011,11 +2011,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if let PatKind::Binding(.., ident, _) = local.pat.kind { self.name = Some(ident.name); - self.state = local.init.as_ref().map_or(VarState::Declared, |init| if is_integer_const(&self.cx, init, 0) { + self.state = local.init.as_ref().map_or(VarState::Declared, |init| { + if is_integer_const(&self.cx, init, 0) { VarState::Warn } else { VarState::Declared - }) + } + }) } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ddad16e163e..f1c8894c0ee 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2460,9 +2460,9 @@ fn derefs_to_slice<'tcx>( ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)), - ty::Array(_, size) => { - size.try_eval_usize(cx.tcx, cx.param_env).map_or(false, |size| size < 32) - }, + ty::Array(_, size) => size + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |size| size < 32), ty::Ref(_, inner, _) => may_slice(cx, inner), _ => false, } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 97909c97fc7..75e123eb593 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -77,9 +77,10 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } (true, true) }, - hir::ExprKind::Block(ref block, _) => { - block.expr.as_ref().map_or((false, false), |expr| check_expression(cx, arg_id, &expr)) - }, + hir::ExprKind::Block(ref block, _) => block + .expr + .as_ref() + .map_or((false, false), |expr| check_expression(cx, arg_id, &expr)), hir::ExprKind::Match(_, arms, _) => { let mut found_mapping = false; let mut found_filtering = false; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 6ec7f8cae5d..5eb8398d68e 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MinMaxPass { } } -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Clone, Copy)] enum MinMax { Min, Max, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 5b0f9d6e3ec..3d4225f36a7 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -683,11 +683,9 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: /// of what it means for an expression to be "used". fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind { - ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => { - SpanlessEq::new(cx).eq_expr(rhs, expr) - }, - _ => is_used(cx, parent), - }) + ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr), + _ => is_used(cx, parent), + }) } /// Tests whether an expression is in a macro expansion (e.g., something diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 7e299dd5fd9..ab9ea76a838 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -260,7 +260,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OptionIfLetElse { detection.some_expr, if detection.wrap_braces { " }" } else { "" }, ), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 3c939744173..faef7e724dd 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -259,15 +259,15 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - if let Some(rpos) = fn_source.rfind("->") { - #[allow(clippy::cast_possible_truncation)] - ( - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - } else { - (ty.span, Applicability::MaybeIncorrect) - } + fn_source + .rfind("->") + .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) } else { (ty.span, Applicability::MaybeIncorrect) }; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index de94fb87147..f16db2df3a9 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -166,9 +166,9 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { let var_ty = cx.tables.node_type_opt(pat_id); var_ty.map_or(false, |var_ty| match var_ty.kind { - ty::Adt(..) => false, - _ => true, - }) + ty::Adt(..) => false, + _ => true, + }) } fn check_pat<'tcx>( diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index df87c1b9802..d6f31a99bb3 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1205,14 +1205,19 @@ fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast // has parens on the outside, they are no longer needed. let mut applicability = Applicability::MachineApplicable; let opt = snippet_opt(cx, op.span); - let sugg = opt.as_ref().map_or_else(|| { - applicability = Applicability::HasPlaceholders; - ".." - }, |snip| if should_strip_parens(op, snip) { - &snip[1..snip.len() - 1] - } else { - snip.as_str() - }); + let sugg = opt.as_ref().map_or_else( + || { + applicability = Applicability::HasPlaceholders; + ".." + }, + |snip| { + if should_strip_parens(op, snip) { + &snip[1..snip.len() - 1] + } else { + snip.as_str() + } + }, + ); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index eac7ae2358e..39a8c020872 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -167,10 +167,13 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind; then { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; - let should_check = parameters.as_ref().map_or(true, |params| !params.parenthesized && !params.args.iter().any(|arg| match arg { + let should_check = parameters.as_ref().map_or( + true, + |params| !params.parenthesized && !params.args.iter().any(|arg| match arg { GenericArg::Lifetime(_) => true, _ => false, - })); + }) + ); if should_check { let visitor = &mut UseSelfVisitor { diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index 2d72f9c3fe1..4bb4b087c55 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -66,39 +66,44 @@ pub fn get_attr<'a>( let attr_segments = &attr.path.segments; if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" { BUILTIN_ATTRIBUTES - .iter() - .find_map(|(builtin_name, deprecation_status)| { - if *builtin_name == attr_segments[1].ident.to_string() { - Some(deprecation_status) - } else { - None - } - }).map_or_else(|| { - sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); - false - }, |deprecation_status| { - let mut diag = sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute"); - match *deprecation_status { - DeprecationStatus::Deprecated => { - diag.emit(); - false - }, - DeprecationStatus::Replaced(new_name) => { - diag.span_suggestion( - attr_segments[1].ident.span, - "consider using", - new_name.to_string(), - Applicability::MachineApplicable, - ); - diag.emit(); + .iter() + .find_map(|(builtin_name, deprecation_status)| { + if *builtin_name == attr_segments[1].ident.to_string() { + Some(deprecation_status) + } else { + None + } + }) + .map_or_else( + || { + sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); false }, - DeprecationStatus::None => { - diag.cancel(); - attr_segments[1].ident.to_string() == name + |deprecation_status| { + let mut diag = + sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute"); + match *deprecation_status { + DeprecationStatus::Deprecated => { + diag.emit(); + false + }, + DeprecationStatus::Replaced(new_name) => { + diag.span_suggestion( + attr_segments[1].ident.span, + "consider using", + new_name.to_string(), + Applicability::MachineApplicable, + ); + diag.emit(); + false + }, + DeprecationStatus::None => { + diag.cancel(); + attr_segments[1].ident.to_string() == name + }, + } }, - } - }) + ) } else { false } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 6f23e968006..3a3b79925ff 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -601,8 +601,10 @@ pub fn first_line_of_span(cx: &T, span: Span) -> Span { fn first_char_in_first_line(cx: &T, span: Span) -> Option { let line_span = line_span(cx, span); - snippet_opt(cx, line_span).and_then(|snip| snip.find(|c: char| !c.is_whitespace()) - .map(|pos| line_span.lo() + BytePos::from_usize(pos))) + snippet_opt(cx, line_span).and_then(|snip| { + snip.find(|c: char| !c.is_whitespace()) + .map(|pos| line_span.lo() + BytePos::from_usize(pos)) + }) } /// Returns the indentation of the line of a span @@ -723,20 +725,20 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio .get_enclosing_scope(hir_id) .and_then(|enclosing_id| map.find(enclosing_id)); enclosing_node.and_then(|node| match node { - Node::Block(block) => Some(block), - Node::Item(&Item { - kind: ItemKind::Fn(_, _, eid), - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Fn(_, eid), - .. - }) => match cx.tcx.hir().body(eid).value.kind { - ExprKind::Block(ref block, _) => Some(block), - _ => None, - }, - _ => None, + Node::Block(block) => Some(block), + Node::Item(&Item { + kind: ItemKind::Fn(_, _, eid), + .. }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(_, eid), + .. + }) => match cx.tcx.hir().body(eid).value.kind { + ExprKind::Block(ref block, _) => Some(block), + _ => None, + }, + _ => None, + }) } /// Returns the base type for HIR references and pointers. diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 20bea3cbabe..0ac7714fbeb 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -492,15 +492,19 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { /// before it on its line. fn indentation(cx: &T, span: Span) -> Option { let lo = cx.sess().source_map().lookup_char_pos(span.lo()); - lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */).and_then(|line| if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { - // We can mix char and byte positions here because we only consider `[ \t]`. - if lo.col == CharPos(pos) { - Some(line[..pos].into()) + lo.file + .get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) + .and_then(|line| { + if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') { + // We can mix char and byte positions here because we only consider `[ \t]`. + if lo.col == CharPos(pos) { + Some(line[..pos].into()) + } else { + None + } } else { None } - } else { - None }) } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 3b10b7b82a0..063f94582b9 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -297,10 +297,13 @@ impl EarlyLintPass for Write { if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) { if fmt_str.symbol == Symbol::intern("") { let mut applicability = Applicability::MachineApplicable; - let suggestion = expr.map_or_else(|| { - applicability = Applicability::HasPlaceholders; - Cow::Borrowed("v") - }, |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable)); + let suggestion = expr.map_or_else( + || { + applicability = Applicability::HasPlaceholders; + Cow::Borrowed("v") + }, + |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable), + ); span_lint_and_sugg( cx, -- cgit 1.4.1-3-g733a5 From 1740dda76386aff7205b2a709a32c95e8cbc0d57 Mon Sep 17 00:00:00 2001 From: robojumper Date: Sun, 5 Jul 2020 22:11:19 +0200 Subject: fix match_like_matches_macro in clippy --- clippy_lints/src/assign_ops.rs | 1 + clippy_lints/src/comparison_chain.rs | 5 +---- clippy_lints/src/eq_op.rs | 30 +++++++++++++++--------------- clippy_lints/src/escape.rs | 5 +---- clippy_lints/src/eta_reduction.rs | 5 +---- clippy_lints/src/formatting.rs | 12 ++---------- clippy_lints/src/functions.rs | 8 +------- clippy_lints/src/lib.rs | 11 ++++++----- clippy_lints/src/lifetimes.rs | 16 ++++++++-------- clippy_lints/src/loops.rs | 10 ++-------- clippy_lints/src/methods/mod.rs | 16 +++++----------- clippy_lints/src/misc.rs | 7 +------ clippy_lints/src/misc_early.rs | 18 ++++++------------ clippy_lints/src/missing_inline.rs | 9 +++++---- clippy_lints/src/new_without_default.rs | 10 ++++++---- clippy_lints/src/non_copy_const.rs | 8 ++++---- clippy_lints/src/precedence.rs | 10 ++-------- clippy_lints/src/regex.rs | 7 +------ clippy_lints/src/shadow.rs | 5 +---- clippy_lints/src/temporary_assignment.rs | 8 +------- clippy_lints/src/types.rs | 29 ++++++++--------------------- clippy_lints/src/unnamed_address.rs | 14 +++++--------- clippy_lints/src/use_self.rs | 6 ++---- clippy_lints/src/utils/ast_utils.rs | 5 +---- clippy_lints/src/utils/mod.rs | 11 ++--------- clippy_lints/src/utils/numeric_literal.rs | 2 +- src/driver.rs | 9 ++------- 27 files changed, 91 insertions(+), 186 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index bc6e868823f..3d48bf739eb 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -237,6 +237,7 @@ fn is_commutative(op: hir::BinOpKind) -> bool { use rustc_hir::BinOpKind::{ Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub, }; + #[allow(clippy::match_like_matches_macro)] match op { Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true, Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false, diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 26476af4cb6..25ccabc1c88 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -122,8 +122,5 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { } fn kind_is_cmp(kind: BinOpKind) -> bool { - match kind { - BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq => true, - _ => false, - } + matches!(kind, BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq) } diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index ca921dcfdfe..7839908fe4c 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -214,20 +214,20 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } fn is_valid_operator(op: BinOp) -> bool { - match op.node { + matches!( + op.node, BinOpKind::Sub - | BinOpKind::Div - | BinOpKind::Eq - | BinOpKind::Lt - | BinOpKind::Le - | BinOpKind::Gt - | BinOpKind::Ge - | BinOpKind::Ne - | BinOpKind::And - | BinOpKind::Or - | BinOpKind::BitXor - | BinOpKind::BitAnd - | BinOpKind::BitOr => true, - _ => false, - } + | BinOpKind::Div + | BinOpKind::Eq + | BinOpKind::Lt + | BinOpKind::Le + | BinOpKind::Gt + | BinOpKind::Ge + | BinOpKind::Ne + | BinOpKind::And + | BinOpKind::Or + | BinOpKind::BitXor + | BinOpKind::BitAnd + | BinOpKind::BitOr + ) } diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index d40cdfcca9f..32fc01149d8 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -105,10 +105,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { _ => return false, } - match map.find(map.get_parent_node(id)) { - Some(Node::Param(_)) => true, - _ => false, - } + matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_))) } impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index ceed6a74c4f..fb26b9fc27d 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -175,10 +175,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { match (&lhs.kind, &rhs.kind) { (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2), - (l, r) => match (l, r) { - (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false, - (_, _) => true, - }, + (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))), } } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 156246fb8bb..1bd16e6cce5 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -305,18 +305,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { } fn is_block(expr: &Expr) -> bool { - if let ExprKind::Block(..) = expr.kind { - true - } else { - false - } + matches!(expr.kind, ExprKind::Block(..)) } /// Check if the expression is an `if` or `if let` fn is_if(expr: &Expr) -> bool { - if let ExprKind::If(..) = expr.kind { - true - } else { - false - } + matches!(expr.kind, ExprKind::If(..)) } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 3f030dd8422..63133a4872a 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -645,13 +645,7 @@ fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { use hir::ExprKind::{Field, Index, Path}; match e.kind { - Path(ref qpath) => { - if let Res::Local(_) = qpath_res(cx, qpath, e.hir_id) { - false - } else { - true - } - }, + Path(ref qpath) => !matches!(qpath_res(cx, qpath, e.hir_id), Res::Local(_)), Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner), _ => false, } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fe34e4390d6..c4f1af8f4e4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -277,7 +277,6 @@ mod question_mark; mod ranges; mod redundant_clone; mod redundant_field_names; -mod redundant_pattern_matching; mod redundant_pub_crate; mod redundant_static_lifetimes; mod reference; @@ -623,11 +622,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &matches::INFALLIBLE_DESTRUCTURING_MATCH, &matches::MATCH_AS_REF, &matches::MATCH_BOOL, + &matches::MATCH_LIKE_MATCHES_MACRO, &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, &matches::MATCH_SINGLE_BINDING, &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, &matches::MATCH_WILD_ERR_ARM, + &matches::REDUNDANT_PATTERN_MATCHING, &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, &matches::SINGLE_MATCH, &matches::SINGLE_MATCH_ELSE, @@ -757,7 +758,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &ranges::REVERSED_EMPTY_RANGES, &redundant_clone::REDUNDANT_CLONE, &redundant_field_names::REDUNDANT_FIELD_NAMES, - &redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, &redundant_pub_crate::REDUNDANT_PUB_CRATE, &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, &reference::DEREF_ADDROF, @@ -956,7 +956,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box missing_doc::MissingDoc::new()); store.register_late_pass(|| box missing_inline::MissingInline); store.register_late_pass(|| box if_let_some_result::OkIfLet); - store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching); store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); let enum_variant_size_threshold = conf.enum_variant_size_threshold; @@ -1295,9 +1294,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_AS_REF), + LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_SINGLE_BINDING), + LintId::of(&matches::REDUNDANT_PATTERN_MATCHING), LintId::of(&matches::SINGLE_MATCH), LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), @@ -1387,7 +1388,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::REVERSED_EMPTY_RANGES), LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), @@ -1488,8 +1488,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(&map_clone::MAP_CLONE), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), + LintId::of(&matches::REDUNDANT_PATTERN_MATCHING), LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), @@ -1526,7 +1528,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr::PTR_ARG), LintId::of(&question_mark::QUESTION_MARK), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&returns::NEEDLESS_RETURN), diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index a79f94855bd..168f9f953e4 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -129,10 +129,10 @@ fn check_fn_inner<'tcx>( } let mut bounds_lts = Vec::new(); - let types = generics.params.iter().filter(|param| match param.kind { - GenericParamKind::Type { .. } => true, - _ => false, - }); + let types = generics + .params + .iter() + .filter(|param| matches!(param.kind, GenericParamKind::Type { .. })); for typ in types { for bound in typ.bounds { let mut visitor = RefVisitor::new(cx); @@ -337,10 +337,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) { if let Some(ref last_path_segment) = last_path_segment(qpath).args { if !last_path_segment.parenthesized - && !last_path_segment.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) + && !last_path_segment + .args + .iter() + .any(|arg| matches!(arg, GenericArg::Lifetime(_))) { let hir_id = ty.hir_id; match self.cx.qpath_res(qpath, hir_id) { diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index b803d753b6d..396bb659109 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2091,17 +2091,11 @@ fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } fn is_loop(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Loop(..) => true, - _ => false, - } + matches!(expr.kind, ExprKind::Loop(..)) } fn is_conditional(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Match(..) => true, - _ => false, - } + matches!(expr.kind, ExprKind::Match(..)) } fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f1c8894c0ee..4c595029ff7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1844,10 +1844,10 @@ fn lint_expect_fun_call( ty::Ref(ty::ReStatic, ..) ) }), - hir::ExprKind::Path(ref p) => match cx.qpath_res(p, arg.hir_id) { - hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) => true, - _ => false, - }, + hir::ExprKind::Path(ref p) => matches!( + cx.qpath_res(p, arg.hir_id), + hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) + ), _ => false, } } @@ -2028,13 +2028,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp .tables() .expr_adjustments(arg) .iter() - .filter(|adj| { - if let ty::adjustment::Adjust::Deref(_) = adj.kind { - true - } else { - false - } - }) + .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) .count(); let derefs: String = iter::repeat('*').take(deref_count).collect(); snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet))); diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 3d4225f36a7..400f4b609af 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -694,12 +694,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::MacroKind; if expr.span.from_expansion() { let data = expr.span.ctxt().outer_expn_data(); - - if let ExpnKind::Macro(MacroKind::Attr, _) = data.kind { - true - } else { - false - } + matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _)) } else { false } diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index ad39e59d067..b84a1a3fe24 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -641,28 +641,22 @@ fn check_unneeded_wildcard_pattern(cx: &EarlyContext<'_>, pat: &Pat) { ); } - #[allow(clippy::trivially_copy_pass_by_ref)] - fn is_wild>(pat: &&P) -> bool { - if let PatKind::Wild = pat.kind { - true - } else { - false - } - } - if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) { if let Some((left_index, left_pat)) = patterns[..rest_index] .iter() .rev() - .take_while(is_wild) + .take_while(|pat| matches!(pat.kind, PatKind::Wild)) .enumerate() .last() { span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0); } - if let Some((right_index, right_pat)) = - patterns[rest_index + 1..].iter().take_while(is_wild).enumerate().last() + if let Some((right_index, right_pat)) = patterns[rest_index + 1..] + .iter() + .take_while(|pat| matches!(pat.kind, PatKind::Wild)) + .enumerate() + .last() { span_lint( cx, diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index bf80b62afe6..9c962673537 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -71,10 +71,11 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp fn is_executable(cx: &LateContext<'_>) -> bool { use rustc_session::config::CrateType; - cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t { - CrateType::Executable => true, - _ => false, - }) + cx.tcx + .sess + .crate_types() + .iter() + .any(|t: &CrateType| matches!(t, CrateType::Executable)) } declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 2597f5f6f17..621ebdef2f0 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -80,10 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // can't be implemented for unsafe new return; } - if impl_item.generics.params.iter().any(|gen| match gen.kind { - hir::GenericParamKind::Type { .. } => true, - _ => false, - }) { + if impl_item + .generics + .params + .iter() + .any(|gen| matches!(gen.kind, hir::GenericParamKind::Type { .. })) + { // when the result of `new()` depends on a type parameter we should not require // an // impl of `Default` diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index c11a2ff9ee0..a3521c31a6b 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -238,10 +238,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { let ty = if needs_check_adjustment { let adjustments = cx.tables().expr_adjustments(dereferenced_expr); - if let Some(i) = adjustments.iter().position(|adj| match adj.kind { - Adjust::Borrow(_) | Adjust::Deref(_) => true, - _ => false, - }) { + if let Some(i) = adjustments + .iter() + .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_))) + { if i == 0 { cx.tables().expr_ty(dereferenced_expr) } else { diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 7dce23dd223..04be96aa64c 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -148,17 +148,11 @@ fn is_arith_expr(expr: &Expr) -> bool { #[must_use] fn is_bit_op(op: BinOpKind) -> bool { use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr}; - match op { - BitXor | BitAnd | BitOr | Shl | Shr => true, - _ => false, - } + matches!(op, BitXor | BitAnd | BitOr | Shl | Shr) } #[must_use] fn is_arith_op(op: BinOpKind) -> bool { use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub}; - match op { - Add | Sub | Mul | Div | Rem => true, - _ => false, - } + matches!(op, Add | Sub | Mul | Div | Rem) } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index d8c8eff2c85..f204a0ffb2c 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -99,12 +99,7 @@ fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { use regex_syntax::hir::Anchor::{EndText, StartText}; use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal}; - let is_literal = |e: &[regex_syntax::hir::Hir]| { - e.iter().all(|e| match *e.kind() { - Literal(_) => true, - _ => false, - }) - }; + let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_))); match *s.kind() { Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"), diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 4cdff63f118..194786c5c41 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -165,10 +165,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { let var_ty = cx.tables().node_type_opt(pat_id); - var_ty.map_or(false, |var_ty| match var_ty.kind { - ty::Adt(..) => false, - _ => true, - }) + var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..))) } fn check_pat<'tcx>( diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 509bbfd27c1..1aeff1baa36 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -25,13 +25,7 @@ declare_clippy_lint! { fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match &expr.kind { ExprKind::Struct(..) | ExprKind::Tup(..) => true, - ExprKind::Path(qpath) => { - if let Res::Def(DefKind::Const, ..) = cx.qpath_res(qpath, expr.hir_id) { - true - } else { - false - } - }, + ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)), _ => false, } } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index d6f31a99bb3..71207caecf5 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -775,11 +775,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { .iter() .filter(|arg| { if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) { - if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind { - false - } else { - true - } + !matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar)) } else { false } @@ -899,17 +895,11 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { } fn is_unit(ty: Ty<'_>) -> bool { - match ty.kind { - ty::Tuple(slice) if slice.is_empty() => true, - _ => false, - } + matches!(ty.kind, ty::Tuple(slice) if slice.is_empty()) } fn is_unit_literal(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Tup(ref slice) if slice.is_empty() => true, - _ => false, - } + matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty()) } declare_clippy_lint! { @@ -1154,10 +1144,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { } fn is_isize_or_usize(typ: Ty<'_>) -> bool { - match typ.kind { - ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => true, - _ => false, - } + matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) } fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) { @@ -1737,10 +1724,10 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { TyKind::TraitObject(ref param_bounds, _) => { let has_lifetime_parameters = param_bounds.iter().any(|bound| { - bound.bound_generic_params.iter().any(|gen| match gen.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }) + bound + .bound_generic_params + .iter() + .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. })) }); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index b9aa202b328..25d136e564d 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -58,10 +58,10 @@ declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COM impl LateLintPass<'_> for UnnamedAddress { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn is_comparison(binop: BinOpKind) -> bool { - match binop { - BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true, - _ => false, - } + matches!( + binop, + BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt + ) } fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { @@ -72,11 +72,7 @@ impl LateLintPass<'_> for UnnamedAddress { } fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ty::FnDef(..) = cx.tables().expr_ty(expr).kind { - true - } else { - false - } + matches!(cx.tables().expr_ty(expr).kind, ty::FnDef(..)) } if_chain! { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 39a8c020872..776c6bc57ca 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -169,10 +169,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; let should_check = parameters.as_ref().map_or( true, - |params| !params.parenthesized && !params.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }) + |params| !params.parenthesized + &&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) ); if should_check { diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index e19a79dd8da..58c1103da9f 100755 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -387,10 +387,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { } pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { - match (l, r) { - (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) => true, - _ => false, - } + matches!((l, r), (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))) } pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3a3b79925ff..0b4cba3fc42 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -102,11 +102,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { #[must_use] pub fn in_macro(span: Span) -> bool { if span.from_expansion() { - if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind { - false - } else { - true - } + !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) } else { false } @@ -127,10 +123,7 @@ pub fn is_present_in_source(cx: &T, span: Span) -> bool { /// Checks if given pattern is a wildcard (`_`) pub fn is_wild<'tcx>(pat: &impl std::ops::Deref>) -> bool { - match pat.kind { - PatKind::Wild => true, - _ => false, - } + matches!(pat.kind, PatKind::Wild) } /// Checks if type is struct, enum or union type with the given def path. diff --git a/clippy_lints/src/utils/numeric_literal.rs b/clippy_lints/src/utils/numeric_literal.rs index 7a79741b30b..87cb454f654 100644 --- a/clippy_lints/src/utils/numeric_literal.rs +++ b/clippy_lints/src/utils/numeric_literal.rs @@ -51,7 +51,7 @@ impl<'a> NumericLiteral<'a> { pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option> { if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) { let (unsuffixed, suffix) = split_suffix(&src, lit_kind); - let float = if let LitKind::Float(..) = lit_kind { true } else { false }; + let float = matches!(lit_kind, LitKind::Float(..)); Some(NumericLiteral::new(unsuffixed, suffix, float)) } else { None diff --git a/src/driver.rs b/src/driver.rs index decd3a79cce..47315fa64cd 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -382,13 +382,8 @@ pub fn main() { let should_describe_lints = || { let args: Vec<_> = env::args().collect(); - args.windows(2).any(|args| { - args[1] == "help" - && match args[0].as_str() { - "-W" | "-A" | "-D" | "-F" => true, - _ => false, - } - }) + args.windows(2) + .any(|args| args[1] == "help" && matches!(args[0].as_str(), "-W" | "-A" | "-D" | "-F")) }; if !wrapper_mode && should_describe_lints() { -- cgit 1.4.1-3-g733a5 From 201999ccfd18a9debe1f186f30f40659ebc6b933 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 13 Jul 2020 10:33:25 -0700 Subject: improve advice in iter_nth_zero The "use .next()" replacement advice is on the last line of the code snippet, where it is vulnerable to truncation. Display that advice at the beginning instead. closes #5783 --- clippy_lints/src/methods/mod.rs | 4 ++-- tests/ui/iter_nth_zero.stderr | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4c595029ff7..565a08f1292 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2348,8 +2348,8 @@ fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_ar cx, ITER_NTH_ZERO, expr.span, - "called `.nth(0)` on a `std::iter::Iterator`", - "try calling", + "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", + "try calling .next() instead of .nth(0)", format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)), applicability, ); diff --git a/tests/ui/iter_nth_zero.stderr b/tests/ui/iter_nth_zero.stderr index 2b20a4ceb4a..6c4200a7905 100644 --- a/tests/ui/iter_nth_zero.stderr +++ b/tests/ui/iter_nth_zero.stderr @@ -1,22 +1,22 @@ -error: called `.nth(0)` on a `std::iter::Iterator` +error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:20:14 | LL | let _x = s.iter().nth(0); - | ^^^^^^^^^^^^^^^ help: try calling: `s.iter().next()` + | ^^^^^^^^^^^^^^^ help: try calling .next() instead of .nth(0): `s.iter().next()` | = note: `-D clippy::iter-nth-zero` implied by `-D warnings` -error: called `.nth(0)` on a `std::iter::Iterator` +error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:25:14 | LL | let _y = iter.nth(0); - | ^^^^^^^^^^^ help: try calling: `iter.next()` + | ^^^^^^^^^^^ help: try calling .next() instead of .nth(0): `iter.next()` -error: called `.nth(0)` on a `std::iter::Iterator` +error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:30:22 | LL | let _unwrapped = iter2.nth(0).unwrap(); - | ^^^^^^^^^^^^ help: try calling: `iter2.next()` + | ^^^^^^^^^^^^ help: try calling .next() instead of .nth(0): `iter2.next()` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From e83b3eb9930ab527451edaaa6f524acd26c1bf1c Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Tue, 14 Jul 2020 09:20:19 -0700 Subject: formatting nits --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/iter_nth_zero.stderr | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 565a08f1292..69e985cc0a4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2349,7 +2349,7 @@ fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_ar ITER_NTH_ZERO, expr.span, "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", - "try calling .next() instead of .nth(0)", + "try calling `.next()` instead of `.nth(0)`", format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)), applicability, ); diff --git a/tests/ui/iter_nth_zero.stderr b/tests/ui/iter_nth_zero.stderr index 6c4200a7905..29c56f3a94f 100644 --- a/tests/ui/iter_nth_zero.stderr +++ b/tests/ui/iter_nth_zero.stderr @@ -2,7 +2,7 @@ error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:20:14 | LL | let _x = s.iter().nth(0); - | ^^^^^^^^^^^^^^^ help: try calling .next() instead of .nth(0): `s.iter().next()` + | ^^^^^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `s.iter().next()` | = note: `-D clippy::iter-nth-zero` implied by `-D warnings` @@ -10,13 +10,13 @@ error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:25:14 | LL | let _y = iter.nth(0); - | ^^^^^^^^^^^ help: try calling .next() instead of .nth(0): `iter.next()` + | ^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `iter.next()` error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:30:22 | LL | let _unwrapped = iter2.nth(0).unwrap(); - | ^^^^^^^^^^^^ help: try calling .next() instead of .nth(0): `iter2.next()` + | ^^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `iter2.next()` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From b375f1dd20bf07175ec06d13e1e9dc8b20287cd3 Mon Sep 17 00:00:00 2001 From: Dmitry Murzin Date: Sat, 25 Jul 2020 17:09:44 +0300 Subject: Add suggestion for `iter_skip_next` lint --- clippy_lints/src/methods/mod.rs | 24 ++++++++++++++---------- tests/ui/iter_skip_next.fixed | 22 ++++++++++++++++++++++ tests/ui/iter_skip_next.rs | 8 ++++---- tests/ui/iter_skip_next.stderr | 23 ++++++++--------------- 4 files changed, 48 insertions(+), 29 deletions(-) create mode 100644 tests/ui/iter_skip_next.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 97cc58023f5..56686f6d24f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1408,7 +1408,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), - ["next", "skip"] => lint_iter_skip_next(cx, expr), + ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]), ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), @@ -2436,17 +2436,21 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: ); } -fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { +fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { // lint if caller of skip is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - span_lint_and_help( - cx, - ITER_SKIP_NEXT, - expr.span, - "called `skip(x).next()` on an iterator", - None, - "this is more succinctly expressed by calling `nth(x)`", - ); + if let [caller, n] = skip_args { + let hint = format!(".nth({})", snippet(cx, n.span, "..")); + span_lint_and_sugg( + cx, + ITER_SKIP_NEXT, + expr.span.trim_start(caller.span).unwrap(), + "called `skip(x).next()` on an iterator", + "use `nth` instead", + hint, + Applicability::MachineApplicable, + ); + } } } diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed new file mode 100644 index 00000000000..928b6acb951 --- /dev/null +++ b/tests/ui/iter_skip_next.fixed @@ -0,0 +1,22 @@ +// run-rustfix +// aux-build:option_helpers.rs + +#![warn(clippy::iter_skip_next)] +#![allow(clippy::blacklisted_name)] +#![allow(clippy::iter_nth)] + +extern crate option_helpers; + +use option_helpers::IteratorFalsePositives; + +/// Checks implementation of `ITER_SKIP_NEXT` lint +fn main() { + let some_vec = vec![0, 1, 2, 3]; + let _ = some_vec.iter().nth(42); + let _ = some_vec.iter().cycle().nth(42); + let _ = (1..10).nth(10); + let _ = &some_vec[..].iter().nth(3); + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.skip(42).next(); + let _ = foo.filter().skip(42).next(); +} diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index a65ca3bbb13..7075e2598eb 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -1,15 +1,17 @@ +// run-rustfix // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::blacklisted_name)] +#![allow(clippy::iter_nth)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; /// Checks implementation of `ITER_SKIP_NEXT` lint -fn iter_skip_next() { - let mut some_vec = vec![0, 1, 2, 3]; +fn main() { + let some_vec = vec![0, 1, 2, 3]; let _ = some_vec.iter().skip(42).next(); let _ = some_vec.iter().cycle().skip(42).next(); let _ = (1..10).skip(10).next(); @@ -18,5 +20,3 @@ fn iter_skip_next() { let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); } - -fn main() {} diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index 5709f335529..feedc2f288a 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,35 +1,28 @@ error: called `skip(x).next()` on an iterator - --> $DIR/iter_skip_next.rs:13:13 + --> $DIR/iter_skip_next.rs:15:28 | LL | let _ = some_vec.iter().skip(42).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` | = note: `-D clippy::iter-skip-next` implied by `-D warnings` - = help: this is more succinctly expressed by calling `nth(x)` error: called `skip(x).next()` on an iterator - --> $DIR/iter_skip_next.rs:14:13 + --> $DIR/iter_skip_next.rs:16:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this is more succinctly expressed by calling `nth(x)` + | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` error: called `skip(x).next()` on an iterator - --> $DIR/iter_skip_next.rs:15:13 + --> $DIR/iter_skip_next.rs:17:20 | LL | let _ = (1..10).skip(10).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this is more succinctly expressed by calling `nth(x)` + | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` error: called `skip(x).next()` on an iterator - --> $DIR/iter_skip_next.rs:16:14 + --> $DIR/iter_skip_next.rs:18:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this is more succinctly expressed by calling `nth(x)` + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)` error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From a427c99f3d2a0b2c55d19af73bcad81f1dc761ab Mon Sep 17 00:00:00 2001 From: Dmitry Murzin Date: Sat, 25 Jul 2020 20:04:59 +0300 Subject: Handle mapping to Option in `map_flatten` lint --- clippy_lints/src/methods/mod.rs | 26 ++++++++++++++++++++++---- tests/ui/map_flatten.fixed | 1 + tests/ui/map_flatten.rs | 1 + tests/ui/map_flatten.stderr | 16 +++++++++++----- 4 files changed, 35 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9edcdd979ff..3f62a3cab1c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2569,17 +2569,35 @@ fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Ex fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.map().flatten()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `map(..).flatten()` on an `Iterator`. \ - This is more succinctly expressed by calling `.flat_map(..)`"; + let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); + let is_map_to_option = if let ty::Closure(_def_id, substs) = map_closure_ty.kind { + let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&substs.as_closure().sig().output()); + is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type)) + } else { + false + }; + + let method_to_use = if is_map_to_option { + // `(...).map(...)` has type `impl Iterator> + "filter_map" + } else { + // `(...).map(...)` has type `impl Iterator> + "flat_map" + }; + let msg = &format!( + "called `map(..).flatten()` on an `Iterator`. \ + This is more succinctly expressed by calling `.{}(..)`", + method_to_use + ); let self_snippet = snippet(cx, map_args[0].span, ".."); let func_snippet = snippet(cx, map_args[1].span, ".."); - let hint = format!("{0}.flat_map({1})", self_snippet, func_snippet); + let hint = format!("{0}.{1}({2})", self_snippet, method_to_use, func_snippet); span_lint_and_sugg( cx, MAP_FLATTEN, expr.span, msg, - "try using `flat_map` instead", + &format!("try using `{}` instead", method_to_use), hint, Applicability::MachineApplicable, ); diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index 4171d80f48a..684a28aebcb 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -5,6 +5,7 @@ #![allow(clippy::map_identity)] fn main() { + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); let _: Option<_> = (Some(Some(1))).and_then(|x| x); } diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index 16a0fd090ad..05789ee5232 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -5,6 +5,7 @@ #![allow(clippy::map_identity)] fn main() { + let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); } diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index 00bc41c15e9..d2d15362a6c 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,16 +1,22 @@ -error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` +error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.filter_map(..)` --> $DIR/map_flatten.rs:8:21 | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1))` | = note: `-D clippy::map-flatten` implied by `-D warnings` +error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` + --> $DIR/map_flatten.rs:9:21 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` + error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)` - --> $DIR/map_flatten.rs:9:24 + --> $DIR/map_flatten.rs:10:24 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From d4ba561aafb501972f581c1f8e6d1885959f9306 Mon Sep 17 00:00:00 2001 From: Dmitry Murzin Date: Thu, 30 Jul 2020 22:20:31 +0300 Subject: Review fixes --- clippy_lints/src/methods/mod.rs | 36 ++++++++++++++++-------------------- tests/ui/map_flatten.fixed | 13 +++++++++++++ tests/ui/map_flatten.rs | 13 +++++++++++++ tests/ui/map_flatten.stderr | 40 +++++++++++++++++++++++++++++----------- 4 files changed, 71 insertions(+), 31 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3f62a3cab1c..9217324b18c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2570,11 +2570,16 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map // lint if caller of `.map().flatten()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); - let is_map_to_option = if let ty::Closure(_def_id, substs) = map_closure_ty.kind { - let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&substs.as_closure().sig().output()); - is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type)) - } else { - false + let is_map_to_option = match map_closure_ty.kind { + ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { + let map_closure_sig = match map_closure_ty.kind { + ty::Closure(_, substs) => substs.as_closure().sig(), + _ => map_closure_ty.fn_sig(cx.tcx), + }; + let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output()); + is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type)) + }, + _ => false, }; let method_to_use = if is_map_to_option { @@ -2584,19 +2589,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map // `(...).map(...)` has type `impl Iterator> "flat_map" }; - let msg = &format!( - "called `map(..).flatten()` on an `Iterator`. \ - This is more succinctly expressed by calling `.{}(..)`", - method_to_use - ); - let self_snippet = snippet(cx, map_args[0].span, ".."); let func_snippet = snippet(cx, map_args[1].span, ".."); - let hint = format!("{0}.{1}({2})", self_snippet, method_to_use, func_snippet); + let hint = format!(".{0}({1})", method_to_use, func_snippet); span_lint_and_sugg( cx, MAP_FLATTEN, - expr.span, - msg, + expr.span.with_lo(map_args[0].span.hi()), + "called `map(..).flatten()` on an `Iterator`", &format!("try using `{}` instead", method_to_use), hint, Applicability::MachineApplicable, @@ -2605,16 +2604,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map // lint if caller of `.map().flatten()` is an Option if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) { - let msg = "called `map(..).flatten()` on an `Option`. \ - This is more succinctly expressed by calling `.and_then(..)`"; - let self_snippet = snippet(cx, map_args[0].span, ".."); let func_snippet = snippet(cx, map_args[1].span, ".."); - let hint = format!("{0}.and_then({1})", self_snippet, func_snippet); + let hint = format!(".and_then({})", func_snippet); span_lint_and_sugg( cx, MAP_FLATTEN, - expr.span, - msg, + expr.span.with_lo(map_args[0].span.hi()), + "called `map(..).flatten()` on an `Option`", "try using `and_then` instead", hint, Applicability::MachineApplicable, diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index 684a28aebcb..a5fdf7df613 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -5,7 +5,20 @@ #![allow(clippy::map_identity)] fn main() { + // mapping to Option on Iterator + fn option_id(x: i8) -> Option { + Some(x) + } + let option_id_ref: fn(i8) -> Option = option_id; + let option_id_closure = |x| Some(x); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect(); let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); + + // mapping to Iterator on Iterator let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); + + // mapping to Option on Option let _: Option<_> = (Some(Some(1))).and_then(|x| x); } diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index 05789ee5232..abbc4e16e56 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -5,7 +5,20 @@ #![allow(clippy::map_identity)] fn main() { + // mapping to Option on Iterator + fn option_id(x: i8) -> Option { + Some(x) + } + let option_id_ref: fn(i8) -> Option = option_id; + let option_id_closure = |x| Some(x); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + + // mapping to Iterator on Iterator let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + + // mapping to Option on Option let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); } diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index d2d15362a6c..b6479cd69ea 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,22 +1,40 @@ -error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.filter_map(..)` - --> $DIR/map_flatten.rs:8:21 +error: called `map(..).flatten()` on an `Iterator` + --> $DIR/map_flatten.rs:14:46 | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1))` +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` | = note: `-D clippy::map-flatten` implied by `-D warnings` -error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` - --> $DIR/map_flatten.rs:9:21 +error: called `map(..).flatten()` on an `Iterator` + --> $DIR/map_flatten.rs:15:46 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` + +error: called `map(..).flatten()` on an `Iterator` + --> $DIR/map_flatten.rs:16:46 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` + +error: called `map(..).flatten()` on an `Iterator` + --> $DIR/map_flatten.rs:17:46 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` + +error: called `map(..).flatten()` on an `Iterator` + --> $DIR/map_flatten.rs:20:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` -error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)` - --> $DIR/map_flatten.rs:10:24 +error: called `map(..).flatten()` on an `Option` + --> $DIR/map_flatten.rs:23:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From 0ccdf2913a335c4f0b34098f84baeeb3fc852255 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 3 Aug 2020 16:23:20 -0500 Subject: Remove obsolete known problems unnecessary_fold --- clippy_lints/src/methods/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9edcdd979ff..ff8da6b4015 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1052,8 +1052,7 @@ declare_clippy_lint! { /// /// **Why is this bad?** Readability. /// - /// **Known problems:** False positive in pattern guards. Will be resolved once - /// non-lexical lifetimes are stable. + /// **Known problems:** None. /// /// **Example:** /// ```rust -- cgit 1.4.1-3-g733a5 From a77e881ec9f324cdc544150f897d8b34281f92e4 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Wed, 17 Jun 2020 01:16:34 +0200 Subject: should_impl_trait - ignore methods with lifetime params --- clippy_lints/src/methods/mod.rs | 11 ++++++++++- tests/ui/methods.rs | 5 +++++ tests/ui/methods.stderr | 26 +++++++++++++------------- 3 files changed, 28 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 570ae66d595..3009aa3a64e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1497,11 +1497,20 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if cx.access_levels.is_exported(impl_item.hir_id) { // check missing trait implementations for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS { + let no_lifetime_params = || { + impl_item.generics.params.iter().filter(|p| match p.kind { + hir::GenericParamKind::Lifetime { .. } => true, + _ => false, + }).count() == 0 + }; if name == method_name && sig.decl.inputs.len() == n_args && out_type.matches(cx, &sig.decl.output) && self_kind.matches(cx, self_ty, first_arg_ty) && - fn_header_equals(*fn_header, sig.header) { + fn_header_equals(*fn_header, sig.header) && + // ignore methods with lifetime params, risk of false positive + no_lifetime_params() + { span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!( "defining a method called `{}` on this type; consider implementing \ the `{}` trait or choosing a less ambiguous name", name, trait_name)); diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 7880cf36415..3b267b0dab2 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -10,6 +10,7 @@ clippy::non_ascii_literal, clippy::new_without_default, clippy::needless_pass_by_value, + clippy::needless_lifetimes, clippy::print_stdout, clippy::must_use_candidate, clippy::use_self, @@ -82,6 +83,10 @@ impl T { fn new(self) -> Self { unimplemented!(); } + + pub fn next<'b>(&'b mut self) -> Option<&'b mut T> { + unimplemented!(); + } } pub struct T1; diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 01cf487ac14..9b8ecaed692 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:39:5 + --> $DIR/methods.rs:40:5 | LL | / pub fn add(self, other: T) -> T { LL | | self @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: methods called `new` usually return `Self` - --> $DIR/methods.rs:169:5 + --> $DIR/methods.rs:174:5 | LL | / fn new() -> i32 { LL | | 0 @@ -19,7 +19,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:188:13 + --> $DIR/methods.rs:193:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:191:13 + --> $DIR/methods.rs:196:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -38,7 +38,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:208:22 + --> $DIR/methods.rs:213:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -46,25 +46,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:209:20 + --> $DIR/methods.rs:214:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:210:20 + --> $DIR/methods.rs:215:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:211:22 + --> $DIR/methods.rs:216:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:214:13 + --> $DIR/methods.rs:219:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -74,13 +74,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:220:22 + --> $DIR/methods.rs:225:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:223:13 + --> $DIR/methods.rs:228:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -90,13 +90,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:229:22 + --> $DIR/methods.rs:234:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:232:13 + --> $DIR/methods.rs:237:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ -- cgit 1.4.1-3-g733a5 From 2bc0ecd44b4d09476eade641e02451d949a1c8e2 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Fri, 19 Jun 2020 22:12:51 +0200 Subject: should_implement_trait - add test cases for every checked trait method --- clippy_lints/src/methods/mod.rs | 1 + tests/ui/methods.rs | 146 ++++++++++++++++++++-- tests/ui/methods.stderr | 264 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 386 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3009aa3a64e..c225a3bd359 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3424,6 +3424,7 @@ const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30 ("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), ("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"), ("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), + // FIXME: default doesn't work ("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"), ("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), ("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 3b267b0dab2..adf81607440 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -37,9 +37,136 @@ use option_helpers::IteratorFalsePositives; pub struct T; impl T { + // ******************************************* + // complete trait method list, should lint all + // ******************************************* pub fn add(self, other: T) -> T { - self + unimplemented!() + } + + pub fn as_mut(&mut self) -> &mut T { + unimplemented!() + } + + pub fn as_ref(&self) -> &T { + unimplemented!() + } + + pub fn bitand(self, rhs: T) -> T { + unimplemented!() + } + + pub fn bitor(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn bitxor(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn borrow(&self) -> &str { + unimplemented!() + } + + pub fn borrow_mut(&mut self) -> &mut str { + unimplemented!() + } + + pub fn clone(&self) -> Self { + unimplemented!() + } + + pub fn cmp(&self, other: &Self) -> Self { + unimplemented!() + } + + pub fn default() -> Self { + unimplemented!() + } + + pub fn deref(&self) -> &Self { + unimplemented!() + } + + pub fn deref_mut(&mut self) -> &mut Self { + unimplemented!() + } + + pub fn div(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn drop(&mut self) { + unimplemented!() + } + + pub fn eq(&self, other: &Self) -> bool { + unimplemented!() + } + + pub fn from_iter(iter: T) -> Self { + unimplemented!() + } + + pub fn from_str(s: &str) -> Result { + unimplemented!() + } + + pub fn hash(&self, state: &mut T) { + unimplemented!() + } + + pub fn index(&self, index: usize) -> &Self { + unimplemented!() + } + + pub fn index_mut(&mut self, index: usize) -> &mut Self { + unimplemented!() + } + + pub fn into_iter(self) -> Self { + unimplemented!() + } + + pub fn mul(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn neg(self) -> Self { + unimplemented!() + } + + pub fn next(&mut self) -> Option { + unimplemented!() + } + + pub fn not(self) -> Self { + unimplemented!() + } + + pub fn rem(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn shl(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn shr(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn sub(self, rhs: Self) -> Self { + unimplemented!() } + // ***************** + // complete list end + // ***************** +} + +pub struct T1; +impl T1 { + // corner cases: should not lint // no error, not public interface pub(crate) fn drop(&mut self) {} @@ -50,22 +177,22 @@ impl T { } // no error, private function - fn eq(&self, other: T) -> bool { + fn eq(&self, other: Self) -> bool { true } // No error; self is a ref. - fn sub(&self, other: T) -> &T { + fn sub(&self, other: Self) -> &Self { self } // No error; different number of arguments. - fn div(self) -> T { + fn div(self) -> Self { self } // No error; wrong return type. - fn rem(self, other: T) {} + fn rem(self, other: Self) {} // Fine fn into_u32(self) -> u32 { @@ -89,16 +216,15 @@ impl T { } } -pub struct T1; - -impl T1 { +pub struct T2; +impl T2 { // Shouldn't trigger lint as it is unsafe. - pub unsafe fn add(self, rhs: T1) -> T1 { + pub unsafe fn add(self, rhs: Self) -> Self { self } // Should not trigger lint since this is an async function. - pub async fn next(&mut self) -> Option { + pub async fn next(&mut self) -> Option { None } } diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 9b8ecaed692..5105fff8f5b 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,15 +1,249 @@ error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:40:5 + --> $DIR/methods.rs:43:5 | LL | / pub fn add(self, other: T) -> T { -LL | | self +LL | | unimplemented!() LL | | } | |_____^ | = note: `-D clippy::should-implement-trait` implied by `-D warnings` +error: defining a method called `as_mut` on this type; consider implementing the `std::convert::AsMut` trait or choosing a less ambiguous name + --> $DIR/methods.rs:47:5 + | +LL | / pub fn as_mut(&mut self) -> &mut T { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `as_ref` on this type; consider implementing the `std::convert::AsRef` trait or choosing a less ambiguous name + --> $DIR/methods.rs:51:5 + | +LL | / pub fn as_ref(&self) -> &T { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `bitand` on this type; consider implementing the `std::ops::BitAnd` trait or choosing a less ambiguous name + --> $DIR/methods.rs:55:5 + | +LL | / pub fn bitand(self, rhs: T) -> T { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `bitor` on this type; consider implementing the `std::ops::BitOr` trait or choosing a less ambiguous name + --> $DIR/methods.rs:59:5 + | +LL | / pub fn bitor(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `bitxor` on this type; consider implementing the `std::ops::BitXor` trait or choosing a less ambiguous name + --> $DIR/methods.rs:63:5 + | +LL | / pub fn bitxor(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `borrow` on this type; consider implementing the `std::borrow::Borrow` trait or choosing a less ambiguous name + --> $DIR/methods.rs:67:5 + | +LL | / pub fn borrow(&self) -> &str { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `borrow_mut` on this type; consider implementing the `std::borrow::BorrowMut` trait or choosing a less ambiguous name + --> $DIR/methods.rs:71:5 + | +LL | / pub fn borrow_mut(&mut self) -> &mut str { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `clone` on this type; consider implementing the `std::clone::Clone` trait or choosing a less ambiguous name + --> $DIR/methods.rs:75:5 + | +LL | / pub fn clone(&self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `cmp` on this type; consider implementing the `std::cmp::Ord` trait or choosing a less ambiguous name + --> $DIR/methods.rs:79:5 + | +LL | / pub fn cmp(&self, other: &Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `deref` on this type; consider implementing the `std::ops::Deref` trait or choosing a less ambiguous name + --> $DIR/methods.rs:87:5 + | +LL | / pub fn deref(&self) -> &Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `deref_mut` on this type; consider implementing the `std::ops::DerefMut` trait or choosing a less ambiguous name + --> $DIR/methods.rs:91:5 + | +LL | / pub fn deref_mut(&mut self) -> &mut Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `div` on this type; consider implementing the `std::ops::Div` trait or choosing a less ambiguous name + --> $DIR/methods.rs:95:5 + | +LL | / pub fn div(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `drop` on this type; consider implementing the `std::ops::Drop` trait or choosing a less ambiguous name + --> $DIR/methods.rs:99:5 + | +LL | / pub fn drop(&mut self) { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `eq` on this type; consider implementing the `std::cmp::PartialEq` trait or choosing a less ambiguous name + --> $DIR/methods.rs:103:5 + | +LL | / pub fn eq(&self, other: &Self) -> bool { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `from_iter` on this type; consider implementing the `std::iter::FromIterator` trait or choosing a less ambiguous name + --> $DIR/methods.rs:107:5 + | +LL | / pub fn from_iter(iter: T) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `from_str` on this type; consider implementing the `std::str::FromStr` trait or choosing a less ambiguous name + --> $DIR/methods.rs:111:5 + | +LL | / pub fn from_str(s: &str) -> Result { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/methods.rs:111:5 + | +LL | / pub fn from_str(s: &str) -> Result { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = note: `-D clippy::missing-errors-doc` implied by `-D warnings` + +error: defining a method called `hash` on this type; consider implementing the `std::hash::Hash` trait or choosing a less ambiguous name + --> $DIR/methods.rs:115:5 + | +LL | / pub fn hash(&self, state: &mut T) { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `index` on this type; consider implementing the `std::ops::Index` trait or choosing a less ambiguous name + --> $DIR/methods.rs:119:5 + | +LL | / pub fn index(&self, index: usize) -> &Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `index_mut` on this type; consider implementing the `std::ops::IndexMut` trait or choosing a less ambiguous name + --> $DIR/methods.rs:123:5 + | +LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `into_iter` on this type; consider implementing the `std::iter::IntoIterator` trait or choosing a less ambiguous name + --> $DIR/methods.rs:127:5 + | +LL | / pub fn into_iter(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `mul` on this type; consider implementing the `std::ops::Mul` trait or choosing a less ambiguous name + --> $DIR/methods.rs:131:5 + | +LL | / pub fn mul(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `neg` on this type; consider implementing the `std::ops::Neg` trait or choosing a less ambiguous name + --> $DIR/methods.rs:135:5 + | +LL | / pub fn neg(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `next` on this type; consider implementing the `std::iter::Iterator` trait or choosing a less ambiguous name + --> $DIR/methods.rs:139:5 + | +LL | / pub fn next(&mut self) -> Option { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `not` on this type; consider implementing the `std::ops::Not` trait or choosing a less ambiguous name + --> $DIR/methods.rs:143:5 + | +LL | / pub fn not(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `rem` on this type; consider implementing the `std::ops::Rem` trait or choosing a less ambiguous name + --> $DIR/methods.rs:147:5 + | +LL | / pub fn rem(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `shl` on this type; consider implementing the `std::ops::Shl` trait or choosing a less ambiguous name + --> $DIR/methods.rs:151:5 + | +LL | / pub fn shl(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `shr` on this type; consider implementing the `std::ops::Shr` trait or choosing a less ambiguous name + --> $DIR/methods.rs:155:5 + | +LL | / pub fn shr(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + +error: defining a method called `sub` on this type; consider implementing the `std::ops::Sub` trait or choosing a less ambiguous name + --> $DIR/methods.rs:159:5 + | +LL | / pub fn sub(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + error: methods called `new` usually return `Self` - --> $DIR/methods.rs:174:5 + --> $DIR/methods.rs:300:5 | LL | / fn new() -> i32 { LL | | 0 @@ -19,7 +253,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:193:13 + --> $DIR/methods.rs:319:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +262,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:196:13 + --> $DIR/methods.rs:322:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -38,7 +272,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:213:22 + --> $DIR/methods.rs:339:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -46,25 +280,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:214:20 + --> $DIR/methods.rs:340:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:215:20 + --> $DIR/methods.rs:341:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:216:22 + --> $DIR/methods.rs:342:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:219:13 + --> $DIR/methods.rs:345:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -74,13 +308,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:225:22 + --> $DIR/methods.rs:351:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:228:13 + --> $DIR/methods.rs:354:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -90,13 +324,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:234:22 + --> $DIR/methods.rs:360:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:237:13 + --> $DIR/methods.rs:363:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -105,5 +339,5 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: aborting due to 13 previous errors +error: aborting due to 42 previous errors -- cgit 1.4.1-3-g733a5 From e6b2254f9e55743dbace44cc73c6447b6bda58e5 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sun, 21 Jun 2020 00:12:09 +0200 Subject: should_implement_trait - pr remarks --- clippy_lints/src/methods/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c225a3bd359..a75989e3f13 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1498,10 +1498,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { // check missing trait implementations for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS { let no_lifetime_params = || { - impl_item.generics.params.iter().filter(|p| match p.kind { - hir::GenericParamKind::Lifetime { .. } => true, - _ => false, - }).count() == 0 + !impl_item.generics.params.iter() + .any(|p| matches!( + p.kind, + hir::GenericParamKind::Lifetime { .. })) }; if name == method_name && sig.decl.inputs.len() == n_args && @@ -1510,7 +1510,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn_header_equals(*fn_header, sig.header) && // ignore methods with lifetime params, risk of false positive no_lifetime_params() - { + { span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!( "defining a method called `{}` on this type; consider implementing \ the `{}` trait or choosing a less ambiguous name", name, trait_name)); -- cgit 1.4.1-3-g733a5 From 7cc1a2ed879e45605a53b802cfa5291c9a51284c Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Tue, 23 Jun 2020 21:27:48 +0200 Subject: should_implement_trait - filter on explicit lifetime param only --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a75989e3f13..bad1bb7224e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1501,7 +1501,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { !impl_item.generics.params.iter() .any(|p| matches!( p.kind, - hir::GenericParamKind::Lifetime { .. })) + hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit })) }; if name == method_name && sig.decl.inputs.len() == n_args && -- cgit 1.4.1-3-g733a5 From 166c520e9a8b1a45819255e75dee737136aa6ec8 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Thu, 30 Jul 2020 01:41:12 +0200 Subject: should_impl_trait - pr comments --- clippy_lints/src/methods/mod.rs | 150 ++++++++----- tests/ui/methods.rs | 197 +---------------- tests/ui/methods.stderr | 270 ++---------------------- tests/ui/should_impl_trait/corner_cases.rs | 83 ++++++++ tests/ui/should_impl_trait/method_list_1.rs | 87 ++++++++ tests/ui/should_impl_trait/method_list_1.stderr | 143 +++++++++++++ tests/ui/should_impl_trait/method_list_2.rs | 88 ++++++++ tests/ui/should_impl_trait/method_list_2.stderr | 153 ++++++++++++++ 8 files changed, 670 insertions(+), 501 deletions(-) create mode 100644 tests/ui/should_impl_trait/corner_cases.rs create mode 100644 tests/ui/should_impl_trait/method_list_1.rs create mode 100644 tests/ui/should_impl_trait/method_list_1.stderr create mode 100644 tests/ui/should_impl_trait/method_list_2.rs create mode 100644 tests/ui/should_impl_trait/method_list_2.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bad1bb7224e..a549c3b78ef 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1495,25 +1495,31 @@ impl<'tcx> LateLintPass<'tcx> for Methods { then { if cx.access_levels.is_exported(impl_item.hir_id) { - // check missing trait implementations - for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS { - let no_lifetime_params = || { - !impl_item.generics.params.iter() - .any(|p| matches!( - p.kind, - hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit })) - }; - if name == method_name && - sig.decl.inputs.len() == n_args && - out_type.matches(cx, &sig.decl.output) && - self_kind.matches(cx, self_ty, first_arg_ty) && - fn_header_equals(*fn_header, sig.header) && - // ignore methods with lifetime params, risk of false positive - no_lifetime_params() + // check missing trait implementations + for method_config in &TRAIT_METHODS { + if name == method_config.method_name && + sig.decl.inputs.len() == method_config.param_count && + method_config.output_type.matches(cx, &sig.decl.output) && + method_config.self_kind.matches(cx, self_ty, first_arg_ty) && + fn_header_equals(*method_config.fn_header, sig.header) && + method_config.lifetime_param_cond(&impl_item) { - span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!( - "defining a method called `{}` on this type; consider implementing \ - the `{}` trait or choosing a less ambiguous name", name, trait_name)); + span_lint_and_help( + cx, + SHOULD_IMPLEMENT_TRAIT, + impl_item.span, + &format!( + "method `{}` can be confused for the standard trait method `{}::{}`", + method_config.method_name, + method_config.trait_name, + method_config.method_name + ), + None, + &format!( + "consider implementing the trait `{}` or choosing a less ambiguous method name", + method_config.trait_name + ) + ); } } } @@ -3412,39 +3418,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader { abi: rustc_target::spec::abi::Abi::Rust, }; +struct ShouldImplTraitCase { + trait_name: &'static str, + method_name: &'static str, + param_count: usize, + fn_header: &'static hir::FnHeader, + // implicit self kind expected (none, self, &self, ...) + self_kind: SelfKind, + // checks against the output type + output_type: OutType, + // certain methods with explicit lifetimes can't implement the equivalent trait method + lint_explicit_lifetime: bool, +} +impl ShouldImplTraitCase { + const fn new( + trait_name: &'static str, + method_name: &'static str, + param_count: usize, + fn_header: &'static hir::FnHeader, + self_kind: SelfKind, + output_type: OutType, + lint_explicit_lifetime: bool, + ) -> ShouldImplTraitCase { + ShouldImplTraitCase { + trait_name, + method_name, + param_count, + fn_header, + self_kind, + output_type, + lint_explicit_lifetime, + } + } + + fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool { + self.lint_explicit_lifetime + || !impl_item.generics.params.iter().any(|p| { + matches!( + p.kind, + hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + } + ) + }) + } +} + #[rustfmt::skip] -const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30] = [ - ("add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Add"), - ("as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), - ("as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), - ("bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitAnd"), - ("bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitOr"), - ("bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitXor"), - ("borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"), - ("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), - ("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"), - ("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), +const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ + ShouldImplTraitCase::new("std::ops::Add", "add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, true), // FIXME: default doesn't work - ("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"), - ("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), - ("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), - ("div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Div"), - ("drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), - ("eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), - ("from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::iter::FromIterator"), - ("from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::str::FromStr"), - ("hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), - ("index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Index"), - ("index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), - ("into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), - ("mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Mul"), - ("neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Neg"), - ("next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), - ("not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Not"), - ("rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Rem"), - ("shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shl"), - ("shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shr"), - ("sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Sub"), + ShouldImplTraitCase::new("std::default::Default", "default", 0, &FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::Div", "div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, true), + ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, true), + ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, true), + ShouldImplTraitCase::new("std::ops::Index", "index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, false), + ShouldImplTraitCase::new("std::ops::Not", "not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), ]; #[rustfmt::skip] diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index adf81607440..80dd2f744b3 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -34,201 +34,6 @@ use std::sync::{self, Arc}; use option_helpers::IteratorFalsePositives; -pub struct T; - -impl T { - // ******************************************* - // complete trait method list, should lint all - // ******************************************* - pub fn add(self, other: T) -> T { - unimplemented!() - } - - pub fn as_mut(&mut self) -> &mut T { - unimplemented!() - } - - pub fn as_ref(&self) -> &T { - unimplemented!() - } - - pub fn bitand(self, rhs: T) -> T { - unimplemented!() - } - - pub fn bitor(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn bitxor(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn borrow(&self) -> &str { - unimplemented!() - } - - pub fn borrow_mut(&mut self) -> &mut str { - unimplemented!() - } - - pub fn clone(&self) -> Self { - unimplemented!() - } - - pub fn cmp(&self, other: &Self) -> Self { - unimplemented!() - } - - pub fn default() -> Self { - unimplemented!() - } - - pub fn deref(&self) -> &Self { - unimplemented!() - } - - pub fn deref_mut(&mut self) -> &mut Self { - unimplemented!() - } - - pub fn div(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn drop(&mut self) { - unimplemented!() - } - - pub fn eq(&self, other: &Self) -> bool { - unimplemented!() - } - - pub fn from_iter(iter: T) -> Self { - unimplemented!() - } - - pub fn from_str(s: &str) -> Result { - unimplemented!() - } - - pub fn hash(&self, state: &mut T) { - unimplemented!() - } - - pub fn index(&self, index: usize) -> &Self { - unimplemented!() - } - - pub fn index_mut(&mut self, index: usize) -> &mut Self { - unimplemented!() - } - - pub fn into_iter(self) -> Self { - unimplemented!() - } - - pub fn mul(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn neg(self) -> Self { - unimplemented!() - } - - pub fn next(&mut self) -> Option { - unimplemented!() - } - - pub fn not(self) -> Self { - unimplemented!() - } - - pub fn rem(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn shl(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn shr(self, rhs: Self) -> Self { - unimplemented!() - } - - pub fn sub(self, rhs: Self) -> Self { - unimplemented!() - } - // ***************** - // complete list end - // ***************** -} - -pub struct T1; -impl T1 { - // corner cases: should not lint - - // 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: Self) -> bool { - true - } - - // No error; self is a ref. - fn sub(&self, other: Self) -> &Self { - self - } - - // No error; different number of arguments. - fn div(self) -> Self { - self - } - - // No error; wrong return type. - fn rem(self, other: Self) {} - - // Fine - fn into_u32(self) -> u32 { - 0 - } - - fn into_u16(&self) -> u16 { - 0 - } - - fn to_something(self) -> u32 { - 0 - } - - fn new(self) -> Self { - unimplemented!(); - } - - pub fn next<'b>(&'b mut self) -> Option<&'b mut T> { - unimplemented!(); - } -} - -pub struct T2; -impl T2 { - // Shouldn't trigger lint as it is unsafe. - pub unsafe fn add(self, rhs: Self) -> Self { - self - } - - // Should not trigger lint since this is an async function. - pub async fn next(&mut self) -> Option { - None - } -} - struct Lt<'a> { foo: &'a u32, } @@ -302,6 +107,8 @@ impl BadNew { } } +struct T; + impl Mul for T { type Output = T; // No error, obviously. diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 5105fff8f5b..2a0a43e83a6 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,249 +1,5 @@ -error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:43:5 - | -LL | / pub fn add(self, other: T) -> T { -LL | | unimplemented!() -LL | | } - | |_____^ - | - = note: `-D clippy::should-implement-trait` implied by `-D warnings` - -error: defining a method called `as_mut` on this type; consider implementing the `std::convert::AsMut` trait or choosing a less ambiguous name - --> $DIR/methods.rs:47:5 - | -LL | / pub fn as_mut(&mut self) -> &mut T { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `as_ref` on this type; consider implementing the `std::convert::AsRef` trait or choosing a less ambiguous name - --> $DIR/methods.rs:51:5 - | -LL | / pub fn as_ref(&self) -> &T { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `bitand` on this type; consider implementing the `std::ops::BitAnd` trait or choosing a less ambiguous name - --> $DIR/methods.rs:55:5 - | -LL | / pub fn bitand(self, rhs: T) -> T { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `bitor` on this type; consider implementing the `std::ops::BitOr` trait or choosing a less ambiguous name - --> $DIR/methods.rs:59:5 - | -LL | / pub fn bitor(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `bitxor` on this type; consider implementing the `std::ops::BitXor` trait or choosing a less ambiguous name - --> $DIR/methods.rs:63:5 - | -LL | / pub fn bitxor(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `borrow` on this type; consider implementing the `std::borrow::Borrow` trait or choosing a less ambiguous name - --> $DIR/methods.rs:67:5 - | -LL | / pub fn borrow(&self) -> &str { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `borrow_mut` on this type; consider implementing the `std::borrow::BorrowMut` trait or choosing a less ambiguous name - --> $DIR/methods.rs:71:5 - | -LL | / pub fn borrow_mut(&mut self) -> &mut str { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `clone` on this type; consider implementing the `std::clone::Clone` trait or choosing a less ambiguous name - --> $DIR/methods.rs:75:5 - | -LL | / pub fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `cmp` on this type; consider implementing the `std::cmp::Ord` trait or choosing a less ambiguous name - --> $DIR/methods.rs:79:5 - | -LL | / pub fn cmp(&self, other: &Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `deref` on this type; consider implementing the `std::ops::Deref` trait or choosing a less ambiguous name - --> $DIR/methods.rs:87:5 - | -LL | / pub fn deref(&self) -> &Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `deref_mut` on this type; consider implementing the `std::ops::DerefMut` trait or choosing a less ambiguous name - --> $DIR/methods.rs:91:5 - | -LL | / pub fn deref_mut(&mut self) -> &mut Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `div` on this type; consider implementing the `std::ops::Div` trait or choosing a less ambiguous name - --> $DIR/methods.rs:95:5 - | -LL | / pub fn div(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `drop` on this type; consider implementing the `std::ops::Drop` trait or choosing a less ambiguous name - --> $DIR/methods.rs:99:5 - | -LL | / pub fn drop(&mut self) { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `eq` on this type; consider implementing the `std::cmp::PartialEq` trait or choosing a less ambiguous name - --> $DIR/methods.rs:103:5 - | -LL | / pub fn eq(&self, other: &Self) -> bool { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `from_iter` on this type; consider implementing the `std::iter::FromIterator` trait or choosing a less ambiguous name - --> $DIR/methods.rs:107:5 - | -LL | / pub fn from_iter(iter: T) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `from_str` on this type; consider implementing the `std::str::FromStr` trait or choosing a less ambiguous name - --> $DIR/methods.rs:111:5 - | -LL | / pub fn from_str(s: &str) -> Result { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: docs for function returning `Result` missing `# Errors` section - --> $DIR/methods.rs:111:5 - | -LL | / pub fn from_str(s: &str) -> Result { -LL | | unimplemented!() -LL | | } - | |_____^ - | - = note: `-D clippy::missing-errors-doc` implied by `-D warnings` - -error: defining a method called `hash` on this type; consider implementing the `std::hash::Hash` trait or choosing a less ambiguous name - --> $DIR/methods.rs:115:5 - | -LL | / pub fn hash(&self, state: &mut T) { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `index` on this type; consider implementing the `std::ops::Index` trait or choosing a less ambiguous name - --> $DIR/methods.rs:119:5 - | -LL | / pub fn index(&self, index: usize) -> &Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `index_mut` on this type; consider implementing the `std::ops::IndexMut` trait or choosing a less ambiguous name - --> $DIR/methods.rs:123:5 - | -LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `into_iter` on this type; consider implementing the `std::iter::IntoIterator` trait or choosing a less ambiguous name - --> $DIR/methods.rs:127:5 - | -LL | / pub fn into_iter(self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `mul` on this type; consider implementing the `std::ops::Mul` trait or choosing a less ambiguous name - --> $DIR/methods.rs:131:5 - | -LL | / pub fn mul(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `neg` on this type; consider implementing the `std::ops::Neg` trait or choosing a less ambiguous name - --> $DIR/methods.rs:135:5 - | -LL | / pub fn neg(self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `next` on this type; consider implementing the `std::iter::Iterator` trait or choosing a less ambiguous name - --> $DIR/methods.rs:139:5 - | -LL | / pub fn next(&mut self) -> Option { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `not` on this type; consider implementing the `std::ops::Not` trait or choosing a less ambiguous name - --> $DIR/methods.rs:143:5 - | -LL | / pub fn not(self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `rem` on this type; consider implementing the `std::ops::Rem` trait or choosing a less ambiguous name - --> $DIR/methods.rs:147:5 - | -LL | / pub fn rem(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `shl` on this type; consider implementing the `std::ops::Shl` trait or choosing a less ambiguous name - --> $DIR/methods.rs:151:5 - | -LL | / pub fn shl(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `shr` on this type; consider implementing the `std::ops::Shr` trait or choosing a less ambiguous name - --> $DIR/methods.rs:155:5 - | -LL | / pub fn shr(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - -error: defining a method called `sub` on this type; consider implementing the `std::ops::Sub` trait or choosing a less ambiguous name - --> $DIR/methods.rs:159:5 - | -LL | / pub fn sub(self, rhs: Self) -> Self { -LL | | unimplemented!() -LL | | } - | |_____^ - error: methods called `new` usually return `Self` - --> $DIR/methods.rs:300:5 + --> $DIR/methods.rs:105:5 | LL | / fn new() -> i32 { LL | | 0 @@ -253,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:319:13 + --> $DIR/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -262,7 +18,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:322:13 + --> $DIR/methods.rs:129:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -272,7 +28,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:339:22 + --> $DIR/methods.rs:146:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -280,25 +36,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:340:20 + --> $DIR/methods.rs:147:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:341:20 + --> $DIR/methods.rs:148:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:342:22 + --> $DIR/methods.rs:149:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:345:13 + --> $DIR/methods.rs:152:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -308,13 +64,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:351:22 + --> $DIR/methods.rs:158:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:354:13 + --> $DIR/methods.rs:161:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -324,13 +80,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:360:22 + --> $DIR/methods.rs:167:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:363:13 + --> $DIR/methods.rs:170:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -339,5 +95,5 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: aborting due to 42 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/should_impl_trait/corner_cases.rs b/tests/ui/should_impl_trait/corner_cases.rs new file mode 100644 index 00000000000..6c5ffe6aba8 --- /dev/null +++ b/tests/ui/should_impl_trait/corner_cases.rs @@ -0,0 +1,83 @@ +// edition:2018 + +#![warn(clippy::all, clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::needless_pass_by_value, + clippy::must_use_candidate, + clippy::unused_self, + clippy::needless_lifetimes, + clippy::missing_safety_doc, + clippy::wrong_self_convention +)] + +use std::ops::Mul; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} + +pub struct T1; +impl T1 { + // corner cases: should not lint + + // 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: Self) -> bool { + true + } + + // No error; self is a ref. + fn sub(&self, other: Self) -> &Self { + self + } + + // No error; different number of arguments. + fn div(self) -> Self { + self + } + + // No error; wrong return type. + fn rem(self, other: Self) {} + + // Fine + fn into_u32(self) -> u32 { + 0 + } + + fn into_u16(&self) -> u16 { + 0 + } + + fn to_something(self) -> u32 { + 0 + } + + fn new(self) -> Self { + unimplemented!(); + } + + pub fn next<'b>(&'b mut self) -> Option<&'b mut T1> { + unimplemented!(); + } +} + +pub struct T2; +impl T2 { + // Shouldn't trigger lint as it is unsafe. + pub unsafe fn add(self, rhs: Self) -> Self { + self + } + + // Should not trigger lint since this is an async function. + pub async fn next(&mut self) -> Option { + None + } +} diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs new file mode 100644 index 00000000000..f8d248fc98d --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_1.rs @@ -0,0 +1,87 @@ +// edition:2018 + +#![warn(clippy::all, clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::needless_pass_by_value, + clippy::must_use_candidate, + clippy::unused_self, + clippy::needless_lifetimes, + clippy::missing_safety_doc, + clippy::wrong_self_convention +)] + +use std::ops::Mul; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} +pub struct T; + +impl T { + // ***************************************** + // trait method list part 1, should lint all + // ***************************************** + pub fn add(self, other: T) -> T { + unimplemented!() + } + + pub fn as_mut(&mut self) -> &mut T { + unimplemented!() + } + + pub fn as_ref(&self) -> &T { + unimplemented!() + } + + pub fn bitand(self, rhs: T) -> T { + unimplemented!() + } + + pub fn bitor(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn bitxor(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn borrow(&self) -> &str { + unimplemented!() + } + + pub fn borrow_mut(&mut self) -> &mut str { + unimplemented!() + } + + pub fn clone(&self) -> Self { + unimplemented!() + } + + pub fn cmp(&self, other: &Self) -> Self { + unimplemented!() + } + + pub fn default() -> Self { + unimplemented!() + } + + pub fn deref(&self) -> &Self { + unimplemented!() + } + + pub fn deref_mut(&mut self) -> &mut Self { + unimplemented!() + } + + pub fn div(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn drop(&mut self) { + unimplemented!() + } + // ********** + // part 1 end + // ********** +} diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr new file mode 100644 index 00000000000..2b7d4628c3f --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -0,0 +1,143 @@ +error: method `add` can be confused for the standard trait method `std::ops::Add::add` + --> $DIR/method_list_1.rs:25:5 + | +LL | / pub fn add(self, other: T) -> T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = note: `-D clippy::should-implement-trait` implied by `-D warnings` + = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name + +error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` + --> $DIR/method_list_1.rs:29:5 + | +LL | / pub fn as_mut(&mut self) -> &mut T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name + +error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` + --> $DIR/method_list_1.rs:33:5 + | +LL | / pub fn as_ref(&self) -> &T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name + +error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` + --> $DIR/method_list_1.rs:37:5 + | +LL | / pub fn bitand(self, rhs: T) -> T { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name + +error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` + --> $DIR/method_list_1.rs:41:5 + | +LL | / pub fn bitor(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name + +error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` + --> $DIR/method_list_1.rs:45:5 + | +LL | / pub fn bitxor(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name + +error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` + --> $DIR/method_list_1.rs:49:5 + | +LL | / pub fn borrow(&self) -> &str { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name + +error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` + --> $DIR/method_list_1.rs:53:5 + | +LL | / pub fn borrow_mut(&mut self) -> &mut str { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name + +error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` + --> $DIR/method_list_1.rs:57:5 + | +LL | / pub fn clone(&self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name + +error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` + --> $DIR/method_list_1.rs:61:5 + | +LL | / pub fn cmp(&self, other: &Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name + +error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` + --> $DIR/method_list_1.rs:69:5 + | +LL | / pub fn deref(&self) -> &Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name + +error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` + --> $DIR/method_list_1.rs:73:5 + | +LL | / pub fn deref_mut(&mut self) -> &mut Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name + +error: method `div` can be confused for the standard trait method `std::ops::Div::div` + --> $DIR/method_list_1.rs:77:5 + | +LL | / pub fn div(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name + +error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` + --> $DIR/method_list_1.rs:81:5 + | +LL | / pub fn drop(&mut self) { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name + +error: aborting due to 14 previous errors + diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs new file mode 100644 index 00000000000..ed5e0d384bf --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -0,0 +1,88 @@ +// edition:2018 + +#![warn(clippy::all, clippy::pedantic)] +#![allow( + clippy::missing_errors_doc, + clippy::needless_pass_by_value, + clippy::must_use_candidate, + clippy::unused_self, + clippy::needless_lifetimes, + clippy::missing_safety_doc, + clippy::wrong_self_convention +)] + +use std::ops::Mul; +use std::rc::{self, Rc}; +use std::sync::{self, Arc}; + +fn main() {} +pub struct T; + +impl T { + // ***************************************** + // trait method list part 2, should lint all + // ***************************************** + + pub fn eq(&self, other: &Self) -> bool { + unimplemented!() + } + + pub fn from_iter(iter: T) -> Self { + unimplemented!() + } + + pub fn from_str(s: &str) -> Result { + unimplemented!() + } + + pub fn hash(&self, state: &mut T) { + unimplemented!() + } + + pub fn index(&self, index: usize) -> &Self { + unimplemented!() + } + + pub fn index_mut(&mut self, index: usize) -> &mut Self { + unimplemented!() + } + + pub fn into_iter(self) -> Self { + unimplemented!() + } + + pub fn mul(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn neg(self) -> Self { + unimplemented!() + } + + pub fn next(&mut self) -> Option { + unimplemented!() + } + + pub fn not(self) -> Self { + unimplemented!() + } + + pub fn rem(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn shl(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn shr(self, rhs: Self) -> Self { + unimplemented!() + } + + pub fn sub(self, rhs: Self) -> Self { + unimplemented!() + } + // ********** + // part 2 end + // ********** +} diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr new file mode 100644 index 00000000000..b6fd4356956 --- /dev/null +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -0,0 +1,153 @@ +error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq` + --> $DIR/method_list_2.rs:26:5 + | +LL | / pub fn eq(&self, other: &Self) -> bool { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = note: `-D clippy::should-implement-trait` implied by `-D warnings` + = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name + +error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` + --> $DIR/method_list_2.rs:30:5 + | +LL | / pub fn from_iter(iter: T) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name + +error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` + --> $DIR/method_list_2.rs:34:5 + | +LL | / pub fn from_str(s: &str) -> Result { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name + +error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` + --> $DIR/method_list_2.rs:38:5 + | +LL | / pub fn hash(&self, state: &mut T) { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name + +error: method `index` can be confused for the standard trait method `std::ops::Index::index` + --> $DIR/method_list_2.rs:42:5 + | +LL | / pub fn index(&self, index: usize) -> &Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name + +error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` + --> $DIR/method_list_2.rs:46:5 + | +LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name + +error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` + --> $DIR/method_list_2.rs:50:5 + | +LL | / pub fn into_iter(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name + +error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` + --> $DIR/method_list_2.rs:54:5 + | +LL | / pub fn mul(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name + +error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` + --> $DIR/method_list_2.rs:58:5 + | +LL | / pub fn neg(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name + +error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` + --> $DIR/method_list_2.rs:62:5 + | +LL | / pub fn next(&mut self) -> Option { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name + +error: method `not` can be confused for the standard trait method `std::ops::Not::not` + --> $DIR/method_list_2.rs:66:5 + | +LL | / pub fn not(self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name + +error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` + --> $DIR/method_list_2.rs:70:5 + | +LL | / pub fn rem(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name + +error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` + --> $DIR/method_list_2.rs:74:5 + | +LL | / pub fn shl(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name + +error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` + --> $DIR/method_list_2.rs:78:5 + | +LL | / pub fn shr(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name + +error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` + --> $DIR/method_list_2.rs:82:5 + | +LL | / pub fn sub(self, rhs: Self) -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name + +error: aborting due to 15 previous errors + -- cgit 1.4.1-3-g733a5 From f9ba829f6701ae03a5c226044dbbde13ce87e123 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sun, 9 Aug 2020 15:35:41 +0200 Subject: should_impl_trait - self linting --- clippy_lints/src/methods/mod.rs | 67 +++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 33 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a549c3b78ef..07e55ab0762 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1470,6 +1470,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } + #[allow(clippy::too_many_lines)] fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { if in_external_macro(cx.sess(), impl_item.span) { return; @@ -1501,7 +1502,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { sig.decl.inputs.len() == method_config.param_count && method_config.output_type.matches(cx, &sig.decl.output) && method_config.self_kind.matches(cx, self_ty, first_arg_ty) && - fn_header_equals(*method_config.fn_header, sig.header) && + fn_header_equals(method_config.fn_header, sig.header) && method_config.lifetime_param_cond(&impl_item) { span_lint_and_help( @@ -3422,7 +3423,7 @@ struct ShouldImplTraitCase { trait_name: &'static str, method_name: &'static str, param_count: usize, - fn_header: &'static hir::FnHeader, + fn_header: hir::FnHeader, // implicit self kind expected (none, self, &self, ...) self_kind: SelfKind, // checks against the output type @@ -3435,7 +3436,7 @@ impl ShouldImplTraitCase { trait_name: &'static str, method_name: &'static str, param_count: usize, - fn_header: &'static hir::FnHeader, + fn_header: hir::FnHeader, self_kind: SelfKind, output_type: OutType, lint_explicit_lifetime: bool, @@ -3466,37 +3467,37 @@ impl ShouldImplTraitCase { #[rustfmt::skip] const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ - ShouldImplTraitCase::new("std::ops::Add", "add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, true), - ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), + ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), // FIXME: default doesn't work - ShouldImplTraitCase::new("std::default::Default", "default", 0, &FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::Div", "div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, true), - ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, true), - ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, true), - ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, true), - ShouldImplTraitCase::new("std::ops::Index", "index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, true), - ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, true), - ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, false), - ShouldImplTraitCase::new("std::ops::Not", "not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), - ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true), + ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true), + ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true), + ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true), + ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true), + ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), + ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false), + ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), + ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ]; #[rustfmt::skip] -- cgit 1.4.1-3-g733a5 From 6af297f80e59050c87078f1ba6f05c97d6f90fd7 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Tue, 11 Aug 2020 12:42:50 +0200 Subject: iter-next-slice: make lint adhere to lint message convention --- clippy_lints/src/methods/mod.rs | 4 ++-- tests/ui/iter_next_slice.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 570ae66d595..f4eb9c4516f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2280,7 +2280,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ cx, ITER_NEXT_SLICE, expr.span, - "Using `.iter().next()` on a Slice without end index.", + "using `.iter().next()` on a Slice without end index", "try calling", format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), applicability, @@ -2299,7 +2299,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ cx, ITER_NEXT_SLICE, expr.span, - "Using `.iter().next()` on an array", + "using `.iter().next()` on an array", "try calling", format!( "{}.get(0)", diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr index bbf61df0cda..8c10a252ee0 100644 --- a/tests/ui/iter_next_slice.stderr +++ b/tests/ui/iter_next_slice.stderr @@ -1,4 +1,4 @@ -error: Using `.iter().next()` on an array +error: using `.iter().next()` on an array --> $DIR/iter_next_slice.rs:9:5 | LL | s.iter().next(); @@ -6,19 +6,19 @@ LL | s.iter().next(); | = note: `-D clippy::iter-next-slice` implied by `-D warnings` -error: Using `.iter().next()` on a Slice without end index. +error: using `.iter().next()` on a Slice without end index --> $DIR/iter_next_slice.rs:12:5 | LL | s[2..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` -error: Using `.iter().next()` on a Slice without end index. +error: using `.iter().next()` on a Slice without end index --> $DIR/iter_next_slice.rs:15:5 | LL | v[5..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` -error: Using `.iter().next()` on an array +error: using `.iter().next()` on an array --> $DIR/iter_next_slice.rs:18:5 | LL | v.iter().next(); -- cgit 1.4.1-3-g733a5 From 48a142559de48ff38326e8276ffdfce9ef3b5c95 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 13 Aug 2020 13:52:21 -0600 Subject: docs: typo in `temporary_cstring_as_ptr`: s/point/&s --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f4eb9c4516f..b6266ef2ba1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -799,7 +799,7 @@ declare_clippy_lint! { /// call_some_ffi_func(c_str); /// } /// ``` - /// Here `c_str` point to a freed address. The correct use would be: + /// Here `c_str` points to a freed address. The correct use would be: /// ```rust /// # use std::ffi::CString; /// # fn call_some_ffi_func(_: *const i8) {} -- cgit 1.4.1-3-g733a5 From ae56e988a2ae7b59c684cbbc5c326cb8097b3688 Mon Sep 17 00:00:00 2001 From: Christoph Walcher Date: Fri, 14 Aug 2020 12:52:19 +0200 Subject: Merge lint with `single_char_pattern` --- clippy_lints/src/lib.rs | 8 ++- clippy_lints/src/methods/mod.rs | 89 +++++++++++++++++++++++++++----- clippy_lints/src/single_char_push_str.rs | 62 ---------------------- src/lintlist/mod.rs | 2 +- tests/ui/single_char_push_str.fixed | 5 ++ tests/ui/single_char_push_str.rs | 5 ++ tests/ui/single_char_push_str.stderr | 20 ++++++- 7 files changed, 108 insertions(+), 83 deletions(-) delete mode 100644 clippy_lints/src/single_char_push_str.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4f261ba932e..5e4a4a4f49c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -287,7 +287,6 @@ mod repeat_once; mod returns; mod serde_api; mod shadow; -mod single_char_push_str; mod single_component_path_imports; mod slow_vector_initialization; mod stable_sort_primitive; @@ -678,6 +677,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::SEARCH_IS_SOME, &methods::SHOULD_IMPLEMENT_TRAIT, &methods::SINGLE_CHAR_PATTERN, + &methods::SINGLE_CHAR_PUSH_STR, &methods::SKIP_WHILE_NEXT, &methods::STRING_EXTEND_CHARS, &methods::SUSPICIOUS_MAP, @@ -776,7 +776,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_REUSE, &shadow::SHADOW_SAME, &shadow::SHADOW_UNRELATED, - &single_char_push_str::SINGLE_CHAR_PUSH_STR, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, &stable_sort_primitive::STABLE_SORT_PRIMITIVE, @@ -934,7 +933,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack}); store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented); store.register_late_pass(|| box strings::StringLitAsBytes); - store.register_late_pass(|| box single_char_push_str::SingleCharPushStrPass); store.register_late_pass(|| box derive::Derive); store.register_late_pass(|| box types::CharLitAsU8); store.register_late_pass(|| box vec::UselessVec); @@ -1352,6 +1350,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), LintId::of(&methods::SINGLE_CHAR_PATTERN), + LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::SUSPICIOUS_MAP), @@ -1419,7 +1418,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&serde_api::SERDE_API_MISUSE), - LintId::of(&single_char_push_str::SINGLE_CHAR_PUSH_STR), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), @@ -1536,6 +1534,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::UNNECESSARY_FOLD), LintId::of(&methods::WRONG_SELF_CONVENTION), @@ -1560,7 +1559,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), - LintId::of(&single_char_push_str::SINGLE_CHAR_PUSH_STR), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b6266ef2ba1..2986a5a5944 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1306,6 +1306,29 @@ declare_clippy_lint! { "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`" } +declare_clippy_lint! { + /// **What it does:** Warns when using push_str with a single-character string literal, + /// and push with a char would work fine. + /// + /// **Why is this bad?** it's less clear that we are pushing a single character + /// + /// **Known problems:** None + /// + /// **Example:** + /// ``` + /// let mut string = String::new(); + /// string.push_str("R"); + /// ``` + /// Could be written as + /// ``` + /// let mut string = String::new(); + /// string.push('R'); + /// ``` + pub SINGLE_CHAR_PUSH_STR, + style, + "`push_str()` used with a single-character string literal as parameter" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1327,6 +1350,7 @@ declare_lint_pass!(Methods => [ INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, + SINGLE_CHAR_PUSH_STR, SEARCH_IS_SOME, TEMPORARY_CSTRING_AS_PTR, FILTER_NEXT, @@ -1441,6 +1465,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::lint(cx, expr, &args[0], self_ty); } + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + lint_single_char_push_string(cx, expr, args); + } + } + match self_ty.kind { ty::Ref(_, ty, _) if ty.kind == ty::Str => { for &(method, pos) in &PATTERN_METHODS { @@ -3124,15 +3154,18 @@ fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryEx } } -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { +fn get_hint_if_single_char_arg<'tcx>( + cx: &LateContext<'tcx>, + arg: &'tcx hir::Expr<'_>, + applicability: &mut Applicability, +) -> Option { if_chain! { if let hir::ExprKind::Lit(lit) = &arg.kind; if let ast::LitKind::Str(r, style) = lit.node; - if r.as_str().len() == 1; + let string = r.as_str(); + if string.len() == 1; then { - let mut applicability = Applicability::MachineApplicable; - let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability); + let snip = snippet_with_applicability(cx, arg.span, &string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { let nhash = nhash as usize; // for raw string: r##"a"## @@ -3142,19 +3175,47 @@ fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr &snip[1..(snip.len() - 1)] }; let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "try using a `char` instead", - hint, - applicability, - ); + Some(hint) + } else { + None } } } +/// lint for length-1 `str`s for methods in `PATTERN_METHODS` +fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "try using a `char` instead", + hint, + applicability, + ); + } +} + +/// lint for length-1 `str`s as argument for `push_str` +fn lint_single_char_push_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let sugg = format!("{}.push({})", base_string_snippet, extension_string); + span_lint_and_sugg( + cx, + SINGLE_CHAR_PUSH_STR, + expr.span, + "calling `push_str()` using a single-character string literal", + "consider using `push` with a character literal", + sugg, + applicability, + ); + } +} + /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" diff --git a/clippy_lints/src/single_char_push_str.rs b/clippy_lints/src/single_char_push_str.rs deleted file mode 100644 index 68bbef7261a..00000000000 --- a/clippy_lints/src/single_char_push_str.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_sugg}; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// **What it does:** Warns when using push_str with a single-character string literal, - /// and push with a char would work fine. - /// - /// **Why is this bad?** This is in all probability not the intended outcome. At - /// the least it hurts readability of the code. - /// - /// **Known problems:** None - /// - /// **Example:** - /// ``` - /// let mut string = String::new(); - /// string.push_str("R"); - /// ``` - /// Could be written as - /// ``` - /// let mut string = String::new(); - /// string.push('R'); - /// ``` - pub SINGLE_CHAR_PUSH_STR, - style, - "`push_str()` used with a single-character string literal as parameter" -} - -declare_lint_pass!(SingleCharPushStrPass => [SINGLE_CHAR_PUSH_STR]); - -impl<'tcx> LateLintPass<'tcx> for SingleCharPushStrPass { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind; - if let [base_string, extension_string] = args; - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, fn_def_id, &paths::PUSH_STR); - if let ExprKind::Lit(ref lit) = extension_string.kind; - if let LitKind::Str(symbol,_) = lit.node; - let extension_string_val = symbol.as_str().to_string(); - if extension_string_val.len() == 1; - then { - let mut applicability = Applicability::MachineApplicable; - let base_string_snippet = snippet_with_applicability(cx, base_string.span, "_", &mut applicability); - let sugg = format!("{}.push({:?})", base_string_snippet, extension_string_val.chars().next().unwrap()); - span_lint_and_sugg( - cx, - SINGLE_CHAR_PUSH_STR, - expr.span, - "calling `push_str()` using a single-character string literal", - "consider using `push` with a character literal", - sugg, - applicability - ); - } - } - } -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 000ab8b8f36..4fd32776874 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2017,7 +2017,7 @@ pub static ref ALL_LINTS: Vec = vec![ group: "style", desc: "`push_str()` used with a single-character string literal as parameter", deprecation: None, - module: "single_char_push_str", + module: "methods", }, Lint { name: "single_component_path_imports", diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed index 49607c49218..0812c026a64 100644 --- a/tests/ui/single_char_push_str.fixed +++ b/tests/ui/single_char_push_str.fixed @@ -7,4 +7,9 @@ fn main() { string.push('\''); string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push('\x52'); + string.push('\u{0052}'); + string.push('a'); } diff --git a/tests/ui/single_char_push_str.rs b/tests/ui/single_char_push_str.rs index bbeebd027b1..ab293bbe4ee 100644 --- a/tests/ui/single_char_push_str.rs +++ b/tests/ui/single_char_push_str.rs @@ -7,4 +7,9 @@ fn main() { string.push_str("'"); string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push_str("\x52"); + string.push_str("\u{0052}"); + string.push_str(r##"a"##); } diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr index 453ec2d42f1..0e9bdaa23e7 100644 --- a/tests/ui/single_char_push_str.stderr +++ b/tests/ui/single_char_push_str.stderr @@ -12,5 +12,23 @@ error: calling `push_str()` using a single-character string literal LL | string.push_str("'"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` -error: aborting due to 2 previous errors +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:12:5 + | +LL | string.push_str("/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:13:5 + | +LL | string.push_str("/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:14:5 + | +LL | string.push_str(r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` + +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From b381ade1795f36149e36a646cdc83ee2fff032bf Mon Sep 17 00:00:00 2001 From: Christoph Walcher Date: Sat, 15 Aug 2020 01:40:47 +0200 Subject: elide lifetimes --- clippy_lints/src/methods/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2986a5a5944..614773a7e26 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1310,7 +1310,7 @@ declare_clippy_lint! { /// **What it does:** Warns when using push_str with a single-character string literal, /// and push with a char would work fine. /// - /// **Why is this bad?** it's less clear that we are pushing a single character + /// **Why is this bad?** It's less clear that we are pushing a single character /// /// **Known problems:** None /// @@ -3154,9 +3154,9 @@ fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryEx } } -fn get_hint_if_single_char_arg<'tcx>( - cx: &LateContext<'tcx>, - arg: &'tcx hir::Expr<'_>, +fn get_hint_if_single_char_arg( + cx: &LateContext<'_>, + arg: &hir::Expr<'_>, applicability: &mut Applicability, ) -> Option { if_chain! { @@ -3183,7 +3183,7 @@ fn get_hint_if_single_char_arg<'tcx>( } /// lint for length-1 `str`s for methods in `PATTERN_METHODS` -fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { +fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { let mut applicability = Applicability::MachineApplicable; if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { span_lint_and_sugg( @@ -3199,7 +3199,7 @@ fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr } /// lint for length-1 `str`s as argument for `push_str` -fn lint_single_char_push_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { +fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); -- cgit 1.4.1-3-g733a5 From a3ea65c2d9bc52f308745ae488435388fce753a2 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Mon, 15 Jun 2020 11:21:56 +0200 Subject: Implement new lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/methods/mod.rs | 130 +++++++++++++++++++++++++++++- src/lintlist/mod.rs | 7 ++ tests/ui/unnecessary_lazy_eval.fixed | 105 +++++++++++++++++++++++++ tests/ui/unnecessary_lazy_eval.rs | 105 +++++++++++++++++++++++++ tests/ui/unnecessary_lazy_eval.stderr | 144 ++++++++++++++++++++++++++++++++++ 7 files changed, 494 insertions(+), 1 deletion(-) create mode 100644 tests/ui/unnecessary_lazy_eval.fixed create mode 100644 tests/ui/unnecessary_lazy_eval.rs create mode 100644 tests/ui/unnecessary_lazy_eval.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 50fe7612909..c21190e9b9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1646,6 +1646,7 @@ Released 2018-09-13 [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option +[`option_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_unwrap_or_else [`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 986e9d9bee4..cb29f71387b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -672,6 +672,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::OK_EXPECT, &methods::OPTION_AS_REF_DEREF, &methods::OPTION_MAP_OR_NONE, + &methods::UNNECESSARY_LAZY_EVALUATION, &methods::OR_FUN_CALL, &methods::RESULT_MAP_OR_INTO_OPTION, &methods::SEARCH_IS_SOME, @@ -1360,6 +1361,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::UNINIT_ASSUMED_INIT), LintId::of(&methods::UNNECESSARY_FILTER_MAP), LintId::of(&methods::UNNECESSARY_FOLD), + LintId::of(&methods::UNNECESSARY_LAZY_EVALUATION), LintId::of(&methods::USELESS_ASREF), LintId::of(&methods::WRONG_SELF_CONVENTION), LintId::of(&methods::ZST_OFFSET), @@ -1610,6 +1612,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::OPTION_AS_REF_DEREF), + LintId::of(&methods::UNNECESSARY_LAZY_EVALUATION), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::SUSPICIOUS_MAP), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2330978e67f..61b7f2647ee 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1329,6 +1329,32 @@ declare_clippy_lint! { "`push_str()` used with a single-character string literal as parameter" } +declare_clippy_lint! { + /// **What it does:** Looks for unnecessary lazily evaluated closures on `Option` and `Result`. + /// + /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// let opt: Option = None; + /// + /// opt.unwrap_or_else(|| 42); + /// ``` + /// Use instead: + /// ```rust + /// let opt: Option = None; + /// + /// opt.unwrap_or(42); + /// ``` + pub UNNECESSARY_LAZY_EVALUATION, + style, + "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1378,6 +1404,7 @@ declare_lint_pass!(Methods => [ ZST_OFFSET, FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, + UNNECESSARY_LAZY_EVALUATION, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1398,13 +1425,18 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]), ["expect", ..] => lint_expect(cx, expr, arg_lists[0]), ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), - ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]), + ["unwrap_or_else", "map"] => { + lint_lazy_eval(cx, expr, arg_lists[0], true, "unwrap_or"); + lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]); + }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => { + lint_lazy_eval(cx, expr, arg_lists[0], false, "and"); bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); }, ["or_else", ..] => { + lint_lazy_eval(cx, expr, arg_lists[0], false, "or"); bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]); }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), @@ -1448,6 +1480,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), + ["unwrap_or_else", ..] => lint_lazy_eval(cx, expr, arg_lists[0], true, "unwrap_or"), + ["get_or_insert_with", ..] => lint_lazy_eval(cx, expr, arg_lists[0], true, "get_or_insert"), + ["ok_or_else", ..] => lint_lazy_eval(cx, expr, arg_lists[0], true, "ok_or"), _ => {}, } @@ -2663,6 +2698,99 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } } +/// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be +/// replaced with `(return value of simple closure)` +fn lint_lazy_eval<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr<'_>, + args: &'tcx [hir::Expr<'_>], + allow_variant_calls: bool, + simplify_using: &str, +) { + let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&args[0]), sym!(option_type)); + let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&args[0]), sym!(result_type)); + + if !is_option && !is_result { + return; + } + + // Return true if the expression is an accessor of any of the arguments + fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { + params.iter().any(|arg| { + if_chain! { + if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; + if let [p, ..] = path.segments; + then { + ident.name == p.ident.name + } else { + false + } + } + }) + } + + fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { + paths.iter().any(|candidate| match_qpath(path, candidate)) + } + + if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { + let body = cx.tcx.hir().body(eid); + let ex = &body.value; + let params = &body.params; + + let simplify = match ex.kind { + // Closures returning literals can be unconditionally simplified + hir::ExprKind::Lit(_) => true, + + // Reading fields can be simplified if the object is not an argument of the closure + hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), + + // Paths can be simplified if the root is not the argument, this also covers None + hir::ExprKind::Path(_) => !expr_uses_argument(ex, params), + + // Calls to Some, Ok, Err can be considered literals if they don't derive an argument + hir::ExprKind::Call(ref func, ref args) => if_chain! { + if allow_variant_calls; // Disable lint when rules conflict with bind_instead_of_map + if let hir::ExprKind::Path(ref path) = func.kind; + if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); + then { + !args.iter().any(|arg| expr_uses_argument(arg, params)) + } else { + false + } + }, + + // For anything more complex than the above, a closure is probably the right solution, + // or the case is handled by an other lint + _ => false, + }; + + if simplify { + let msg = if is_option { + "unnecessary closure used to substitute value for `Option::None`" + } else { + "unnecessary closure used to substitute value for `Result::Err`" + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_LAZY_EVALUATION, + expr.span, + msg, + &format!("Use `{}` instead", simplify_using), + format!( + "{0}.{1}({2})", + snippet(cx, args[0].span, ".."), + simplify_using, + snippet(cx, ex.span, ".."), + ), + Applicability::MachineApplicable, + ); + } + } +} + /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s fn lint_map_unwrap_or_else<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 233f95deedd..1e76163f946 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2383,6 +2383,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, + Lint { + name: "unnecessary_lazy_eval", + group: "style", + desc: "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation", + deprecation: None, + module: "methods", + }, Lint { name: "unnecessary_mut_passed", group: "style", diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed new file mode 100644 index 00000000000..fcfa6dfe12d --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -0,0 +1,105 @@ +// run-rustfix +#![warn(clippy::unnecessary_lazy_evaluation)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::bind_instead_of_map)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: u32, +} + +impl SomeStruct { + fn return_some_field(&self) -> u32 { + self.some_field + } +} + +fn some_call() -> T { + T::default() +} + +fn main() { + let astronomers_pi = 10; + let ext_str = SomeStruct { some_field: 10 }; + + // Should lint - Option + let mut opt = Some(42); + let ext_opt = Some(42); + let _ = opt.unwrap_or(2); + let _ = opt.unwrap_or(astronomers_pi); + let _ = opt.unwrap_or(ext_str.some_field); + let _ = opt.and(ext_opt); + let _ = opt.or(ext_opt); + let _ = opt.or(None); + let _ = opt.get_or_insert(2); + let _ = opt.ok_or(2); + + // Cases when unwrap is not called on a simple variable + let _ = Some(10).unwrap_or(2); + let _ = Some(10).and(ext_opt); + let _: Option = None.or(ext_opt); + let _ = None.get_or_insert(2); + let _: Result = None.ok_or(2); + let _: Option = None.or(None); + + let mut deep = Deep(Some(42)); + let _ = deep.0.unwrap_or(2); + let _ = deep.0.and(ext_opt); + let _ = deep.0.or(None); + let _ = deep.0.get_or_insert(2); + let _ = deep.0.ok_or(2); + + // Should not lint - Option + let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); + let _ = opt.or_else(some_call); + let _ = opt.or_else(|| some_call()); + let _: Result = opt.ok_or_else(|| some_call()); + let _: Result = opt.ok_or_else(some_call); + let _ = deep.0.get_or_insert_with(|| some_call()); + let _ = deep.0.or_else(some_call); + let _ = deep.0.or_else(|| some_call()); + + // These are handled by bind_instead_of_map + let _: Option = None.or_else(|| Some(3)); + let _ = deep.0.or_else(|| Some(3)); + let _ = opt.or_else(|| Some(3)); + + // Should lint - Result + let res: Result = Err(5); + let res2: Result = Err(SomeStruct { some_field: 5 }); + + let _ = res2.unwrap_or(2); + let _ = res2.unwrap_or(astronomers_pi); + let _ = res2.unwrap_or(ext_str.some_field); + + // Should not lint - Result + let _ = res.unwrap_or_else(|err| err); + let _ = res2.unwrap_or_else(|err| err.some_field); + let _ = res2.unwrap_or_else(|err| err.return_some_field()); + let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + + let _: Result = res.and_then(|x| Ok(x)); + let _: Result = res.and_then(|x| Err(x)); + + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.or_else(|err| Err(err)); + + // These are handled by bind_instead_of_map + let _: Result = res.and_then(|_| Ok(2)); + let _: Result = res.and_then(|_| Ok(astronomers_pi)); + let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + + let _: Result = res.and_then(|_| Err(2)); + let _: Result = res.and_then(|_| Err(astronomers_pi)); + let _: Result = res.and_then(|_| Err(ext_str.some_field)); + + let _: Result = res.or_else(|_| Ok(2)); + let _: Result = res.or_else(|_| Ok(astronomers_pi)); + let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); +} diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs new file mode 100644 index 00000000000..04b3c8ae1e2 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -0,0 +1,105 @@ +// run-rustfix +#![warn(clippy::unnecessary_lazy_eval)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::bind_instead_of_map)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: u32, +} + +impl SomeStruct { + fn return_some_field(&self) -> u32 { + self.some_field + } +} + +fn some_call() -> T { + T::default() +} + +fn main() { + let astronomers_pi = 10; + let ext_str = SomeStruct { some_field: 10 }; + + // Should lint - Option + let mut opt = Some(42); + let ext_opt = Some(42); + let _ = opt.unwrap_or_else(|| 2); + let _ = opt.unwrap_or_else(|| astronomers_pi); + let _ = opt.unwrap_or_else(|| ext_str.some_field); + let _ = opt.and_then(|_| ext_opt); + let _ = opt.or_else(|| ext_opt); + let _ = opt.or_else(|| None); + let _ = opt.get_or_insert_with(|| 2); + let _ = opt.ok_or_else(|| 2); + + // Cases when unwrap is not called on a simple variable + let _ = Some(10).unwrap_or_else(|| 2); + let _ = Some(10).and_then(|_| ext_opt); + let _: Option = None.or_else(|| ext_opt); + let _ = None.get_or_insert_with(|| 2); + let _: Result = None.ok_or_else(|| 2); + let _: Option = None.or_else(|| None); + + let mut deep = Deep(Some(42)); + let _ = deep.0.unwrap_or_else(|| 2); + let _ = deep.0.and_then(|_| ext_opt); + let _ = deep.0.or_else(|| None); + let _ = deep.0.get_or_insert_with(|| 2); + let _ = deep.0.ok_or_else(|| 2); + + // Should not lint - Option + let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); + let _ = opt.or_else(some_call); + let _ = opt.or_else(|| some_call()); + let _: Result = opt.ok_or_else(|| some_call()); + let _: Result = opt.ok_or_else(some_call); + let _ = deep.0.get_or_insert_with(|| some_call()); + let _ = deep.0.or_else(some_call); + let _ = deep.0.or_else(|| some_call()); + + // These are handled by bind_instead_of_map + let _: Option = None.or_else(|| Some(3)); + let _ = deep.0.or_else(|| Some(3)); + let _ = opt.or_else(|| Some(3)); + + // Should lint - Result + let res: Result = Err(5); + let res2: Result = Err(SomeStruct { some_field: 5 }); + + let _ = res2.unwrap_or_else(|_| 2); + let _ = res2.unwrap_or_else(|_| astronomers_pi); + let _ = res2.unwrap_or_else(|_| ext_str.some_field); + + // Should not lint - Result + let _ = res.unwrap_or_else(|err| err); + let _ = res2.unwrap_or_else(|err| err.some_field); + let _ = res2.unwrap_or_else(|err| err.return_some_field()); + let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + + let _: Result = res.and_then(|x| Ok(x)); + let _: Result = res.and_then(|x| Err(x)); + + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.or_else(|err| Err(err)); + + // These are handled by bind_instead_of_map + let _: Result = res.and_then(|_| Ok(2)); + let _: Result = res.and_then(|_| Ok(astronomers_pi)); + let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + + let _: Result = res.and_then(|_| Err(2)); + let _: Result = res.and_then(|_| Err(astronomers_pi)); + let _: Result = res.and_then(|_| Err(ext_str.some_field)); + + let _: Result = res.or_else(|_| Ok(2)); + let _: Result = res.or_else(|_| Ok(astronomers_pi)); + let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); +} diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr new file mode 100644 index 00000000000..b941bf84246 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -0,0 +1,144 @@ +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:30:13 + | +LL | let _ = opt.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` + | + = note: `-D clippy::unnecessary-lazy-evaluation` implied by `-D warnings` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:31:13 + | +LL | let _ = opt.unwrap_or_else(|| astronomers_pi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:32:13 + | +LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:33:13 + | +LL | let _ = opt.and_then(|_| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:34:13 + | +LL | let _ = opt.or_else(|| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:35:13 + | +LL | let _ = opt.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:36:13 + | +LL | let _ = opt.get_or_insert_with(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:37:13 + | +LL | let _ = opt.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:40:13 + | +LL | let _ = Some(10).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:41:13 + | +LL | let _ = Some(10).and_then(|_| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:42:26 + | +LL | let _: Option = None.or_else(|| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:43:13 + | +LL | let _ = None.get_or_insert_with(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:44:31 + | +LL | let _: Result = None.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:45:26 + | +LL | let _: Option = None.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:48:13 + | +LL | let _ = deep.0.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:49:13 + | +LL | let _ = deep.0.and_then(|_| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:50:13 + | +LL | let _ = deep.0.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:51:13 + | +LL | let _ = deep.0.get_or_insert_with(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:52:13 + | +LL | let _ = deep.0.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:73:13 + | +LL | let _ = res2.unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:74:13 + | +LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:75:13 + | +LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` + +error: unknown clippy lint: clippy::unnecessary_lazy_eval + --> $DIR/unnecessary_lazy_eval.rs:2:9 + | +LL | #![warn(clippy::unnecessary_lazy_eval)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unnecessary_lazy_evaluation` + | + = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings` + +error: aborting due to 23 previous errors + -- cgit 1.4.1-3-g733a5 From 848af393103d769458a206547ea4506fd0229304 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Mon, 15 Jun 2020 14:55:23 +0200 Subject: Add note to `or_fun_call`, list checked methods --- clippy_lints/src/methods/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 61b7f2647ee..c672ca41dec 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1330,11 +1330,21 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Looks for unnecessary lazily evaluated closures on `Option` and `Result`. + /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary + /// lazily evaluated closures on `Option` and `Result`. + /// + /// This lint suggests changing the following functions, when eager evaluation results in + /// simpler code: + /// - `unwrap_or_else` to `unwrap_or` + /// - `and_then` to `and` + /// - `or_else` to `or` + /// - `get_or_insert_with` to `get_or_insert` + /// - `ok_or_else` to `ok_or` /// /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases. /// - /// **Known problems:** None. + /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have + /// side effects. Eagerly evaluating them can change the semantics of the program. /// /// **Example:** /// -- cgit 1.4.1-3-g733a5 From a7cc5d40683b9351c35a627b05886f43fdec684f Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Mon, 15 Jun 2020 15:26:02 +0200 Subject: Also simplify if the closure body is an index expression --- clippy_lints/src/methods/mod.rs | 10 ++++++ tests/ui/unnecessary_lazy_eval.fixed | 60 +++++++++++++++++-------------- tests/ui/unnecessary_lazy_eval.rs | 60 +++++++++++++++++-------------- tests/ui/unnecessary_lazy_eval.stderr | 68 ++++++++++++++++++++--------------- 4 files changed, 116 insertions(+), 82 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c672ca41dec..ed8eaba75d1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2753,6 +2753,16 @@ fn lint_lazy_eval<'a, 'tcx>( // Closures returning literals can be unconditionally simplified hir::ExprKind::Lit(_) => true, + hir::ExprKind::Index(ref object, ref index) => { + // arguments are not being indexed into + if !expr_uses_argument(object, params) { + // arguments are not used as index + !expr_uses_argument(index, params) + } else { + false + } + }, + // Reading fields can be simplified if the object is not an argument of the closure hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index fcfa6dfe12d..c806cf8dce4 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -3,15 +3,15 @@ #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] -struct Deep(Option); +struct Deep(Option); #[derive(Copy, Clone)] struct SomeStruct { - some_field: u32, + some_field: usize, } impl SomeStruct { - fn return_some_field(&self) -> u32 { + fn return_some_field(&self) -> usize { self.some_field } } @@ -22,6 +22,7 @@ fn some_call() -> T { fn main() { let astronomers_pi = 10; + let ext_arr: [usize; 1] = [2]; let ext_str = SomeStruct { some_field: 10 }; // Should lint - Option @@ -30,19 +31,21 @@ fn main() { let _ = opt.unwrap_or(2); let _ = opt.unwrap_or(astronomers_pi); let _ = opt.unwrap_or(ext_str.some_field); + let _ = opt.unwrap_or(ext_arr[0]); let _ = opt.and(ext_opt); let _ = opt.or(ext_opt); let _ = opt.or(None); let _ = opt.get_or_insert(2); let _ = opt.ok_or(2); + let _ = opt.ok_or(ext_arr[0]); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or(2); let _ = Some(10).and(ext_opt); - let _: Option = None.or(ext_opt); + let _: Option = None.or(ext_opt); let _ = None.get_or_insert(2); - let _: Result = None.ok_or(2); - let _: Option = None.or(None); + let _: Result = None.ok_or(2); + let _: Option = None.or(None); let mut deep = Deep(Some(42)); let _ = deep.0.unwrap_or(2); @@ -55,20 +58,22 @@ fn main() { let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); - let _: Result = opt.ok_or_else(|| some_call()); - let _: Result = opt.ok_or_else(some_call); + let _: Result = opt.ok_or_else(|| some_call()); + let _: Result = opt.ok_or_else(some_call); let _ = deep.0.get_or_insert_with(|| some_call()); let _ = deep.0.or_else(some_call); let _ = deep.0.or_else(|| some_call()); // These are handled by bind_instead_of_map - let _: Option = None.or_else(|| Some(3)); + let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); + let _ = Some(10).and_then(|idx| Some(idx)); + let _: Option = None.or_else(|| Some(3)); let _ = deep.0.or_else(|| Some(3)); let _ = opt.or_else(|| Some(3)); // Should lint - Result - let res: Result = Err(5); - let res2: Result = Err(SomeStruct { some_field: 5 }); + let res: Result = Err(5); + let res2: Result = Err(SomeStruct { some_field: 5 }); let _ = res2.unwrap_or(2); let _ = res2.unwrap_or(astronomers_pi); @@ -76,30 +81,31 @@ fn main() { // Should not lint - Result let _ = res.unwrap_or_else(|err| err); + let _ = res.unwrap_or_else(|err| ext_arr[err]); let _ = res2.unwrap_or_else(|err| err.some_field); let _ = res2.unwrap_or_else(|err| err.return_some_field()); let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); - let _: Result = res.and_then(|x| Ok(x)); - let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.and_then(|x| Ok(x)); + let _: Result = res.and_then(|x| Err(x)); - let _: Result = res.or_else(|err| Ok(err)); - let _: Result = res.or_else(|err| Err(err)); + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.or_else(|err| Err(err)); // These are handled by bind_instead_of_map - let _: Result = res.and_then(|_| Ok(2)); - let _: Result = res.and_then(|_| Ok(astronomers_pi)); - let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + let _: Result = res.and_then(|_| Ok(2)); + let _: Result = res.and_then(|_| Ok(astronomers_pi)); + let _: Result = res.and_then(|_| Ok(ext_str.some_field)); - let _: Result = res.and_then(|_| Err(2)); - let _: Result = res.and_then(|_| Err(astronomers_pi)); - let _: Result = res.and_then(|_| Err(ext_str.some_field)); + let _: Result = res.and_then(|_| Err(2)); + let _: Result = res.and_then(|_| Err(astronomers_pi)); + let _: Result = res.and_then(|_| Err(ext_str.some_field)); - let _: Result = res.or_else(|_| Ok(2)); - let _: Result = res.or_else(|_| Ok(astronomers_pi)); - let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + let _: Result = res.or_else(|_| Ok(2)); + let _: Result = res.or_else(|_| Ok(astronomers_pi)); + let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - let _: Result = res.or_else(|_| Err(2)); - let _: Result = res.or_else(|_| Err(astronomers_pi)); - let _: Result = res.or_else(|_| Err(ext_str.some_field)); + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); } diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 04b3c8ae1e2..dfc6d3ba573 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -3,15 +3,15 @@ #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] -struct Deep(Option); +struct Deep(Option); #[derive(Copy, Clone)] struct SomeStruct { - some_field: u32, + some_field: usize, } impl SomeStruct { - fn return_some_field(&self) -> u32 { + fn return_some_field(&self) -> usize { self.some_field } } @@ -22,6 +22,7 @@ fn some_call() -> T { fn main() { let astronomers_pi = 10; + let ext_arr: [usize; 1] = [2]; let ext_str = SomeStruct { some_field: 10 }; // Should lint - Option @@ -30,19 +31,21 @@ fn main() { let _ = opt.unwrap_or_else(|| 2); let _ = opt.unwrap_or_else(|| astronomers_pi); let _ = opt.unwrap_or_else(|| ext_str.some_field); + let _ = opt.unwrap_or_else(|| ext_arr[0]); let _ = opt.and_then(|_| ext_opt); let _ = opt.or_else(|| ext_opt); let _ = opt.or_else(|| None); let _ = opt.get_or_insert_with(|| 2); let _ = opt.ok_or_else(|| 2); + let _ = opt.ok_or_else(|| ext_arr[0]); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or_else(|| 2); let _ = Some(10).and_then(|_| ext_opt); - let _: Option = None.or_else(|| ext_opt); + let _: Option = None.or_else(|| ext_opt); let _ = None.get_or_insert_with(|| 2); - let _: Result = None.ok_or_else(|| 2); - let _: Option = None.or_else(|| None); + let _: Result = None.ok_or_else(|| 2); + let _: Option = None.or_else(|| None); let mut deep = Deep(Some(42)); let _ = deep.0.unwrap_or_else(|| 2); @@ -55,20 +58,22 @@ fn main() { let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); - let _: Result = opt.ok_or_else(|| some_call()); - let _: Result = opt.ok_or_else(some_call); + let _: Result = opt.ok_or_else(|| some_call()); + let _: Result = opt.ok_or_else(some_call); let _ = deep.0.get_or_insert_with(|| some_call()); let _ = deep.0.or_else(some_call); let _ = deep.0.or_else(|| some_call()); // These are handled by bind_instead_of_map - let _: Option = None.or_else(|| Some(3)); + let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); + let _ = Some(10).and_then(|idx| Some(idx)); + let _: Option = None.or_else(|| Some(3)); let _ = deep.0.or_else(|| Some(3)); let _ = opt.or_else(|| Some(3)); // Should lint - Result - let res: Result = Err(5); - let res2: Result = Err(SomeStruct { some_field: 5 }); + let res: Result = Err(5); + let res2: Result = Err(SomeStruct { some_field: 5 }); let _ = res2.unwrap_or_else(|_| 2); let _ = res2.unwrap_or_else(|_| astronomers_pi); @@ -76,30 +81,31 @@ fn main() { // Should not lint - Result let _ = res.unwrap_or_else(|err| err); + let _ = res.unwrap_or_else(|err| ext_arr[err]); let _ = res2.unwrap_or_else(|err| err.some_field); let _ = res2.unwrap_or_else(|err| err.return_some_field()); let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); - let _: Result = res.and_then(|x| Ok(x)); - let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.and_then(|x| Ok(x)); + let _: Result = res.and_then(|x| Err(x)); - let _: Result = res.or_else(|err| Ok(err)); - let _: Result = res.or_else(|err| Err(err)); + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.or_else(|err| Err(err)); // These are handled by bind_instead_of_map - let _: Result = res.and_then(|_| Ok(2)); - let _: Result = res.and_then(|_| Ok(astronomers_pi)); - let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + let _: Result = res.and_then(|_| Ok(2)); + let _: Result = res.and_then(|_| Ok(astronomers_pi)); + let _: Result = res.and_then(|_| Ok(ext_str.some_field)); - let _: Result = res.and_then(|_| Err(2)); - let _: Result = res.and_then(|_| Err(astronomers_pi)); - let _: Result = res.and_then(|_| Err(ext_str.some_field)); + let _: Result = res.and_then(|_| Err(2)); + let _: Result = res.and_then(|_| Err(astronomers_pi)); + let _: Result = res.and_then(|_| Err(ext_str.some_field)); - let _: Result = res.or_else(|_| Ok(2)); - let _: Result = res.or_else(|_| Ok(astronomers_pi)); - let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + let _: Result = res.or_else(|_| Ok(2)); + let _: Result = res.or_else(|_| Ok(astronomers_pi)); + let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - let _: Result = res.or_else(|_| Err(2)); - let _: Result = res.or_else(|_| Err(astronomers_pi)); - let _: Result = res.or_else(|_| Err(ext_str.some_field)); + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); } diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index b941bf84246..15591817540 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:30:13 + --> $DIR/unnecessary_lazy_eval.rs:31:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` @@ -7,43 +7,49 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluation` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:31:13 + --> $DIR/unnecessary_lazy_eval.rs:32:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:32:13 + --> $DIR/unnecessary_lazy_eval.rs:33:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:33:13 + --> $DIR/unnecessary_lazy_eval.rs:34:13 + | +LL | let _ = opt.unwrap_or_else(|| ext_arr[0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:35:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:34:13 + --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:35:13 + --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:36:13 + --> $DIR/unnecessary_lazy_eval.rs:38:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:37:13 + --> $DIR/unnecessary_lazy_eval.rs:39:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` @@ -51,83 +57,89 @@ LL | let _ = opt.ok_or_else(|| 2); error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:40:13 | +LL | let _ = opt.ok_or_else(|| ext_arr[0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:43:13 + | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:41:13 + --> $DIR/unnecessary_lazy_eval.rs:44:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:42:26 + --> $DIR/unnecessary_lazy_eval.rs:45:28 | -LL | let _: Option = None.or_else(|| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` +LL | let _: Option = None.or_else(|| ext_opt); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:43:13 + --> $DIR/unnecessary_lazy_eval.rs:46:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:44:31 + --> $DIR/unnecessary_lazy_eval.rs:47:35 | -LL | let _: Result = None.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` +LL | let _: Result = None.ok_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:45:26 + --> $DIR/unnecessary_lazy_eval.rs:48:28 | -LL | let _: Option = None.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` +LL | let _: Option = None.or_else(|| None); + | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:13 + --> $DIR/unnecessary_lazy_eval.rs:51:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:13 + --> $DIR/unnecessary_lazy_eval.rs:52:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:13 + --> $DIR/unnecessary_lazy_eval.rs:53:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:13 + --> $DIR/unnecessary_lazy_eval.rs:54:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:52:13 + --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:73:13 + --> $DIR/unnecessary_lazy_eval.rs:78:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:74:13 + --> $DIR/unnecessary_lazy_eval.rs:79:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:75:13 + --> $DIR/unnecessary_lazy_eval.rs:80:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` @@ -140,5 +152,5 @@ LL | #![warn(clippy::unnecessary_lazy_eval)] | = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings` -error: aborting due to 23 previous errors +error: aborting due to 25 previous errors -- cgit 1.4.1-3-g733a5 From 75637c1edac6db37b3c8aa17ef6b5a91db699a00 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Mon, 15 Jun 2020 20:01:18 +0200 Subject: Catch function calls in argument lists, add tests that tuples don't get linted --- clippy_lints/src/methods/mod.rs | 25 ++++++++++-------- tests/ui/unnecessary_lazy_eval.fixed | 8 +++++- tests/ui/unnecessary_lazy_eval.rs | 8 +++++- tests/ui/unnecessary_lazy_eval.stderr | 48 +++++++++++++++++------------------ 4 files changed, 52 insertions(+), 37 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ed8eaba75d1..463ef48f62c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2744,12 +2744,8 @@ fn lint_lazy_eval<'a, 'tcx>( paths.iter().any(|candidate| match_qpath(path, candidate)) } - if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { - let body = cx.tcx.hir().body(eid); - let ex = &body.value; - let params = &body.params; - - let simplify = match ex.kind { + fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { + match expr.kind { // Closures returning literals can be unconditionally simplified hir::ExprKind::Lit(_) => true, @@ -2767,15 +2763,16 @@ fn lint_lazy_eval<'a, 'tcx>( hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), // Paths can be simplified if the root is not the argument, this also covers None - hir::ExprKind::Path(_) => !expr_uses_argument(ex, params), + hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), // Calls to Some, Ok, Err can be considered literals if they don't derive an argument hir::ExprKind::Call(ref func, ref args) => if_chain! { - if allow_variant_calls; // Disable lint when rules conflict with bind_instead_of_map + if variant_calls; // Disable lint when rules conflict with bind_instead_of_map if let hir::ExprKind::Path(ref path) = func.kind; if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); then { - !args.iter().any(|arg| expr_uses_argument(arg, params)) + // Recursively check all arguments + args.iter().all(|arg| can_simplify(arg, params, variant_calls)) } else { false } @@ -2784,9 +2781,15 @@ fn lint_lazy_eval<'a, 'tcx>( // For anything more complex than the above, a closure is probably the right solution, // or the case is handled by an other lint _ => false, - }; + } + } + + if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { + let body = cx.tcx.hir().body(eid); + let ex = &body.value; + let params = &body.params; - if simplify { + if can_simplify(ex, params, allow_variant_calls) { let msg = if is_option { "unnecessary closure used to substitute value for `Option::None`" } else { diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index c806cf8dce4..7f9d90a8569 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -25,9 +25,12 @@ fn main() { let ext_arr: [usize; 1] = [2]; let ext_str = SomeStruct { some_field: 10 }; - // Should lint - Option let mut opt = Some(42); let ext_opt = Some(42); + let nested_opt = Some(Some(42)); + let nested_tuple_opt = Some(Some((42, 43))); + + // Should lint - Option let _ = opt.unwrap_or(2); let _ = opt.unwrap_or(astronomers_pi); let _ = opt.unwrap_or(ext_str.some_field); @@ -56,6 +59,9 @@ fn main() { // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); + let _ = nested_opt.unwrap_or_else(|| Some(some_call())); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); let _: Result = opt.ok_or_else(|| some_call()); diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index dfc6d3ba573..ca8238d6dcf 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -25,9 +25,12 @@ fn main() { let ext_arr: [usize; 1] = [2]; let ext_str = SomeStruct { some_field: 10 }; - // Should lint - Option let mut opt = Some(42); let ext_opt = Some(42); + let nested_opt = Some(Some(42)); + let nested_tuple_opt = Some(Some((42, 43))); + + // Should lint - Option let _ = opt.unwrap_or_else(|| 2); let _ = opt.unwrap_or_else(|| astronomers_pi); let _ = opt.unwrap_or_else(|| ext_str.some_field); @@ -56,6 +59,9 @@ fn main() { // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); + let _ = nested_opt.unwrap_or_else(|| Some(some_call())); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); let _: Result = opt.ok_or_else(|| some_call()); diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 15591817540..b8ec654e5c7 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:31:13 + --> $DIR/unnecessary_lazy_eval.rs:34:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` @@ -7,139 +7,139 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluation` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:32:13 + --> $DIR/unnecessary_lazy_eval.rs:35:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:33:13 + --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:34:13 + --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.unwrap_or_else(|| ext_arr[0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:35:13 + --> $DIR/unnecessary_lazy_eval.rs:38:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:36:13 + --> $DIR/unnecessary_lazy_eval.rs:39:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:37:13 + --> $DIR/unnecessary_lazy_eval.rs:40:13 | LL | let _ = opt.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:38:13 + --> $DIR/unnecessary_lazy_eval.rs:41:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:39:13 + --> $DIR/unnecessary_lazy_eval.rs:42:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:40:13 + --> $DIR/unnecessary_lazy_eval.rs:43:13 | LL | let _ = opt.ok_or_else(|| ext_arr[0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:43:13 + --> $DIR/unnecessary_lazy_eval.rs:46:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:44:13 + --> $DIR/unnecessary_lazy_eval.rs:47:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:45:28 + --> $DIR/unnecessary_lazy_eval.rs:48:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:46:13 + --> $DIR/unnecessary_lazy_eval.rs:49:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:47:35 + --> $DIR/unnecessary_lazy_eval.rs:50:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:28 + --> $DIR/unnecessary_lazy_eval.rs:51:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:13 + --> $DIR/unnecessary_lazy_eval.rs:54:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:52:13 + --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:53:13 + --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:54:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:55:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:78:13 + --> $DIR/unnecessary_lazy_eval.rs:84:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:79:13 + --> $DIR/unnecessary_lazy_eval.rs:85:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:80:13 + --> $DIR/unnecessary_lazy_eval.rs:86:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` -- cgit 1.4.1-3-g733a5 From a7083eea1c8821ff187218f55a1ac17b0f2c0fcb Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 26 Jul 2020 20:18:12 +0200 Subject: Removed the extra lifetime parameter --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 463ef48f62c..6693c358a02 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2710,8 +2710,8 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map /// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be /// replaced with `(return value of simple closure)` -fn lint_lazy_eval<'a, 'tcx>( - cx: &LateContext<'a, 'tcx>, +fn lint_lazy_eval<'tcx>( + cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], allow_variant_calls: bool, -- cgit 1.4.1-3-g733a5 From 94cf90e5a56bbd9adbf6d6181d046ede9b96a7d8 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 26 Jul 2020 20:52:00 +0200 Subject: Apply suggested change Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6693c358a02..4578c228107 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2717,8 +2717,8 @@ fn lint_lazy_eval<'tcx>( allow_variant_calls: bool, simplify_using: &str, ) { - let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&args[0]), sym!(option_type)); + let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&args[0]), sym!(result_type)); if !is_option && !is_result { return; -- cgit 1.4.1-3-g733a5 From 9c41822d34c69dbfded4d9d8b4b8962564be80f1 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 26 Jul 2020 21:08:07 +0200 Subject: Apply suggested change Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4578c228107..70a6b1f5021 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2717,8 +2717,8 @@ fn lint_lazy_eval<'tcx>( allow_variant_calls: bool, simplify_using: &str, ) { - let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); if !is_option && !is_result { return; -- cgit 1.4.1-3-g733a5 From d71b418ac511ee604af9320e401a7ff3fd115482 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 16 Aug 2020 20:47:50 +0200 Subject: Moved to submodule, don't trigger if map_unwrap_or does --- clippy_lints/src/methods/mod.rs | 136 +++------------------- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 113 ++++++++++++++++++ 2 files changed, 132 insertions(+), 117 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_lazy_eval.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 70a6b1f5021..bfc89a74742 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3,6 +3,7 @@ mod inefficient_to_string; mod manual_saturating_arithmetic; mod option_map_unwrap_or; mod unnecessary_filter_map; +mod unnecessary_lazy_eval; use std::borrow::Cow; use std::fmt; @@ -1436,17 +1437,18 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["expect", ..] => lint_expect(cx, expr, arg_lists[0]), ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { - lint_lazy_eval(cx, expr, arg_lists[0], true, "unwrap_or"); - lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]); + if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"); + } }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => { - lint_lazy_eval(cx, expr, arg_lists[0], false, "and"); + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and"); bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); }, ["or_else", ..] => { - lint_lazy_eval(cx, expr, arg_lists[0], false, "or"); + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or"); bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]); }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), @@ -1490,9 +1492,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), - ["unwrap_or_else", ..] => lint_lazy_eval(cx, expr, arg_lists[0], true, "unwrap_or"), - ["get_or_insert_with", ..] => lint_lazy_eval(cx, expr, arg_lists[0], true, "get_or_insert"), - ["ok_or_else", ..] => lint_lazy_eval(cx, expr, arg_lists[0], true, "ok_or"), + ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"), + ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"), + ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"), _ => {}, } @@ -2708,119 +2710,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } } -/// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be -/// replaced with `(return value of simple closure)` -fn lint_lazy_eval<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - args: &'tcx [hir::Expr<'_>], - allow_variant_calls: bool, - simplify_using: &str, -) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); - - if !is_option && !is_result { - return; - } - - // Return true if the expression is an accessor of any of the arguments - fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { - params.iter().any(|arg| { - if_chain! { - if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; - if let [p, ..] = path.segments; - then { - ident.name == p.ident.name - } else { - false - } - } - }) - } - - fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { - paths.iter().any(|candidate| match_qpath(path, candidate)) - } - - fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { - match expr.kind { - // Closures returning literals can be unconditionally simplified - hir::ExprKind::Lit(_) => true, - - hir::ExprKind::Index(ref object, ref index) => { - // arguments are not being indexed into - if !expr_uses_argument(object, params) { - // arguments are not used as index - !expr_uses_argument(index, params) - } else { - false - } - }, - - // Reading fields can be simplified if the object is not an argument of the closure - hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), - - // Paths can be simplified if the root is not the argument, this also covers None - hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), - - // Calls to Some, Ok, Err can be considered literals if they don't derive an argument - hir::ExprKind::Call(ref func, ref args) => if_chain! { - if variant_calls; // Disable lint when rules conflict with bind_instead_of_map - if let hir::ExprKind::Path(ref path) = func.kind; - if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); - then { - // Recursively check all arguments - args.iter().all(|arg| can_simplify(arg, params, variant_calls)) - } else { - false - } - }, - - // For anything more complex than the above, a closure is probably the right solution, - // or the case is handled by an other lint - _ => false, - } - } - - if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { - let body = cx.tcx.hir().body(eid); - let ex = &body.value; - let params = &body.params; - - if can_simplify(ex, params, allow_variant_calls) { - let msg = if is_option { - "unnecessary closure used to substitute value for `Option::None`" - } else { - "unnecessary closure used to substitute value for `Result::Err`" - }; - - span_lint_and_sugg( - cx, - UNNECESSARY_LAZY_EVALUATION, - expr.span, - msg, - &format!("Use `{}` instead", simplify_using), - format!( - "{0}.{1}({2})", - snippet(cx, args[0].span, ".."), - simplify_using, - snippet(cx, ex.span, ".."), - ), - Applicability::MachineApplicable, - ); - } - } -} - /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s fn lint_map_unwrap_or_else<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>], unwrap_args: &'tcx [hir::Expr<'_>], -) { +) -> bool { // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type)); @@ -2832,10 +2728,10 @@ fn lint_map_unwrap_or_else<'tcx>( let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx); if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { - return; + return false; } } else { - return; + return false; } // lint message @@ -2865,9 +2761,15 @@ fn lint_map_unwrap_or_else<'tcx>( map_snippet, unwrap_snippet, ), ); + true } else if same_span && multiline { span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); - }; + true + } else { + false + } + } else { + false } } diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs new file mode 100644 index 00000000000..0dbedc4919c --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -0,0 +1,113 @@ +use crate::utils::{match_qpath, span_lint_and_sugg, snippet, is_type_diagnostic_item}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::UNNECESSARY_LAZY_EVALUATION; + +/// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be +/// replaced with `(return value of simple closure)` +pub(super) fn lint<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + args: &'tcx [hir::Expr<'_>], + allow_variant_calls: bool, + simplify_using: &str, +) { + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); + + if !is_option && !is_result { + return; + } + + // Return true if the expression is an accessor of any of the arguments + fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { + params.iter().any(|arg| { + if_chain! { + if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; + if let [p, ..] = path.segments; + then { + ident.name == p.ident.name + } else { + false + } + } + }) + } + + fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { + paths.iter().any(|candidate| match_qpath(path, candidate)) + } + + fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { + match expr.kind { + // Closures returning literals can be unconditionally simplified + hir::ExprKind::Lit(_) => true, + + hir::ExprKind::Index(ref object, ref index) => { + // arguments are not being indexed into + if !expr_uses_argument(object, params) { + // arguments are not used as index + !expr_uses_argument(index, params) + } else { + false + } + }, + + // Reading fields can be simplified if the object is not an argument of the closure + hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), + + // Paths can be simplified if the root is not the argument, this also covers None + hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), + + // Calls to Some, Ok, Err can be considered literals if they don't derive an argument + hir::ExprKind::Call(ref func, ref args) => if_chain! { + if variant_calls; // Disable lint when rules conflict with bind_instead_of_map + if let hir::ExprKind::Path(ref path) = func.kind; + if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); + then { + // Recursively check all arguments + args.iter().all(|arg| can_simplify(arg, params, variant_calls)) + } else { + false + } + }, + + // For anything more complex than the above, a closure is probably the right solution, + // or the case is handled by an other lint + _ => false, + } + } + + if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { + let body = cx.tcx.hir().body(eid); + let ex = &body.value; + let params = &body.params; + + if can_simplify(ex, params, allow_variant_calls) { + let msg = if is_option { + "unnecessary closure used to substitute value for `Option::None`" + } else { + "unnecessary closure used to substitute value for `Result::Err`" + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_LAZY_EVALUATION, + expr.span, + msg, + &format!("Use `{}` instead", simplify_using), + format!( + "{0}.{1}({2})", + snippet(cx, args[0].span, ".."), + simplify_using, + snippet(cx, ex.span, ".."), + ), + Applicability::MachineApplicable, + ); + } + } +} -- cgit 1.4.1-3-g733a5 From 8a14c115369f163e7f96544df48b26376a06a3fb Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 16 Aug 2020 20:50:30 +0200 Subject: Cleanup, explain return value --- clippy_lints/src/methods/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bfc89a74742..c2b2cb98012 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2711,6 +2711,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s +/// Return true if lint triggered fn lint_map_unwrap_or_else<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -2761,16 +2762,14 @@ fn lint_map_unwrap_or_else<'tcx>( map_snippet, unwrap_snippet, ), ); - true + return true; } else if same_span && multiline { span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); - true - } else { - false + return true; } - } else { - false } + + false } /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s -- cgit 1.4.1-3-g733a5 From 3b52d7f780f2023d6596fe73c0a71f663b26bc33 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 16 Aug 2020 20:51:16 +0200 Subject: run cargo dev fmt --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 0dbedc4919c..b44089f7bfc 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_qpath, span_lint_and_sugg, snippet, is_type_diagnostic_item}; +use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -- cgit 1.4.1-3-g733a5 From b7ee8685ac83e0f3f32ac5ab5d597d5451d07057 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 16 Aug 2020 21:04:02 +0200 Subject: Fix dogfooding test errors --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 172 +++++++++++----------- 1 file changed, 85 insertions(+), 87 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index b44089f7bfc..a3e7e9971f8 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -6,6 +6,66 @@ use rustc_lint::LateContext; use super::UNNECESSARY_LAZY_EVALUATION; +// Return true if the expression is an accessor of any of the arguments +fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { + params.iter().any(|arg| { + if_chain! { + if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; + if let [p, ..] = path.segments; + then { + ident.name == p.ident.name + } else { + false + } + } + }) +} + +fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { + paths.iter().any(|candidate| match_qpath(path, candidate)) +} + +fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { + match expr.kind { + // Closures returning literals can be unconditionally simplified + hir::ExprKind::Lit(_) => true, + + hir::ExprKind::Index(ref object, ref index) => { + // arguments are not being indexed into + if expr_uses_argument(object, params) { + false + } else { + // arguments are not used as index + !expr_uses_argument(index, params) + } + }, + + // Reading fields can be simplified if the object is not an argument of the closure + hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), + + // Paths can be simplified if the root is not the argument, this also covers None + hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), + + // Calls to Some, Ok, Err can be considered literals if they don't derive an argument + hir::ExprKind::Call(ref func, ref args) => if_chain! { + if variant_calls; // Disable lint when rules conflict with bind_instead_of_map + if let hir::ExprKind::Path(ref path) = func.kind; + if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); + then { + // Recursively check all arguments + args.iter().all(|arg| can_simplify(arg, params, variant_calls)) + } else { + false + } + }, + + // For anything more complex than the above, a closure is probably the right solution, + // or the case is handled by an other lint + _ => false, + } +} + /// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be /// replaced with `(return value of simple closure)` pub(super) fn lint<'tcx>( @@ -18,96 +78,34 @@ pub(super) fn lint<'tcx>( let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); - if !is_option && !is_result { - return; - } - - // Return true if the expression is an accessor of any of the arguments - fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { - params.iter().any(|arg| { - if_chain! { - if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; - if let [p, ..] = path.segments; - then { - ident.name == p.ident.name - } else { - false - } - } - }) - } + if is_option || is_result { + if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { + let body = cx.tcx.hir().body(eid); + let ex = &body.value; + let params = &body.params; - fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { - paths.iter().any(|candidate| match_qpath(path, candidate)) - } - - fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { - match expr.kind { - // Closures returning literals can be unconditionally simplified - hir::ExprKind::Lit(_) => true, - - hir::ExprKind::Index(ref object, ref index) => { - // arguments are not being indexed into - if !expr_uses_argument(object, params) { - // arguments are not used as index - !expr_uses_argument(index, params) + if can_simplify(ex, params, allow_variant_calls) { + let msg = if is_option { + "unnecessary closure used to substitute value for `Option::None`" } else { - false - } - }, - - // Reading fields can be simplified if the object is not an argument of the closure - hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), - - // Paths can be simplified if the root is not the argument, this also covers None - hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), + "unnecessary closure used to substitute value for `Result::Err`" + }; - // Calls to Some, Ok, Err can be considered literals if they don't derive an argument - hir::ExprKind::Call(ref func, ref args) => if_chain! { - if variant_calls; // Disable lint when rules conflict with bind_instead_of_map - if let hir::ExprKind::Path(ref path) = func.kind; - if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); - then { - // Recursively check all arguments - args.iter().all(|arg| can_simplify(arg, params, variant_calls)) - } else { - false - } - }, - - // For anything more complex than the above, a closure is probably the right solution, - // or the case is handled by an other lint - _ => false, - } - } - - if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { - let body = cx.tcx.hir().body(eid); - let ex = &body.value; - let params = &body.params; - - if can_simplify(ex, params, allow_variant_calls) { - let msg = if is_option { - "unnecessary closure used to substitute value for `Option::None`" - } else { - "unnecessary closure used to substitute value for `Result::Err`" - }; - - span_lint_and_sugg( - cx, - UNNECESSARY_LAZY_EVALUATION, - expr.span, - msg, - &format!("Use `{}` instead", simplify_using), - format!( - "{0}.{1}({2})", - snippet(cx, args[0].span, ".."), - simplify_using, - snippet(cx, ex.span, ".."), - ), - Applicability::MachineApplicable, - ); + span_lint_and_sugg( + cx, + UNNECESSARY_LAZY_EVALUATION, + expr.span, + msg, + &format!("Use `{}` instead", simplify_using), + format!( + "{0}.{1}({2})", + snippet(cx, args[0].span, ".."), + simplify_using, + snippet(cx, ex.span, ".."), + ), + Applicability::MachineApplicable, + ); + } } } } -- cgit 1.4.1-3-g733a5 From fc1e07e0c1803edb3ade2db2f46034cf227642c9 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sun, 16 Aug 2020 22:16:39 +0200 Subject: Rename lint to use plural form --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 6 +++--- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 4 ++-- src/lintlist/mod.rs | 2 +- tests/ui/unnecessary_lazy_eval.fixed | 2 +- tests/ui/unnecessary_lazy_eval.rs | 2 +- tests/ui/unnecessary_lazy_eval.stderr | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 675dfd420a7..f662de122f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1754,7 +1754,7 @@ Released 2018-09-13 [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold -[`unnecessary_lazy_evaluation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluation +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ae7045884f7..17501e8e6da 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -685,7 +685,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::UNINIT_ASSUMED_INIT, &methods::UNNECESSARY_FILTER_MAP, &methods::UNNECESSARY_FOLD, - &methods::UNNECESSARY_LAZY_EVALUATION, + &methods::UNNECESSARY_LAZY_EVALUATIONS, &methods::UNWRAP_USED, &methods::USELESS_ASREF, &methods::WRONG_PUB_SELF_CONVENTION, @@ -1361,7 +1361,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::UNINIT_ASSUMED_INIT), LintId::of(&methods::UNNECESSARY_FILTER_MAP), LintId::of(&methods::UNNECESSARY_FOLD), - LintId::of(&methods::UNNECESSARY_LAZY_EVALUATION), + LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), LintId::of(&methods::USELESS_ASREF), LintId::of(&methods::WRONG_SELF_CONVENTION), LintId::of(&methods::ZST_OFFSET), @@ -1542,7 +1542,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::UNNECESSARY_FOLD), - LintId::of(&methods::UNNECESSARY_LAZY_EVALUATION), + LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), LintId::of(&methods::WRONG_SELF_CONVENTION), LintId::of(&misc::TOPLEVEL_REF_ARG), LintId::of(&misc::ZERO_PTR), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c2b2cb98012..0f50a4c813a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1361,7 +1361,7 @@ declare_clippy_lint! { /// /// opt.unwrap_or(42); /// ``` - pub UNNECESSARY_LAZY_EVALUATION, + pub UNNECESSARY_LAZY_EVALUATIONS, style, "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation" } @@ -1415,7 +1415,7 @@ declare_lint_pass!(Methods => [ ZST_OFFSET, FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, - UNNECESSARY_LAZY_EVALUATION, + UNNECESSARY_LAZY_EVALUATIONS, ]); impl<'tcx> LateLintPass<'tcx> for Methods { diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a3e7e9971f8..31517659c34 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use super::UNNECESSARY_LAZY_EVALUATION; +use super::UNNECESSARY_LAZY_EVALUATIONS; // Return true if the expression is an accessor of any of the arguments fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { @@ -93,7 +93,7 @@ pub(super) fn lint<'tcx>( span_lint_and_sugg( cx, - UNNECESSARY_LAZY_EVALUATION, + UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, &format!("Use `{}` instead", simplify_using), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2a66d3495ed..3229c8da507 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2384,7 +2384,7 @@ pub static ref ALL_LINTS: Vec = vec![ module: "methods", }, Lint { - name: "unnecessary_lazy_evaluation", + name: "unnecessary_lazy_evaluations", group: "style", desc: "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation", deprecation: None, diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 7f9d90a8569..fa66e68794e 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::unnecessary_lazy_evaluation)] +#![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index fd8f8ed0329..04f47d1aa29 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::unnecessary_lazy_evaluation)] +#![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index e86b7ed6253..5c1b2eb1f14 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -4,7 +4,7 @@ error: unnecessary closure used to substitute value for `Option::None` LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` | - = note: `-D clippy::unnecessary-lazy-evaluation` implied by `-D warnings` + = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:35:13 -- cgit 1.4.1-3-g733a5 From 11efd75aeb8637bd5444104a57f1051b86c0d62b Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 21 Aug 2020 07:23:04 +0200 Subject: Fix false negative in `option_as_ref_deref` --- clippy_lints/src/methods/mod.rs | 7 ++++++- tests/ui/option_as_ref_deref.fixed | 3 +++ tests/ui/option_as_ref_deref.rs | 3 +++ tests/ui/option_as_ref_deref.stderr | 8 +++++++- 4 files changed, 19 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2498c48f067..22942d9fb0c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3421,7 +3421,12 @@ fn lint_option_as_ref_deref<'tcx>( ]; let is_deref = match map_args[1].kind { - hir::ExprKind::Path(ref expr_qpath) => deref_aliases.iter().any(|path| match_qpath(expr_qpath, path)), + hir::ExprKind::Path(ref expr_qpath) => cx + .qpath_res(expr_qpath, map_args[1].hir_id) + .opt_def_id() + .map_or(false, |fun_def_id| { + deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) + }), hir::ExprKind::Closure(_, _, body_id, _, _) => { let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); diff --git a/tests/ui/option_as_ref_deref.fixed b/tests/ui/option_as_ref_deref.fixed index 076692e6445..07d7f0b45b0 100644 --- a/tests/ui/option_as_ref_deref.fixed +++ b/tests/ui/option_as_ref_deref.fixed @@ -38,4 +38,7 @@ fn main() { let _ = opt.as_deref(); let _ = opt.as_deref_mut(); + + // Issue #5927 + let _ = opt.as_deref(); } diff --git a/tests/ui/option_as_ref_deref.rs b/tests/ui/option_as_ref_deref.rs index 3bf5f715f83..6ae059c9425 100644 --- a/tests/ui/option_as_ref_deref.rs +++ b/tests/ui/option_as_ref_deref.rs @@ -41,4 +41,7 @@ fn main() { let _ = opt.as_ref().map(|x| &**x); let _ = opt.as_mut().map(|x| &mut **x); + + // Issue #5927 + let _ = opt.as_ref().map(std::ops::Deref::deref); } diff --git a/tests/ui/option_as_ref_deref.stderr b/tests/ui/option_as_ref_deref.stderr index a106582a633..62f28232475 100644 --- a/tests/ui/option_as_ref_deref.stderr +++ b/tests/ui/option_as_ref_deref.stderr @@ -100,5 +100,11 @@ error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done LL | let _ = opt.as_mut().map(|x| &mut **x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: aborting due to 16 previous errors +error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead + --> $DIR/option_as_ref_deref.rs:46:13 + | +LL | let _ = opt.as_ref().map(std::ops::Deref::deref); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From 3d820f71fe820c0bb7a1204e28ce549407a937cc Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 24 Aug 2020 14:01:27 +0200 Subject: Fix incorrect suggestion when `clone_on_ref_ptr` is triggered in macros --- clippy_lints/src/methods/mod.rs | 13 +++++++------ tests/ui/unnecessary_clone.rs | 18 ++++++++++++++++++ tests/ui/unnecessary_clone.stderr | 8 +++++++- 3 files changed, 32 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 22942d9fb0c..4f0a533592c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2150,18 +2150,19 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir:: return; }; + let snippet = if in_macro(arg.span) { + snippet_with_macro_callsite(cx, arg.span, "_") + } else { + snippet(cx, arg.span, "_") + }; + span_lint_and_sugg( cx, CLONE_ON_REF_PTR, expr.span, "using `.clone()` on a ref-counted pointer", "try this", - format!( - "{}::<{}>::clone(&{})", - caller_type, - subst.type_at(0), - snippet(cx, arg.span, "_") - ), + format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet), Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak ); } diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 2c9d4d39e6c..e785ac02feb 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -90,3 +90,21 @@ mod many_derefs { let _ = &encoded.clone(); } } + +mod issue2076 { + use std::rc::Rc; + + macro_rules! try_opt { + ($expr: expr) => { + match $expr { + Some(value) => value, + None => return None, + } + }; + } + + fn func() -> Option> { + let rc = Rc::new(42); + Some(try_opt!(Some(rc)).clone()) + } +} diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 113fab69009..5ffa6c4fd06 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -96,5 +96,11 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let _ = &<&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: using `.clone()` on a ref-counted pointer + --> $DIR/unnecessary_clone.rs:108:14 + | +LL | Some(try_opt!(Some(rc)).clone()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` + +error: aborting due to 12 previous errors -- cgit 1.4.1-3-g733a5 From 370fc45a0a2af502d43f0e1831def314e0580a92 Mon Sep 17 00:00:00 2001 From: Thibaud Date: Tue, 25 Aug 2020 22:20:35 +0200 Subject: Update clippy_lints/src/methods/mod.rs Co-authored-by: Eduardo Broto --- clippy_lints/src/methods/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4f0a533592c..1ef54d285f6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2150,11 +2150,7 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir:: return; }; - let snippet = if in_macro(arg.span) { - snippet_with_macro_callsite(cx, arg.span, "_") - } else { - snippet(cx, arg.span, "_") - }; + let snippet = snippet_with_macro_callsite(cx, arg.span, "_"); span_lint_and_sugg( cx, -- cgit 1.4.1-3-g733a5 From 2a3ee5fa854b49530008582900c6ea7fac120d1c Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 7 Jul 2020 22:47:32 +0200 Subject: Fix FP in `new_ret_no_self`: trigger in trait def instead of impl block --- clippy_lints/src/methods/mod.rs | 58 ++++++++++++++++-- tests/ui/new_ret_no_self.rs | 130 ++++++++++++++++++++++++++++++++++++++++ tests/ui/new_ret_no_self.stderr | 30 +++++++++- 3 files changed, 212 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1ef54d285f6..8e91cbb3cdf 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -15,6 +15,7 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{FnRetTy, FnSig, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; @@ -28,11 +29,11 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, - is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, - remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, - walk_ptrs_ty_depth, SpanlessEq, + is_ctor_or_promotable_const_function, is_expn_of, is_self_ty, is_type_diagnostic_item, iter_input_pats, + last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, + span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1631,6 +1632,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } + // if this impl block implements a trait, lint in trait definition instead + if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind { + return; + } + if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id); @@ -1670,6 +1676,48 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if_chain! { + if !in_external_macro(cx.tcx.sess, item.span); + if !item.span.from_expansion(); + if item.ident.name == sym!(new); + if let TraitItemKind::Fn(FnSig { decl, .. }, _) = &item.kind; + if let FnRetTy::Return(ret_ty) = &decl.output; + + then { + let mut visitor = HasSelfVisitor { has_self_ty: false }; + visitor.visit_ty(ret_ty); + if !visitor.has_self_ty { + span_lint( + cx, + NEW_RET_NO_SELF, + item.span, + "methods called `new` usually return `Self`", + ); + } + } + } + } +} + +struct HasSelfVisitor { + pub has_self_ty: bool, +} + +impl<'tcx> intravisit::Visitor<'tcx> for HasSelfVisitor { + type Map = Map<'tcx>; + + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { + if is_self_ty(ty) { + self.has_self_ty = true; + } else { + intravisit::walk_ty(self, ty); + } + } + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } } /// Checks for the `OR_FUN_CALL` lint. diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index 2c2d1e27589..e98360ea691 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -210,3 +210,133 @@ impl<'a> WithLifetime<'a> { unimplemented!(); } } + +mod issue5435 { + struct V; + + pub trait TraitRetSelf { + // should not trigger lint + fn new() -> Self; + } + + pub trait TraitRet { + // should trigger lint as we are in trait definition + fn new() -> String; + } + pub struct StructRet; + impl TraitRet for StructRet { + // should not trigger lint as we are in the impl block + fn new() -> String { + unimplemented!(); + } + } + + pub trait TraitRet2 { + // should trigger lint + fn new(_: String) -> String; + } + + trait TupleReturnerOk { + // should not trigger lint + fn new() -> (Self, u32) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait TupleReturnerOk2 { + // should not trigger lint (it doesn't matter which element in the tuple is Self) + fn new() -> (u32, Self) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait TupleReturnerOk3 { + // should not trigger lint (tuple can contain multiple Self) + fn new() -> (Self, Self) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait TupleReturnerBad { + // should trigger lint + fn new() -> (u32, u32) { + unimplemented!(); + } + } + + trait MutPointerReturnerOk { + // should not trigger lint + fn new() -> *mut Self + where + Self: Sized, + { + unimplemented!(); + } + } + + trait MutPointerReturnerOk2 { + // should not trigger lint + fn new() -> *const Self + where + Self: Sized, + { + unimplemented!(); + } + } + + trait MutPointerReturnerBad { + // should trigger lint + fn new() -> *mut V { + unimplemented!(); + } + } + + trait GenericReturnerOk { + // should not trigger lint + fn new() -> Option + where + Self: Sized, + { + unimplemented!(); + } + } + + trait NestedReturnerOk { + // should not trigger lint + fn new() -> (Option, u32) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait NestedReturnerOk2 { + // should not trigger lint + fn new() -> ((Self, u32), u32) + where + Self: Sized, + { + unimplemented!(); + } + } + + trait NestedReturnerOk3 { + // should not trigger lint + fn new() -> Option<(Self, u32)> + where + Self: Sized, + { + unimplemented!(); + } + } +} diff --git a/tests/ui/new_ret_no_self.stderr b/tests/ui/new_ret_no_self.stderr index dd5a24bcbe7..8217bc6187f 100644 --- a/tests/ui/new_ret_no_self.stderr +++ b/tests/ui/new_ret_no_self.stderr @@ -48,5 +48,33 @@ LL | | unimplemented!(); LL | | } | |_____^ -error: aborting due to 6 previous errors +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:224:9 + | +LL | fn new() -> String; + | ^^^^^^^^^^^^^^^^^^^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:236:9 + | +LL | fn new(_: String) -> String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:271:9 + | +LL | / fn new() -> (u32, u32) { +LL | | unimplemented!(); +LL | | } + | |_________^ + +error: methods called `new` usually return `Self` + --> $DIR/new_ret_no_self.rs:298:9 + | +LL | / fn new() -> *mut V { +LL | | unimplemented!(); +LL | | } + | |_________^ + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 3cb75c2e5cdd4f450f2974c5e052d569674d95fd Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 25 Aug 2020 09:16:08 +0200 Subject: Remove expansion restriction + fix doc and tests naming --- clippy_lints/src/methods/mod.rs | 34 ++++++++++++++++++++++++---------- tests/ui/new_ret_no_self.rs | 6 +++--- 2 files changed, 27 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8e91cbb3cdf..2388310628f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -725,6 +725,7 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** + /// In an impl block: /// ```rust /// # struct Foo; /// # struct NotAFoo; @@ -737,25 +738,40 @@ declare_clippy_lint! { /// /// ```rust /// # struct Foo; - /// # struct FooError; + /// struct Bar(Foo); /// impl Foo { - /// // Good. Return type contains `Self` - /// fn new() -> Result { - /// # Ok(Foo) + /// // Bad. The type name must contain `Self` + /// fn new() -> Bar { + /// # Bar(Foo) /// } /// } /// ``` /// /// ```rust /// # struct Foo; - /// struct Bar(Foo); + /// # struct FooError; /// impl Foo { - /// // Bad. The type name must contain `Self`. - /// fn new() -> Bar { - /// # Bar(Foo) + /// // Good. Return type contains `Self` + /// fn new() -> Result { + /// # Ok(Foo) /// } /// } /// ``` + /// + /// Or in a trait definition: + /// ```rust + /// pub trait Trait { + /// // Bad. The type name must contain `Self` + /// fn new(); + /// } + /// ``` + /// + /// ```rust + /// pub trait Trait { + /// // Good. Return type contains `Self` + /// fn new() -> Self; + /// } + /// ``` pub NEW_RET_NO_SELF, style, "not returning type containing `Self` in a `new` method" @@ -1679,8 +1695,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if_chain! { - if !in_external_macro(cx.tcx.sess, item.span); - if !item.span.from_expansion(); if item.ident.name == sym!(new); if let TraitItemKind::Fn(FnSig { decl, .. }, _) = &item.kind; if let FnRetTy::Return(ret_ty) = &decl.output; diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index e98360ea691..e82873629a5 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -137,9 +137,9 @@ impl MutPointerReturnerOk { } } -struct MutPointerReturnerOk2; +struct ConstPointerReturnerOk2; -impl MutPointerReturnerOk2 { +impl ConstPointerReturnerOk2 { // should not trigger lint pub fn new() -> *const Self { unimplemented!(); @@ -283,7 +283,7 @@ mod issue5435 { } } - trait MutPointerReturnerOk2 { + trait ConstPointerReturnerOk2 { // should not trigger lint fn new() -> *const Self where -- cgit 1.4.1-3-g733a5 From 504612622f2801b43dbe3e6788d2404d394376df Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 27 Aug 2020 18:24:59 +0200 Subject: Merge logic of looking for `Self` type --- clippy_lints/src/methods/mod.rs | 62 +++++++++++------------------------------ clippy_lints/src/utils/mod.rs | 11 +++++++- 2 files changed, 26 insertions(+), 47 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2388310628f..63e0c183113 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -15,12 +15,11 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{FnRetTy, FnSig, TraitItem, TraitItemKind}; +use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Ty, TyS}; +use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -28,8 +27,8 @@ use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, - is_ctor_or_promotable_const_function, is_expn_of, is_self_ty, is_type_diagnostic_item, iter_input_pats, + contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, + is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, @@ -1656,16 +1655,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id); - let contains_self_ty = |ty: Ty<'tcx>| { - ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty), - - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) - }; - // walk the return type and check for Self (this does not check associated types) - if contains_self_ty(ret_ty) { + if contains_ty(ret_ty, self_ty) { return; } @@ -1675,7 +1666,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { for &(predicate, _span) in cx.tcx.predicates_of(def_id).predicates { if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { // walk the associated type and check for Self - if contains_self_ty(projection_predicate.ty) { + if contains_ty(projection_predicate.ty, self_ty) { return; } } @@ -1696,44 +1687,23 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if_chain! { if item.ident.name == sym!(new); - if let TraitItemKind::Fn(FnSig { decl, .. }, _) = &item.kind; - if let FnRetTy::Return(ret_ty) = &decl.output; + if let TraitItemKind::Fn(_, _) = item.kind; + let ret_ty = return_ty(cx, item.hir_id); + let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); + if !contains_ty(ret_ty, self_ty); then { - let mut visitor = HasSelfVisitor { has_self_ty: false }; - visitor.visit_ty(ret_ty); - if !visitor.has_self_ty { - span_lint( - cx, - NEW_RET_NO_SELF, - item.span, - "methods called `new` usually return `Self`", - ); - } + span_lint( + cx, + NEW_RET_NO_SELF, + item.span, + "methods called `new` usually return `Self`", + ); } } } } -struct HasSelfVisitor { - pub has_self_ty: bool, -} - -impl<'tcx> intravisit::Visitor<'tcx> for HasSelfVisitor { - type Map = Map<'tcx>; - - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { - if is_self_ty(ty) { - self.has_self_ty = true; - } else { - intravisit::walk_ty(self, ty); - } - } - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } -} - /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] fn lint_or_fun_call<'tcx>( diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index e6be5c4588f..07ec59f452a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -42,7 +42,8 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; use rustc_mir::const_eval; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; @@ -866,6 +867,14 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> cx.tcx.erase_late_bound_regions(&ret_ty) } +/// Walk into `ty` and returns `true` if any inner type is the same as `other_ty` +pub fn contains_ty<'tcx>(ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + /// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind { -- cgit 1.4.1-3-g733a5 From 73b1ee1a614aaad7dd43958280ff4a444c8b737e Mon Sep 17 00:00:00 2001 From: Thibaud Date: Fri, 28 Aug 2020 09:33:05 +0200 Subject: Update clippy_lints/src/methods/mod.rs Co-authored-by: Eduardo Broto --- clippy_lints/src/methods/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 63e0c183113..9996df69470 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1686,6 +1686,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if_chain! { + if !in_external_macro(cx.tcx.sess, item.span); if item.ident.name == sym!(new); if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id); -- cgit 1.4.1-3-g733a5 From 17b2ba5ded12f59dba63ece659b5cd714b763800 Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:24:15 -0700 Subject: Syntax-highlight `single_char_push_str` lint --- clippy_lints/src/methods/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9996df69470..7c4a78cbdcd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1324,20 +1324,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using push_str with a single-character string literal, - /// and push with a char would work fine. + /// **What it does:** Warns when using `push_str` with a single-character string literal, + /// and `push` with a `char` would work fine. /// - /// **Why is this bad?** It's less clear that we are pushing a single character + /// **Why is this bad?** It's less clear that we are pushing a single character. /// /// **Known problems:** None /// /// **Example:** - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push_str("R"); /// ``` /// Could be written as - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push('R'); /// ``` -- cgit 1.4.1-3-g733a5 From 2487f8f461134f93459415642f730ac6c4a2d659 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Fri, 11 Sep 2020 16:52:25 +0200 Subject: into_iter_on_ref: rephrase lint message: will not move the x -> will not consume the x imo that's a bit clearer. --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/into_iter_on_ref.stderr | 54 ++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ba69c8266b1..98e027b6d22 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3374,7 +3374,7 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_ INTO_ITER_ON_REF, method_span, &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not move the `{}`", + "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", method_name, kind, ), "call directly", diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 1cd6400b019..28003b365bb 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -1,4 +1,4 @@ -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:14:30 | LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() @@ -6,157 +6,157 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() | = note: `-D clippy::into-iter-on-ref` implied by `-D warnings` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:15:46 | LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:16:41 | LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:17:44 | LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:19:32 | LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:20:36 | LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:21:40 | LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Option` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option` --> $DIR/into_iter_on_ref.rs:23:24 | LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Option` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option` --> $DIR/into_iter_on_ref.rs:24:28 | LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Result` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result` --> $DIR/into_iter_on_ref.rs:25:32 | LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Result` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result` --> $DIR/into_iter_on_ref.rs:26:37 | LL | let _ = (&mut Err::(7)).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:27:34 | LL | let _ = (&Vec::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Vec` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:28:38 | LL | let _ = (&mut Vec::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeMap` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap` --> $DIR/into_iter_on_ref.rs:29:44 | LL | let _ = (&BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `BTreeMap` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap` --> $DIR/into_iter_on_ref.rs:30:48 | LL | let _ = (&mut BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `VecDeque` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque` --> $DIR/into_iter_on_ref.rs:31:39 | LL | let _ = (&VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `VecDeque` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque` --> $DIR/into_iter_on_ref.rs:32:43 | LL | let _ = (&mut VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `LinkedList` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList` --> $DIR/into_iter_on_ref.rs:33:41 | LL | let _ = (&LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `LinkedList` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList` --> $DIR/into_iter_on_ref.rs:34:45 | LL | let _ = (&mut LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashMap` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap` --> $DIR/into_iter_on_ref.rs:35:43 | LL | let _ = (&HashMap::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `HashMap` +error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap` --> $DIR/into_iter_on_ref.rs:36:47 | LL | let _ = (&mut HashMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeSet` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet` --> $DIR/into_iter_on_ref.rs:38:39 | LL | let _ = (&BTreeSet::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BinaryHeap` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap` --> $DIR/into_iter_on_ref.rs:39:41 | LL | let _ = (&BinaryHeap::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashSet` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet` --> $DIR/into_iter_on_ref.rs:40:38 | LL | let _ = (&HashSet::::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Path` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path` --> $DIR/into_iter_on_ref.rs:41:43 | LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `PathBuf` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf` --> $DIR/into_iter_on_ref.rs:42:47 | LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` +error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:44:26 | LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() -- cgit 1.4.1-3-g733a5 From 332c2dcb4dfe5151d7c8d44cdf96c4abd06db593 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 6 Sep 2020 23:48:04 +0200 Subject: Fix dogfood after MatchTypeOnDiagItem --- clippy_lints/src/loops.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 6c54c07869a..3d2fd0eee85 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1114,7 +1114,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if let Some(self_expr) = args.get(0); if let Some(pushed_item) = args.get(1); // Check that the method being called is push() on a Vec - if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type)); if path.ident.name.as_str() == "push"; then { return Some((self_expr, pushed_item)) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 98e027b6d22..de966cccd11 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1808,7 +1808,7 @@ fn lint_or_fun_call<'tcx>( _ => (), } - if match_type(cx, ty, &paths::VEC) { + if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { return; } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9494efe736c..60e5e7bfed3 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,6 +1,6 @@ use crate::utils; use crate::utils::sugg::Sugg; -use crate::utils::{match_type, paths, span_lint_and_sugg}; +use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -73,7 +73,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { path.ident.name.to_ident_string() == "ok" - && match_type(cx, &cx.typeck_results().expr_ty(&receiver), &paths::RESULT) + && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type)) } else { false } -- cgit 1.4.1-3-g733a5 From 6ba36bcfd3802d9520d0ac48dabfe6dc06d8dc82 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sat, 22 Aug 2020 00:43:04 +0200 Subject: option_if_let_else - distinguish pure from impure else expressions --- clippy_lints/src/methods/bind_instead_of_map.rs | 21 ++-- clippy_lints/src/methods/mod.rs | 66 ++++------- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 76 ++----------- clippy_lints/src/option_if_let_else.rs | 33 +++--- clippy_lints/src/utils/eager_or_lazy.rs | 128 ++++++++++++++++++++++ clippy_lints/src/utils/mod.rs | 1 + clippy_lints/src/utils/sugg.rs | 2 +- clippy_lints/src/utils/usage.rs | 66 +++++++++++ tests/ui/option_if_let_else.fixed | 10 ++ tests/ui/option_if_let_else.rs | 15 +++ tests/ui/option_if_let_else.stderr | 36 ++++-- tests/ui/unnecessary_lazy_eval.fixed | 42 +++---- tests/ui/unnecessary_lazy_eval.rs | 26 +++-- tests/ui/unnecessary_lazy_eval.stderr | 112 +++++++++++++------ 14 files changed, 420 insertions(+), 214 deletions(-) create mode 100644 clippy_lints/src/utils/eager_or_lazy.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 498f12518f8..ae37942e55a 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -12,6 +12,7 @@ use rustc_middle::hir::map::Map; use rustc_span::Span; pub(crate) struct OptionAndThenSome; + impl BindInsteadOfMap for OptionAndThenSome { const TYPE_NAME: &'static str = "Option"; const TYPE_QPATH: &'static [&'static str] = &paths::OPTION; @@ -24,6 +25,7 @@ impl BindInsteadOfMap for OptionAndThenSome { } pub(crate) struct ResultAndThenOk; + impl BindInsteadOfMap for ResultAndThenOk { const TYPE_NAME: &'static str = "Result"; const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; @@ -36,6 +38,7 @@ impl BindInsteadOfMap for ResultAndThenOk { } pub(crate) struct ResultOrElseErrInfo; + impl BindInsteadOfMap for ResultOrElseErrInfo { const TYPE_NAME: &'static str = "Result"; const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; @@ -120,9 +123,9 @@ pub(crate) trait BindInsteadOfMap { } } - fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) { + fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool { let mut suggs = Vec::new(); - let can_sugg = find_all_ret_expressions(cx, closure_expr, |ret_expr| { + let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| { if_chain! { if !in_macro(ret_expr.span); if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind; @@ -153,12 +156,13 @@ pub(crate) trait BindInsteadOfMap { ) }); } + can_sugg } /// Lint use of `_.and_then(|x| Some(y))` for `Option`s - fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool { if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) { - return; + return false; } match args[1].kind { @@ -166,8 +170,10 @@ pub(crate) trait BindInsteadOfMap { let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); - if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { - Self::lint_closure(cx, expr, closure_expr); + if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { + true + } else { + Self::lint_closure(cx, expr, closure_expr) } }, // `_.and_then(Some)` case, which is no-op. @@ -181,8 +187,9 @@ pub(crate) trait BindInsteadOfMap { snippet(cx, args[0].span, "..").into(), Applicability::MachineApplicable, ); + true }, - _ => {}, + _ => false, } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 98e027b6d22..914f9f94e77 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -25,14 +25,15 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; +use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, - last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, - method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, + is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, + match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, + single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, + walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1454,18 +1455,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"); + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"); } }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and"); - bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); - bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); + let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); + let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); + if !biom_option_linted && !biom_result_linted { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and"); + } }, ["or_else", ..] => { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or"); - bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]); + if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) { + unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or"); + } }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), @@ -1508,9 +1512,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), - ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"), - ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"), - ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"), + ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), + ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), + ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), _ => {}, } @@ -1714,37 +1718,6 @@ fn lint_or_fun_call<'tcx>( name: &str, args: &'tcx [hir::Expr<'_>], ) { - // Searches an expression for method calls or function calls that aren't ctors - struct FunCallFinder<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - found: bool, - } - - impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - let call_found = match &expr.kind { - // ignore enum and struct constructors - hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), - hir::ExprKind::MethodCall(..) => true, - _ => false, - }; - - if call_found { - self.found |= true; - } - - if !self.found { - intravisit::walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - } - /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. fn check_unwrap_or_default( cx: &LateContext<'_>, @@ -1825,8 +1798,7 @@ fn lint_or_fun_call<'tcx>( if_chain! { if know_types.iter().any(|k| k.2.contains(&name)); - let mut finder = FunCallFinder { cx: &cx, found: false }; - if { finder.visit_expr(&arg); finder.found }; + if is_lazyness_candidate(cx, arg); if !contains_return(&arg); let self_ty = cx.typeck_results().expr_ty(self_expr); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 31517659c34..08b3eab9b7c 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,78 +1,17 @@ -use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg}; -use if_chain::if_chain; +use crate::utils::{eager_or_lazy, usage}; +use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use super::UNNECESSARY_LAZY_EVALUATIONS; -// Return true if the expression is an accessor of any of the arguments -fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool { - params.iter().any(|arg| { - if_chain! { - if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind; - if let [p, ..] = path.segments; - then { - ident.name == p.ident.name - } else { - false - } - } - }) -} - -fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool { - paths.iter().any(|candidate| match_qpath(path, candidate)) -} - -fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool { - match expr.kind { - // Closures returning literals can be unconditionally simplified - hir::ExprKind::Lit(_) => true, - - hir::ExprKind::Index(ref object, ref index) => { - // arguments are not being indexed into - if expr_uses_argument(object, params) { - false - } else { - // arguments are not used as index - !expr_uses_argument(index, params) - } - }, - - // Reading fields can be simplified if the object is not an argument of the closure - hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params), - - // Paths can be simplified if the root is not the argument, this also covers None - hir::ExprKind::Path(_) => !expr_uses_argument(expr, params), - - // Calls to Some, Ok, Err can be considered literals if they don't derive an argument - hir::ExprKind::Call(ref func, ref args) => if_chain! { - if variant_calls; // Disable lint when rules conflict with bind_instead_of_map - if let hir::ExprKind::Path(ref path) = func.kind; - if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]); - then { - // Recursively check all arguments - args.iter().all(|arg| can_simplify(arg, params, variant_calls)) - } else { - false - } - }, - - // For anything more complex than the above, a closure is probably the right solution, - // or the case is handled by an other lint - _ => false, - } -} - /// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be /// replaced with `(return value of simple closure)` pub(super) fn lint<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], - allow_variant_calls: bool, simplify_using: &str, ) { let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); @@ -81,10 +20,13 @@ pub(super) fn lint<'tcx>( if is_option || is_result { if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { let body = cx.tcx.hir().body(eid); - let ex = &body.value; - let params = &body.params; + let body_expr = &body.value; + + if usage::BindingUsageFinder::are_params_used(cx, body) { + return; + } - if can_simplify(ex, params, allow_variant_calls) { + if eager_or_lazy::is_eagerness_candidate(cx, body_expr) { let msg = if is_option { "unnecessary closure used to substitute value for `Option::None`" } else { @@ -101,7 +43,7 @@ pub(super) fn lint<'tcx>( "{0}.{1}({2})", snippet(cx, args[0].span, ".."), simplify_using, - snippet(cx, ex.span, ".."), + snippet(cx, body_expr.span, ".."), ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9494efe736c..5e2652b48cb 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,4 +1,5 @@ use crate::utils; +use crate::utils::eager_or_lazy; use crate::utils::sugg::Sugg; use crate::utils::{match_type, paths, span_lint_and_sugg}; use if_chain::if_chain; @@ -13,22 +14,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more - /// idiomatically done with `Option::map_or` (if the else bit is a simple - /// expression) or `Option::map_or_else` (if the else bit is a longer - /// block). + /// idiomatically done with `Option::map_or` (if the else bit is a pure + /// expression) or `Option::map_or_else` (if the else bit is an impure + /// expresion). /// /// **Why is this bad?** /// Using the dedicated functions of the Option type is clearer and /// more concise than an if let expression. /// /// **Known problems:** - /// This lint uses whether the block is just an expression or if it has - /// more statements to decide whether to use `Option::map_or` or - /// `Option::map_or_else`. If you have a single expression which calls - /// an expensive function, then it would be more efficient to use - /// `Option::map_or_else`, but this lint would suggest `Option::map_or`. - /// - /// Also, this lint uses a deliberately conservative metric for checking + /// This lint uses a deliberately conservative metric for checking /// if the inside of either body contains breaks or continues which will /// cause it to not suggest a fix if either block contains a loop with /// continues or breaks contained within the loop. @@ -92,6 +87,7 @@ struct OptionIfLetElseOccurence { struct ReturnBreakContinueMacroVisitor { seen_return_break_continue: bool, } + impl ReturnBreakContinueMacroVisitor { fn new() -> ReturnBreakContinueMacroVisitor { ReturnBreakContinueMacroVisitor { @@ -99,6 +95,7 @@ impl ReturnBreakContinueMacroVisitor { } } } + impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { @@ -157,7 +154,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { } /// If this is the else body of an if/else expression, then we need to wrap -/// it in curcly braces. Otherwise, we don't. +/// it in curly braces. Otherwise, we don't. fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { if let Some(Expr { @@ -199,7 +196,10 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo /// If this expression is the option if let/else construct we're detecting, then /// this function returns an `OptionIfLetElseOccurence` struct with details if /// this construct is found, or None if this construct is not found. -fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn detect_option_if_let_else<'tcx>( + cx: &'_ LateContext<'tcx>, + expr: &'_ Expr<'tcx>, +) -> Option { if_chain! { if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; @@ -214,10 +214,7 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option "map_or_else", - _ => "map_or", - }; + let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" }; let capture_name = id.name.to_ident_string(); let wrap_braces = should_wrap_in_braces(cx, expr); let (as_ref, as_mut) = match &cond_expr.kind { @@ -243,8 +240,8 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option LateLintPass<'a> for OptionIfLetElse { - fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) { +impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(detection) = detect_option_if_let_else(cx, expr) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs new file mode 100644 index 00000000000..6938d9971d9 --- /dev/null +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -0,0 +1,128 @@ +//! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa. +//! +//! Things to consider: +//! - has the expression side-effects? +//! - is the expression computationally expensive? +//! +//! See lints: +//! - unnecessary-lazy-evaluations +//! - or-fun-call +//! - option-if-let-else + +use crate::utils::is_ctor_or_promotable_const_function; +use rustc_hir::def::{DefKind, Res}; + +use rustc_hir::intravisit; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; + +use rustc_hir::{Block, Expr, ExprKind, Path, QPath}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; + +/// Is the expr pure (is it free from side-effects)? +/// This function is named so to stress that it isn't exhaustive and returns FNs. +fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true, + ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr), + ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)), + ExprKind::Struct(_, fields, expr) => { + fields.iter().all(|f| identify_some_pure_patterns(f.expr)) + && expr.map_or(true, |e| identify_some_pure_patterns(e)) + }, + ExprKind::Call( + &Expr { + kind: + ExprKind::Path(QPath::Resolved( + _, + Path { + res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..), + .. + }, + )), + .. + }, + args, + ) => args.iter().all(|expr| identify_some_pure_patterns(expr)), + ExprKind::Block( + &Block { + stmts, + expr: Some(expr), + .. + }, + _, + ) => stmts.is_empty() && identify_some_pure_patterns(expr), + ExprKind::Box(..) + | ExprKind::Array(..) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::DropTemps(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Block(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Index(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::InlineAsm(..) + | ExprKind::LlvmInlineAsm(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) + | ExprKind::Err => false, + } +} + +/// Identify some potentially computationally expensive patterns. +/// This function is named so to stress that its implementation is non-exhaustive. +/// It returns FNs and FPs. +fn identify_some_potentially_expensive_patterns<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + // Searches an expression for method calls or function calls that aren't ctors + struct FunCallFinder<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + found: bool, + } + + impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + let call_found = match &expr.kind { + // ignore enum and struct constructors + ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), + ExprKind::MethodCall(..) => true, + _ => false, + }; + + if call_found { + self.found |= true; + } + + if !self.found { + intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + } + + let mut finder = FunCallFinder { cx, found: false }; + finder.visit_expr(expr); + finder.found +} + +pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + !identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr) +} + +pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + identify_some_potentially_expensive_patterns(cx, expr) +} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3ebbfed6456..7efeef62690 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -10,6 +10,7 @@ pub mod comparisons; pub mod conf; pub mod constants; mod diagnostics; +pub mod eager_or_lazy; pub mod higher; mod hir_utils; pub mod inspector; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 811fde388d1..ec8b7e59b59 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -49,7 +49,7 @@ impl<'a> Sugg<'a> { /// Convenience function around `hir_opt` for suggestions with a default /// text. pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default))) + Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default))) } /// Same as `hir`, but it adapts the applicability level by following rules: diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 4a64b935ac9..ea1dc3be29b 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,6 +1,8 @@ use crate::utils::match_var; use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_hir::intravisit; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; @@ -108,3 +110,67 @@ pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool { walk_expr(&mut visitor, body); !visitor.used } + +pub struct ParamBindingIdCollector { + binding_hir_ids: Vec, +} +impl<'tcx> ParamBindingIdCollector { + fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { + let mut finder = ParamBindingIdCollector { + binding_hir_ids: Vec::new(), + }; + finder.visit_body(body); + finder.binding_hir_ids + } +} +impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector { + type Map = Map<'tcx>; + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + if let hir::PatKind::Binding(_, hir_id, ..) = param.pat.kind { + self.binding_hir_ids.push(hir_id); + } + } + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } +} + +pub struct BindingUsageFinder<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + binding_ids: Vec, + usage_found: bool, +} +impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { + pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool { + let mut finder = BindingUsageFinder { + cx, + binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body), + usage_found: false, + }; + finder.visit_body(body); + finder.usage_found + } +} +impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if !self.usage_found { + intravisit::walk_expr(self, expr); + } + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { + if let hir::def::Res::Local(id) = path.res { + if self.binding_ids.contains(&id) { + self.usage_found = true; + } + } + } + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 695a460cc4e..a7fb00a2705 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::option_if_let_else)] +#![allow(clippy::redundant_closure)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) @@ -36,6 +37,14 @@ fn longer_body(arg: Option) -> u32 { }) } +fn impure_else(arg: Option) { + let side_effect = || { + println!("return 1"); + 1 + }; + let _ = arg.map_or_else(|| side_effect(), |x| x); +} + fn test_map_or_else(arg: Option) { let _ = arg.map_or_else(|| { let mut y = 1; @@ -71,4 +80,5 @@ fn main() { let _ = longer_body(None); test_map_or_else(None); let _ = negative_tests(None); + let _ = impure_else(None); } diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index dee80d26bd9..895fd86321f 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::option_if_let_else)] +#![allow(clippy::redundant_closure)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { @@ -52,6 +53,19 @@ fn longer_body(arg: Option) -> u32 { } } +fn impure_else(arg: Option) { + let side_effect = || { + println!("return 1"); + 1 + }; + let _ = if let Some(x) = arg { + x + } else { + // map_or_else must be suggested + side_effect() + }; +} + fn test_map_or_else(arg: Option) { let _ = if let Some(x) = arg { x * x * x * x @@ -89,4 +103,5 @@ fn main() { let _ = longer_body(None); test_map_or_else(None); let _ = negative_tests(None); + let _ = impure_else(None); } diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 7005850efaf..b69fe767682 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:5:5 + --> $DIR/option_if_let_else.rs:6:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,7 +11,7 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:15:12 + --> $DIR/option_if_let_else.rs:16:12 | LL | } else if let Some(x) = string { | ____________^ @@ -22,19 +22,19 @@ LL | | } | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:23:13 + --> $DIR/option_if_let_else.rs:24:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:24:13 + --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:25:13 + --> $DIR/option_if_let_else.rs:26:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -54,13 +54,13 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:31:13 + --> $DIR/option_if_let_else.rs:32:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:32:13 + --> $DIR/option_if_let_else.rs:33:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -80,7 +80,7 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:38:13 + --> $DIR/option_if_let_else.rs:39:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -100,7 +100,7 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:47:5 + --> $DIR/option_if_let_else.rs:48:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -119,7 +119,19 @@ LL | }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:56:13 + --> $DIR/option_if_let_else.rs:61:13 + | +LL | let _ = if let Some(x) = arg { + | _____________^ +LL | | x +LL | | } else { +LL | | // map_or_else must be suggested +LL | | side_effect() +LL | | }; + | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` + +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:70:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -142,10 +154,10 @@ LL | }, |x| x * x * x * x); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:85:13 + --> $DIR/option_if_let_else.rs:99:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index fa66e68794e..4980c111499 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -2,6 +2,7 @@ #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] +#![allow(clippy::map_identity)] struct Deep(Option); @@ -34,13 +35,13 @@ fn main() { let _ = opt.unwrap_or(2); let _ = opt.unwrap_or(astronomers_pi); let _ = opt.unwrap_or(ext_str.some_field); - let _ = opt.unwrap_or(ext_arr[0]); + let _ = opt.unwrap_or_else(|| ext_arr[0]); let _ = opt.and(ext_opt); let _ = opt.or(ext_opt); let _ = opt.or(None); let _ = opt.get_or_insert(2); let _ = opt.ok_or(2); - let _ = opt.ok_or(ext_arr[0]); + let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or(2); @@ -60,7 +61,6 @@ fn main() { // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); let _ = nested_opt.unwrap_or_else(|| Some(some_call())); - let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); @@ -69,13 +69,16 @@ fn main() { let _ = deep.0.get_or_insert_with(|| some_call()); let _ = deep.0.or_else(some_call); let _ = deep.0.or_else(|| some_call()); + let _ = opt.ok_or_else(|| ext_arr[0]); - // These are handled by bind_instead_of_map + // should not lint, bind_instead_of_map takes priority let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); let _ = Some(10).and_then(|idx| Some(idx)); - let _: Option = None.or_else(|| Some(3)); - let _ = deep.0.or_else(|| Some(3)); - let _ = opt.or_else(|| Some(3)); + + // should lint, bind_instead_of_map doesn't apply + let _: Option = None.or(Some(3)); + let _ = deep.0.or(Some(3)); + let _ = opt.or(Some(3)); // Should lint - Result let res: Result = Err(5); @@ -92,26 +95,27 @@ fn main() { let _ = res2.unwrap_or_else(|err| err.return_some_field()); let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + // should not lint, bind_instead_of_map takes priority let _: Result = res.and_then(|x| Ok(x)); - let _: Result = res.and_then(|x| Err(x)); - - let _: Result = res.or_else(|err| Ok(err)); let _: Result = res.or_else(|err| Err(err)); - // These are handled by bind_instead_of_map let _: Result = res.and_then(|_| Ok(2)); let _: Result = res.and_then(|_| Ok(astronomers_pi)); let _: Result = res.and_then(|_| Ok(ext_str.some_field)); - let _: Result = res.and_then(|_| Err(2)); - let _: Result = res.and_then(|_| Err(astronomers_pi)); - let _: Result = res.and_then(|_| Err(ext_str.some_field)); - - let _: Result = res.or_else(|_| Ok(2)); - let _: Result = res.or_else(|_| Ok(astronomers_pi)); - let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - let _: Result = res.or_else(|_| Err(2)); let _: Result = res.or_else(|_| Err(astronomers_pi)); let _: Result = res.or_else(|_| Err(ext_str.some_field)); + + // should lint, bind_instead_of_map doesn't apply + let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.or_else(|err| Ok(err)); + + let _: Result = res.and(Err(2)); + let _: Result = res.and(Err(astronomers_pi)); + let _: Result = res.and(Err(ext_str.some_field)); + + let _: Result = res.or(Ok(2)); + let _: Result = res.or(Ok(astronomers_pi)); + let _: Result = res.or(Ok(ext_str.some_field)); } diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 04f47d1aa29..0b270939ec2 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -2,6 +2,7 @@ #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] +#![allow(clippy::map_identity)] struct Deep(Option); @@ -40,7 +41,7 @@ fn main() { let _ = opt.or_else(|| None); let _ = opt.get_or_insert_with(|| 2); let _ = opt.ok_or_else(|| 2); - let _ = opt.ok_or_else(|| ext_arr[0]); + let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or_else(|| 2); @@ -60,7 +61,6 @@ fn main() { // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); let _ = nested_opt.unwrap_or_else(|| Some(some_call())); - let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call()))); let _ = opt.or_else(some_call); let _ = opt.or_else(|| some_call()); @@ -69,10 +69,13 @@ fn main() { let _ = deep.0.get_or_insert_with(|| some_call()); let _ = deep.0.or_else(some_call); let _ = deep.0.or_else(|| some_call()); + let _ = opt.ok_or_else(|| ext_arr[0]); - // These are handled by bind_instead_of_map + // should not lint, bind_instead_of_map takes priority let _ = Some(10).and_then(|idx| Some(ext_arr[idx])); let _ = Some(10).and_then(|idx| Some(idx)); + + // should lint, bind_instead_of_map doesn't apply let _: Option = None.or_else(|| Some(3)); let _ = deep.0.or_else(|| Some(3)); let _ = opt.or_else(|| Some(3)); @@ -92,17 +95,22 @@ fn main() { let _ = res2.unwrap_or_else(|err| err.return_some_field()); let _ = res2.unwrap_or_else(|_| ext_str.return_some_field()); + // should not lint, bind_instead_of_map takes priority let _: Result = res.and_then(|x| Ok(x)); - let _: Result = res.and_then(|x| Err(x)); - - let _: Result = res.or_else(|err| Ok(err)); let _: Result = res.or_else(|err| Err(err)); - // These are handled by bind_instead_of_map let _: Result = res.and_then(|_| Ok(2)); let _: Result = res.and_then(|_| Ok(astronomers_pi)); let _: Result = res.and_then(|_| Ok(ext_str.some_field)); + let _: Result = res.or_else(|_| Err(2)); + let _: Result = res.or_else(|_| Err(astronomers_pi)); + let _: Result = res.or_else(|_| Err(ext_str.some_field)); + + // should lint, bind_instead_of_map doesn't apply + let _: Result = res.and_then(|x| Err(x)); + let _: Result = res.or_else(|err| Ok(err)); + let _: Result = res.and_then(|_| Err(2)); let _: Result = res.and_then(|_| Err(astronomers_pi)); let _: Result = res.and_then(|_| Err(ext_str.some_field)); @@ -110,8 +118,4 @@ fn main() { let _: Result = res.or_else(|_| Ok(2)); let _: Result = res.or_else(|_| Ok(astronomers_pi)); let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - - let _: Result = res.or_else(|_| Err(2)); - let _: Result = res.or_else(|_| Err(astronomers_pi)); - let _: Result = res.or_else(|_| Err(ext_str.some_field)); } diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 5c1b2eb1f14..1cf7ac46346 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:34:13 + --> $DIR/unnecessary_lazy_eval.rs:35:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` @@ -7,142 +7,190 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:35:13 + --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:36:13 + --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:37:13 - | -LL | let _ = opt.unwrap_or_else(|| ext_arr[0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])` - -error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:38:13 + --> $DIR/unnecessary_lazy_eval.rs:39:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:39:13 + --> $DIR/unnecessary_lazy_eval.rs:40:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:40:13 + --> $DIR/unnecessary_lazy_eval.rs:41:13 | LL | let _ = opt.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:41:13 + --> $DIR/unnecessary_lazy_eval.rs:42:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:42:13 + --> $DIR/unnecessary_lazy_eval.rs:43:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:43:13 + --> $DIR/unnecessary_lazy_eval.rs:44:13 | -LL | let _ = opt.ok_or_else(|| ext_arr[0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])` +LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:46:13 + --> $DIR/unnecessary_lazy_eval.rs:47:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:47:13 + --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:28 + --> $DIR/unnecessary_lazy_eval.rs:49:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:13 + --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:35 + --> $DIR/unnecessary_lazy_eval.rs:51:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:28 + --> $DIR/unnecessary_lazy_eval.rs:52:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:54:13 + --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:55:13 + --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:56:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:59:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:79:28 + | +LL | let _: Option = None.or_else(|| Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(Some(3))` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:80:13 + | +LL | let _ = deep.0.or_else(|| Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(Some(3))` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:81:13 + | +LL | let _ = opt.or_else(|| Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(Some(3))` + error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:84:13 + --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:85:13 + --> $DIR/unnecessary_lazy_eval.rs:88:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:86:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` -error: aborting due to 24 previous errors +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:114:35 + | +LL | let _: Result = res.and_then(|_| Err(2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:115:35 + | +LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:116:35 + | +LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:118:35 + | +LL | let _: Result = res.or_else(|_| Ok(2)); + | ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:119:35 + | +LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:120:35 + | +LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))` + +error: aborting due to 32 previous errors -- cgit 1.4.1-3-g733a5 From ce064722469672a504d8a1720ab4d2f681c21610 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Fri, 11 Sep 2020 15:06:49 +1200 Subject: replace `walk_ptrs_ty` with `peel_refs` --- clippy_lints/src/bytecount.rs | 7 +++---- clippy_lints/src/duration_subsec.rs | 4 ++-- clippy_lints/src/entry.rs | 4 ++-- clippy_lints/src/fallible_impl_from.rs | 6 ++---- clippy_lints/src/format.rs | 4 ++-- clippy_lints/src/inherent_to_string.rs | 4 ++-- clippy_lints/src/len_zero.rs | 4 ++-- clippy_lints/src/match_on_vec_items.rs | 5 ++--- clippy_lints/src/matches.rs | 4 ++-- clippy_lints/src/methods/mod.rs | 22 +++++++++++----------- clippy_lints/src/misc.rs | 6 +++--- clippy_lints/src/mut_key.rs | 4 ++-- clippy_lints/src/open_options.rs | 6 +++--- clippy_lints/src/path_buf_push_overwrite.rs | 4 ++-- clippy_lints/src/repeat_once.rs | 4 ++-- clippy_lints/src/strings.rs | 4 ++-- clippy_lints/src/swap.rs | 3 +-- clippy_lints/src/unwrap_in_result.rs | 6 +++--- clippy_lints/src/utils/internal_lints.rs | 6 +++--- clippy_lints/src/utils/mod.rs | 8 -------- 20 files changed, 51 insertions(+), 64 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 189c07427ae..d7d02ebf985 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,6 +1,5 @@ use crate::utils::{ - contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, - span_lint_and_sugg, walk_ptrs_ty, + contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_ast::ast::UintTy; @@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind; if op.node == BinOpKind::Eq; if match_type(cx, - walk_ptrs_ty(cx.typeck_results().expr_ty(&filter_args[0])), + cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(), &paths::SLICE_ITER); then { let needle = match get_path_name(l) { @@ -63,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { _ => { return; } } }; - if ty::Uint(UintTy::U8) != *walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind() { + if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() { return; } let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 8ece44878fe..c0529a34cc4 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind; if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind; - if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION); + if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right); then { let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) { diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index d616502a82a..35a5d00f4aa 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,6 +1,6 @@ use crate::utils::SpanlessEq; use crate::utils::{get_item_name, higher, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; -use crate::utils::{snippet_with_applicability, span_lint_and_then, walk_ptrs_ty}; +use crate::utils::{snippet_with_applicability, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; @@ -106,7 +106,7 @@ fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind; then { let map = ¶ms[0]; - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(map)); + let obj_ty = cx.typeck_results().expr_ty(map).peel_refs(); return if match_type(cx, obj_ty, &paths::BTREEMAP) { Some(("BTreeMap", map, key)) diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 000762334f6..a9e05fddbe7 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,7 +1,5 @@ use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT}; -use crate::utils::{ - is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, -}; +use crate::utils::{is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -96,7 +94,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8bd85af8768..d6541010bca 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,7 +1,7 @@ use crate::utils::paths; use crate::utils::{ is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, - span_lint_and_then, walk_ptrs_ty, + span_lint_and_then, }; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -90,7 +90,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind; if pats.len() == 1; then { - let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0])); + let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs(); if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { return None; } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index f330fa8fab8..0877b44d901 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -5,7 +5,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{ get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, - trait_ref_of_method, walk_ptrs_ty, + trait_ref_of_method, }; declare_clippy_lint! { @@ -125,7 +125,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { // Get the real type of 'self' let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id); let self_type = cx.tcx.fn_sig(fn_def_id).input(0); - let self_type = walk_ptrs_ty(self_type.skip_binder()); + let self_type = self_type.skip_binder().peel_refs(); // Emit either a warning or an error if implements_trait(cx, self_type, display_trait_id, &[]) { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 42a98dc963d..c9c4891bb08 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -285,7 +285,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { }) } - let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)); + let ty = &cx.typeck_results().expr_ty(expr).peel_refs(); match ty.kind() { ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { cx.tcx diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 57966452253..331b6c6c34a 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -1,4 +1,3 @@ -use crate::utils::walk_ptrs_ty; use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -90,12 +89,12 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - let ty = walk_ptrs_ty(ty); + let ty = ty.peel_refs(); is_type_diagnostic_item(cx, ty, sym!(vec_type)) } fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - let ty = walk_ptrs_ty(ty); + let ty = ty.peel_refs(); is_type_lang_item(cx, ty, LangItem::RangeFull) } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7ba7397c29c..11380f83316 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -6,7 +6,7 @@ use crate::utils::{ expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, walk_ptrs_ty, + span_lint_and_then, }; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -794,7 +794,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms } fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { - let ex_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(ex)); + let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) { for arm in arms { if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 184aee95efa..dadd0f8ebb7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -32,8 +32,8 @@ use crate::utils::{ is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, - walk_ptrs_ty_depth, SpanlessEq, + span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, + SpanlessEq, }; declare_clippy_lint! { @@ -1774,7 +1774,7 @@ fn lint_or_fun_call<'tcx>( ) { if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); match ty.kind() { ty::Slice(_) | ty::Array(_, _) => return, @@ -1881,7 +1881,7 @@ fn lint_expect_fun_call( && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); - let base_type = walk_ptrs_ty(arg_type); + let base_type = arg_type.peel_refs(); *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) } { @@ -2142,7 +2142,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg)); + let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { @@ -2173,7 +2173,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E let arg = &args[1]; if let Some(arglists) = method_chain_args(arg, &["chars"]) { let target = &arglists[0][0]; - let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target)); + let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { @@ -2201,7 +2201,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E } fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) { lint_string_extend(cx, expr, args); } @@ -2384,7 +2384,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ } } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type)) || matches!( - &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(), + &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), ty::Array(_, _) ) { @@ -2587,7 +2587,7 @@ fn derefs_to_slice<'tcx>( /// lint use of `unwrap()` for `Option`s and `Result`s fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0])); + let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { Some((UNWRAP_USED, "an Option", "None")) @@ -2615,7 +2615,7 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E /// lint use of `expect()` for `Option`s and `Result`s fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0])); + let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { Some((EXPECT_USED, "an Option", "None")) @@ -3134,7 +3134,7 @@ fn lint_chars_cmp( if segment.ident.name == sym!(Some); then { let mut applicability = Applicability::MachineApplicable; - let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0])); + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); if *self_ty.kind() != ty::Str { return false; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 67a3685fd0d..909e79f661a 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -17,7 +17,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq, + span_lint_and_then, span_lint_hir_and_then, SpanlessEq, }; declare_clippy_lint! { @@ -561,7 +561,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(); + let value = &cx.typeck_results().expr_ty(expr).peel_refs().kind(); if let ty::Array(arr_ty, _) = value { return matches!(arr_ty.kind(), ty::Float(_)); @@ -571,7 +571,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(), ty::Array(_, _)) + matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) } fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 0826ad0ab55..8a2dbdc50ea 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty}; +use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; @@ -98,7 +98,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased // generics (because the compiler cannot ensure immutability for unknown types). fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { - let ty = walk_ptrs_ty(ty); + let ty = ty.peel_refs(); if let Adt(def, substs) = ty.kind() { if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET] .iter() diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index e99d0317ba2..73a99a3a2f8 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty}; +use crate::utils::{match_type, paths, span_lint}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -30,7 +30,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); impl<'tcx> LateLintPass<'tcx> for OpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0])); + let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); get_open_options(cx, &arguments[0], &mut options); @@ -58,7 +58,7 @@ enum OpenOption { fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind { - let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0])); + let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index b8583402928..6eeb031d383 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_type, paths, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{match_type, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if path.ident.name == sym!(push); if args.len() == 2; - if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::PATH_BUF); + if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::PATH_BUF); if let Some(get_index_arg) = args.get(1); if let ExprKind::Lit(ref lit) = get_index_arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index c0890018d46..ae601353009 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,5 +1,5 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count); if !in_macro(receiver.span); then { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&receiver)); + let ty = cx.typeck_results().expr_ty(&receiver).peel_refs(); if ty.is_str() { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 7a659bf779c..15b66684eab 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned; use if_chain::if_chain; use crate::utils::SpanlessEq; -use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without @@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(e)), sym!(string_type)) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type)) } fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 47a73ca9a24..54b38d9f4ce 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,7 +1,6 @@ use crate::utils::sugg::Sugg; use crate::utils::{ differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, - walk_ptrs_ty, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -194,7 +193,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr< if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind { if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind { if eq_expr_value(cx, lhs1, lhs2) { - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1)); + let ty = cx.typeck_results().expr_ty(lhs1).peel_refs(); if matches!(ty.kind(), ty::Slice(_)) || matches!(ty.kind(), ty::Array(_, _)) diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 1c7e62ecd3d..0f8797243ec 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,4 +1,4 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then, walk_ptrs_ty}; +use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -81,7 +81,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { @@ -91,7 +91,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); + let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index f201494a024..bfe426a25eb 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,6 +1,6 @@ use crate::utils::{ is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints, - snippet, span_lint, span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq, + snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId}; @@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(&*fn_name.as_str()); - let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); + let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); then { @@ -460,7 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let args = arg_lists[1]; if args.len() == 1; let self_arg = &args[0]; - let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg)); + let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); then { span_lint_and_sugg( diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 95eedf88178..ea52741b7cc 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -754,14 +754,6 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { } } -/// Returns the base type for references and raw pointers. -pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { - match ty.kind() { - ty::Ref(_, ty, _) => walk_ptrs_ty(ty), - _ => ty, - } -} - /// Returns the base type for references and raw pointers, and count reference /// depth. pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { -- cgit 1.4.1-3-g733a5 From 7021d70d2e57e081597ea34eb18226a71b665ecd Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 6 Oct 2020 23:58:32 +0800 Subject: Use more concrete explanation for methods Show some code rather than "a single method call". --- clippy_lints/src/methods/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index dadd0f8ebb7..a9650e531b6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -400,8 +400,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call using `_.flat_map(_)` + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.flat_map(_)` /// /// **Known problems:** /// @@ -424,8 +424,8 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter(_).map(_)`, /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar. /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.filter_map(_)`. /// /// **Known problems:** Often requires a condition + Option/Iterator creation /// inside the closure. @@ -452,8 +452,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter_map(_).next()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.find_map(_)`. /// /// **Known problems:** None /// @@ -496,8 +496,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `_.find(_).map(_)`. /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.find_map(_)`. /// /// **Known problems:** Often requires a condition + Option/Iterator creation /// inside the closure. @@ -1276,8 +1276,8 @@ 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). /// - /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.as_deref()`. /// /// **Known problems:** None. /// -- cgit 1.4.1-3-g733a5 From b05aeaa9bce36d69d9ee13d1b5f6a271b6e8c1e5 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 6 Oct 2020 23:32:38 +0200 Subject: Run fmt --- clippy_lints/src/future_not_send.rs | 9 ++------- clippy_lints/src/methods/mod.rs | 4 +--- clippy_lints/src/utils/mod.rs | 3 +-- 3 files changed, 4 insertions(+), 12 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index d2a322e1223..71a30d1c33d 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -92,13 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { |db| { cx.tcx.infer_ctxt().enter(|infcx| { for FulfillmentError { obligation, .. } in send_errors { - infcx.maybe_note_obligation_cause_for_async_await( - db, - &obligation, - ); - if let Trait(trait_pred, _) = - obligation.predicate.skip_binders() - { + infcx.maybe_note_obligation_cause_for_async_await(db, &obligation); + if let Trait(trait_pred, _) = obligation.predicate.skip_binders() { db.note(&format!( "`{}` doesn't implement `{}`", trait_pred.self_ty(), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e0651f9ab5d..ec70b2f1e20 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1668,9 +1668,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { 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::PredicateAtom::Projection(projection_predicate) = - predicate.skip_binders() - { + if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { // walk the associated type and check for Self if contains_ty(projection_predicate.ty, self_ty) { return; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 247effde19b..b2a8e3f08d5 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1287,8 +1287,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() { - if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() - { + if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { return true; } } -- cgit 1.4.1-3-g733a5 From f0cf3bdca198ead0e1d76115bf30a2eef72e8c58 Mon Sep 17 00:00:00 2001 From: HMPerson1 Date: Sun, 25 Oct 2020 21:20:57 -0400 Subject: Add lint for replacing `.map().collect()` with `.try_for_each()` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/mod.rs | 59 +++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 ++++ tests/ui/map_collect_result_unit.fixed | 16 +++++++++ tests/ui/map_collect_result_unit.rs | 16 +++++++++ tests/ui/map_collect_result_unit.stderr | 16 +++++++++ 7 files changed, 118 insertions(+) create mode 100644 tests/ui/map_collect_result_unit.fixed create mode 100644 tests/ui/map_collect_result_unit.rs create mode 100644 tests/ui/map_collect_result_unit.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 25f3b5da198..287cf6bb725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1802,6 +1802,7 @@ Released 2018-09-13 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone +[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry [`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3be8bc0e36d..138d1ab9b50 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -697,6 +697,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, &methods::MANUAL_SATURATING_ARITHMETIC, + &methods::MAP_COLLECT_RESULT_UNIT, &methods::MAP_FLATTEN, &methods::MAP_UNWRAP_OR, &methods::NEW_RET_NO_SELF, @@ -1420,6 +1421,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_AS_REF_DEREF), @@ -1615,6 +1617,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_MAP_OR_NONE), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c0824bacbc7..5f9bed90845 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1383,6 +1383,27 @@ declare_clippy_lint! { "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.map(_).collect::()`. + /// + /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// (0..3).map(|t| Err(t)).collect::>(); + /// ``` + /// Use instead: + /// ```rust + /// (0..3).try_for_each(|t| Err(t)); + /// ``` + pub MAP_COLLECT_RESULT_UNIT, + style, + "using `.map(_).collect::()`, which can be replaced with `try_for_each`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1433,6 +1454,7 @@ declare_lint_pass!(Methods => [ FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, UNNECESSARY_LAZY_EVALUATIONS, + MAP_COLLECT_RESULT_UNIT, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1515,6 +1537,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), + ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), _ => {}, } @@ -3501,6 +3524,42 @@ fn lint_option_as_ref_deref<'tcx>( } } +fn lint_map_collect( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + map_args: &[hir::Expr<'_>], + collect_args: &[hir::Expr<'_>], +) { + if_chain! { + // called on Iterator + if let [map_expr] = collect_args; + if match_trait_method(cx, map_expr, &paths::ITERATOR); + // return of collect `Result<(),_>` + let collect_ret_ty = cx.typeck_results().expr_ty(expr); + if is_type_diagnostic_item(cx, collect_ret_ty, sym!(result_type)); + if let ty::Adt(_, substs) = collect_ret_ty.kind(); + if let Some(result_t) = substs.types().next(); + if result_t.is_unit(); + // get parts for snippet + if let [iter, map_fn] = map_args; + then { + span_lint_and_sugg( + cx, + MAP_COLLECT_RESULT_UNIT, + expr.span, + "`.map().collect()` can be replaced with `.try_for_each()`", + "try this", + format!( + "{}.try_for_each({})", + snippet(cx, iter.span, ".."), + snippet(cx, map_fn.span, "..") + ), + Applicability::MachineApplicable, + ); + } + } +} + /// Given a `Result` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { match ty.kind() { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 6272ce45efb..d9b3e5c17f4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1222,6 +1222,13 @@ vec![ deprecation: None, module: "map_clone", }, + Lint { + name: "map_collect_result_unit", + group: "style", + desc: "using `.map(_).collect::()`, which can be replaced with `try_for_each`", + deprecation: None, + module: "methods", + }, Lint { name: "map_entry", group: "perf", diff --git a/tests/ui/map_collect_result_unit.fixed b/tests/ui/map_collect_result_unit.fixed new file mode 100644 index 00000000000..e66c9cc2420 --- /dev/null +++ b/tests/ui/map_collect_result_unit.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::map_collect_result_unit)] + +fn main() { + { + let _ = (0..3).try_for_each(|t| Err(t + 1)); + let _: Result<(), _> = (0..3).try_for_each(|t| Err(t + 1)); + + let _ = (0..3).try_for_each(|t| Err(t + 1)); + } +} + +fn _ignore() { + let _ = (0..3).map(|t| Err(t + 1)).collect::, _>>(); + let _ = (0..3).map(|t| Err(t + 1)).collect::>>(); +} diff --git a/tests/ui/map_collect_result_unit.rs b/tests/ui/map_collect_result_unit.rs new file mode 100644 index 00000000000..6f08f4c3c53 --- /dev/null +++ b/tests/ui/map_collect_result_unit.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::map_collect_result_unit)] + +fn main() { + { + let _ = (0..3).map(|t| Err(t + 1)).collect::>(); + let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); + + let _ = (0..3).try_for_each(|t| Err(t + 1)); + } +} + +fn _ignore() { + let _ = (0..3).map(|t| Err(t + 1)).collect::, _>>(); + let _ = (0..3).map(|t| Err(t + 1)).collect::>>(); +} diff --git a/tests/ui/map_collect_result_unit.stderr b/tests/ui/map_collect_result_unit.stderr new file mode 100644 index 00000000000..8b06e13baa6 --- /dev/null +++ b/tests/ui/map_collect_result_unit.stderr @@ -0,0 +1,16 @@ +error: `.map().collect()` can be replaced with `.try_for_each()` + --> $DIR/map_collect_result_unit.rs:6:17 + | +LL | let _ = (0..3).map(|t| Err(t + 1)).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` + | + = note: `-D clippy::map-collect-result-unit` implied by `-D warnings` + +error: `.map().collect()` can be replaced with `.try_for_each()` + --> $DIR/map_collect_result_unit.rs:7:32 + | +LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 2911d9c7de4c0acf7bdd6a2d6983d1fccbeb6a69 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 18 Oct 2020 13:09:06 +0200 Subject: Use better placeholders for some methods lint messages --- clippy_lints/src/methods/mod.rs | 58 ++++++++++++------------ clippy_lints/src/methods/option_map_unwrap_or.rs | 8 ++-- tests/ui/filter_map_next.stderr | 4 +- tests/ui/filter_methods.stderr | 8 ++-- tests/ui/find_map.stderr | 4 +- tests/ui/iter_skip_next.stderr | 8 ++-- tests/ui/map_unwrap_or.stderr | 40 ++++++++-------- tests/ui/methods.stderr | 4 +- tests/ui/option_map_or_none.stderr | 4 +- tests/ui/skip_while_next.stderr | 8 ++-- 10 files changed, 73 insertions(+), 73 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c0824bacbc7..fc77cd52b8f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1748,7 +1748,7 @@ fn lint_or_fun_call<'tcx>( "try this", format!( "{}.unwrap_or_default()", - snippet_with_applicability(cx, self_expr.span, "_", &mut applicability) + snippet_with_applicability(cx, self_expr.span, "..", &mut applicability) ), applicability, ); @@ -2155,7 +2155,7 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir:: return; }; - let snippet = snippet_with_macro_callsite(cx, arg.span, "_"); + let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); span_lint_and_sugg( cx, @@ -2191,9 +2191,9 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E "try this", format!( "{}.push_str({}{})", - snippet_with_applicability(cx, args[0].span, "_", &mut applicability), + snippet_with_applicability(cx, args[0].span, "..", &mut applicability), ref_str, - snippet_with_applicability(cx, target.span, "_", &mut applicability) + snippet_with_applicability(cx, target.span, "..", &mut applicability) ), applicability, ); @@ -2460,7 +2460,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: let mut applicability = Applicability::MachineApplicable; let expr_ty = cx.typeck_results().expr_ty(&get_args[0]); let get_args_str = if get_args.len() > 1 { - snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability) + snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability) } else { return; // not linting on a .get().unwrap() chain or variant }; @@ -2520,7 +2520,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: format!( "{}{}[{}]", borrow_str, - snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability), + snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability), get_args_str ), applicability, @@ -2536,7 +2536,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[ cx, ITER_SKIP_NEXT, expr.span.trim_start(caller.span).unwrap(), - "called `skip(x).next()` on an iterator", + "called `skip(..).next()` on an iterator", "use `nth` instead", hint, Applicability::MachineApplicable, @@ -2739,11 +2739,11 @@ fn lint_map_unwrap_or_else<'tcx>( // lint message let msg = if is_option { - "called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling \ - `map_or_else(g, f)` instead" + "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling \ + `map_or_else(, )` instead" } else { - "called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling \ - `.map_or_else(g, f)` instead" + "called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling \ + `.map_or_else(, )` instead" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_args[1].span, ".."); @@ -2809,8 +2809,8 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map if is_option { let self_snippet = snippet(cx, map_or_args[0].span, ".."); let func_snippet = snippet(cx, map_or_args[2].span, ".."); - let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \ - `and_then(f)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ + `and_then(..)` instead"; ( OPTION_MAP_OR_NONE, msg, @@ -2848,8 +2848,8 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.filter().next()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find(p)` instead."; + let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { // add note if not multi-line @@ -2879,9 +2879,9 @@ fn lint_skip_while_next<'tcx>( cx, SKIP_WHILE_NEXT, expr.span, - "called `skip_while(p).next()` on an `Iterator`", + "called `skip_while(

).next()` on an `Iterator`", None, - "this is more succinctly expressed by calling `.find(!p)` instead", + "this is more succinctly expressed by calling `.find(!

)` instead", ); } } @@ -2895,7 +2895,7 @@ fn lint_filter_map<'tcx>( ) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).map(q)` on an `Iterator`"; + let msg = "called `filter(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } @@ -2904,8 +2904,8 @@ fn lint_filter_map<'tcx>( /// lint use of `filter_map().next()` for `Iterators` fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find_map(p)` instead."; + let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find_map(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { span_lint_and_note( @@ -2931,7 +2931,7 @@ fn lint_find_map<'tcx>( ) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, &map_args[0], &paths::ITERATOR) { - let msg = "called `find(p).map(q)` on an `Iterator`"; + let msg = "called `find(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.find_map(..)` instead"; span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint); } @@ -2946,7 +2946,7 @@ fn lint_filter_map_map<'tcx>( ) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(p).map(q)` on an `Iterator`"; + let msg = "called `filter_map(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } @@ -2961,7 +2961,7 @@ fn lint_filter_flat_map<'tcx>( ) { // lint if caller of `.filter().flat_map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).flat_map(q)` on an `Iterator`"; + let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); @@ -2977,7 +2977,7 @@ fn lint_filter_map_flat_map<'tcx>( ) { // lint if caller of `.filter_map().flat_map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`"; + let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); @@ -3148,9 +3148,9 @@ fn lint_chars_cmp( "like this", format!("{}{}.{}({})", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability), + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, - snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)), + snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), applicability, ); @@ -3197,7 +3197,7 @@ fn lint_chars_cmp_with_unwrap<'tcx>( "like this", format!("{}{}.{}('{}')", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability), + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, c), applicability, @@ -3272,7 +3272,7 @@ fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &h fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { - let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let base_string_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); let sugg = format!("{}.push({})", base_string_snippet, extension_string); span_lint_and_sugg( cx, @@ -3315,7 +3315,7 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re expr.span, &format!("this call to `{}` does nothing", call_name), "try this", - snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(), + snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, ); } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 95fa28e1c0f..d30b85d6a78 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -53,15 +53,15 @@ pub(super) fn lint<'tcx>( // lint message // comparing the snippet from source to raw text ("None") below is safe // because we already have checked the type. - let arg = if unwrap_snippet == "None" { "None" } else { "a" }; + let arg = if unwrap_snippet == "None" { "None" } else { "" }; let unwrap_snippet_none = unwrap_snippet == "None"; let suggest = if unwrap_snippet_none { - "and_then(f)" + "and_then()" } else { - "map_or(a, f)" + "map_or(, )" }; let msg = &format!( - "called `map(f).unwrap_or({})` on an `Option` value. \ + "called `map().unwrap_or({})` on an `Option` value. \ This can be done more directly by calling `{}` instead", arg, suggest ); diff --git a/tests/ui/filter_map_next.stderr b/tests/ui/filter_map_next.stderr index d69ae212414..01281ebaf6a 100644 --- a/tests/ui/filter_map_next.stderr +++ b/tests/ui/filter_map_next.stderr @@ -1,4 +1,4 @@ -error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead. +error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. --> $DIR/filter_map_next.rs:6:32 | LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); @@ -7,7 +7,7 @@ LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next = note: `-D clippy::filter-map-next` implied by `-D warnings` = note: replace `filter_map(|s| s.parse().ok()).next()` with `find_map(|s| s.parse().ok())` -error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead. +error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. --> $DIR/filter_map_next.rs:10:26 | LL | let _: Option = vec![1, 2, 3, 4, 5, 6] diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 84a957a374c..91718dd1175 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,4 +1,4 @@ -error: called `filter(p).map(q)` on an `Iterator` +error: called `filter(..).map(..)` on an `Iterator` --> $DIR/filter_methods.rs:5:21 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); @@ -7,7 +7,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = note: `-D clippy::filter-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.filter_map(..)` instead -error: called `filter(p).flat_map(q)` on an `Iterator` +error: called `filter(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:7:21 | LL | let _: Vec<_> = vec![5_i8; 6] @@ -19,7 +19,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: called `filter_map(p).flat_map(q)` on an `Iterator` +error: called `filter_map(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:13:21 | LL | let _: Vec<_> = vec![5_i8; 6] @@ -31,7 +31,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: called `filter_map(p).map(q)` on an `Iterator` +error: called `filter_map(..).map(..)` on an `Iterator` --> $DIR/filter_methods.rs:19:21 | LL | let _: Vec<_> = vec![5_i8; 6] diff --git a/tests/ui/find_map.stderr b/tests/ui/find_map.stderr index f279850fef8..aea3cc62afc 100644 --- a/tests/ui/find_map.stderr +++ b/tests/ui/find_map.stderr @@ -1,4 +1,4 @@ -error: called `find(p).map(q)` on an `Iterator` +error: called `find(..).map(..)` on an `Iterator` --> $DIR/find_map.rs:20:26 | LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s| s.parse().unwrap()); @@ -7,7 +7,7 @@ LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s = note: `-D clippy::find-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.find_map(..)` instead -error: called `find(p).map(q)` on an `Iterator` +error: called `find(..).map(..)` on an `Iterator` --> $DIR/find_map.rs:23:29 | LL | let _: Option = desserts_of_the_week diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index feedc2f288a..486de718bb5 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,4 +1,4 @@ -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:15:28 | LL | let _ = some_vec.iter().skip(42).next(); @@ -6,19 +6,19 @@ LL | let _ = some_vec.iter().skip(42).next(); | = note: `-D clippy::iter-skip-next` implied by `-D warnings` -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:16:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:17:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:18:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index b62080a073f..6fa2800e9bd 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -1,4 +1,4 @@ -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead --> $DIR/map_unwrap_or.rs:17:13 | LL | let _ = opt.map(|x| x + 1) @@ -8,12 +8,12 @@ LL | | .unwrap_or(0); | |_____________________^ | = note: `-D clippy::map-unwrap-or` implied by `-D warnings` -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = opt.map_or(0, |x| x + 1); | ^^^^^^ ^^ -- -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead --> $DIR/map_unwrap_or.rs:21:13 | LL | let _ = opt.map(|x| { @@ -23,7 +23,7 @@ LL | | } LL | | ).unwrap_or(0); | |__________________^ | -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = opt.map_or(0, |x| { LL | x + 1 @@ -31,7 +31,7 @@ LL | } LL | ); | -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead --> $DIR/map_unwrap_or.rs:25:13 | LL | let _ = opt.map(|x| x + 1) @@ -41,25 +41,25 @@ LL | | 0 LL | | }); | |__________^ | -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = opt.map_or({ LL | 0 LL | }, |x| x + 1); | -error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead --> $DIR/map_unwrap_or.rs:30:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `and_then(f)` instead +help: use `and_then()` instead | LL | let _ = opt.and_then(|x| Some(x + 1)); | ^^^^^^^^ -- -error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead --> $DIR/map_unwrap_or.rs:32:13 | LL | let _ = opt.map(|x| { @@ -69,7 +69,7 @@ LL | | } LL | | ).unwrap_or(None); | |_____________________^ | -help: use `and_then(f)` instead +help: use `and_then()` instead | LL | let _ = opt.and_then(|x| { LL | Some(x + 1) @@ -77,7 +77,7 @@ LL | } LL | ); | -error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead --> $DIR/map_unwrap_or.rs:36:13 | LL | let _ = opt @@ -86,23 +86,23 @@ LL | | .map(|x| Some(x + 1)) LL | | .unwrap_or(None); | |________________________^ | -help: use `and_then(f)` instead +help: use `and_then()` instead | LL | .and_then(|x| Some(x + 1)); | ^^^^^^^^ -- -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead --> $DIR/map_unwrap_or.rs:47:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | ^^^^^^ ^^^ -- -error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead +error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:51:13 | LL | let _ = opt.map(|x| x + 1) @@ -113,7 +113,7 @@ LL | | .unwrap_or_else(|| 0); | = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` -error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead +error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:55:13 | LL | let _ = opt.map(|x| { @@ -123,7 +123,7 @@ LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ -error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead +error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:59:13 | LL | let _ = opt.map(|x| x + 1) @@ -133,7 +133,7 @@ LL | | 0 LL | | ); | |_________^ -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead +error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:88:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line @@ -141,7 +141,7 @@ LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even t | = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead +error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:90:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); @@ -149,7 +149,7 @@ LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); | = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead +error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:91:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 2a0a43e83a6..74d8533d4da 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -8,7 +8,7 @@ LL | | } | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` -error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. --> $DIR/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); @@ -17,7 +17,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: `-D clippy::filter-next` implied by `-D warnings` = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` -error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. --> $DIR/methods.rs:129:13 | LL | let _ = v.iter().filter(|&x| { diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 6f707987dbc..1cba29412b8 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead --> $DIR/option_map_or_none.rs:10:13 | LL | let _ = opt.map_or(None, |x| Some(x + 1)); @@ -6,7 +6,7 @@ LL | let _ = opt.map_or(None, |x| Some(x + 1)); | = note: `-D clippy::option-map-or-none` implied by `-D warnings` -error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead --> $DIR/option_map_or_none.rs:13:13 | LL | let _ = opt.map_or(None, |x| { diff --git a/tests/ui/skip_while_next.stderr b/tests/ui/skip_while_next.stderr index a6b7bcd63ff..269cc13468b 100644 --- a/tests/ui/skip_while_next.stderr +++ b/tests/ui/skip_while_next.stderr @@ -1,13 +1,13 @@ -error: called `skip_while(p).next()` on an `Iterator` +error: called `skip_while(

).next()` on an `Iterator` --> $DIR/skip_while_next.rs:14:13 | LL | let _ = v.iter().skip_while(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::skip-while-next` implied by `-D warnings` - = help: this is more succinctly expressed by calling `.find(!p)` instead + = help: this is more succinctly expressed by calling `.find(!

)` instead -error: called `skip_while(p).next()` on an `Iterator` +error: called `skip_while(

).next()` on an `Iterator` --> $DIR/skip_while_next.rs:17:13 | LL | let _ = v.iter().skip_while(|&x| { @@ -17,7 +17,7 @@ LL | | } LL | | ).next(); | |___________________________^ | - = help: this is more succinctly expressed by calling `.find(!p)` instead + = help: this is more succinctly expressed by calling `.find(!

)` instead error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 3fec6f568daababf3520e2a818b4c1db79266b92 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 19 Oct 2020 18:47:02 +0200 Subject: Improve some suggestions for `filter_map_next`, `filter_next` and `map_unwrap_or` lints --- clippy_lints/src/methods/mod.rs | 30 ++++++++++++++++-------------- tests/ui/filter_map_next.stderr | 3 +-- tests/ui/map_unwrap_or.stderr | 16 ++++------------ tests/ui/methods.stderr | 3 +-- 4 files changed, 22 insertions(+), 30 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fc77cd52b8f..d3e26a09ad4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -32,8 +32,7 @@ use crate::utils::{ is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, - SpanlessEq, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -2753,16 +2752,15 @@ fn lint_map_unwrap_or_else<'tcx>( let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt(); if same_span && !multiline { - span_lint_and_note( + let var_snippet = snippet(cx, map_args[0].span, ".."); + span_lint_and_sugg( cx, MAP_UNWRAP_OR, expr.span, msg, - None, - &format!( - "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`", - map_snippet, unwrap_snippet, - ), + "try this", + format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet), + Applicability::MachineApplicable, ); return true; } else if same_span && multiline { @@ -2852,14 +2850,16 @@ fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, fil `.find(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { + let iter_snippet = snippet(cx, filter_args[0].span, ".."); // add note if not multi-line - span_lint_and_note( + span_lint_and_sugg( cx, FILTER_NEXT, expr.span, msg, - None, - &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet), + "try this", + format!("{}.find({})", iter_snippet, filter_snippet), + Applicability::MachineApplicable, ); } else { span_lint(cx, FILTER_NEXT, expr.span, msg); @@ -2908,13 +2908,15 @@ fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, `.find_map(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { - span_lint_and_note( + let iter_snippet = snippet(cx, filter_args[0].span, ".."); + span_lint_and_sugg( cx, FILTER_MAP_NEXT, expr.span, msg, - None, - &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet), + "try this", + format!("{}.find_map({})", iter_snippet, filter_snippet), + Applicability::MachineApplicable, ); } else { span_lint(cx, FILTER_MAP_NEXT, expr.span, msg); diff --git a/tests/ui/filter_map_next.stderr b/tests/ui/filter_map_next.stderr index 01281ebaf6a..bcedf11e536 100644 --- a/tests/ui/filter_map_next.stderr +++ b/tests/ui/filter_map_next.stderr @@ -2,10 +2,9 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly --> $DIR/filter_map_next.rs:6:32 | LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())` | = note: `-D clippy::filter-map-next` implied by `-D warnings` - = note: replace `filter_map(|s| s.parse().ok()).next()` with `find_map(|s| s.parse().ok())` error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. --> $DIR/filter_map_next.rs:10:26 diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 6fa2800e9bd..1975abb3e9f 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -109,9 +109,7 @@ LL | let _ = opt.map(|x| x + 1) | _____________^ LL | | // Should lint even though this call is on a separate line. LL | | .unwrap_or_else(|| 0); - | |_____________________________^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` + | |_____________________________^ help: try this: `opt.map_or_else(|| 0, |x| x + 1)` error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:55:13 @@ -137,25 +135,19 @@ error: called `map().unwrap_or_else()` on a `Result` value. This can be do --> $DIR/map_unwrap_or.rs:88:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|e| 0, |x| x + 1)` error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:90:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|e| 0, |x| x + 1)` error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead --> $DIR/map_unwrap_or.rs:91:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|e| 0, |x| x + 1)` error: aborting due to 13 previous errors diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 74d8533d4da..2df1941aaaa 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -12,10 +12,9 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expr --> $DIR/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)` | = note: `-D clippy::filter-next` implied by `-D warnings` - = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. --> $DIR/methods.rs:129:13 -- cgit 1.4.1-3-g733a5 From c0d1002d9328104808253b5cb680d0cd0ab70c1a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 30 Oct 2020 16:06:27 -0500 Subject: Fix unnecessary_lazy_eval suggestion applicability Fixes #6240 --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 12 +++++++++++- tests/ui/unnecessary_lazy_eval_unfixable.rs | 18 ++++++++++++++++++ tests/ui/unnecessary_lazy_eval_unfixable.stderr | 22 ++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/ui/unnecessary_lazy_eval_unfixable.rs create mode 100644 tests/ui/unnecessary_lazy_eval_unfixable.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 08b3eab9b7c..aec1b7e2e46 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -32,6 +32,16 @@ pub(super) fn lint<'tcx>( } else { "unnecessary closure used to substitute value for `Result::Err`" }; + let applicability = if body + .params + .iter() + .all(|param| matches!(param.pat.kind, hir::PatKind::Wild)) + { + Applicability::MachineApplicable + } else { + // replacing the lambda may break type inference + Applicability::MaybeIncorrect + }; span_lint_and_sugg( cx, @@ -45,7 +55,7 @@ pub(super) fn lint<'tcx>( simplify_using, snippet(cx, body_expr.span, ".."), ), - Applicability::MachineApplicable, + applicability, ); } } diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs new file mode 100644 index 00000000000..2e923bc97a2 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -0,0 +1,18 @@ +#![warn(clippy::unnecessary_lazy_evaluations)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: usize, +} + +fn main() { + // fix will break type inference + let _ = Ok(1).unwrap_or_else(|()| 2); + mod e { + pub struct E; + } + let _ = Ok(1).unwrap_or_else(|e::E| 2); + let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); +} diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr new file mode 100644 index 00000000000..581d641cbf5 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -0,0 +1,22 @@ +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 + | +LL | let _ = Ok(1).unwrap_or_else(|()| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | + = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 + | +LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 + | +LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 2350ee75b2cc9c3d8cfbbb8d950012678913b92d Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Sun, 13 Sep 2020 13:00:45 +0200 Subject: single_char_push_str lint using insert_str() on single-char literals and suggest insert() changelog: single_char_push_str: lint using string.insert_str() with single char literals and suggests string.insert() with a char Fixes #6026 --- clippy_lints/src/methods/mod.rs | 25 +++++++++++++++++++-- clippy_lints/src/utils/paths.rs | 1 + tests/ui/single_char_insert_str.fixed | 18 +++++++++++++++ tests/ui/single_char_insert_str.rs | 18 +++++++++++++++ tests/ui/single_char_insert_str.stderr | 40 ++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/ui/single_char_insert_str.fixed create mode 100644 tests/ui/single_char_insert_str.rs create mode 100644 tests/ui/single_char_insert_str.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3c3093e869c..86e7c57afae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1290,8 +1290,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using `push_str` with a single-character string literal, - /// and `push` with a `char` would work fine. + /// **What it does:** Warns when using `push_str` with a single-character string literal + /// where `push` with a `char` would work fine. /// /// **Why is this bad?** It's less clear that we are pushing a single character. /// @@ -1521,6 +1521,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { lint_single_char_push_string(cx, expr, args); + } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { + lint_single_char_insert_string(cx, expr, args); } } @@ -3255,6 +3257,25 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args } } +/// lint for length-1 `str`s as argument for `insert_str` +fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { + let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let pos_arg = snippet(cx, args[1].span, ".."); + let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); + span_lint_and_sugg( + cx, + SINGLE_CHAR_PUSH_STR, + expr.span, + "calling `insert_str()` using a single-character string literal", + "consider using `insert` with a character literal", + sugg, + applicability, + ); + } +} + /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index cd72fdd61fd..34d5c8d2eb7 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -52,6 +52,7 @@ pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entr pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"]; pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; +pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; diff --git a/tests/ui/single_char_insert_str.fixed b/tests/ui/single_char_insert_str.fixed new file mode 100644 index 00000000000..c3416720ec3 --- /dev/null +++ b/tests/ui/single_char_insert_str.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![warn(clippy::single_char_push_str)] + +fn main() { + let mut string = String::new(); + string.insert(0, 'R'); + string.insert(1, '\''); + + string.insert(0, 'u'); + string.insert_str(2, "st"); + string.insert_str(0, ""); + string.insert(0, '\x52'); + string.insert(0, '\u{0052}'); + let x: usize = 2; + string.insert(x, 'a'); + const Y: usize = 1; + string.insert(Y, 'a'); +} diff --git a/tests/ui/single_char_insert_str.rs b/tests/ui/single_char_insert_str.rs new file mode 100644 index 00000000000..2295669e81d --- /dev/null +++ b/tests/ui/single_char_insert_str.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![warn(clippy::single_char_push_str)] + +fn main() { + let mut string = String::new(); + string.insert_str(0, "R"); + string.insert_str(1, "'"); + + string.insert(0, 'u'); + string.insert_str(2, "st"); + string.insert_str(0, ""); + string.insert_str(0, "\x52"); + string.insert_str(0, "\u{0052}"); + let x: usize = 2; + string.insert_str(x, r##"a"##); + const Y: usize = 1; + string.insert_str(Y, r##"a"##); +} diff --git a/tests/ui/single_char_insert_str.stderr b/tests/ui/single_char_insert_str.stderr new file mode 100644 index 00000000000..65dc8a69d69 --- /dev/null +++ b/tests/ui/single_char_insert_str.stderr @@ -0,0 +1,40 @@ +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:6:5 + | +LL | string.insert_str(0, "R"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` + | + = note: `-D clippy::single-char-push-str` implied by `-D warnings` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:7:5 + | +LL | string.insert_str(1, "'"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:12:5 + | +LL | string.insert_str(0, "/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:13:5 + | +LL | string.insert_str(0, "/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:15:5 + | +LL | string.insert_str(x, r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:17:5 + | +LL | string.insert_str(Y, r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` + +error: aborting due to 6 previous errors + -- cgit 1.4.1-3-g733a5 From c6412aeebc432ab49d46fe1f45a0fb5322c805d1 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Mon, 14 Sep 2020 15:31:04 +0200 Subject: handle macros returning Strings in single_char_push_str and single_char_insert_str --- clippy_lints/src/methods/mod.rs | 6 ++++-- tests/ui/single_char_insert_str.fixed | 8 ++++++++ tests/ui/single_char_insert_str.rs | 8 ++++++++ tests/ui/single_char_insert_str.stderr | 20 +++++++++++++------- tests/ui/single_char_push_str.fixed | 8 ++++++++ tests/ui/single_char_push_str.rs | 8 ++++++++ tests/ui/single_char_push_str.stderr | 10 +++++----- 7 files changed, 54 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 86e7c57afae..68a152270e0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3243,7 +3243,8 @@ fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &h fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { - let base_string_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); + let base_string_snippet = + snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability); let sugg = format!("{}.push({})", base_string_snippet, extension_string); span_lint_and_sugg( cx, @@ -3261,7 +3262,8 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { - let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let base_string_snippet = + snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); let pos_arg = snippet(cx, args[1].span, ".."); let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); span_lint_and_sugg( diff --git a/tests/ui/single_char_insert_str.fixed b/tests/ui/single_char_insert_str.fixed index c3416720ec3..fd43f913330 100644 --- a/tests/ui/single_char_insert_str.fixed +++ b/tests/ui/single_char_insert_str.fixed @@ -1,6 +1,12 @@ // run-rustfix #![warn(clippy::single_char_push_str)] +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + fn main() { let mut string = String::new(); string.insert(0, 'R'); @@ -15,4 +21,6 @@ fn main() { string.insert(x, 'a'); const Y: usize = 1; string.insert(Y, 'a'); + + get_string!().insert(1, '?'); } diff --git a/tests/ui/single_char_insert_str.rs b/tests/ui/single_char_insert_str.rs index 2295669e81d..4278f7ef9fd 100644 --- a/tests/ui/single_char_insert_str.rs +++ b/tests/ui/single_char_insert_str.rs @@ -1,6 +1,12 @@ // run-rustfix #![warn(clippy::single_char_push_str)] +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + fn main() { let mut string = String::new(); string.insert_str(0, "R"); @@ -15,4 +21,6 @@ fn main() { string.insert_str(x, r##"a"##); const Y: usize = 1; string.insert_str(Y, r##"a"##); + + get_string!().insert_str(1, "?"); } diff --git a/tests/ui/single_char_insert_str.stderr b/tests/ui/single_char_insert_str.stderr index 65dc8a69d69..3d00c91a2ac 100644 --- a/tests/ui/single_char_insert_str.stderr +++ b/tests/ui/single_char_insert_str.stderr @@ -1,5 +1,5 @@ error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:6:5 + --> $DIR/single_char_insert_str.rs:12:5 | LL | string.insert_str(0, "R"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` @@ -7,34 +7,40 @@ LL | string.insert_str(0, "R"); = note: `-D clippy::single-char-push-str` implied by `-D warnings` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:7:5 + --> $DIR/single_char_insert_str.rs:13:5 | LL | string.insert_str(1, "'"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:12:5 + --> $DIR/single_char_insert_str.rs:18:5 | LL | string.insert_str(0, "/x52"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:13:5 + --> $DIR/single_char_insert_str.rs:19:5 | LL | string.insert_str(0, "/u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:15:5 + --> $DIR/single_char_insert_str.rs:21:5 | LL | string.insert_str(x, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:17:5 + --> $DIR/single_char_insert_str.rs:23:5 | LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` -error: aborting due to 6 previous errors +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_insert_str.rs:25:5 + | +LL | get_string!().insert_str(1, "?"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` + +error: aborting due to 7 previous errors diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed index 0812c026a64..da742fe70e2 100644 --- a/tests/ui/single_char_push_str.fixed +++ b/tests/ui/single_char_push_str.fixed @@ -1,6 +1,12 @@ // run-rustfix #![warn(clippy::single_char_push_str)] +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + fn main() { let mut string = String::new(); string.push('R'); @@ -12,4 +18,6 @@ fn main() { string.push('\x52'); string.push('\u{0052}'); string.push('a'); + + get_string!().push_str("ö"); } diff --git a/tests/ui/single_char_push_str.rs b/tests/ui/single_char_push_str.rs index ab293bbe4ee..a8203e6503e 100644 --- a/tests/ui/single_char_push_str.rs +++ b/tests/ui/single_char_push_str.rs @@ -1,6 +1,12 @@ // run-rustfix #![warn(clippy::single_char_push_str)] +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + fn main() { let mut string = String::new(); string.push_str("R"); @@ -12,4 +18,6 @@ fn main() { string.push_str("\x52"); string.push_str("\u{0052}"); string.push_str(r##"a"##); + + get_string!().push_str("ö"); } diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr index 0e9bdaa23e7..1f535589121 100644 --- a/tests/ui/single_char_push_str.stderr +++ b/tests/ui/single_char_push_str.stderr @@ -1,5 +1,5 @@ error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:6:5 + --> $DIR/single_char_push_str.rs:12:5 | LL | string.push_str("R"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` @@ -7,25 +7,25 @@ LL | string.push_str("R"); = note: `-D clippy::single-char-push-str` implied by `-D warnings` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:7:5 + --> $DIR/single_char_push_str.rs:13:5 | LL | string.push_str("'"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:12:5 + --> $DIR/single_char_push_str.rs:18:5 | LL | string.push_str("/x52"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:13:5 + --> $DIR/single_char_push_str.rs:19:5 | LL | string.push_str("/u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:14:5 + --> $DIR/single_char_push_str.rs:20:5 | LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` -- cgit 1.4.1-3-g733a5 From c1eb8ceede6538590a39721c65ee2f943ceffe40 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Thu, 24 Sep 2020 16:36:29 +0200 Subject: get_hint_if_single_char_arg: fix bug where multi-char letters are not detected properly --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/single_char_pattern.fixed | 6 +++--- tests/ui/single_char_pattern.stderr | 20 +++++++++++++++++++- tests/ui/single_char_push_str.fixed | 2 +- tests/ui/single_char_push_str.stderr | 8 +++++++- 5 files changed, 31 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 68a152270e0..5cc3c25e01d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3204,7 +3204,7 @@ fn get_hint_if_single_char_arg( if let hir::ExprKind::Lit(lit) = &arg.kind; if let ast::LitKind::Str(r, style) = lit.node; let string = r.as_str(); - if string.len() == 1; + if string.chars().count() == 1; then { let snip = snippet_with_applicability(cx, arg.span, &string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 3871c4f2268..817a06199ff 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -18,9 +18,9 @@ fn main() { // // We may not want to suggest changing these anyway // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984 - x.split("ß"); - x.split("ℝ"); - x.split("💣"); + x.split('ß'); + x.split('ℝ'); + x.split('💣'); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.contains('x'); diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index fe7211c53f8..ecaabd9155b 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -6,6 +6,24 @@ LL | x.split("x"); | = note: `-D clippy::single-char-pattern` implied by `-D warnings` +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:21:13 + | +LL | x.split("ß"); + | ^^^ help: try using a `char` instead: `'ß'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:22:13 + | +LL | x.split("ℝ"); + | ^^^ help: try using a `char` instead: `'ℝ'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:23:13 + | +LL | x.split("💣"); + | ^^^^ help: try using a `char` instead: `'💣'` + error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:26:16 | @@ -162,5 +180,5 @@ error: single-character string constant used as pattern LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` -error: aborting due to 27 previous errors +error: aborting due to 30 previous errors diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed index da742fe70e2..3c550bee9a3 100644 --- a/tests/ui/single_char_push_str.fixed +++ b/tests/ui/single_char_push_str.fixed @@ -19,5 +19,5 @@ fn main() { string.push('\u{0052}'); string.push('a'); - get_string!().push_str("ö"); + get_string!().push('ö'); } diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr index 1f535589121..d6e6e635cc5 100644 --- a/tests/ui/single_char_push_str.stderr +++ b/tests/ui/single_char_push_str.stderr @@ -30,5 +30,11 @@ error: calling `push_str()` using a single-character string literal LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` -error: aborting due to 5 previous errors +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_push_str.rs:22:5 + | +LL | get_string!().push_str("ö"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` + +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From d958269fe5afb26ee5026be5bc0cea459593bccf Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 8 Oct 2020 00:03:26 +0200 Subject: Rename single_char_push_str to single_char_add_str --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 6 +-- clippy_lints/src/methods/mod.rs | 16 ++++--- src/lintlist/mod.rs | 12 ++--- tests/ui/single_char_add_str.fixed | 43 ++++++++++++++++++ tests/ui/single_char_add_str.rs | 43 ++++++++++++++++++ tests/ui/single_char_add_str.stderr | 82 ++++++++++++++++++++++++++++++++++ tests/ui/single_char_insert_str.fixed | 26 ----------- tests/ui/single_char_insert_str.rs | 26 ----------- tests/ui/single_char_insert_str.stderr | 46 ------------------- tests/ui/single_char_pattern.fixed | 6 --- tests/ui/single_char_pattern.rs | 6 --- tests/ui/single_char_pattern.stderr | 58 ++++++++++++------------ tests/ui/single_char_push_str.fixed | 23 ---------- tests/ui/single_char_push_str.rs | 23 ---------- tests/ui/single_char_push_str.stderr | 40 ----------------- 16 files changed, 216 insertions(+), 242 deletions(-) create mode 100644 tests/ui/single_char_add_str.fixed create mode 100644 tests/ui/single_char_add_str.rs create mode 100644 tests/ui/single_char_add_str.stderr delete mode 100644 tests/ui/single_char_insert_str.fixed delete mode 100644 tests/ui/single_char_insert_str.rs delete mode 100644 tests/ui/single_char_insert_str.stderr delete mode 100644 tests/ui/single_char_push_str.fixed delete mode 100644 tests/ui/single_char_push_str.rs delete mode 100644 tests/ui/single_char_push_str.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b63dbb7eff..27e861b0d3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1939,8 +1939,8 @@ Released 2018-09-13 [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern -[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 97358e06c63..f2056c72c07 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -713,8 +713,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::RESULT_MAP_OR_INTO_OPTION, &methods::SEARCH_IS_SOME, &methods::SHOULD_IMPLEMENT_TRAIT, + &methods::SINGLE_CHAR_ADD_STR, &methods::SINGLE_CHAR_PATTERN, - &methods::SINGLE_CHAR_PUSH_STR, &methods::SKIP_WHILE_NEXT, &methods::STRING_EXTEND_CHARS, &methods::SUSPICIOUS_MAP, @@ -1438,8 +1438,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(&methods::SINGLE_CHAR_ADD_STR), LintId::of(&methods::SINGLE_CHAR_PATTERN), - LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::SUSPICIOUS_MAP), @@ -1631,7 +1631,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(&methods::SINGLE_CHAR_PUSH_STR), + LintId::of(&methods::SINGLE_CHAR_ADD_STR), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::UNNECESSARY_FOLD), LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5cc3c25e01d..89a2db2b76b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1290,8 +1290,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using `push_str` with a single-character string literal - /// where `push` with a `char` would work fine. + /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal + /// where `push`/`insert` with a `char` would work fine. /// /// **Why is this bad?** It's less clear that we are pushing a single character. /// @@ -1300,16 +1300,18 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let mut string = String::new(); + /// string.insert_str(0, "R"); /// string.push_str("R"); /// ``` /// Could be written as /// ```rust /// let mut string = String::new(); + /// string.insert(0, 'R'); /// string.push('R'); /// ``` - pub SINGLE_CHAR_PUSH_STR, + pub SINGLE_CHAR_ADD_STR, style, - "`push_str()` used with a single-character string literal as parameter" + "`push_str()` or `insert_str()` used with a single-character string literal as parameter" } declare_clippy_lint! { @@ -1390,7 +1392,7 @@ declare_lint_pass!(Methods => [ INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, - SINGLE_CHAR_PUSH_STR, + SINGLE_CHAR_ADD_STR, SEARCH_IS_SOME, FILTER_NEXT, SKIP_WHILE_NEXT, @@ -3248,7 +3250,7 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args let sugg = format!("{}.push({})", base_string_snippet, extension_string); span_lint_and_sugg( cx, - SINGLE_CHAR_PUSH_STR, + SINGLE_CHAR_ADD_STR, expr.span, "calling `push_str()` using a single-character string literal", "consider using `push` with a character literal", @@ -3268,7 +3270,7 @@ fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ar let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); span_lint_and_sugg( cx, - SINGLE_CHAR_PUSH_STR, + SINGLE_CHAR_ADD_STR, expr.span, "calling `insert_str()` using a single-character string literal", "consider using `insert` with a character literal", diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 016bda77ef5..b22bb074238 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2147,16 +2147,16 @@ vec![ module: "non_expressive_names", }, Lint { - name: "single_char_pattern", - group: "perf", - desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", + name: "single_char_add_str", + group: "style", + desc: "`push_str()` or `insert_str()` used with a single-character string literal as parameter", deprecation: None, module: "methods", }, Lint { - name: "single_char_push_str", - group: "style", - desc: "`push_str()` used with a single-character string literal as parameter", + name: "single_char_pattern", + group: "perf", + desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", deprecation: None, module: "methods", }, diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed new file mode 100644 index 00000000000..2feba4b8069 --- /dev/null +++ b/tests/ui/single_char_add_str.fixed @@ -0,0 +1,43 @@ +// run-rustfix +#![warn(clippy::single_char_add_str)] + +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + +fn main() { + // `push_str` tests + + let mut string = String::new(); + string.push('R'); + string.push('\''); + + string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push('\x52'); + string.push('\u{0052}'); + string.push('a'); + + get_string!().push('ö'); + + // `insert_str` tests + + let mut string = String::new(); + string.insert(0, 'R'); + string.insert(1, '\''); + + string.insert(0, 'u'); + string.insert_str(2, "st"); + string.insert_str(0, ""); + string.insert(0, '\x52'); + string.insert(0, '\u{0052}'); + let x: usize = 2; + string.insert(x, 'a'); + const Y: usize = 1; + string.insert(Y, 'a'); + + get_string!().insert(1, '?'); +} diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs new file mode 100644 index 00000000000..681b3d10345 --- /dev/null +++ b/tests/ui/single_char_add_str.rs @@ -0,0 +1,43 @@ +// run-rustfix +#![warn(clippy::single_char_add_str)] + +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + +fn main() { + // `push_str` tests + + let mut string = String::new(); + string.push_str("R"); + string.push_str("'"); + + string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push_str("\x52"); + string.push_str("\u{0052}"); + string.push_str(r##"a"##); + + get_string!().push_str("ö"); + + // `insert_str` tests + + let mut string = String::new(); + string.insert_str(0, "R"); + string.insert_str(1, "'"); + + string.insert(0, 'u'); + string.insert_str(2, "st"); + string.insert_str(0, ""); + string.insert_str(0, "\x52"); + string.insert_str(0, "\u{0052}"); + let x: usize = 2; + string.insert_str(x, r##"a"##); + const Y: usize = 1; + string.insert_str(Y, r##"a"##); + + get_string!().insert_str(1, "?"); +} diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr new file mode 100644 index 00000000000..2b17279a564 --- /dev/null +++ b/tests/ui/single_char_add_str.stderr @@ -0,0 +1,82 @@ +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:14:5 + | +LL | string.push_str("R"); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` + | + = note: `-D clippy::single-char-add-str` implied by `-D warnings` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:15:5 + | +LL | string.push_str("'"); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:20:5 + | +LL | string.push_str("/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:21:5 + | +LL | string.push_str("/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:22:5 + | +LL | string.push_str(r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:24:5 + | +LL | get_string!().push_str("ö"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:29:5 + | +LL | string.insert_str(0, "R"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:30:5 + | +LL | string.insert_str(1, "'"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:35:5 + | +LL | string.insert_str(0, "/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:36:5 + | +LL | string.insert_str(0, "/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:38:5 + | +LL | string.insert_str(x, r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:40:5 + | +LL | string.insert_str(Y, r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:42:5 + | +LL | get_string!().insert_str(1, "?"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` + +error: aborting due to 13 previous errors + diff --git a/tests/ui/single_char_insert_str.fixed b/tests/ui/single_char_insert_str.fixed deleted file mode 100644 index fd43f913330..00000000000 --- a/tests/ui/single_char_insert_str.fixed +++ /dev/null @@ -1,26 +0,0 @@ -// run-rustfix -#![warn(clippy::single_char_push_str)] - -macro_rules! get_string { - () => { - String::from("Hello world!") - }; -} - -fn main() { - let mut string = String::new(); - string.insert(0, 'R'); - string.insert(1, '\''); - - string.insert(0, 'u'); - string.insert_str(2, "st"); - string.insert_str(0, ""); - string.insert(0, '\x52'); - string.insert(0, '\u{0052}'); - let x: usize = 2; - string.insert(x, 'a'); - const Y: usize = 1; - string.insert(Y, 'a'); - - get_string!().insert(1, '?'); -} diff --git a/tests/ui/single_char_insert_str.rs b/tests/ui/single_char_insert_str.rs deleted file mode 100644 index 4278f7ef9fd..00000000000 --- a/tests/ui/single_char_insert_str.rs +++ /dev/null @@ -1,26 +0,0 @@ -// run-rustfix -#![warn(clippy::single_char_push_str)] - -macro_rules! get_string { - () => { - String::from("Hello world!") - }; -} - -fn main() { - let mut string = String::new(); - string.insert_str(0, "R"); - string.insert_str(1, "'"); - - string.insert(0, 'u'); - string.insert_str(2, "st"); - string.insert_str(0, ""); - string.insert_str(0, "\x52"); - string.insert_str(0, "\u{0052}"); - let x: usize = 2; - string.insert_str(x, r##"a"##); - const Y: usize = 1; - string.insert_str(Y, r##"a"##); - - get_string!().insert_str(1, "?"); -} diff --git a/tests/ui/single_char_insert_str.stderr b/tests/ui/single_char_insert_str.stderr deleted file mode 100644 index 3d00c91a2ac..00000000000 --- a/tests/ui/single_char_insert_str.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:12:5 - | -LL | string.insert_str(0, "R"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` - | - = note: `-D clippy::single-char-push-str` implied by `-D warnings` - -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:13:5 - | -LL | string.insert_str(1, "'"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')` - -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:18:5 - | -LL | string.insert_str(0, "/x52"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')` - -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:19:5 - | -LL | string.insert_str(0, "/u{0052}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')` - -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:21:5 - | -LL | string.insert_str(x, r##"a"##); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` - -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:23:5 - | -LL | string.insert_str(Y, r##"a"##); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` - -error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_insert_str.rs:25:5 - | -LL | get_string!().insert_str(1, "?"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` - -error: aborting due to 7 previous errors - diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 817a06199ff..d8b5f19e144 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -12,12 +12,6 @@ fn main() { let y = "x"; x.split(y); - // Not yet testing for multi-byte characters - // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern` - // should have done this but produced an ICE - // - // We may not want to suggest changing these anyway - // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984 x.split('ß'); x.split('ℝ'); x.split('💣'); diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 32afe339cd8..a7bc73e3756 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -12,12 +12,6 @@ fn main() { let y = "x"; x.split(y); - // Not yet testing for multi-byte characters - // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern` - // should have done this but produced an ICE - // - // We may not want to suggest changing these anyway - // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984 x.split("ß"); x.split("ℝ"); x.split("💣"); diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index ecaabd9155b..ee4e7e50efd 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -7,175 +7,175 @@ LL | x.split("x"); = note: `-D clippy::single-char-pattern` implied by `-D warnings` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:21:13 + --> $DIR/single_char_pattern.rs:15:13 | LL | x.split("ß"); | ^^^ help: try using a `char` instead: `'ß'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:22:13 + --> $DIR/single_char_pattern.rs:16:13 | LL | x.split("ℝ"); | ^^^ help: try using a `char` instead: `'ℝ'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:23:13 + --> $DIR/single_char_pattern.rs:17:13 | LL | x.split("💣"); | ^^^^ help: try using a `char` instead: `'💣'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:26:16 + --> $DIR/single_char_pattern.rs:20:16 | LL | x.contains("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:27:19 + --> $DIR/single_char_pattern.rs:21:19 | LL | x.starts_with("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:28:17 + --> $DIR/single_char_pattern.rs:22:17 | LL | x.ends_with("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:29:12 + --> $DIR/single_char_pattern.rs:23:12 | LL | x.find("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:30:13 + --> $DIR/single_char_pattern.rs:24:13 | LL | x.rfind("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:31:14 + --> $DIR/single_char_pattern.rs:25:14 | LL | x.rsplit("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:32:24 + --> $DIR/single_char_pattern.rs:26:24 | LL | x.split_terminator("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:33:25 + --> $DIR/single_char_pattern.rs:27:25 | LL | x.rsplit_terminator("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:34:17 + --> $DIR/single_char_pattern.rs:28:17 | LL | x.splitn(0, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:35:18 + --> $DIR/single_char_pattern.rs:29:18 | LL | x.rsplitn(0, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:36:15 + --> $DIR/single_char_pattern.rs:30:15 | LL | x.matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:37:16 + --> $DIR/single_char_pattern.rs:31:16 | LL | x.rmatches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:38:21 + --> $DIR/single_char_pattern.rs:32:21 | LL | x.match_indices("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:39:22 + --> $DIR/single_char_pattern.rs:33:22 | LL | x.rmatch_indices("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:40:26 + --> $DIR/single_char_pattern.rs:34:26 | LL | x.trim_start_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:41:24 + --> $DIR/single_char_pattern.rs:35:24 | LL | x.trim_end_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:43:13 + --> $DIR/single_char_pattern.rs:37:13 | LL | x.split("/n"); | ^^^^ help: try using a `char` instead: `'/n'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:44:13 + --> $DIR/single_char_pattern.rs:38:13 | LL | x.split("'"); | ^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:45:13 + --> $DIR/single_char_pattern.rs:39:13 | LL | x.split("/'"); | ^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:50:31 + --> $DIR/single_char_pattern.rs:44:31 | LL | x.replace(";", ",").split(","); // issue #2978 | ^^^ help: try using a `char` instead: `','` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:51:19 + --> $DIR/single_char_pattern.rs:45:19 | LL | x.starts_with("/x03"); // issue #2996 | ^^^^^^ help: try using a `char` instead: `'/x03'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:58:13 + --> $DIR/single_char_pattern.rs:52:13 | LL | x.split(r"a"); | ^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:59:13 + --> $DIR/single_char_pattern.rs:53:13 | LL | x.split(r#"a"#); | ^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:60:13 + --> $DIR/single_char_pattern.rs:54:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:61:13 + --> $DIR/single_char_pattern.rs:55:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:62:13 + --> $DIR/single_char_pattern.rs:56:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed deleted file mode 100644 index 3c550bee9a3..00000000000 --- a/tests/ui/single_char_push_str.fixed +++ /dev/null @@ -1,23 +0,0 @@ -// run-rustfix -#![warn(clippy::single_char_push_str)] - -macro_rules! get_string { - () => { - String::from("Hello world!") - }; -} - -fn main() { - let mut string = String::new(); - string.push('R'); - string.push('\''); - - string.push('u'); - string.push_str("st"); - string.push_str(""); - string.push('\x52'); - string.push('\u{0052}'); - string.push('a'); - - get_string!().push('ö'); -} diff --git a/tests/ui/single_char_push_str.rs b/tests/ui/single_char_push_str.rs deleted file mode 100644 index a8203e6503e..00000000000 --- a/tests/ui/single_char_push_str.rs +++ /dev/null @@ -1,23 +0,0 @@ -// run-rustfix -#![warn(clippy::single_char_push_str)] - -macro_rules! get_string { - () => { - String::from("Hello world!") - }; -} - -fn main() { - let mut string = String::new(); - string.push_str("R"); - string.push_str("'"); - - string.push('u'); - string.push_str("st"); - string.push_str(""); - string.push_str("\x52"); - string.push_str("\u{0052}"); - string.push_str(r##"a"##); - - get_string!().push_str("ö"); -} diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr deleted file mode 100644 index d6e6e635cc5..00000000000 --- a/tests/ui/single_char_push_str.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:12:5 - | -LL | string.push_str("R"); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` - | - = note: `-D clippy::single-char-push-str` implied by `-D warnings` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:13:5 - | -LL | string.push_str("'"); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:18:5 - | -LL | string.push_str("/x52"); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:19:5 - | -LL | string.push_str("/u{0052}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:20:5 - | -LL | string.push_str(r##"a"##); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:22:5 - | -LL | get_string!().push_str("ö"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` - -error: aborting due to 6 previous errors - -- cgit 1.4.1-3-g733a5 From f8ac1f99efd996bea2b05c83a915a830d69e1690 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 30 Oct 2020 23:47:22 +0100 Subject: Address suggestions in PR review --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 1 + clippy_lints/src/methods/mod.rs | 2 +- tests/ui/single_char_add_str.fixed | 2 ++ tests/ui/single_char_add_str.rs | 2 ++ tests/ui/single_char_add_str.stderr | 14 +++++++++++++- 6 files changed, 20 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e861b0d3e..be47eeaa073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ Current beta, release 2020-11-19 * [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998) * [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044) * [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831) -* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881) +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881) ### Moves and Deprecations diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f2056c72c07..9d9097002d6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1958,6 +1958,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"); ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion"); ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters"); + ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str"); } // only exists to let the dogfood integration test works. diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 89a2db2b76b..558c90249cc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3266,7 +3266,7 @@ fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ar if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { let base_string_snippet = snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); - let pos_arg = snippet(cx, args[1].span, ".."); + let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability); let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); span_lint_and_sugg( cx, diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed index 2feba4b8069..63a6d37a9cc 100644 --- a/tests/ui/single_char_add_str.fixed +++ b/tests/ui/single_char_add_str.fixed @@ -38,6 +38,8 @@ fn main() { string.insert(x, 'a'); const Y: usize = 1; string.insert(Y, 'a'); + string.insert(Y, '"'); + string.insert(Y, '\''); get_string!().insert(1, '?'); } diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs index 681b3d10345..a799ea7d885 100644 --- a/tests/ui/single_char_add_str.rs +++ b/tests/ui/single_char_add_str.rs @@ -38,6 +38,8 @@ fn main() { string.insert_str(x, r##"a"##); const Y: usize = 1; string.insert_str(Y, r##"a"##); + string.insert_str(Y, r##"""##); + string.insert_str(Y, r##"'"##); get_string!().insert_str(1, "?"); } diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr index 2b17279a564..55d91583ad0 100644 --- a/tests/ui/single_char_add_str.stderr +++ b/tests/ui/single_char_add_str.stderr @@ -72,11 +72,23 @@ error: calling `insert_str()` using a single-character string literal LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:41:5 + | +LL | string.insert_str(Y, r##"""##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` + error: calling `insert_str()` using a single-character string literal --> $DIR/single_char_add_str.rs:42:5 | +LL | string.insert_str(Y, r##"'"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '/'')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:44:5 + | LL | get_string!().insert_str(1, "?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From 22cc77a232a0ec73475ff54b5116adf9defc8667 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 2 Nov 2020 10:32:55 -0600 Subject: Use const rustc sym where possible --- clippy_lints/src/attrs.rs | 22 ++++----- clippy_lints/src/booleans.rs | 5 +- clippy_lints/src/bytecount.rs | 3 +- clippy_lints/src/cognitive_complexity.rs | 6 +-- clippy_lints/src/doc.rs | 10 ++-- clippy_lints/src/explicit_write.rs | 3 +- clippy_lints/src/fallible_impl_from.rs | 8 ++-- clippy_lints/src/format.rs | 13 +++--- clippy_lints/src/functions.rs | 3 +- clippy_lints/src/get_last_with_len.rs | 3 +- clippy_lints/src/if_let_some_result.rs | 3 +- clippy_lints/src/inherent_to_string.rs | 3 +- clippy_lints/src/inline_fn_without_body.rs | 4 +- clippy_lints/src/loops.rs | 22 ++++----- clippy_lints/src/manual_non_exhaustive.rs | 10 ++-- clippy_lints/src/manual_unwrap_or.rs | 5 +- clippy_lints/src/map_clone.rs | 4 +- clippy_lints/src/map_identity.rs | 5 +- clippy_lints/src/map_unit_fn.rs | 5 +- clippy_lints/src/match_on_vec_items.rs | 3 +- clippy_lints/src/matches.rs | 9 ++-- clippy_lints/src/methods/inefficient_to_string.rs | 3 +- clippy_lints/src/methods/mod.rs | 56 +++++++++++------------ clippy_lints/src/methods/option_map_unwrap_or.rs | 4 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 5 +- clippy_lints/src/missing_doc.rs | 7 +-- clippy_lints/src/missing_inline.rs | 3 +- clippy_lints/src/needless_borrow.rs | 3 +- clippy_lints/src/needless_pass_by_value.rs | 10 ++-- clippy_lints/src/new_without_default.rs | 3 +- clippy_lints/src/non_expressive_names.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 3 +- clippy_lints/src/panic_in_result_fn.rs | 4 +- clippy_lints/src/partialeq_ne_impl.rs | 3 +- clippy_lints/src/pass_by_ref_or_value.rs | 6 +-- clippy_lints/src/ptr.rs | 6 +-- clippy_lints/src/ptr_offset_with_cast.rs | 3 +- clippy_lints/src/question_mark.rs | 3 +- clippy_lints/src/ranges.rs | 3 +- clippy_lints/src/redundant_clone.rs | 3 +- clippy_lints/src/repeat_once.rs | 3 +- clippy_lints/src/returns.rs | 3 +- clippy_lints/src/strings.rs | 3 +- clippy_lints/src/swap.rs | 3 +- clippy_lints/src/try_err.rs | 9 ++-- clippy_lints/src/types.rs | 10 ++-- clippy_lints/src/unnecessary_sort_by.rs | 3 +- clippy_lints/src/unwrap.rs | 9 ++-- clippy_lints/src/unwrap_in_result.rs | 14 +++--- clippy_lints/src/useless_conversion.rs | 5 +- clippy_lints/src/utils/mod.rs | 3 +- clippy_lints/src/write.rs | 5 +- 52 files changed, 192 insertions(+), 158 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index f6eadbdef0b..a004abb58b8 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -16,6 +16,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_span::symbol::{Symbol, SymbolStr}; use semver::Version; @@ -286,14 +287,14 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { }, _ => {}, } - if items.is_empty() || !attr.has_name(sym!(deprecated)) { + if items.is_empty() || !attr.has_name(sym::deprecated) { return; } for item in items { if_chain! { if let NestedMetaItem::MetaItem(mi) = &item; if let MetaItemKind::NameValue(lit) = &mi.kind; - if mi.has_name(sym!(since)); + if mi.has_name(sym::since); then { check_semver(cx, item.span(), lit); } @@ -309,7 +310,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { - let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym!(macro_use))); + let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym::macro_use)); for attr in item.attrs { if in_external_macro(cx.sess(), attr.span) { @@ -326,7 +327,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { match item.kind { ItemKind::Use(..) => { if is_word(lint, sym!(unused_imports)) - || is_word(lint, sym!(deprecated)) + || is_word(lint, sym::deprecated) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) || extract_clippy_lint(lint) @@ -411,8 +412,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMet let lint_store = cx.lints(); for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { - if let CheckLintNameResult::Tool(Err((None, _))) = - lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) + if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym::clippy)) { span_lint_and_then( cx, @@ -529,10 +529,10 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut for attr in attrs { if let Some(values) = attr.meta_item_list() { - if values.len() != 1 || !attr.has_name(sym!(inline)) { + if values.len() != 1 || !attr.has_name(sym::inline) { continue; } - if is_word(&values[0], sym!(always)) { + if is_word(&values[0], sym::always) { span_lint( cx, INLINE_ALWAYS, @@ -623,12 +623,12 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { if_chain! { // check cfg_attr - if attr.has_name(sym!(cfg_attr)); + if attr.has_name(sym::cfg_attr); if let Some(items) = attr.meta_item_list(); if items.len() == 2; // check for `rustfmt` if let Some(feature_item) = items[0].meta_item(); - if feature_item.has_name(sym!(rustfmt)); + if feature_item.has_name(sym::rustfmt); // check for `rustfmt_skip` and `rustfmt::skip` if let Some(skip_item) = &items[1].meta_item(); if skip_item.has_name(sym!(rustfmt_skip)) || @@ -690,7 +690,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { } if_chain! { - if attr.has_name(sym!(cfg)); + if attr.has_name(sym::cfg); if let Some(list) = attr.meta_item_list(); let mismatched = find_mismatched_target_os(&list); if !mismatched.is_empty(); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 280a2c7fe67..90bb0bd555f 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -11,6 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for boolean expressions that can be written more @@ -253,8 +254,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { }, ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => { let type_of_receiver = cx.typeck_results().expr_ty(&args[0]); - if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type)) - && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type)) + if !is_type_diagnostic_item(cx, type_of_receiver, sym::option_type) + && !is_type_diagnostic_item(cx, type_of_receiver, sym::result_type) { return None; } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index d7d02ebf985..38a0e27c4cf 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use rustc_span::Symbol; declare_clippy_lint! { @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = filter_args[0].kind { let p = path.ident.name; - if (p == sym!(iter) || p == sym!(iter_mut)) && args.len() == 1 { + if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { &args[0] } else { &filter_args[0] diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 14ef8c319ef..b1bc2ec29e1 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::{sym, BytePos}; use crate::utils::{is_type_diagnostic_item, snippet_opt, span_lint_and_help, LimitStack}; @@ -61,7 +61,7 @@ impl CognitiveComplexity { helper.visit_expr(expr); let CCHelper { cc, returns } = helper; let ret_ty = cx.typeck_results().node_type(expr.hir_id); - let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) { + let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::result_type) { returns } else { #[allow(clippy::integer_division)] @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { hir_id: HirId, ) { let def_id = cx.tcx.hir().local_def_id(hir_id); - if !cx.tcx.has_attr(def_id.to_def_id(), sym!(test)) { + if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) { self.check(cx, kind, decl, body, span); } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 07f604cf714..edecba57e44 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -15,7 +15,7 @@ use rustc_parse::maybe_new_parser_from_source_str; use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span}; -use rustc_span::{FileName, Pos}; +use rustc_span::{sym, FileName, Pos}; use std::io; use std::ops::Range; use url::Url; @@ -237,7 +237,7 @@ fn lint_for_missing_headers<'tcx>( ); } if !headers.errors { - if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { span_lint( cx, MISSING_ERRORS_DOC, @@ -255,7 +255,7 @@ fn lint_for_missing_headers<'tcx>( if let ty::Opaque(_, subs) = ret_ty.kind(); if let Some(gen) = subs.types().next(); if let ty::Generator(_, subs, _) = gen.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type)); + if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::result_type); then { span_lint( cx, @@ -333,7 +333,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span); spans.extend_from_slice(¤t_spans); doc.push_str(&comment); - } else if attr.has_name(sym!(doc)) { + } else if attr.has_name(sym::doc) { // ignore mix of sugared and non-sugared doc // don't trigger the safety or errors check return DocHeaders { @@ -479,7 +479,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, span: Span) { | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) => return false, // We found a main function ... - ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym!(main) => { + ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym::main => { let is_async = matches!(sig.header.asyncness, Async::Yes{..}); let returns_nothing = match &sig.decl.output { FnRetTy::Default(..) => true, diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 0240e80d814..f8038d06e50 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -5,6 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be @@ -33,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { if_chain! { // match call to unwrap if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args, _) = expr.kind; - if unwrap_fun.ident.name == sym!(unwrap); + if unwrap_fun.ident.name == sym::unwrap; // match call to write_fmt if !unwrap_args.is_empty(); if let ExprKind::MethodCall(ref write_fun, _, write_args, _) = diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index a9e05fddbe7..fe817fe94f2 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` @@ -95,8 +95,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) { self.result.push(expr.span); } @@ -113,7 +113,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h for impl_item in impl_items { if_chain! { - if impl_item.ident.name == sym!(from); + if impl_item.ident.name == sym::from; if let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind; then { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 26da058598e..8e41e0e34da 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -10,6 +10,7 @@ use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, MatchSource, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for the use of `format!("string literal with no @@ -91,7 +92,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & if pats.len() == 1; then { let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs(); - if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym::string_type) { return None; } if let ExprKind::Lit(ref lit) = format_args.kind { @@ -186,15 +187,15 @@ fn check_unformatted(expr: &Expr<'_>) -> bool { if exprs.len() == 1; // struct `core::fmt::rt::v1::Argument` if let ExprKind::Struct(_, ref fields, _) = exprs[0].kind; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym!(format)); + if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); // struct `core::fmt::rt::v1::FormatSpec` if let ExprKind::Struct(_, ref fields, _) = format_field.expr.kind; - if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym!(precision)); + if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision); if let ExprKind::Path(ref precision_path) = precision_field.expr.kind; - if last_path_segment(precision_path).ident.name == sym!(Implied); - if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym!(width)); + if last_path_segment(precision_path).ident.name == sym::Implied; + if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width); if let ExprKind::Path(ref width_qpath) = width_field.expr.kind; - if last_path_segment(width_qpath).ident.name == sym!(Implied); + if last_path_segment(width_qpath).ident.name == sym::Implied; then { return true; } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 9c0efef95de..8b58d1f2601 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -16,6 +16,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; @@ -473,7 +474,7 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span if !in_external_macro(cx.sess(), item_span); if let hir::FnRetTy::Return(ref ty) = decl.output; if let hir::TyKind::Path(ref qpath) = ty.kind; - if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym!(result_type)); + if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym::result_type); if let Some(ref args) = last_path_segment(qpath).args; if let [_, hir::GenericArg::Type(ref err_ty)] = args.args; if let hir::TyKind::Tup(t) = err_ty.kind; diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 48ebcf5ebcd..cdd8a42e7cd 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for using `x.get(x.len() - 1)` instead of @@ -55,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for GetLastWithLen { // Argument 0 (the struct we're calling the method on) is a vector if let Some(struct_calling_on) = args.get(0); let struct_ty = cx.typeck_results().expr_ty(struct_calling_on); - if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type)); + if is_type_diagnostic_item(cx, struct_ty, sym::vec_type); // Argument to "get" is a subtraction if let Some(get_index_arg) = args.get(1); diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 28b20cdeac3..e0a1f4c5ca4 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -4,6 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:*** Checks for unnecessary `ok()` in if let. @@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet { if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym!(result_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type); if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; then { diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 0877b44d901..b723d06a688 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -2,6 +2,7 @@ use if_chain::if_chain; use rustc_hir::{ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use crate::utils::{ get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, @@ -107,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { if decl.inputs.len() == 1; // Check if return type is String - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type)); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::string_type); // Filters instances of to_string which are required by a trait if trait_ref_of_method(cx, impl_item.hir_id).is_none(); diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 4b605fdb366..d1c3fdc7146 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// **What it does:** Checks for `#[inline]` on trait methods without bodies @@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { for attr in attrs { - if !attr.has_name(sym!(inline)) { + if !attr.has_name(sym::inline) { continue; } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c3f75f283f4..c7d3f4e9b08 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -619,9 +619,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops { } let lhs_constructor = last_path_segment(qpath); - if method_path.ident.name == sym!(next) + if method_path.ident.name == sym::next && match_trait_method(cx, match_expr, &paths::ITERATOR) - && lhs_constructor.ident.name == sym!(Some) + && lhs_constructor.ident.name == sym::Some && (pat_args.is_empty() || !is_refutable(cx, &pat_args[0]) && !is_used_inside(cx, iter_expr, &arms[0].body) @@ -985,13 +985,13 @@ fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool { _ => false, }; - is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) + is_slice || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) } fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { if let ExprKind::MethodCall(method, _, args, _) = expr.kind; - if method.ident.name == sym!(clone); + if method.ident.name == sym::clone; if args.len() == 1; if let Some(arg) = args.get(0); then { arg } else { expr } @@ -1355,7 +1355,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if let Some(self_expr) = args.get(0); if let Some(pushed_item) = args.get(1); // Check that the method being called is push() on a Vec - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::vec_type); if path.ident.name.as_str() == "push"; then { return Some((self_expr, pushed_item)) @@ -1736,7 +1736,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: /// Checks for `for` loops over `Option`s and `Result`s. fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, ty, sym!(option_type)) { + if is_type_diagnostic_item(cx, ty, sym::option_type) { span_lint_and_help( cx, FOR_LOOPS_OVER_FALLIBLES, @@ -1753,7 +1753,7 @@ fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { snippet(cx, arg.span, "_") ), ); - } else if is_type_diagnostic_item(cx, ty, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::result_type) { span_lint_and_help( cx, FOR_LOOPS_OVER_FALLIBLES, @@ -2186,8 +2186,8 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // a range index op if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind; - if (meth.ident.name == sym!(index) && match_trait_method(self.cx, expr, &paths::INDEX)) - || (meth.ident.name == sym!(index_mut) && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); + if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) + || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(&args[1], &args[0], expr); then { return } } @@ -2333,7 +2333,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { // will allow further borrows afterwards let ty = cx.typeck_results().expr_ty(e); is_iterable_array(ty, cx) || - is_type_diagnostic_item(cx, ty, sym!(vec_type)) || + is_type_diagnostic_item(cx, ty, sym::vec_type) || match_type(cx, ty, &paths::LINKED_LIST) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || is_type_diagnostic_item(cx, ty, sym!(hashset_type)) || @@ -2890,7 +2890,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); then { let ty = cx.typeck_results().node_type(ty.hir_id); - if is_type_diagnostic_item(cx, ty, sym!(vec_type)) || + if is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) || match_type(cx, ty, &paths::BTREEMAP) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 9c623821fdd..a1450b0d5fe 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -5,7 +5,7 @@ use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. @@ -83,9 +83,9 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants } fn is_doc_hidden(attr: &Attribute) -> bool { - attr.has_name(sym!(doc)) + attr.has_name(sym::doc) && match attr.meta_item_list() { - Some(l) => attr::list_contains_name(&l, sym!(hidden)), + Some(l) => attr::list_contains_name(&l, sym::hidden), None => false, } } @@ -102,7 +102,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants "this seems like a manual implementation of the non-exhaustive pattern", |diag| { if_chain! { - if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive))); + if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)); let header_span = cx.sess.source_map().span_until_char(item.span, '{'); if let Some(snippet) = snippet_opt(cx, header_span); then { @@ -154,7 +154,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: "this seems like a manual implementation of the non-exhaustive pattern", |diag| { if_chain! { - if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive))); + if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)); let header_span = find_header_span(cx, item, data); if let Some(snippet) = snippet_opt(cx, header_span); then { diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 22aa37e41fe..9e2c6c7f231 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -8,6 +8,7 @@ use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** @@ -97,9 +98,9 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym!(option_type)) { + if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym::option_type) { Some(Case::Option) - } else if utils::is_type_diagnostic_item(cx, ty, sym!(result_type)) { + } else if utils::is_type_diagnostic_item(cx, ty, sym::result_type) { Some(Case::Result) } else { None diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 6d1c2ffbfbd..034cd99a9be 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if args.len() == 2; if method.ident.as_str() == "map"; let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR); + if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index d4c2e66ff4b..6b782385a38 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -7,6 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function. @@ -65,8 +66,8 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a if args.len() == 2 && method.ident.as_str() == "map"; let caller_ty = cx.typeck_results().expr_ty(&args[0]); if match_trait_method(cx, expr, &paths::ITERATOR) - || is_type_diagnostic_item(cx, caller_ty, sym!(result_type)) - || is_type_diagnostic_item(cx, caller_ty, sym!(option_type)); + || is_type_diagnostic_item(cx, caller_ty, sym::result_type) + || is_type_diagnostic_item(cx, caller_ty, sym::option_type); then { Some(args) } else { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 076ef235b8b..e50d11a4d71 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `option.map(f)` where f is a function @@ -206,9 +207,9 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr let var_arg = &map_args[0]; let (map_type, variant, lint) = - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(option_type)) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::option_type) { ("Option", "Some", OPTION_MAP_UNIT_FN) - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(result_type)) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::result_type) { ("Result", "Ok", RESULT_MAP_UNIT_FN) } else { return; diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 331b6c6c34a..086dae9422f 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -5,6 +5,7 @@ use rustc_hir::{Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`. @@ -90,7 +91,7 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); let ty = ty.peel_refs(); - is_type_diagnostic_item(cx, ty, sym!(vec_type)) + is_type_diagnostic_item(cx, ty, sym::vec_type) } fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 4bdfca1a292..c6dca54e250 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -22,7 +22,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::Bound; @@ -662,7 +662,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp } } else { // not a block, don't lint - return; + return; }; let ty = cx.typeck_results().expr_ty(ex); @@ -840,7 +840,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); - if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) { + if is_type_diagnostic_item(cx, ex_ty, sym::result_type) { for arm in arms { if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind { let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); @@ -1509,6 +1509,7 @@ mod redundant_pattern_match { use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; + use rustc_span::sym; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { @@ -1552,7 +1553,7 @@ mod redundant_pattern_match { if_chain! { if keyword == "while"; if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; - if method_path.ident.name == sym!(next); + if method_path.ident.name == sym::next; if match_trait_method(cx, op, &paths::ITERATOR); then { return; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 5dae7efad97..c83b6f2c329 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -7,6 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; /// Checks for the `INEFFICIENT_TO_STRING` lint pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { @@ -50,7 +51,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { return true; } - if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, ty, sym::string_type) { return true; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3c3093e869c..167b8cc2422 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1677,7 +1677,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, item.span); - if item.ident.name == sym!(new); + if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id); let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); @@ -1767,7 +1767,7 @@ fn lint_or_fun_call<'tcx>( _ => (), } - if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { + if is_type_diagnostic_item(cx, ty, sym::vec_type) { return; } } @@ -1864,11 +1864,11 @@ fn lint_expect_fun_call( hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, hir::ExprKind::MethodCall(method_name, _, call_args, _) => { if call_args.len() == 1 - && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) + && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref)) && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type) } { &call_args[0] @@ -1886,7 +1886,7 @@ fn lint_expect_fun_call( // converted to string. fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { let arg_ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, arg_ty, sym::string_type) { return false; } if let ty::Ref(_, ty, ..) = arg_ty.kind() { @@ -1973,9 +1973,9 @@ fn lint_expect_fun_call( } let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); - let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) { + let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) { "||" - } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) { "|_|" } else { return; @@ -2162,7 +2162,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" - } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { "&" } else { return; @@ -2188,14 +2188,14 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); - if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, obj_ty, sym::string_type) { lint_string_extend(cx, expr, args); } } fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym!(vec_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type); if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])); if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); @@ -2348,7 +2348,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ ); } } - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type)) + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type) || matches!( &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), ty::Array(_, _) @@ -2381,7 +2381,7 @@ fn lint_iter_nth<'tcx>( let mut_str = if is_mut { "_mut" } else { "" }; let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { "slice" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vec_type)) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { "Vec" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { "VecDeque" @@ -2434,7 +2434,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() { needs_ref = get_args_str.parse::().is_ok(); "slice" - } else if is_type_diagnostic_item(cx, expr_ty, sym!(vec_type)) { + } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { needs_ref = get_args_str.parse::().is_ok(); "Vec" } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) { @@ -2520,7 +2520,7 @@ fn derefs_to_slice<'tcx>( match ty.kind() { ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), ty::Array(_, size) => size .try_eval_usize(cx.tcx, cx.param_env) .map_or(false, |size| size < 32), @@ -2530,7 +2530,7 @@ fn derefs_to_slice<'tcx>( } if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { - if path.ident.name == sym!(iter) && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { Some(&args[0]) } else { None @@ -2555,9 +2555,9 @@ fn derefs_to_slice<'tcx>( fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { Some((UNWRAP_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { Some((UNWRAP_USED, "a Result", "Err")) } else { None @@ -2607,7 +2607,7 @@ fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::E fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) { if_chain! { // lint if the caller of `ok()` is a `Result` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym!(result_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type); let result_type = cx.typeck_results().expr_ty(&ok_args[0]); if let Some(error_type) = get_error_type(cx, result_type); if has_debug_impl(error_type, cx); @@ -2637,7 +2637,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map _ => map_closure_ty.fn_sig(cx.tcx), }; let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output()); - is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type)) + is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type) }, _ => false, }; @@ -2663,7 +2663,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } // lint if caller of `.map().flatten()` is an Option - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { let func_snippet = snippet(cx, map_args[1].span, ".."); let hint = format!(".and_then({})", func_snippet); span_lint_and_sugg( @@ -2687,8 +2687,8 @@ fn lint_map_unwrap_or_else<'tcx>( unwrap_args: &'tcx [hir::Expr<'_>], ) -> bool { // lint if the caller of `map()` is an `Option` - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); if is_option || is_result { // Don't make a suggestion that may fail to compile due to mutably borrowing @@ -2741,8 +2741,8 @@ fn lint_map_unwrap_or_else<'tcx>( /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type); // There are two variants of this `map_or` lint: // (1) using `map_or` as an adapter from `Result` to `Option` @@ -3100,7 +3100,7 @@ fn lint_chars_cmp( if arg_char.len() == 1; if let hir::ExprKind::Path(ref qpath) = fun.kind; if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym!(Some); + if segment.ident.name == sym::Some; then { let mut applicability = Applicability::MachineApplicable; let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); @@ -3375,7 +3375,7 @@ fn lint_option_as_ref_deref<'tcx>( let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); - if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) { + if !is_type_diagnostic_item(cx, option_ty, sym::option_type) { return; } @@ -3482,7 +3482,7 @@ fn lint_map_collect( if match_trait_method(cx, map_expr, &paths::ITERATOR); // return of collect `Result<(),_>` let collect_ret_ty = cx.typeck_results().expr_ty(expr); - if is_type_diagnostic_item(cx, collect_ret_ty, sym!(result_type)); + if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); if let ty::Adt(_, substs) = collect_ret_ty.kind(); if let Some(result_t) = substs.types().next(); if result_t.is_unit(); @@ -3509,7 +3509,7 @@ fn lint_map_collect( /// Given a `Result` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { match ty.kind() { - ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1), + ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1), _ => None, } } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index d30b85d6a78..7763fd5f113 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -7,7 +7,7 @@ use rustc_hir::{self, HirId, Path}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::{sym, Symbol}; use super::MAP_UNWRAP_OR; @@ -20,7 +20,7 @@ pub(super) fn lint<'tcx>( map_span: Span, ) { // lint if the caller of `map()` is an `Option` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { if !is_copy(cx, cx.typeck_results().expr_ty(&unwrap_args[1])) { // Do not lint if the `map` argument uses identifiers in the `map` // argument that are also used in the `unwrap_or` argument diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 08b3eab9b7c..cde89983a26 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -3,6 +3,7 @@ use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::UNNECESSARY_LAZY_EVALUATIONS; @@ -14,8 +15,8 @@ pub(super) fn lint<'tcx>( args: &'tcx [hir::Expr<'_>], simplify_using: &str, ) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::result_type); if is_option || is_result { if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 813f9c43948..009e3d8937e 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -14,6 +14,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Warns if there is missing doc for any documentable item @@ -105,10 +106,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.has_name(sym!(doc)) + attr.has_name(sym::doc) && match attr.meta_item_list() { None => false, - Some(l) => attr::list_contains_name(&l[..], sym!(hidden)), + Some(l) => attr::list_contains_name(&l[..], sym::hidden), } }); self.doc_hidden_stack.push(doc_hidden); @@ -128,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { hir::ItemKind::Enum(..) => "an enum", hir::ItemKind::Fn(..) => { // ignore main() - if it.ident.name == sym!(main) { + if it.ident.name == sym::main { let def_id = it.hir_id.owner; let def_key = cx.tcx.hir().def_key(def_id); if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) { diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 3eae45b2819..53abe6086ea 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** it lints if an exported function, method, trait method with default impl, @@ -57,7 +58,7 @@ declare_clippy_lint! { } fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { - let has_inline = attrs.iter().any(|a| a.has_name(sym!(inline))); + let has_inline = attrs.iter().any(|a| a.has_name(sym::inline)); if !has_inline { span_lint( cx, diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index b71d5496a37..405c21d608d 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for address of operations (`&`) that are going to @@ -112,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if item.attrs.iter().any(|a| a.has_name(sym!(automatically_derived))) { + if item.attrs.iter().any(|a| a.has_name(sym::automatically_derived)) { debug_assert!(self.derived_item.is_none()); self.derived_item = Some(item.hir_id); } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 7e933c674dd..5c92590f41e 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::can_type_implement_copy; @@ -204,12 +204,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let deref_span = spans_need_deref.get(&canonical_id); if_chain! { - if is_type_diagnostic_item(cx, ty, sym!(vec_type)); + if is_type_diagnostic_item(cx, ty, sym::vec_type); if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]); if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind; if let Some(elem_ty) = path.segments.iter() - .find(|seg| seg.ident.name == sym!(Vec)) + .find(|seg| seg.ident.name == sym::Vec) .and_then(|ps| ps.args.as_ref()) .map(|params| params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), @@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } } - if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, ty, sym::string_type) { if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { diag.span_suggestion( @@ -302,7 +302,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { /// Functions marked with these attributes must have the exact signature. fn requires_exact_signature(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { - [sym!(proc_macro), sym!(proc_macro_attribute), sym!(proc_macro_derive)] + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] .iter() .any(|&allow| attr.has_name(allow)) }) diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 28d1322e946..68fdd0eb269 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for types with a `fn new() -> Self` method and no @@ -91,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // impl of `Default` return; } - if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) { + if sig.decl.inputs.is_empty() && name == sym::new && cx.access_levels.is_reachable(id) { let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); let self_ty = cx.tcx.type_of(self_def_id); if_chain! { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 603440c0f83..485888fa944 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -7,6 +7,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_span::symbol::{Ident, Symbol}; use std::cmp::Ordering; @@ -384,7 +385,7 @@ impl EarlyLintPass for NonExpressiveNames { } fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { - if !attrs.iter().any(|attr| attr.has_name(sym!(test))) { + if !attrs.iter().any(|attr| attr.has_name(sym::test)) { let mut visitor = SimilarNamesLocalVisitor { names: Vec::new(), cx, diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index eb7624b25a3..681dbce9769 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -8,6 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** @@ -66,7 +67,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { path.ident.name.to_ident_string() == "ok" - && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type)) + && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type) } else { false } diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 4077aba6ef1..72dfccc1089 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result. @@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { hir_id: hir::HirId, ) { if !matches!(fn_kind, FnKind::Closure(_)) - && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) + && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { lint_impl_body(cx, span, body); } diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 19d355e64ca..ceecc8dbc06 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -3,6 +3,7 @@ use if_chain::if_chain; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`. @@ -39,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { if trait_ref.path.res.def_id() == eq_trait; then { for impl_item in impl_items { - if impl_item.ident.name == sym!(ne) { + if impl_item.ident.name == sym::ne { span_lint_hir( cx, PARTIALEQ_NE_IMPL, diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 28816c3076d..030650c3256 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -10,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutabil use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_target::spec::Target; @@ -230,8 +230,8 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } for a in attrs { if let Some(meta_items) = a.meta_item_list() { - if a.has_name(sym!(proc_macro_derive)) - || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always))) + if a.has_name(sym::proc_macro_derive) + || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)) { return; } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 6b1c848a946..dcb643a28ae 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::MultiSpan; +use rustc_span::{sym, MultiSpan}; use std::borrow::Cow; declare_clippy_lint! { @@ -181,7 +181,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { + if is_type_diagnostic_item(cx, ty, sym::vec_type) { let mut ty_snippet = None; if_chain! { if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind; @@ -225,7 +225,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::string_type) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { span_lint_and_then( cx, diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 0a2d1b5fbe6..e0996804a59 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -3,6 +3,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use std::fmt; declare_clippy_lint! { @@ -92,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>( ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { if let ExprKind::MethodCall(ref path_segment, _, ref args, _) = expr.kind { if is_expr_ty_raw_ptr(cx, &args[0]) { - if path_segment.ident.name == sym!(offset) { + if path_segment.ident.name == sym::offset { return Some((&args[0], &args[1], Method::Offset)); } if path_segment.ident.name == sym!(wrapping_offset) { diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index dbc676ae224..d9b280b7a85 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,6 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use crate::utils::sugg::Sugg; use crate::utils::{ @@ -143,7 +144,7 @@ impl QuestionMark { fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expression); - is_type_diagnostic_item(cx, expr_ty, sym!(option_type)) + is_type_diagnostic_item(cx, expr_ty, sym::option_type) } fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index de54711d851..79e9a56af9a 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -7,6 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{Span, Spanned}; +use rustc_span::sym; use rustc_span::symbol::Ident; use std::cmp::Ordering; @@ -304,7 +305,7 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: if_chain! { // `.iter()` call if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = *iter; - if iter_path.ident.name == sym!(iter); + if iter_path.ident.name == sym::iter; // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg); if is_integer_const(cx, start, 0); diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 344ed02361d..b4a9804fb25 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -17,6 +17,7 @@ use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; +use rustc_span::sym; use std::convert::TryFrom; use std::ops::ControlFlow; @@ -115,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) - && is_type_diagnostic_item(cx, arg_ty, sym!(string_type))); + && is_type_diagnostic_item(cx, arg_ty, sym::string_type)); let from_deref = !from_borrow && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF) diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index ae601353009..d34e744eb94 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -5,6 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types. @@ -65,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)), Applicability::MachineApplicable, ); - } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::string_type) { span_lint_and_sugg( cx, REPEAT_ONCE, diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index a6e4252a0c8..7f4913a02cb 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -9,6 +9,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then}; @@ -141,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } fn attr_is_cfg(attr: &Attribute) -> bool { - attr.meta_item_list().is_some() && attr.has_name(sym!(cfg)) + attr.meta_item_list().is_some() && attr.has_name(sym::cfg) } fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 3783bd78de2..0dd2da949c4 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -4,6 +4,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; +use rustc_span::sym; use if_chain::if_chain; @@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type)) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::string_type) } fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 54b38d9f4ce..386987eb181 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -8,6 +8,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for manual swapping. @@ -197,7 +198,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr< if matches!(ty.kind(), ty::Slice(_)) || matches!(ty.kind(), ty::Array(_, _)) - || is_type_diagnostic_item(cx, ty, sym!(vec_type)) + || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { return Slice::Swappable(lhs1, idx1, idx2); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 3e747ec4ad9..6f6b6999bf0 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usages of `Err(x)?`. @@ -133,7 +134,7 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { if let ty::Adt(_, subst) = ty.kind(); - if is_type_diagnostic_item(cx, ty, sym!(result_type)); + if is_type_diagnostic_item(cx, ty, sym::result_type); let err_ty = subst.type_at(1); then { Some(err_ty) @@ -151,7 +152,7 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option< let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym!(result_type), ready_def.did); + if cx.tcx.is_diagnostic_item(sym::result_type, ready_def.did); let err_ty = ready_subst.type_at(1); then { @@ -170,11 +171,11 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did); + if cx.tcx.is_diagnostic_item(sym::option_type, ready_def.did); let some_ty = ready_subst.type_at(0); if let ty::Adt(some_def, some_subst) = some_ty.kind(); - if cx.tcx.is_diagnostic_item(sym!(result_type), some_def.did); + if cx.tcx.is_diagnostic_item(sym::result_type, some_def.did); let err_ty = some_subst.type_at(1); then { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 45f3bc3ea85..c7d82da3b8b 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -522,7 +522,7 @@ impl Types { ); return; // don't recurse into the type } - } else if cx.tcx.is_diagnostic_item(sym!(vec_type), def_id) { + } else if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) { if_chain! { // Get the _ part of Vec<_> if let Some(ref last) = last_path_segment(qpath).args; @@ -559,7 +559,7 @@ impl Types { return; // don't recurse into the type } } - } else if cx.tcx.is_diagnostic_item(sym!(option_type), def_id) { + } else if cx.tcx.is_diagnostic_item(sym::option_type, def_id) { if match_type_parameter(cx, qpath, &paths::OPTION).is_some() { span_lint( cx, @@ -1610,7 +1610,7 @@ fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if names.is_empty() { return false; } - if names[0] == sym!(libc) || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) { + if names[0] == sym::libc || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) { return true; } } @@ -2777,7 +2777,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't } if match_path(ty_path, &paths::HASHMAP) { - if method.ident.name == sym!(new) { + if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashMap::default()".to_string()); } else if method.ident.name == sym!(with_capacity) { @@ -2790,7 +2790,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't ); } } else if match_path(ty_path, &paths::HASHSET) { - if method.ident.name == sym!(new) { + if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashSet::default()".to_string()); } else if method.ident.name == sym!(with_capacity) { diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 1307237dbc7..0bccfc15678 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -6,6 +6,7 @@ use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegme use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, subst::GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use rustc_span::symbol::Ident; declare_clippy_lint! { @@ -175,7 +176,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type)); + if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index ea4b8172c9c..f4a77e54dd1 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -11,6 +11,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail. @@ -92,11 +93,11 @@ fn collect_unwrap_info<'tcx>( invert: bool, ) -> Vec> { fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym!(option_type)) && ["is_some", "is_none"].contains(&method_name) + is_type_diagnostic_item(cx, ty, sym::option_type) && ["is_some", "is_none"].contains(&method_name) } fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym!(result_type)) && ["is_ok", "is_err"].contains(&method_name) + is_type_diagnostic_item(cx, ty, sym::result_type) && ["is_ok", "is_err"].contains(&method_name) } if let ExprKind::Binary(op, left, right) = &expr.kind { @@ -168,8 +169,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { if_chain! { if let ExprKind::MethodCall(ref method_name, _, ref args, _) = expr.kind; if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].kind; - if [sym!(unwrap), sym!(unwrap_err)].contains(&method_name.ident.name); - let call_to_unwrap = method_name.ident.name == sym!(unwrap); + if [sym::unwrap, sym!(unwrap_err)].contains(&method_name.ident.name); + let call_to_unwrap = method_name.ident.name == sym::unwrap; if let Some(unwrappable) = self.unwrappables.iter() .find(|u| u.ident.res == path.res); // Span contexts should not differ with the conditional branch diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 0f8797243ec..fde31029330 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for functions of type Result that contain `expect()` or `unwrap()` @@ -57,8 +57,8 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { // first check if it's a method or function if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type)); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::result_type) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::option_type); then { lint_impl_body(cx, impl_item.span, impl_item); } @@ -82,8 +82,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) { self.result.push(expr.span); } @@ -92,8 +92,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) { self.result.push(expr.span); } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 4e4a206a583..c6194b0c6de 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -9,6 +9,7 @@ use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls @@ -106,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, a, sym!(result_type)); + if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if TyS::same_type(a_type, b); @@ -136,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { then { if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); - if is_type_diagnostic_item(cx, a, sym!(result_type)); + if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if TyS::same_type(a_type, b); diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 0a8a4a5f9ae..85e7f055e79 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -52,6 +52,7 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; +use rustc_span::sym as rustc_sym; use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; @@ -974,7 +975,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d /// implementations have. pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| attr.has_name(sym!(automatically_derived))) + attrs.iter().any(|attr| attr.has_name(rustc_sym::automatically_derived)) } /// Remove blocks around an expression. diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index d9d60fffcd7..ff414f748ef 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -10,8 +10,7 @@ use rustc_lexer::unescape::{self, EscapeError}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_parse::parser; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, Span}; +use rustc_span::{sym, BytePos, Span, Symbol}; declare_clippy_lint! { /// **What it does:** This lint warns when you use `println!("")` to @@ -224,7 +223,7 @@ impl EarlyLintPass for Write { .expect("path has at least one segment") .ident .name; - if trait_name == sym!(Debug) { + if trait_name == sym::Debug { self.in_debug_impl = true; } } -- cgit 1.4.1-3-g733a5 From a6611de75a9c6cf8b0ccfa371491a646a743667f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 2 Nov 2020 12:55:05 -0600 Subject: Include bindings as machine applicable --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index aec1b7e2e46..fe54a238aa4 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -35,7 +35,8 @@ pub(super) fn lint<'tcx>( let applicability = if body .params .iter() - .all(|param| matches!(param.pat.kind, hir::PatKind::Wild)) + // bindings are checked to be unused above + .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) { Applicability::MachineApplicable } else { -- cgit 1.4.1-3-g733a5 From 315bab0ea186d5324fba28ccd5db82ecc7996cc4 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 10 Sep 2020 20:14:23 +0200 Subject: Add `from_iter_instead_of_collect` lint implementation --- clippy_lints/src/methods/mod.rs | 59 +++++++++++++++++++++++++++++++++++++++++ clippy_lints/src/utils/paths.rs | 1 + 2 files changed, 60 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3c3093e869c..93b5d4e7efc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1369,6 +1369,38 @@ declare_clippy_lint! { "using `.map(_).collect::()`, which can be replaced with `try_for_each`" } +declare_clippy_lint! { + /// **What it does:** Checks for `from_iter()` function calls that implements `FromIterator` + /// trait. + /// + /// **Why is this bad?** Makes code less readable especially in method chaining. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// use std::iter::FromIterator; + /// + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v = Vec::from_iter(five_fives); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + /// Use instead: + /// ```rust + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v: Vec = five_fives.collect(); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + pub FROM_ITER_INSTEAD_OF_COLLECT, + style, + "use `.collect()` instead of `::from_iter()`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1419,6 +1451,7 @@ declare_lint_pass!(Methods => [ OPTION_AS_REF_DEREF, UNNECESSARY_LAZY_EVALUATIONS, MAP_COLLECT_RESULT_UNIT, + FROM_ITER_INSTEAD_OF_COLLECT, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1505,6 +1538,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } match expr.kind { + hir::ExprKind::Call(ref func, ref args) => { + if let hir::ExprKind::Path(path) = &func.kind { + let path_segment = last_path_segment(path); + if path_segment.ident.name.as_str() == "from_iter" { + lint_from_iter(cx, expr, args); + } + } + }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); @@ -3831,6 +3872,24 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); } +fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let ty = cx.typeck_results().expr_ty(expr); + let id = get_trait_def_id(cx, &paths::FROM_ITERATOR_TRAIT).unwrap(); + + if implements_trait(cx, ty, id, &[]) { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_help( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "use `.collect()` instead of `::from_iter()`", + None, + &format!("consider using `{}.collect()`", iter_expr), + ); + } +} + fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 736a531eda6..3aade8ca8a2 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -44,6 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"]; pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; +pub const FROM_ITERATOR_TRAIT: [&str; 3] = ["std", "iter", "FromIterator"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; -- cgit 1.4.1-3-g733a5 From 8a5d78b71a71317314d7dccef7c73b523f0a44c2 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Fri, 11 Sep 2020 13:29:52 +0200 Subject: Fix `from_iter_instead_of_collect` lint crashing on exprs without path segment --- clippy_lints/src/methods/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 93b5d4e7efc..c0c39dae865 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1540,8 +1540,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(ref func, ref args) => { if let hir::ExprKind::Path(path) = &func.kind { - let path_segment = last_path_segment(path); - if path_segment.ident.name.as_str() == "from_iter" { + if match_qpath(path, &["from_iter"]) { lint_from_iter(cx, expr, args); } } -- cgit 1.4.1-3-g733a5 From 8906040445a6700be2aaf40ec09937b84dea5d6a Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:04:05 +0200 Subject: Improvements from PR feedback --- clippy_lints/src/methods/mod.rs | 14 ++++++++------ clippy_lints/src/utils/paths.rs | 2 +- tests/ui/from_iter_instead_of_collect.rs | 10 +++------- tests/ui/from_iter_instead_of_collect.stderr | 15 ++++++--------- tests/ui/from_iter_instead_of_collect.stdout | 0 5 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 tests/ui/from_iter_instead_of_collect.stdout (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c0c39dae865..70be8909c43 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1370,10 +1370,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `from_iter()` function calls that implements `FromIterator` + /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator` /// trait. /// - /// **Why is this bad?** Makes code less readable especially in method chaining. + /// **Why is this bad?** It is recommended style to use collect. See + /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) /// /// **Known problems:** None. /// @@ -3873,18 +3874,19 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let ty = cx.typeck_results().expr_ty(expr); - let id = get_trait_def_id(cx, &paths::FROM_ITERATOR_TRAIT).unwrap(); + let id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); if implements_trait(cx, ty, id, &[]) { // `expr` implements `FromIterator` trait let iter_expr = snippet(cx, args[0].span, ".."); - span_lint_and_help( + span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, "use `.collect()` instead of `::from_iter()`", - None, - &format!("consider using `{}.collect()`", iter_expr), + "consider using", + format!("`{}.collect()`", iter_expr), + Applicability::MaybeIncorrect ); } } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 3aade8ca8a2..8afbd8930b6 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -44,7 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"]; pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; -pub const FROM_ITERATOR_TRAIT: [&str; 3] = ["std", "iter", "FromIterator"]; +pub const FROM_ITERATOR: [&str; 3] = ["std", "iter", "FromIterator"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 7a1bc64f4bd..9071be33c64 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -4,12 +4,8 @@ use std::collections::HashMap; use std::iter::FromIterator; fn main() { - { - let iter_expr = std::iter::repeat(5).take(5); + let iter_expr = std::iter::repeat(5).take(5); - Vec::from_iter(iter_expr); - HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - //let v: Vec = iter_expr.collect(); - let a: Vec = Vec::new(); - } + Vec::from_iter(iter_expr); + HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index cfb92dfbbfd..1bc787aa795 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,19 +1,16 @@ error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:10:9 + --> $DIR/from_iter_instead_of_collect.rs:9:5 | -LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``iter_expr.collect()`` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` - = help: consider using `iter_expr.collect()` error: use `.collect()` instead of `::from_iter()` - --> $DIR/from_iter_instead_of_collect.rs:11:9 + --> $DIR/from_iter_instead_of_collect.rs:10:5 | -LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using `vec![5, 5, 5, 5].iter().enumerate().collect()` +LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``vec![5, 5, 5, 5].iter().enumerate().collect()`` error: aborting due to 2 previous errors diff --git a/tests/ui/from_iter_instead_of_collect.stdout b/tests/ui/from_iter_instead_of_collect.stdout deleted file mode 100644 index e69de29bb2d..00000000000 -- cgit 1.4.1-3-g733a5 From 854f2cef06f60b37a3176b17b27c1104692f6255 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:36:49 +0200 Subject: Run `cargo dev fmt` --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 70be8909c43..013ed67b8e5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3886,7 +3886,7 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< "use `.collect()` instead of `::from_iter()`", "consider using", format!("`{}.collect()`", iter_expr), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } -- cgit 1.4.1-3-g733a5 From abdb7aeb55461f0355829be49a09ed86af066ae8 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 18:44:12 +0200 Subject: Remove backticks --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/from_iter_instead_of_collect.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 013ed67b8e5..2119cb28fc3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3885,7 +3885,7 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< expr.span, "use `.collect()` instead of `::from_iter()`", "consider using", - format!("`{}.collect()`", iter_expr), + format!("{}.collect()", iter_expr), Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 3263005d7ec..7f248beadbe 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -2,7 +2,7 @@ error: use `.collect()` instead of `::from_iter()` --> $DIR/from_iter_instead_of_collect.rs:8:5 | LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``iter_expr.collect()`` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `iter_expr.collect()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` @@ -10,7 +10,7 @@ error: use `.collect()` instead of `::from_iter()` --> $DIR/from_iter_instead_of_collect.rs:10:5 | LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: ``vec![5, 5, 5, 5].iter().enumerate().collect()`` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `vec![5, 5, 5, 5].iter().enumerate().collect()` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From f359fb872b405fca196f40eadd341d1d06f1fb8b Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Thu, 1 Oct 2020 19:04:19 +0200 Subject: Improve error message --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/from_iter_instead_of_collect.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2119cb28fc3..fde43f0055d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3883,8 +3883,8 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, + "usage of `FromIterator::from_iter`", "use `.collect()` instead of `::from_iter()`", - "consider using", format!("{}.collect()", iter_expr), Applicability::MaybeIncorrect, ); diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 7f248beadbe..46bdc2f4e19 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,16 +1,16 @@ -error: use `.collect()` instead of `::from_iter()` +error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:8:5 | LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `iter_expr.collect()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` -error: use `.collect()` instead of `::from_iter()` +error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:10:5 | LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `vec![5, 5, 5, 5].iter().enumerate().collect()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 52d1ea3c9ad8ea97350ba7a0ca0a8e172cfcae78 Mon Sep 17 00:00:00 2001 From: Piti the little Light Date: Mon, 12 Oct 2020 17:27:50 +0200 Subject: Fix: Don't show lint for types that doesn't implement Iterator --- clippy_lints/src/methods/mod.rs | 7 +++++-- tests/ui/from_iter_instead_of_collect.rs | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fde43f0055d..521b151f5e1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3874,9 +3874,12 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let ty = cx.typeck_results().expr_ty(expr); - let id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); + let arg_ty = cx.typeck_results().expr_ty(&args[0]); - if implements_trait(cx, ty, id, &[]) { + let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); + let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { // `expr` implements `FromIterator` trait let iter_expr = snippet(cx, args[0].span, ".."); span_lint_and_sugg( diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 25b87a0a903..045eb3133d3 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -8,4 +8,6 @@ fn main() { Vec::from_iter(iter_expr); HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + + Vec::from_iter(vec![42u32]); } -- cgit 1.4.1-3-g733a5 From 5253595b3bb6a3cc6502bb2327590e582d1d27e9 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Fri, 6 Nov 2020 19:34:34 +0100 Subject: FROM_ITER_INSTEAD_OF_COLLECT: avoid unwrapping unconditionally Fixes #6302 --- clippy_lints/src/methods/mod.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7186656f4e1..a3fa3bdd36a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3901,21 +3901,24 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); - let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); - let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + if_chain! { + if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); + if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { - // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); - span_lint_and_sugg( - cx, - FROM_ITER_INSTEAD_OF_COLLECT, - expr.span, - "usage of `FromIterator::from_iter`", - "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), - Applicability::MaybeIncorrect, - ); + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + then { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + format!("{}.collect()", iter_expr), + Applicability::MaybeIncorrect, + ); + } } } -- cgit 1.4.1-3-g733a5 From b0994064b03f1f9f8bdb8f594bdaec9dbaa0788a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 29 Oct 2020 16:21:01 -0500 Subject: Make KNOW_TYPES static --- clippy_lints/src/methods/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a3fa3bdd36a..5309253531b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1803,6 +1803,14 @@ fn lint_or_fun_call<'tcx>( or_has_args: bool, span: Span, ) { + // (path, fn_has_argument, methods, suffix) + static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&paths::RESULT, true, &["or", "unwrap_or"], "else"), + ]; + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); @@ -1818,16 +1826,8 @@ fn lint_or_fun_call<'tcx>( } } - // (path, fn_has_argument, methods, suffix) - let know_types: &[(&[_], _, &[_], _)] = &[ - (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else"), - ]; - if_chain! { - if know_types.iter().any(|k| k.2.contains(&name)); + if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); if is_lazyness_candidate(cx, arg); if !contains_return(&arg); @@ -1835,7 +1835,7 @@ fn lint_or_fun_call<'tcx>( let self_ty = cx.typeck_results().expr_ty(self_expr); if let Some(&(_, fn_has_arguments, poss, suffix)) = - know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)); + KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); if poss.contains(&name); -- cgit 1.4.1-3-g733a5 From 9cab08465b5d5b4bb4f5ff406b2e18ca550f7d93 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 29 Oct 2020 15:30:20 -0500 Subject: Fix or_fun_call for index operator --- clippy_lints/src/methods/mod.rs | 45 ++++++++++++++------------------- clippy_lints/src/utils/eager_or_lazy.rs | 7 ++++- tests/ui/or_fun_call.fixed | 9 +++++++ tests/ui/or_fun_call.rs | 9 +++++++ tests/ui/or_fun_call.stderr | 18 ++++++++++--- 5 files changed, 58 insertions(+), 30 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5309253531b..b6fb3d06934 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1797,11 +1797,11 @@ fn lint_or_fun_call<'tcx>( cx: &LateContext<'tcx>, name: &str, method_span: Span, - fun_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - or_has_args: bool, span: Span, + // None if lambda is required + fun_span: Option, ) { // (path, fn_has_argument, methods, suffix) static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ @@ -1840,10 +1840,18 @@ fn lint_or_fun_call<'tcx>( if poss.contains(&name); then { - let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."), + let sugg: Cow<'_, str> = { + let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { + (false, Some(fun_span)) => (fun_span, false), + _ => (arg.span, true), + }; + let snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + if use_lambda { + let l_arg = if fn_has_arguments { "_" } else { "" }; + format!("|{}| {}", l_arg, snippet).into() + } else { + snippet + } }; let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( @@ -1864,28 +1872,13 @@ fn lint_or_fun_call<'tcx>( hir::ExprKind::Call(ref fun, ref or_args) => { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { - check_general_case( - cx, - name, - method_span, - fun.span, - &args[0], - &args[1], - or_has_args, - expr.span, - ); + let fun_span = if or_has_args { None } else { Some(fun.span) }; + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); } }, - hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case( - cx, - name, - method_span, - span, - &args[0], - &args[1], - !or_args.is_empty(), - expr.span, - ), + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + }, _ => {}, } } diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs index 4ceea13df37..8fe5ddee1ca 100644 --- a/clippy_lints/src/utils/eager_or_lazy.rs +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -9,7 +9,7 @@ //! - or-fun-call //! - option-if-let-else -use crate::utils::is_ctor_or_promotable_const_function; +use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -96,6 +96,11 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex let call_found = match &expr.kind { // ignore enum and struct constructors ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), + ExprKind::Index(obj, _) => { + let ty = self.cx.typeck_results().expr_ty(obj); + is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type)) + || match_type(self.cx, ty, &paths::BTREEMAP) + }, ExprKind::MethodCall(..) => true, _ => false, }; diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 2045ffdb5f0..20e5016bc17 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -70,6 +70,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 522f31b72d0..e7192deeebb 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -70,6 +70,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index bc5978b538f..d0c4df0e008 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -78,17 +78,29 @@ error: use of `unwrap_or` followed by a function call LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:76:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:78:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:102:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:97:10 + --> $DIR/or_fun_call.rs:106:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From a1cf2d334d685fa11fdc96fc98f35292254e5651 Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Mon, 5 Oct 2020 21:23:36 -0700 Subject: Added a lint as suggested in 6010 which recommends using `contains()` instead of `find()` follows by `is_some()` on strings Update clippy_lints/src/find_is_some_on_strs.rs Co-authored-by: Takayuki Nakata Update clippy_lints/src/methods/mod.rs Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 38 +++++++++++++++++++++++++++++++++++--- src/lintlist/mod.rs | 2 +- tests/ui/methods.rs | 23 +++++++++++++++++++++-- tests/ui/methods.stderr | 2 -- 4 files changed, 57 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b6fb3d06934..bd04a95e4a1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -515,11 +515,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for an iterator search (such as `find()`, + /// **What it does:** Checks for an iterator or string search (such as `find()`, /// `position()`, or `rposition()`) followed by a call to `is_some()`. /// /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.any(_)`. + /// `_.any(_)` or `_.contains(_)`. /// /// **Known problems:** None. /// @@ -535,7 +535,7 @@ declare_clippy_lint! { /// ``` pub SEARCH_IS_SOME, complexity, - "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`" + "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`" } declare_clippy_lint! { @@ -3041,6 +3041,7 @@ fn lint_flat_map_identity<'tcx>( } /// lint searching an Iterator followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` fn lint_search_is_some<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -3094,6 +3095,37 @@ fn lint_search_is_some<'tcx>( span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); } } + // lint if `find()` is called by `String` or `&str` + else if search_method == "find" { + let is_string_or_str_slice = |e| { + let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); + if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + true + } else { + *self_ty.kind() == ty::Str + } + }; + if_chain! { + if is_string_or_str_slice(&search_args[0]); + if is_string_or_str_slice(&search_args[1]); + then { + let msg = "called `is_some()` after calling `find()` \ + on a string. This is more succinctly expressed by calling \ + `contains()`.".to_string(); + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "try this", + format!("contains({})", find_arg), + applicability, + ); + } + } + } } /// Used for `lint_binary_expr_with_method_call`. diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 4f1b56ed9be..69acd3d9b8b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2121,7 +2121,7 @@ vec![ Lint { name: "search_is_some", group: "complexity", - desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + desc: "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`", deprecation: None, module: "methods", }, diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index d93e5b114ec..92ec00a11d2 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -168,8 +168,27 @@ fn search_is_some() { x < 0 } ).is_some(); - - // Check that we don't lint if the caller is not an `Iterator`. + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // Check caller `find()` is a &`static str case + let _ = "hello world".find("world").is_some(); + let _ = "hello world".find(&s2).is_some(); + let _ = "hello world".find(&s2[2..]).is_some(); + // Check caller of `find()` is a String case + let _ = s1.find("world").is_some(); + let _ = s1.find(&s2).is_some(); + let _ = s1.find(&s2[2..]).is_some(); + // Check caller of `find()` is a slice of String case + let _ = s1[2..].find("world").is_some(); + let _ = s1[2..].find(&s2).is_some(); + let _ = s1[2..].find(&s2[2..]).is_some(); + + // Check that we don't lint if `find()` is called with + // Pattern that is not a string + let _ = s1.find(|c: char| c == 'o' || c == 'l').is_some(); + + // Check that we don't lint if the caller is not an `Iterator` or string let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.find().is_some(); let _ = foo.position().is_some(); diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 8a281c2dbd2..b2b551bd5f8 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -88,5 +88,3 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: aborting due to 11 previous errors - -- cgit 1.4.1-3-g733a5 From e9612f3eca5566b601dda60c999be69e50f89cac Mon Sep 17 00:00:00 2001 From: rsulli55 Date: Sun, 25 Oct 2020 18:11:38 -0700 Subject: Remove `to_string` on msg Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bd04a95e4a1..4df1b3d197f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3111,7 +3111,7 @@ fn lint_search_is_some<'tcx>( then { let msg = "called `is_some()` after calling `find()` \ on a string. This is more succinctly expressed by calling \ - `contains()`.".to_string(); + `contains()`"; let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); span_lint_and_sugg( -- cgit 1.4.1-3-g733a5 From fb74b4802eda6da49f0ea9f2bc1ef238306c1329 Mon Sep 17 00:00:00 2001 From: rsulli55 Date: Sun, 25 Oct 2020 18:11:57 -0700 Subject: Remove borrow Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4df1b3d197f..fc66bf0422f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3118,7 +3118,7 @@ fn lint_search_is_some<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "try this", format!("contains({})", find_arg), applicability, -- cgit 1.4.1-3-g733a5 From ee1b959054aaf69968d440915766e834568de8fd Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Sat, 31 Oct 2020 12:40:56 -0700 Subject: Added period back to lint `search_is_some` and ran `update-all-references.sh` --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/methods.stderr | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fc66bf0422f..19e63fbddf7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3111,7 +3111,7 @@ fn lint_search_is_some<'tcx>( then { let msg = "called `is_some()` after calling `find()` \ on a string. This is more succinctly expressed by calling \ - `contains()`"; + `contains()`."; let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); span_lint_and_sugg( diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index bf4675966df..33aba630a53 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -20,3 +20,5 @@ LL | | ).next(); | = note: `-D clippy::filter-next` implied by `-D warnings` +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From fd303132a27f0fa9bbbfb3282200f8190353574b Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Sat, 7 Nov 2020 00:21:22 -0700 Subject: Cleaned up message and suggestion for `lint_search_is_some` --- clippy_lints/src/methods/mod.rs | 14 ++++---- tests/ui/search_is_some.stderr | 11 +++++-- tests/ui/search_is_some_fixable.stderr | 60 +++++++++++++++++----------------- 3 files changed, 44 insertions(+), 41 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 19e63fbddf7..66f5aa0c6a0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3053,10 +3053,10 @@ fn lint_search_is_some<'tcx>( // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { let msg = format!( - "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \ - expressed by calling `any()`.", + "called `is_some()` after searching an `Iterator` with {}", search_method ); + let hint = "this is more succinctly expressed by calling `any()`"; let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -3084,7 +3084,7 @@ fn lint_search_is_some<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "try this", + "use `any()` instead", format!( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -3092,7 +3092,7 @@ fn lint_search_is_some<'tcx>( Applicability::MachineApplicable, ); } else { - span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); } } // lint if `find()` is called by `String` or `&str` @@ -3109,9 +3109,7 @@ fn lint_search_is_some<'tcx>( if is_string_or_str_slice(&search_args[0]); if is_string_or_str_slice(&search_args[1]); then { - let msg = "called `is_some()` after calling `find()` \ - on a string. This is more succinctly expressed by calling \ - `contains()`."; + let msg = "called `is_some()` after calling `find()` on a string"; let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); span_lint_and_sugg( @@ -3119,7 +3117,7 @@ fn lint_search_is_some<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), msg, - "try this", + "use `contains()` instead", format!("contains({})", find_arg), applicability, ); diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index a124ab1dfd4..43827a6a98d 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,4 +1,4 @@ -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some.rs:13:13 | LL | let _ = v.iter().find(|&x| { @@ -9,8 +9,9 @@ LL | | ).is_some(); | |______________________________^ | = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with position --> $DIR/search_is_some.rs:19:13 | LL | let _ = v.iter().position(|&x| { @@ -19,8 +20,10 @@ LL | | x < 0 LL | | } LL | | ).is_some(); | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with rposition --> $DIR/search_is_some.rs:25:13 | LL | let _ = v.iter().rposition(|&x| { @@ -29,6 +32,8 @@ LL | | x < 0 LL | | } LL | | ).is_some(); | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` error: use of a blacklisted/placeholder name `foo` --> $DIR/search_is_some.rs:31:9 diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index 7a2c063fee8..f4c5d7a3389 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -1,94 +1,94 @@ -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:10:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:11:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:12:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:13:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with position --> $DIR/search_is_some_fixable.rs:16:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with rposition --> $DIR/search_is_some_fixable.rs:19:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:24:27 | LL | let _ = "hello world".find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:25:27 | LL | let _ = "hello world".find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:26:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:28:16 | LL | let _ = s1.find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:29:16 | LL | let _ = s1.find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:30:16 | LL | let _ = s1.find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:32:21 | LL | let _ = s1[2..].find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:33:21 | LL | let _ = s1[2..].find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:34:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From 56d252c53d1d4f7822b336d086659c26a8f0bb4d Mon Sep 17 00:00:00 2001 From: rsulli55 Date: Tue, 10 Nov 2020 23:17:46 -0700 Subject: Update clippy_lints/src/methods/mod.rs Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 66f5aa0c6a0..5c1c1594f7d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3053,7 +3053,7 @@ fn lint_search_is_some<'tcx>( // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { let msg = format!( - "called `is_some()` after searching an `Iterator` with {}", + "called `is_some()` after searching an `Iterator` with `{}`", search_method ); let hint = "this is more succinctly expressed by calling `any()`"; -- cgit 1.4.1-3-g733a5 From df0d565e597ad9c436fadfb8e11a16a92bcb4114 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 2 Oct 2020 18:21:17 +0900 Subject: Move `find_all_ret_expressions` into `utils` --- clippy_lints/src/methods/bind_instead_of_map.rs | 125 +--------------------- clippy_lints/src/unnecessary_wrap.rs | 132 ++---------------------- clippy_lints/src/utils/mod.rs | 1 + clippy_lints/src/utils/visitors.rs | 125 ++++++++++++++++++++++ 4 files changed, 133 insertions(+), 250 deletions(-) create mode 100644 clippy_lints/src/utils/visitors.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index ae37942e55a..540a1484a85 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,14 +1,12 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use crate::utils::{ in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, + snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; use rustc_span::Span; pub(crate) struct OptionAndThenSome; @@ -193,124 +191,3 @@ pub(crate) trait BindInsteadOfMap { } } } - -/// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &hir::Expr<'_>) -> bool { - struct TryFinder { - found: bool, - } - - impl<'hir> intravisit::Visitor<'hir> for TryFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if self.found { - return; - } - match expr.kind { - hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, - _ => intravisit::walk_expr(self, expr), - } - } - } - - let mut visitor = TryFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - -fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool -where - F: FnMut(&'hir hir::Expr<'hir>) -> bool, -{ - struct RetFinder { - in_stmt: bool, - failed: bool, - cb: F, - } - - struct WithStmtGuarg<'a, F> { - val: &'a mut RetFinder, - prev_in_stmt: bool, - } - - impl RetFinder { - fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { - let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); - WithStmtGuarg { - val: self, - prev_in_stmt, - } - } - } - - impl std::ops::Deref for WithStmtGuarg<'_, F> { - type Target = RetFinder; - - fn deref(&self) -> &Self::Target { - self.val - } - } - - impl std::ops::DerefMut for WithStmtGuarg<'_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.val - } - } - - impl Drop for WithStmtGuarg<'_, F> { - fn drop(&mut self) { - self.val.in_stmt = self.prev_in_stmt; - } - } - - impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { - if self.failed { - return; - } - if self.in_stmt { - match expr.kind { - hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), - } - } else { - match expr.kind { - hir::ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); - for arm in arms { - self.visit_expr(arm.body); - } - }, - hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), - hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), - } - } - } - } - - !contains_try(expr) && { - let mut ret_finder = RetFinder { - in_stmt: false, - failed: false, - cb: callback, - }; - ret_finder.visit_expr(expr); - !ret_finder.failed - } -} diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 3ddf921a04b..de13301381e 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,10 +1,13 @@ -use crate::utils::{is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then}; +use crate::utils::{ + is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + visitors::find_all_ret_expressions, +}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::{hir::map::Map, ty::subst::GenericArgKind}; +use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -125,126 +128,3 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { } } } - -// code below is copied from `bind_instead_of_map` - -fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool -where - F: FnMut(&'hir Expr<'hir>) -> bool, -{ - struct RetFinder { - in_stmt: bool, - failed: bool, - cb: F, - } - - struct WithStmtGuarg<'a, F> { - val: &'a mut RetFinder, - prev_in_stmt: bool, - } - - impl RetFinder { - fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { - let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); - WithStmtGuarg { - val: self, - prev_in_stmt, - } - } - } - - impl std::ops::Deref for WithStmtGuarg<'_, F> { - type Target = RetFinder; - - fn deref(&self) -> &Self::Target { - self.val - } - } - - impl std::ops::DerefMut for WithStmtGuarg<'_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.val - } - } - - impl Drop for WithStmtGuarg<'_, F> { - fn drop(&mut self) { - self.val.in_stmt = self.prev_in_stmt; - } - } - - impl<'hir, F: FnMut(&'hir Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_stmt(&mut self, stmt: &'hir Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) - } - - fn visit_expr(&mut self, expr: &'hir Expr<'_>) { - if self.failed { - return; - } - if self.in_stmt { - match expr.kind { - ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), - } - } else { - match expr.kind { - ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); - for arm in arms { - self.visit_expr(arm.body); - } - }, - ExprKind::Block(..) => intravisit::walk_expr(self, expr), - ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), - } - } - } - } - - !contains_try(expr) && { - let mut ret_finder = RetFinder { - in_stmt: false, - failed: false, - cb: callback, - }; - ret_finder.visit_expr(expr); - !ret_finder.failed - } -} - -/// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &Expr<'_>) -> bool { - struct TryFinder { - found: bool, - } - - impl<'hir> intravisit::Visitor<'hir> for TryFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { - if self.found { - return; - } - match expr.kind { - ExprKind::Match(_, _, MatchSource::TryDesugar) => self.found = true, - _ => intravisit::walk_expr(self, expr), - } - } - } - - let mut visitor = TryFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 253b7823bd9..bd62e67f80e 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -21,6 +21,7 @@ pub mod ptr; pub mod qualify_min_const_fn; pub mod sugg; pub mod usage; +pub mod visitors; pub use self::attrs::*; pub use self::diagnostics::*; diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs new file mode 100644 index 00000000000..b0837b6c43e --- /dev/null +++ b/clippy_lints/src/utils/visitors.rs @@ -0,0 +1,125 @@ +use rustc_hir as hir; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; + +/// returns `true` if expr contains match expr desugared from try +fn contains_try(expr: &hir::Expr<'_>) -> bool { + struct TryFinder { + found: bool, + } + + impl<'hir> intravisit::Visitor<'hir> for TryFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + if self.found { + return; + } + match expr.kind { + hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, + _ => intravisit::walk_expr(self, expr), + } + } + } + + let mut visitor = TryFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + +pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool +where + F: FnMut(&'hir hir::Expr<'hir>) -> bool, +{ + struct RetFinder { + in_stmt: bool, + failed: bool, + cb: F, + } + + struct WithStmtGuarg<'a, F> { + val: &'a mut RetFinder, + prev_in_stmt: bool, + } + + impl RetFinder { + fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { + let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); + WithStmtGuarg { + val: self, + prev_in_stmt, + } + } + } + + impl std::ops::Deref for WithStmtGuarg<'_, F> { + type Target = RetFinder; + + fn deref(&self) -> &Self::Target { + self.val + } + } + + impl std::ops::DerefMut for WithStmtGuarg<'_, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val + } + } + + impl Drop for WithStmtGuarg<'_, F> { + fn drop(&mut self) { + self.val.in_stmt = self.prev_in_stmt; + } + } + + impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { + if self.failed { + return; + } + if self.in_stmt { + match expr.kind { + hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => intravisit::walk_expr(self, expr), + } + } else { + match expr.kind { + hir::ExprKind::Match(cond, arms, _) => { + self.inside_stmt(true).visit_expr(cond); + for arm in arms { + self.visit_expr(arm.body); + } + }, + hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), + hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + _ => self.failed |= !(self.cb)(expr), + } + } + } + } + + !contains_try(expr) && { + let mut ret_finder = RetFinder { + in_stmt: false, + failed: false, + cb: callback, + }; + ret_finder.visit_expr(expr); + !ret_finder.failed + } +} -- cgit 1.4.1-3-g733a5 From 034244f1081ee65ce9a258e99cf39baa5d692bca Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 Nov 2020 15:00:03 -0500 Subject: Small grammar, punctuation, and code style improvements to docs --- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/regex.rs | 4 ++-- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/useless_conversion.rs | 6 +++--- src/lintlist/mod.rs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8e2f03d6e4e..8842901d90b 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -69,7 +69,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparing to an empty slice such as "" or [],` + /// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`, /// and suggests using `.is_empty()` where applicable. /// /// **Why is this bad?** Some structures can answer `.is_empty()` much faster diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ff0a3532465..fa174404365 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1351,7 +1351,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).collect::()`. + /// **What it does:** Checks for usage of `_.map(_).collect::()`. /// /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. /// diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 95594e38c9e..d06ab143482 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -11,7 +11,7 @@ use std::convert::TryFrom; declare_clippy_lint! { /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation - /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct + /// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct /// regex syntax. /// /// **Why is this bad?** This will lead to a runtime panic. @@ -29,7 +29,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex) - /// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`). + /// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). /// /// **Why is this bad?** Matching the regex can likely be replaced by `==` or /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index ade5fff5ffc..2501635e7ef 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// let mut twins = vec!((1,1), (2,2)); + /// let mut twins = vec!((1, 1), (2, 2)); /// twins.sort_by_key(|x| { x.1; }); /// ``` pub UNIT_RETURN_EXPECTING_ORD, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c6194b0c6de..99c38e8f176 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,8 +12,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls - /// that useless converts to the same type as caller. + /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls + /// that uselessly convert to the same type. /// /// **Why is this bad?** Redundant code. /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` that perform useless conversions to the same type" } #[derive(Default)] diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 79b24b83680..1d906d20ad4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2751,7 +2751,7 @@ vec![ Lint { name: "useless_conversion", group: "complexity", - desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type", + desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type", deprecation: None, module: "useless_conversion", }, -- cgit 1.4.1-3-g733a5 From aaa43250455c19ae54c821518c42219f6460038c Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Wed, 21 Oct 2020 18:17:34 +0530 Subject: add support for minimum supported rust version. add configuration option for minimum supported rust version add msrv attribute to some lints listed in #6097 add tests --- clippy_lints/src/lib.rs | 23 ++++++-- clippy_lints/src/manual_non_exhaustive.rs | 33 ++++++++++- clippy_lints/src/manual_strip.rs | 37 ++++++++++-- clippy_lints/src/matches.rs | 39 +++++++++++-- clippy_lints/src/methods/mod.rs | 51 +++++++++++++--- clippy_lints/src/utils/attrs.rs | 17 ++++++ clippy_lints/src/utils/conf.rs | 2 + clippy_lints/src/utils/mod.rs | 49 ++++++++++++++++ tests/ui-toml/invalid_min_rust_version/clippy.toml | 1 + .../invalid_min_rust_version.rs | 3 + .../invalid_min_rust_version.stderr | 4 ++ tests/ui-toml/min_rust_version/clippy.toml | 1 + tests/ui-toml/min_rust_version/min_rust_version.rs | 68 ++++++++++++++++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/min_rust_version_attr.rs | 51 ++++++++++++++++ tests/ui/min_rust_version_invalid_attr.rs | 4 ++ tests/ui/min_rust_version_invalid_attr.stderr | 8 +++ tests/ui/min_rust_version_no_patch.rs | 14 +++++ tests/ui/min_rust_version_outer_attr.rs | 4 ++ tests/ui/min_rust_version_outer_attr.stderr | 8 +++ 20 files changed, 390 insertions(+), 29 deletions(-) create mode 100644 tests/ui-toml/invalid_min_rust_version/clippy.toml create mode 100644 tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs create mode 100644 tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr create mode 100644 tests/ui-toml/min_rust_version/clippy.toml create mode 100644 tests/ui-toml/min_rust_version/min_rust_version.rs create mode 100644 tests/ui/min_rust_version_attr.rs create mode 100644 tests/ui/min_rust_version_invalid_attr.rs create mode 100644 tests/ui/min_rust_version_invalid_attr.stderr create mode 100644 tests/ui/min_rust_version_no_patch.rs create mode 100644 tests/ui/min_rust_version_outer_attr.rs create mode 100644 tests/ui/min_rust_version_outer_attr.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e8cbd00c22..866dae110cc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -44,6 +44,7 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; +use crate::utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; use rustc_session::Session; @@ -933,7 +934,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); // end register lints, do not remove this comment, it’s used in `update_lints` - store.register_late_pass(|| box await_holding_invalid::AwaitHolding); store.register_late_pass(|| box serde_api::SerdeAPI); store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); @@ -969,7 +969,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box strings::StringAdd); store.register_late_pass(|| box implicit_return::ImplicitReturn); store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); - store.register_late_pass(|| box methods::Methods); + + let parsed_msrv = conf.msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s)); + None + }) + }); + + let msrv = parsed_msrv.clone(); + store.register_late_pass(move || box methods::Methods::new(msrv.clone())); + let msrv = parsed_msrv.clone(); + store.register_late_pass(move || box matches::Matches::new(msrv.clone())); + let msrv = parsed_msrv.clone(); + store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv.clone())); + let msrv = parsed_msrv; + store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv.clone())); + store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -983,7 +999,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box types::Casts); let type_complexity_threshold = conf.type_complexity_threshold; store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold)); - store.register_late_pass(|| box matches::Matches::default()); store.register_late_pass(|| box minmax::MinMaxPass); store.register_late_pass(|| box open_options::OpenOptions); store.register_late_pass(|| box zero_div_zero::ZeroDiv); @@ -1144,7 +1159,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box if_let_mutex::IfLetMutex); store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); - store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); @@ -1166,7 +1180,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); - store.register_late_pass(|| box manual_strip::ManualStrip); store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index a1450b0d5fe..4762ba16ac7 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,11 +1,20 @@ -use crate::utils::{snippet_opt, span_lint_and_then}; +use crate::utils::{get_inner_attr, meets_msrv, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; +use semver::{Version, VersionReq}; + +const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version { + major: 1, + minor: 40, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. @@ -55,10 +64,26 @@ declare_clippy_lint! { "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" } -declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); +#[derive(Clone)] +pub struct ManualNonExhaustive { + msrv: Option, +} + +impl ManualNonExhaustive { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustive { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) { + return; + } + match &item.kind { ItemKind::Enum(def, _) => { check_manual_non_exhaustive_enum(cx, item, &def.variants); @@ -73,6 +98,8 @@ impl EarlyLintPass for ManualNonExhaustive { _ => {}, } } + + extract_msrv_attr!(EarlyContext); } fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 4afb0ab3bad..446641ca114 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,21 +1,31 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, + eq_expr_value, get_inner_attr, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, + span_lint_and_then, }; use if_chain::if_chain; -use rustc_ast::ast::LitKind; +use rustc_ast::ast::{Attribute, LitKind}; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::BinOpKind; use rustc_hir::{BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; +use semver::{Version, VersionReq}; + +const MANUAL_STRIP_MSRV: Version = Version { + major: 1, + minor: 45, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; declare_clippy_lint! { /// **What it does:** @@ -51,7 +61,18 @@ declare_clippy_lint! { "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing" } -declare_lint_pass!(ManualStrip => [MANUAL_STRIP]); +pub struct ManualStrip { + msrv: Option, +} + +impl ManualStrip { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualStrip => [MANUAL_STRIP]); #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum StripKind { @@ -61,6 +82,10 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { + return; + } + if_chain! { if let Some((cond, then, _)) = higher::if_block(&expr); if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind; @@ -114,6 +139,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { } } } + + extract_msrv_attr!(LateContext); } // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index af59917e801..5c38abbd9c6 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,14 +2,14 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::usage::is_unused; use crate::utils::{ - expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, - is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, - snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, + expr_block, get_arg_name, get_inner_attr, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, + is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, + remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, + span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; +use rustc_ast::ast::{Attribute, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; @@ -23,6 +23,7 @@ use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::{sym, Symbol}; +use semver::{Version, VersionReq}; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::Bound; @@ -527,9 +528,20 @@ declare_clippy_lint! { #[derive(Default)] pub struct Matches { + msrv: Option, infallible_destructuring_match_linted: bool, } +impl Matches { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { + msrv, + ..Matches::default() + } + } +} + impl_lint_pass!(Matches => [ SINGLE_MATCH, MATCH_REF_PATS, @@ -549,6 +561,14 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); +const MATCH_LIKE_MATCHES_MACRO_MSRV: Version = Version { + major: 1, + minor: 42, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; + impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { @@ -556,7 +576,12 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } redundant_pattern_match::check(cx, expr); - if !check_match_like_matches(cx, expr) { + + if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) { + if !check_match_like_matches(cx, expr) { + lint_match_arms(cx, expr); + } + } else { lint_match_arms(cx, expr); } @@ -640,6 +665,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } } + + extract_msrv_attr!(LateContext); } #[rustfmt::skip] diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fa174404365..6b478986067 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -12,6 +12,7 @@ use std::iter; use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; use rustc_ast::ast; +use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; @@ -20,7 +21,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -28,12 +29,14 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, - match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, - single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, + contains_ty, get_arg_name, get_inner_attr, get_parent_expr, get_trait_def_id, has_iter_method, higher, + implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, + match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, + walk_ptrs_ty_depth, SpanlessEq, }; +use semver::{Version, VersionReq}; declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. @@ -1404,7 +1407,18 @@ declare_clippy_lint! { "use `.collect()` instead of `::from_iter()`" } -declare_lint_pass!(Methods => [ +pub struct Methods { + msrv: Option, +} + +impl Methods { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, @@ -1531,8 +1545,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { check_pointer_offset(cx, expr, arg_lists[0]) }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), - ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), - ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), + ["map", "as_ref"] => { + lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) + }, + ["map", "as_mut"] => { + lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) + }, ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), @@ -1738,6 +1756,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } } + + extract_msrv_attr!(LateContext); } /// Checks for the `OR_FUN_CALL` lint. @@ -3453,6 +3473,14 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { ); } +const OPTION_AS_REF_DEREF_MSRV: Version = Version { + major: 1, + minor: 40, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; + /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s fn lint_option_as_ref_deref<'tcx>( cx: &LateContext<'tcx>, @@ -3460,7 +3488,12 @@ fn lint_option_as_ref_deref<'tcx>( as_ref_args: &[hir::Expr<'_>], map_args: &[hir::Expr<'_>], is_mut: bool, + msrv: Option<&VersionReq>, ) { + if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { + return; + } + let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index e6d41341a55..aed6ee5dc57 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -21,6 +21,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ DeprecationStatus::Replaced("cognitive_complexity"), ), ("dump", DeprecationStatus::None), + ("msrv", DeprecationStatus::None), ]; pub struct LimitStack { @@ -123,6 +124,22 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' } } +pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option { + let mut unique_attr = None; + for attr in get_attr(sess, attrs, name) { + match attr.style { + ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()), + ast::AttrStyle::Inner => { + sess.span_err(attr.span, &format!("`{}` is defined multiple times", name)); + }, + ast::AttrStyle::Outer => { + sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name)); + }, + } + } + unique_attr +} + /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0ac8fff69f0..fc6304118d9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -106,6 +106,8 @@ macro_rules! define_Conf { pub use self::helpers::Conf; define_Conf! { + /// Lint: MANUAL_NON_EXHAUSTIVE, MANUAL_STRIP, OPTION_AS_REF_DEREF, MATCH_LIKE_MATCHES_MACRO. The minimum rust version that the project supports + (msrv, "msrv": Option, None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names, "blacklisted_names": Vec, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index e9c71e23a67..f8e88512048 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -51,6 +51,7 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; +use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::sym as rustc_sym; @@ -58,10 +59,58 @@ use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; use rustc_trait_selection::traits::query::normalize::AtExt; +use semver::{Version, VersionReq}; use smallvec::SmallVec; use crate::consts::{constant, Constant}; +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { + if let Ok(version) = VersionReq::parse(msrv) { + return Some(version); + } else if let Some(sess) = sess { + if let Some(span) = span { + sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv)); + } + } + None +} + +pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool { + msrv.map_or(true, |msrv| !msrv.matches(lint_msrv)) +} + +#[macro_export] +macro_rules! extract_msrv_attr { + (LateContext) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::LateContext<'tcx>, attrs: &'tcx [Attribute]) { + match get_inner_attr(cx.sess(), attrs, "msrv") { + Some(msrv_attr) => { + if let Some(msrv) = msrv_attr.value_str() { + self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess()), Some(msrv_attr.span)); + } else { + cx.sess().span_err(msrv_attr.span, "bad clippy attribute"); + } + }, + _ => (), + } + } + }; + (EarlyContext) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::EarlyContext<'tcx>, attrs: &'tcx [Attribute]) { + match get_inner_attr(cx.sess, attrs, "msrv") { + Some(msrv_attr) => { + if let Some(msrv) = msrv_attr.value_str() { + self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess), Some(msrv_attr.span)); + } else { + cx.sess.span_err(msrv_attr.span, "bad clippy attribute"); + } + }, + _ => (), + } + } + }; +} + /// Returns `true` if the two spans come from differing expansions (i.e., one is /// from a macro and one isn't). #[must_use] diff --git a/tests/ui-toml/invalid_min_rust_version/clippy.toml b/tests/ui-toml/invalid_min_rust_version/clippy.toml new file mode 100644 index 00000000000..088b12b2dac --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/clippy.toml @@ -0,0 +1 @@ +msrv = "invalid.version" diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs new file mode 100644 index 00000000000..2ebf28645e5 --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs @@ -0,0 +1,3 @@ +#![allow(clippy::redundant_clone)] + +fn main() {} diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr new file mode 100644 index 00000000000..e9d8fd2e0f5 --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr @@ -0,0 +1,4 @@ +error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version + +error: aborting due to previous error + diff --git a/tests/ui-toml/min_rust_version/clippy.toml b/tests/ui-toml/min_rust_version/clippy.toml new file mode 100644 index 00000000000..8e17d8074c4 --- /dev/null +++ b/tests/ui-toml/min_rust_version/clippy.toml @@ -0,0 +1 @@ +msrv = "1.0.0" diff --git a/tests/ui-toml/min_rust_version/min_rust_version.rs b/tests/ui-toml/min_rust_version/min_rust_version.rs new file mode 100644 index 00000000000..bc41efa42a1 --- /dev/null +++ b/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -0,0 +1,68 @@ +#![allow(clippy::redundant_clone)] +#![warn(clippy::manual_non_exhaustive)] + +use std::ops::Deref; + +mod enums { + enum E { + A, + B, + #[doc(hidden)] + _C, + } + + // user forgot to remove the marker + #[non_exhaustive] + enum Ep { + A, + B, + #[doc(hidden)] + _C, + } +} + +fn option_as_ref_deref() { + let mut opt = Some(String::from("123")); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); +} + +fn match_like_matches() { + let _y = match Some(5) { + Some(0) => true, + _ => false, + }; +} + +fn match_same_arms() { + match (1, 2, 3) { + (1, .., 3) => 42, + (.., 3) => 42, //~ ERROR match arms have same body + _ => 0, + }; +} + +fn match_same_arms2() { + let _ = match Some(42) { + Some(_) => 24, + None => 24, //~ ERROR match arms have same body + }; +} + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + option_as_ref_deref(); + match_like_matches(); + match_same_arms(); + match_same_arms2(); + manual_strip_msrv(); +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index a58e7e918e2..af3d9ecf6e8 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs new file mode 100644 index 00000000000..8ed483a3ac6 --- /dev/null +++ b/tests/ui/min_rust_version_attr.rs @@ -0,0 +1,51 @@ +#![allow(clippy::redundant_clone)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.0.0"] + +use std::ops::Deref; + +fn option_as_ref_deref() { + let mut opt = Some(String::from("123")); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); +} + +fn match_like_matches() { + let _y = match Some(5) { + Some(0) => true, + _ => false, + }; +} + +fn match_same_arms() { + match (1, 2, 3) { + (1, .., 3) => 42, + (.., 3) => 42, //~ ERROR match arms have same body + _ => 0, + }; +} + +fn match_same_arms2() { + let _ = match Some(42) { + Some(_) => 24, + None => 24, //~ ERROR match arms have same body + }; +} + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + option_as_ref_deref(); + match_like_matches(); + match_same_arms(); + match_same_arms2(); + manual_strip_msrv(); +} diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs new file mode 100644 index 00000000000..f20841891a7 --- /dev/null +++ b/tests/ui/min_rust_version_invalid_attr.rs @@ -0,0 +1,4 @@ +#![feature(custom_inner_attributes)] +#![clippy::msrv = "invalid.version"] + +fn main() {} diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr new file mode 100644 index 00000000000..6ff88ca56f8 --- /dev/null +++ b/tests/ui/min_rust_version_invalid_attr.stderr @@ -0,0 +1,8 @@ +error: `invalid.version` is not a valid Rust version + --> $DIR/min_rust_version_invalid_attr.rs:2:1 + | +LL | #![clippy::msrv = "invalid.version"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/min_rust_version_no_patch.rs b/tests/ui/min_rust_version_no_patch.rs new file mode 100644 index 00000000000..515fe8f95e9 --- /dev/null +++ b/tests/ui/min_rust_version_no_patch.rs @@ -0,0 +1,14 @@ +#![allow(clippy::redundant_clone)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "^1.0"] + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + manual_strip_msrv() +} diff --git a/tests/ui/min_rust_version_outer_attr.rs b/tests/ui/min_rust_version_outer_attr.rs new file mode 100644 index 00000000000..551948bd72e --- /dev/null +++ b/tests/ui/min_rust_version_outer_attr.rs @@ -0,0 +1,4 @@ +#![feature(custom_inner_attributes)] + +#[clippy::msrv = "invalid.version"] +fn main() {} diff --git a/tests/ui/min_rust_version_outer_attr.stderr b/tests/ui/min_rust_version_outer_attr.stderr new file mode 100644 index 00000000000..579ee7a87d2 --- /dev/null +++ b/tests/ui/min_rust_version_outer_attr.stderr @@ -0,0 +1,8 @@ +error: `msrv` cannot be an outer attribute + --> $DIR/min_rust_version_outer_attr.rs:3:1 + | +LL | #[clippy::msrv = "invalid.version"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From b2e2c0806ec2296bf7d98e0db5cc9c39a55f23ac Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 25 Nov 2020 11:50:13 +0100 Subject: Improve extract_msrv_attr! situation --- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_strip.rs | 5 ++--- clippy_lints/src/matches.rs | 10 +++++----- clippy_lints/src/methods/mod.rs | 12 +++++------- clippy_lints/src/utils/mod.rs | 30 +++++++++++++----------------- 5 files changed, 26 insertions(+), 33 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 4762ba16ac7..703e6feeca5 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_inner_attr, meets_msrv, snippet_opt, span_lint_and_then}; +use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 446641ca114..e17e3adb94f 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,12 +1,11 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - eq_expr_value, get_inner_attr, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, - span_lint_and_then, + eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, }; use if_chain::if_chain; -use rustc_ast::ast::{Attribute, LitKind}; +use rustc_ast::ast::LitKind; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::BinOpKind; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 5c38abbd9c6..d695af4de21 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,14 +2,14 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::usage::is_unused; use crate::utils::{ - expr_block, get_arg_name, get_inner_attr, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, - is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, - remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, - span_lint_and_sugg, span_lint_and_then, + expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, + is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks, + snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, + span_lint_and_then, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; -use rustc_ast::ast::{Attribute, LitKind}; +use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6b478986067..50dd760432d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -12,7 +12,6 @@ use std::iter; use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; use rustc_ast::ast; -use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; @@ -29,12 +28,11 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_inner_attr, get_parent_expr, get_trait_def_id, has_iter_method, higher, - implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, - method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, - walk_ptrs_ty_depth, SpanlessEq, + contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, + is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, + match_trait_method, match_type, match_var, meets_msrv, method_calls, method_chain_args, paths, remove_blocks, + return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, }; use semver::{Version, VersionReq}; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f8e88512048..6f89e51279a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -79,30 +79,26 @@ pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool { msrv.map_or(true, |msrv| !msrv.matches(lint_msrv)) } -#[macro_export] macro_rules! extract_msrv_attr { (LateContext) => { - fn enter_lint_attrs(&mut self, cx: &rustc_lint::LateContext<'tcx>, attrs: &'tcx [Attribute]) { - match get_inner_attr(cx.sess(), attrs, "msrv") { - Some(msrv_attr) => { - if let Some(msrv) = msrv_attr.value_str() { - self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess()), Some(msrv_attr.span)); - } else { - cx.sess().span_err(msrv_attr.span, "bad clippy attribute"); - } - }, - _ => (), - } - } + extract_msrv_attr!(@LateContext, ()); }; (EarlyContext) => { - fn enter_lint_attrs(&mut self, cx: &rustc_lint::EarlyContext<'tcx>, attrs: &'tcx [Attribute]) { - match get_inner_attr(cx.sess, attrs, "msrv") { + extract_msrv_attr!(@EarlyContext); + }; + (@$context:ident$(, $call:tt)?) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) { + use $crate::utils::get_unique_inner_attr; + match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") { Some(msrv_attr) => { if let Some(msrv) = msrv_attr.value_str() { - self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess), Some(msrv_attr.span)); + self.msrv = $crate::utils::parse_msrv( + &msrv.to_string(), + Some(cx.sess$($call)?), + Some(msrv_attr.span), + ); } else { - cx.sess.span_err(msrv_attr.span, "bad clippy attribute"); + cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute"); } }, _ => (), -- cgit 1.4.1-3-g733a5 From f7b2098e1c4f8e13ec2194f7f094f471b4056f97 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 29 Nov 2020 01:55:15 +0900 Subject: Fix a false positive in `unnecessary_wraps` --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 ++ tests/ui/unnecessary_wraps.rs | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 50dd760432d..004b8416fc1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3878,7 +3878,7 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } // Returns `true` if `expr` contains a return expression -fn contains_return(expr: &hir::Expr<'_>) -> bool { +pub(crate) fn contains_return(expr: &hir::Expr<'_>) -> bool { struct RetCallFinder { found: bool, } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 25ecc7a82f1..7b550c702cd 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,3 +1,4 @@ +use crate::methods::contains_return; use crate::utils::{ in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, visitors::find_all_ret_expressions, @@ -95,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if let ExprKind::Path(ref qpath) = func.kind; if match_qpath(qpath, path); if args.len() == 1; + if !contains_return(&args[0]); then { suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string())); true diff --git a/tests/ui/unnecessary_wraps.rs b/tests/ui/unnecessary_wraps.rs index a53dec8f91a..a4570098d71 100644 --- a/tests/ui/unnecessary_wraps.rs +++ b/tests/ui/unnecessary_wraps.rs @@ -109,6 +109,13 @@ impl B for A { } } +fn issue_6384(s: &str) -> Option<&str> { + Some(match s { + "a" => "A", + _ => return None, + }) +} + fn main() { // method calls are not linted func1(true, true); -- cgit 1.4.1-3-g733a5 From 2c26cb14db4d3a86aea0a897f9b727cef4e72e27 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 29 Nov 2020 02:18:05 +0900 Subject: Move `contains_return` to utils/mod.rs --- clippy_lints/src/methods/mod.rs | 43 +++++------------------------------ clippy_lints/src/unnecessary_wraps.rs | 3 +-- clippy_lints/src/utils/mod.rs | 30 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 39 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 004b8416fc1..1476408e0fb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -14,10 +14,8 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; -use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -28,11 +26,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, - match_trait_method, match_type, match_var, meets_msrv, method_calls, method_chain_args, paths, remove_blocks, - return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, + contains_return, contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, + implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, + match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, + walk_ptrs_ty_depth, SpanlessEq, }; use semver::{Version, VersionReq}; @@ -3877,36 +3876,6 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } } -// Returns `true` if `expr` contains a return expression -pub(crate) fn contains_return(expr: &hir::Expr<'_>) -> bool { - struct RetCallFinder { - found: bool, - } - - impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if self.found { - return; - } - if let hir::ExprKind::Ret(..) = &expr.kind { - self.found = true; - } else { - intravisit::walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - } - - let mut visitor = RetCallFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if_chain! { if args.len() == 2; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 7b550c702cd..360df2a6752 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,5 @@ -use crate::methods::contains_return; use crate::utils::{ - in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 6f89e51279a..850abc3bae7 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -572,6 +572,36 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { cn.result } +/// Returns `true` if `expr` contains a return expression +pub fn contains_return(expr: &hir::Expr<'_>) -> bool { + struct RetCallFinder { + found: bool, + } + + impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + if self.found { + return; + } + if let hir::ExprKind::Ret(..) = &expr.kind { + self.found = true; + } else { + hir::intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + } + + let mut visitor = RetCallFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + /// Converts a span to a code snippet if available, otherwise use default. /// /// This is useful if you want to provide suggestions for your lint or more generally, if you want -- cgit 1.4.1-3-g733a5 From cd087e5c5e65fa61c0562ceb2d2488f8f5660454 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Sat, 28 Nov 2020 19:41:27 +0530 Subject: add rustc-semver to dependencies switch Version/VersionReq usages to RustcVersion --- clippy_lints/Cargo.toml | 1 + clippy_lints/src/manual_non_exhaustive.rs | 14 ++++---------- clippy_lints/src/manual_strip.rs | 14 ++++---------- clippy_lints/src/matches.rs | 14 ++++---------- clippy_lints/src/methods/mod.rs | 16 +++++----------- clippy_lints/src/utils/mod.rs | 10 +++++----- 6 files changed, 23 insertions(+), 46 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d9471d25197..45fd87b169f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,6 +28,7 @@ smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" semver = "0.11" +rustc-semver="1.0.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 703e6feeca5..91849e74887 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -4,17 +4,11 @@ use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantDat use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use semver::{Version, VersionReq}; -const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version { - major: 1, - minor: 40, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const MANUAL_NON_EXHAUSTIVE_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. @@ -66,12 +60,12 @@ declare_clippy_lint! { #[derive(Clone)] pub struct ManualNonExhaustive { - msrv: Option, + msrv: Option, } impl ManualNonExhaustive { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv } } } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index e17e3adb94f..f593abdb104 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -13,18 +13,12 @@ use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; -use semver::{Version, VersionReq}; -const MANUAL_STRIP_MSRV: Version = Version { - major: 1, - minor: 45, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); declare_clippy_lint! { /// **What it does:** @@ -61,12 +55,12 @@ declare_clippy_lint! { } pub struct ManualStrip { - msrv: Option, + msrv: Option, } impl ManualStrip { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv } } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7d64fa6c262..86e3e2f637e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -20,10 +20,10 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::{sym, Symbol}; -use semver::{Version, VersionReq}; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::Bound; @@ -535,13 +535,13 @@ declare_clippy_lint! { #[derive(Default)] pub struct Matches { - msrv: Option, + msrv: Option, infallible_destructuring_match_linted: bool, } impl Matches { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv, ..Matches::default() @@ -568,13 +568,7 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); -const MATCH_LIKE_MATCHES_MACRO_MSRV: Version = Version { - major: 1, - minor: 42, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0); impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1476408e0fb..8002c27a5e9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -18,6 +18,7 @@ use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -33,7 +34,6 @@ use crate::utils::{ snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, }; -use semver::{Version, VersionReq}; declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. @@ -1405,12 +1405,12 @@ declare_clippy_lint! { } pub struct Methods { - msrv: Option, + msrv: Option, } impl Methods { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv } } } @@ -3470,13 +3470,7 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { ); } -const OPTION_AS_REF_DEREF_MSRV: Version = Version { - major: 1, - minor: 40, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s fn lint_option_as_ref_deref<'tcx>( @@ -3485,7 +3479,7 @@ fn lint_option_as_ref_deref<'tcx>( as_ref_args: &[hir::Expr<'_>], map_args: &[hir::Expr<'_>], is_mut: bool, - msrv: Option<&VersionReq>, + msrv: Option<&RustcVersion>, ) { if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { return; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 850abc3bae7..d68f0698153 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -51,6 +51,7 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; +use rustc_semver::RustcVersion; use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; @@ -59,13 +60,12 @@ use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; use rustc_trait_selection::traits::query::normalize::AtExt; -use semver::{Version, VersionReq}; use smallvec::SmallVec; use crate::consts::{constant, Constant}; -pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { - if let Ok(version) = VersionReq::parse(msrv) { +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { + if let Ok(version) = RustcVersion::parse(msrv) { return Some(version); } else if let Some(sess) = sess { if let Some(span) = span { @@ -75,8 +75,8 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Opt None } -pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool { - msrv.map_or(true, |msrv| !msrv.matches(lint_msrv)) +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { + msrv.map_or(true, |msrv| msrv > lint_msrv) } macro_rules! extract_msrv_attr { -- cgit 1.4.1-3-g733a5 From fff5fa65816f482357989f25a58e98688cb7363d Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 24 Nov 2020 20:57:09 -0600 Subject: Eat collapsible_match dogfood --- clippy_lints/src/default.rs | 3 +-- clippy_lints/src/if_let_some_result.rs | 3 +-- clippy_lints/src/implicit_return.rs | 3 +-- clippy_lints/src/implicit_saturating_sub.rs | 3 +-- clippy_lints/src/large_const_arrays.rs | 3 +-- clippy_lints/src/large_stack_arrays.rs | 3 +-- clippy_lints/src/loops.rs | 6 ++---- clippy_lints/src/manual_strip.rs | 3 +-- clippy_lints/src/matches.rs | 24 +++++++++------------- .../src/methods/manual_saturating_arithmetic.rs | 3 +-- clippy_lints/src/needless_bool.rs | 11 +++------- clippy_lints/src/question_mark.rs | 3 +-- clippy_lints/src/strings.rs | 3 +-- clippy_lints/src/trait_bounds.rs | 3 +-- clippy_lints/src/transmuting_null.rs | 3 +-- clippy_lints/src/types.rs | 6 ++---- clippy_lints/src/utils/higher.rs | 3 +-- 17 files changed, 30 insertions(+), 56 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 612c5355338..f69f6f1412a 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -280,8 +280,7 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op // only take assignments to fields where the left-hand side field is a field of // the same binding as the previous statement if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind; - if let ExprKind::Path(ref qpath) = binding.kind; - if let QPath::Resolved(_, path) = qpath; + if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind; if let Some(second_binding_name) = path.segments.last(); if second_binding_name.ident.name == binding_name; then { diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index e0a1f4c5ca4..1194bd7e55e 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -41,8 +41,7 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); impl<'tcx> LateLintPass<'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables - if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let + if let ExprKind::Match(ref op, ref body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index ed7f3b9293d..03e95c9e27f 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -68,8 +68,7 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let StmtKind::Semi(expr, ..) = &stmt.kind; // make sure it's a break, otherwise we want to skip - if let ExprKind::Break(.., break_expr) = &expr.kind; - if let Some(break_expr) = break_expr; + if let ExprKind::Break(.., Some(break_expr)) = &expr.kind; then { lint(cx, expr.span, break_expr.span, LINT_BREAK); } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index b57fe8dc426..3a01acd8fdc 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -59,8 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(target) = subtracts_one(cx, e); // Extracting out the variable name - if let ExprKind::Path(ref assign_path) = target.kind; - if let QPath::Resolved(_, ref ares_path) = assign_path; + if let ExprKind::Path(QPath::Resolved(_, ref ares_path)) = target.kind; then { // Handle symmetric conditions in the if statement diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 025ff86da39..a76595ed089 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -52,8 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if let ItemKind::Const(hir_ty, _) = &item.kind; let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let ty::Array(element_type, cst) = ty.kind(); - if let ConstKind::Value(val) = cst.val; - if let ConstValue::Scalar(element_count) = val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 9fd3780e14e..9a448ab1256 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); - if let ConstKind::Value(val) = cst.val; - if let ConstValue::Scalar(element_count) = val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 143cbea5537..b0de355e242 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1919,8 +1919,7 @@ fn check_for_single_element_loop<'tcx>( if_chain! { if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg_expr) = arg.kind; if let PatKind::Binding(.., target, _) = pat.kind; - if let ExprKind::Array(ref arg_expr_list) = arg_expr.kind; - if let [arg_expression] = arg_expr_list; + if let ExprKind::Array([arg_expression]) = arg_expr.kind; if let ExprKind::Path(ref list_item) = arg_expression.kind; if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name); if let ExprKind::Block(ref block, _) = body.kind; @@ -2025,8 +2024,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option let node_str = cx.tcx.hir().get(hir_id); if_chain! { if let Node::Binding(pat) = node_str; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if let BindingAnnotation::Mutable = bind_ann; + if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { return Some(hir_id); } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index e17e3adb94f..80f3045415e 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -225,8 +225,7 @@ fn find_stripping<'tcx>( if is_ref_str(self.cx, ex); let unref = peel_ref(ex); if let ExprKind::Index(indexed, index) = &unref.kind; - if let Some(range) = higher::range(index); - if let higher::Range { start, end, .. } = range; + if let Some(higher::Range { start, end, .. }) = higher::range(index); if let ExprKind::Path(path) = &indexed.kind; if qpath_res(self.cx, path, ex.hir_id) == self.target; then { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7d64fa6c262..c223462af26 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -652,8 +652,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_chain! { if !in_external_macro(cx.sess(), pat.span); if !in_macro(pat.span); - if let PatKind::Struct(ref qpath, fields, true) = pat.kind; - if let QPath::Resolved(_, ref path) = qpath; + if let PatKind::Struct(QPath::Resolved(_, ref path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); let ty = cx.tcx.type_of(def_id); if let ty::Adt(def, _) = ty.kind(); @@ -962,16 +961,14 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) if let QPath::Resolved(_, p) = path { missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } - } else if let PatKind::TupleStruct(ref path, ref patterns, ..) = arm.pat.kind { - if let QPath::Resolved(_, p) = path { - // Some simple checks for exhaustive patterns. - // There is a room for improvements to detect more cases, - // but it can be more expensive to do so. - let is_pattern_exhaustive = - |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); - if patterns.iter().all(is_pattern_exhaustive) { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); - } + } else if let PatKind::TupleStruct(QPath::Resolved(_, p), ref patterns, ..) = arm.pat.kind { + // Some simple checks for exhaustive patterns. + // There is a room for improvements to detect more cases, + // but it can be more expensive to do so. + let is_pattern_exhaustive = + |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); + if patterns.iter().all(is_pattern_exhaustive) { + missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } } } @@ -1446,8 +1443,7 @@ fn is_ref_some_arm(arm: &Arm<'_>) -> Option { if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1; - if let ExprKind::Path(ref qpath) = args[0].kind; - if let &QPath::Resolved(_, ref path2) = qpath; + if let ExprKind::Path(QPath::Resolved(_, ref path2)) = args[0].kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { return Some(rb) diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 40a62575861..44c974b9d98 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -90,8 +90,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option return Some(MinMax::Max), diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index a799a644e97..42f97b2ac49 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,7 +6,6 @@ use crate::utils::sugg::Sugg; use crate::utils::{ higher, is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg, }; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -198,13 +197,9 @@ struct ExpressionInfoWithSpan { } fn is_unary_not(e: &Expr<'_>) -> (bool, Span) { - if_chain! { - if let ExprKind::Unary(unop, operand) = e.kind; - if let UnOp::UnNot = unop; - then { - return (true, operand.span); - } - }; + if let ExprKind::Unary(UnOp::UnNot, operand) = e.kind { + return (true, operand.span); + } (false, e.span) } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d9b280b7a85..b91233ac582 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -176,8 +176,7 @@ impl QuestionMark { if block.stmts.len() == 1; if let Some(expr) = block.stmts.iter().last(); if let StmtKind::Semi(ref expr) = expr.kind; - if let ExprKind::Ret(ret_expr) = expr.kind; - if let Some(ret_expr) = ret_expr; + if let ExprKind::Ret(Some(ret_expr)) = expr.kind; then { return Some(ret_expr); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 42c45be3b45..77e79073378 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -222,8 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if method_names[0] == sym!(as_bytes); // Check for slicer - if let ExprKind::Struct(ref path, _, _) = right.kind; - if let QPath::LangItem(LangItem::Range, _) = path; + if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind; then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index d4acf8df46d..daff5f81e8c 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -168,8 +168,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !in_macro(bound_predicate.span); - if let TyKind::Path(ref path) = bound_predicate.bounded_ty.kind; - if let QPath::Resolved(_, Path { ref segments, .. }) = path; + if let TyKind::Path(QPath::Resolved(_, Path { ref segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(segment) = segments.first(); if let Some(trait_resolutions_direct) = map.get(&segment.ident); then { diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index d60306336c6..6b171a0fa1a 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -48,8 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { if_chain! { if let ExprKind::Path(ref _qpath) = args[0].kind; let x = const_eval_context.expr(&args[0]); - if let Some(constant) = x; - if let Constant::RawPtr(0) = constant; + if let Some(Constant::RawPtr(0)) = x; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c8bdc5a71e6..74ba53e6a9a 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -738,8 +738,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool { fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option> { if_chain! { if let Some(did) = qpath_res(cx, qpath, id).opt_def_id(); - if let Some(node) = cx.tcx.hir().get_if_local(did); - if let Node::GenericParam(generic_param) = node; + if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did); if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; if synthetic == Some(SyntheticTyParamKind::ImplTrait); then { @@ -1470,8 +1469,7 @@ fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast // don't lint for positive constants let const_val = constant(cx, &cx.typeck_results(), op); if_chain! { - if let Some((const_val, _)) = const_val; - if let Constant::Int(n) = const_val; + if let Some((Constant::Int(n), _)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 6d7c5058b4f..01ffac5b559 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -162,8 +162,7 @@ pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr< if let hir::Block { expr: Some(expr), .. } = &**block; if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind; if let hir::ExprKind::DropTemps(cond) = &cond.kind; - if let [arm, ..] = &arms[..]; - if let hir::Arm { body, .. } = arm; + if let [hir::Arm { body, .. }, ..] = &arms[..]; then { return Some((cond, body)); } -- cgit 1.4.1-3-g733a5 From 70f6a2cae22cc1245ee62ca493f3027a76b3a381 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 13 Nov 2020 12:46:37 -0600 Subject: Eat redundant else dogfood --- clippy_lints/src/functions.rs | 13 +++++-------- clippy_lints/src/len_zero.rs | 3 +-- clippy_lints/src/matches.rs | 5 ++--- clippy_lints/src/methods/unnecessary_filter_map.rs | 5 ++--- clippy_lints/src/non_expressive_names.rs | 7 +++---- 5 files changed, 13 insertions(+), 20 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 8b58d1f2601..fd93548b55c 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -405,13 +405,10 @@ impl<'tcx> Functions { break; } if in_comment { - match line.find("*/") { - Some(i) => { - line = &line[i + 2..]; - in_comment = false; - continue; - }, - None => break, + if let Some(i) = line.find("*/") { + line = &line[i + 2..]; + in_comment = false; + continue; } } else { let multi_idx = line.find("/*").unwrap_or_else(|| line.len()); @@ -423,8 +420,8 @@ impl<'tcx> Functions { in_comment = true; continue; } - break; } + break; } if code_in_line { line_count += 1; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8842901d90b..6fe53351090 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -222,9 +222,8 @@ fn check_impl_items(cx: &LateContext<'_>, item: &Item<'_>, impl_items: &[ImplIte let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) { if cx.access_levels.is_exported(is_empty.id.hir_id) { return; - } else { - "a private" } + "a private" } else { "no corresponding" }; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7d64fa6c262..5c3901e5b28 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -696,10 +696,9 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() { // single statement/expr "else" block, don't lint return; - } else { - // block with 2+ statements or 1 expr and 1+ statement - Some(els) } + // block with 2+ statements or 1 expr and 1+ statement + Some(els) } else { // not a block, don't lint return; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 75e123eb593..d082a88cd2d 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -69,10 +69,9 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } } return (true, false); - } else { - // We don't know. It might do anything. - return (true, true); } + // We don't know. It might do anything. + return (true, true); } } (true, true) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 5b42b61fcde..446426b3e61 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -409,11 +409,10 @@ fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { if let Some(b2) = b_chars.next() { // check if there's just one character inserted return a != b2 || a_chars.ne(b_chars); - } else { - // tuple - // ntuple - return true; } + // tuple + // ntuple + return true; } // for item in items true -- cgit 1.4.1-3-g733a5 From a6bb9276f7964b96899d04d680bc04bf99c8bf47 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 9 Nov 2020 23:38:08 +0100 Subject: Lint wrong self convention in trait also --- clippy_lints/src/methods/mod.rs | 49 ++++++++++++++++++++++++++++++----- tests/ui/wrong_self_convention.rs | 26 +++++++++++++++++++ tests/ui/wrong_self_convention.stderr | 34 +++++++++++++++++++++++- 3 files changed, 101 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8002c27a5e9..3c89c1b6ed2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -22,6 +22,7 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; +use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; @@ -1623,10 +1624,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let item = cx.tcx.hir().expect_item(parent); let def_id = cx.tcx.hir().local_def_id(item.hir_id); let self_ty = cx.tcx.type_of(def_id); + + // if this impl block implements a trait, lint in trait definition instead + if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind { + return; + } + if_chain! { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next(); - if let hir::ItemKind::Impl{ of_trait: None, .. } = item.kind; let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id); let method_sig = cx.tcx.fn_sig(method_def_id); @@ -1697,11 +1703,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - // if this impl block implements a trait, lint in trait definition instead - if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind { - return; - } - if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id); @@ -1735,8 +1736,42 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if in_external_macro(cx.tcx.sess, item.span) { + return; + } + + if_chain! { + if let TraitItemKind::Fn(ref sig, _) = item.kind; + if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); + let first_arg_span = first_arg_ty.span; + let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); + let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); + + then { + if let Some((ref conv, self_kinds)) = &CONVENTIONS + .iter() + .find(|(ref conv, _)| conv.check(&item.ident.name.as_str())) + { + if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { + span_lint( + cx, + WRONG_PUB_SELF_CONVENTION, + first_arg_span, + &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", + conv, + &self_kinds + .iter() + .map(|k| k.description()) + .collect::>() + .join(" or ") + ), + ); + } + } + } + } + if_chain! { - if !in_external_macro(cx.tcx.sess, item.span); if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id); diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index f44305d7e48..275866b8248 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -88,3 +88,29 @@ mod issue4037 { } } } + +// Lint also in trait definition (see #6307) +mod issue6307{ + trait T: Sized { + fn as_i32(self) {} + fn as_u32(&self) {} + fn into_i32(&self) {} + fn into_u32(self) {} + fn is_i32(self) {} + fn is_u32(&self) {} + fn to_i32(self) {} + fn to_u32(&self) {} + fn from_i32(self) {} + // check whether the lint can be allowed at the function level + #[allow(clippy::wrong_pub_self_convention)] + fn from_cake(self) {} + + // test for false positives + fn as_(self) {} + fn into_(&self) {} + fn is_(self) {} + fn to_(self) {} + fn from_(self) {} + fn to_mut(&mut self) {} + } +} \ No newline at end of file diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index ef3ad73ebc7..64aa957fed6 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -72,5 +72,37 @@ error: methods called `from_*` usually take no self; consider choosing a less am LL | pub fn from_i64(self) {} | ^^^^ -error: aborting due to 12 previous errors +error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:95:19 + | +LL | fn as_i32(self) {} + | ^^^^ + | + = note: `-D clippy::wrong-pub-self-convention` implied by `-D warnings` + +error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:97:21 + | +LL | fn into_i32(&self) {} + | ^^^^^ + +error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:99:19 + | +LL | fn is_i32(self) {} + | ^^^^ + +error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:101:19 + | +LL | fn to_i32(self) {} + | ^^^^ + +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name + --> $DIR/wrong_self_convention.rs:103:21 + | +LL | fn from_i32(self) {} + | ^^^^ + +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From 4af9382bec3f49d9c7e0f03e9cfb5e8f1c70fdbe Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 10 Nov 2020 08:56:17 +0100 Subject: Common function to lint wrong self convention from impl and trait def --- clippy_lints/src/methods/mod.rs | 88 +++++++++++++++++------------------ tests/ui/wrong_self_convention.rs | 6 +-- tests/ui/wrong_self_convention.stderr | 2 - 3 files changed, 45 insertions(+), 51 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3c89c1b6ed2..9a082a89229 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1674,32 +1674,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - if let Some((ref conv, self_kinds)) = &CONVENTIONS - .iter() - .find(|(ref conv, _)| conv.check(&name)) - { - if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - let lint = if item.vis.node.is_pub() { - WRONG_PUB_SELF_CONVENTION - } else { - WRONG_SELF_CONVENTION - }; - - span_lint( - cx, - lint, - first_arg.pat.span, - &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, - &self_kinds - .iter() - .map(|k| k.description()) - .collect::>() - .join(" or ") - ), - ); - } - } + lint_wrong_self_convention( + cx, + &name, + item.vis.node.is_pub(), + self_ty, + first_arg_ty, + first_arg.pat.span + ); } } @@ -1748,26 +1730,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); then { - if let Some((ref conv, self_kinds)) = &CONVENTIONS - .iter() - .find(|(ref conv, _)| conv.check(&item.ident.name.as_str())) - { - if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - span_lint( - cx, - WRONG_PUB_SELF_CONVENTION, - first_arg_span, - &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, - &self_kinds - .iter() - .map(|k| k.description()) - .collect::>() - .join(" or ") - ), - ); - } - } + lint_wrong_self_convention(cx, &item.ident.name.as_str(), false, self_ty, first_arg_ty, first_arg_span); } } @@ -1792,6 +1755,39 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } +fn lint_wrong_self_convention<'tcx>( + cx: &LateContext<'tcx>, + item_name: &str, + is_pub: bool, + self_ty: &'tcx TyS<'tcx>, + first_arg_ty: &'tcx TyS<'tcx>, + first_arg_span: Span, +) { + let lint = if is_pub { + WRONG_PUB_SELF_CONVENTION + } else { + WRONG_SELF_CONVENTION + }; + if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) { + if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { + span_lint( + cx, + lint, + first_arg_span, + &format!( + "methods called `{}` usually take {}; consider choosing a less ambiguous name", + conv, + &self_kinds + .iter() + .map(|k| k.description()) + .collect::>() + .join(" or ") + ), + ); + } + } +} + /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] fn lint_or_fun_call<'tcx>( diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 275866b8248..795ba77274c 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -90,7 +90,7 @@ mod issue4037 { } // Lint also in trait definition (see #6307) -mod issue6307{ +mod issue6307 { trait T: Sized { fn as_i32(self) {} fn as_u32(&self) {} @@ -102,7 +102,7 @@ mod issue6307{ fn to_u32(&self) {} fn from_i32(self) {} // check whether the lint can be allowed at the function level - #[allow(clippy::wrong_pub_self_convention)] + #[allow(clippy::wrong_self_convention)] fn from_cake(self) {} // test for false positives @@ -113,4 +113,4 @@ mod issue6307{ fn from_(self) {} fn to_mut(&mut self) {} } -} \ No newline at end of file +} diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 64aa957fed6..289da6f059e 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -77,8 +77,6 @@ error: methods called `as_*` usually take self by reference or self by mutable r | LL | fn as_i32(self) {} | ^^^^ - | - = note: `-D clippy::wrong-pub-self-convention` implied by `-D warnings` error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name --> $DIR/wrong_self_convention.rs:97:21 -- cgit 1.4.1-3-g733a5 From a7cfffef263a8b5a5dadfad0b7f56acd83d02b9b Mon Sep 17 00:00:00 2001 From: suyash458 Date: Sat, 5 Dec 2020 04:59:22 -0800 Subject: add MSRV to more lints specified in #6097 update tests --- clippy_lints/src/checked_conversions.rs | 26 +++++++-- clippy_lints/src/lib.rs | 15 +++--- clippy_lints/src/mem_replace.rs | 27 ++++++++-- clippy_lints/src/methods/mod.rs | 23 ++++++-- clippy_lints/src/missing_const_for_fn.rs | 29 ++++++++-- clippy_lints/src/ranges.rs | 29 +++++++--- clippy_lints/src/redundant_field_names.rs | 25 +++++++-- clippy_lints/src/redundant_static_lifetimes.rs | 26 +++++++-- clippy_lints/src/use_self.rs | 25 +++++++-- tests/ui/min_rust_version_attr.rs | 74 +++++++++++++++++++++++++- tests/ui/min_rust_version_attr.stderr | 51 ++++++++---------- 11 files changed, 282 insertions(+), 68 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 28c1a54d2c5..54bc69e058b 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -6,9 +6,12 @@ use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{meets_msrv, snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; + +const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); declare_clippy_lint! { /// **What it does:** Checks for explicit bounds checking when casting. @@ -39,10 +42,25 @@ declare_clippy_lint! { "`try_from` could replace manual bounds checking when casting" } -declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); +pub struct CheckedConversions { + msrv: Option, +} + +impl CheckedConversions { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { + if !meets_msrv(self.msrv.as_ref(), &CHECKED_CONVERSIONS_MSRV) { + return; + } + let result = if_chain! { if !in_external_macro(cx.sess(), item.span); if let ExprKind::Binary(op, ref left, ref right) = &item.kind; @@ -74,6 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { } } } + + extract_msrv_attr!(LateContext); } /// Searches for a single check from unsigned to _ is done diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a92ae9ed8d9..38a25d22aa2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1003,6 +1003,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); + store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)); + store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv)); + store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv)); + store.register_late_pass(move || box mem_replace::MemReplace::new(msrv)); + store.register_late_pass(move || box ranges::Ranges::new(msrv)); + store.register_late_pass(move || box use_self::UseSelf::new(msrv)); + store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv)); + store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); @@ -1013,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box main_recursion::MainRecursion::default()); store.register_late_pass(|| box lifetimes::Lifetimes); store.register_late_pass(|| box entry::HashMapPass); - store.register_late_pass(|| box ranges::Ranges); store.register_late_pass(|| box types::Casts); let type_complexity_threshold = conf.type_complexity_threshold; store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold)); @@ -1058,7 +1065,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box neg_multiply::NegMultiply); store.register_late_pass(|| box mem_discriminant::MemDiscriminant); store.register_late_pass(|| box mem_forget::MemForget); - store.register_late_pass(|| box mem_replace::MemReplace); store.register_late_pass(|| box arithmetic::Arithmetic::default()); store.register_late_pass(|| box assign_ops::AssignOps); store.register_late_pass(|| box let_if_seq::LetIfSeq); @@ -1080,7 +1086,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box pass_by_ref_or_value); store.register_late_pass(|| box ref_option_ref::RefOptionRef); store.register_late_pass(|| box try_err::TryErr); - store.register_late_pass(|| box use_self::UseSelf); store.register_late_pass(|| box bytecount::ByteCount); store.register_late_pass(|| box infinite_iter::InfiniteIter); store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody); @@ -1106,10 +1111,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); - store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); store.register_late_pass(|| box transmuting_null::TransmutingNull); store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite); - store.register_late_pass(|| box checked_conversions::CheckedConversions); store.register_late_pass(|| box integer_division::IntegerDivision); store.register_late_pass(|| box inherent_to_string::InherentToString); let max_trait_bounds = conf.max_trait_bounds; @@ -1138,7 +1141,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box redundant_else::RedundantElse); store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); - store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); @@ -1178,7 +1180,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); - store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index bb0acecc5a9..19087b02077 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,13 +1,14 @@ use crate::utils::{ - in_macro, match_def_path, match_qpath, paths, snippet, snippet_with_applicability, span_lint_and_help, + in_macro, match_def_path, match_qpath, meets_msrv, paths, snippet, snippet_with_applicability, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; @@ -94,7 +95,7 @@ declare_clippy_lint! { "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`" } -declare_lint_pass!(MemReplace => +impl_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { @@ -224,6 +225,19 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< } } +const MEM_REPLACE_WITH_DEFAULT_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); + +pub struct MemReplace { + msrv: Option, +} + +impl MemReplace { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { @@ -236,8 +250,11 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); - check_replace_with_default(cx, src, dest, expr.span); + if meets_msrv(self.msrv.as_ref(), &MEM_REPLACE_WITH_DEFAULT_MSRV) { + check_replace_with_default(cx, src, dest, expr.span); + } } } } + extract_msrv_attr!(LateContext); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8002c27a5e9..5133f31e0e7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1487,7 +1487,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["expect", ..] => lint_expect(cx, expr, arg_lists[0]), ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { - if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) { + if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) { unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"); } }, @@ -1509,7 +1509,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), - ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]), + ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2733,6 +2733,8 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } } +const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); + /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s /// Return true if lint triggered fn lint_map_unwrap_or_else<'tcx>( @@ -2740,7 +2742,11 @@ fn lint_map_unwrap_or_else<'tcx>( expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>], unwrap_args: &'tcx [hir::Expr<'_>], + msrv: Option<&RustcVersion>, ) -> bool { + if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { + return false; + } // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); @@ -2923,9 +2929,20 @@ fn lint_filter_map<'tcx>( } } +const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); + /// lint use of `filter_map().next()` for `Iterators` -fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { +fn lint_filter_map_next<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + filter_args: &'tcx [hir::Expr<'_>], + msrv: Option<&RustcVersion>, +) { if match_trait_method(cx, expr, &paths::ITERATOR) { + if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { + return; + } + let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find_map(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 38e2ce563ee..6ebeaced62a 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,14 +1,19 @@ use crate::utils::qualify_min_const_fn::is_min_const_fn; -use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method}; +use crate::utils::{ + fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method, +}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; +const MISSING_CONST_FOR_FN_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); + declare_clippy_lint! { /// **What it does:** /// @@ -69,7 +74,18 @@ declare_clippy_lint! { "Lint functions definitions that could be made `const fn`" } -declare_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]); +impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]); + +pub struct MissingConstForFn { + msrv: Option, +} + +impl MissingConstForFn { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn check_fn( @@ -81,6 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, hir_id: HirId, ) { + if !meets_msrv(self.msrv.as_ref(), &MISSING_CONST_FOR_FN_MSRV) { + return; + } + let def_id = cx.tcx.hir().local_def_id(hir_id); if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) { @@ -126,6 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); } } + extract_msrv_attr!(LateContext); } /// Returns true if any of the method parameters is a type that implements `Drop`. The method diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 4b514bbd42c..f9173808089 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -3,9 +3,10 @@ use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::sym; use rustc_span::symbol::Ident; @@ -13,8 +14,8 @@ use std::cmp::Ordering; use crate::utils::sugg::Sugg; use crate::utils::{ - get_parent_expr, is_integer_const, single_segment_path, snippet, snippet_opt, snippet_with_applicability, - span_lint, span_lint_and_sugg, span_lint_and_then, + get_parent_expr, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt, + snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{higher, SpanlessEq}; @@ -160,7 +161,20 @@ declare_clippy_lint! { "manually reimplementing {`Range`, `RangeInclusive`}`::contains`" } -declare_lint_pass!(Ranges => [ +const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); + +pub struct Ranges { + msrv: Option, +} + +impl Ranges { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(Ranges => [ RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE, @@ -175,7 +189,9 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_range_zip_with_len(cx, path, args, expr.span); }, ExprKind::Binary(ref op, ref l, ref r) => { - check_possible_range_contains(cx, op.node, l, r, expr.span); + if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) { + check_possible_range_contains(cx, op.node, l, r, expr.span); + } }, _ => {}, } @@ -184,6 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_inclusive_range_minus_one(cx, expr); check_reversed_empty_range(cx, expr); } + extract_msrv_attr!(LateContext); } fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, span: Span) { diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 2a81170e49e..38dcf7a192c 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,9 +1,12 @@ -use crate::utils::span_lint_and_sugg; +use crate::utils::{meets_msrv, span_lint_and_sugg}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +const REDUNDANT_FIELD_NAMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); declare_clippy_lint! { /// **What it does:** Checks for fields in struct literals where shorthands @@ -33,10 +36,25 @@ declare_clippy_lint! { "checks for fields in struct literals where shorthands could be used" } -declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); +pub struct RedundantFieldNames { + msrv: Option, +} + +impl RedundantFieldNames { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_FIELD_NAMES_MSRV) { + return; + } + if in_external_macro(cx.sess, expr.span) { return; } @@ -64,4 +82,5 @@ impl EarlyLintPass for RedundantFieldNames { } } } + extract_msrv_attr!(EarlyContext); } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 7bbcc67aa2d..fcfa3c12755 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,8 +1,11 @@ -use crate::utils::{snippet, span_lint_and_then}; +use crate::utils::{meets_msrv, snippet, span_lint_and_then}; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +const REDUNDANT_STATIC_LIFETIMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); declare_clippy_lint! { /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime. @@ -29,7 +32,18 @@ declare_clippy_lint! { "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them." } -declare_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); +pub struct RedundantStaticLifetimes { + msrv: Option, +} + +impl RedundantStaticLifetimes { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); impl RedundantStaticLifetimes { // Recursively visit types @@ -84,6 +98,10 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_STATIC_LIFETIMES_MSRV) { + return; + } + if !item.span.from_expansion() { if let ItemKind::Const(_, ref var_type, _) = item.kind { self.visit_type(var_type, cx, "constants have by default a `'static` lifetime"); @@ -96,4 +114,6 @@ impl EarlyLintPass for RedundantStaticLifetimes { } } } + + extract_msrv_attr!(EarlyContext); } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5ac4797680b..3b23f885e08 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -12,11 +12,12 @@ use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_middle::ty::{DefIdTree, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{differing_macro_contexts, span_lint_and_sugg}; +use crate::utils::{differing_macro_contexts, meets_msrv, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for unnecessary repetition of structure name when a @@ -53,7 +54,7 @@ declare_clippy_lint! { "unnecessary structure name repetition whereas `Self` is applicable" } -declare_lint_pass!(UseSelf => [USE_SELF]); +impl_lint_pass!(UseSelf => [USE_SELF]); const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; @@ -157,8 +158,25 @@ fn check_trait_method_impl_decl<'tcx>( } } +const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); + +pub struct UseSelf { + msrv: Option, +} + +impl UseSelf { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + return; + } + if in_external_macro(cx.sess(), item.span) { return; } @@ -204,6 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } } + extract_msrv_attr!(LateContext); } struct UseSelfVisitor<'a, 'tcx> { diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 1026cc40d3b..ac75f5e46c3 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![clippy::msrv = "1.0.0"] -use std::ops::Deref; +use std::ops::{Deref, RangeFrom}; fn option_as_ref_deref() { let mut opt = Some(String::from("123")); @@ -42,12 +42,84 @@ pub fn manual_strip_msrv() { } } +pub fn redundant_fieldnames() { + let start = 0; + let _ = RangeFrom { start: start }; +} + +pub fn redundant_static_lifetime() { + const VAR_ONE: &'static str = "Test constant #1"; +} + +pub fn checked_conversion() { + let value: i64 = 42; + let _ = value <= (u32::max_value() as i64) && value >= 0; + let _ = value <= (u32::MAX as i64) && value >= 0; +} + +pub fn filter_map_next() { + let a = ["1", "lol", "3", "NaN", "5"]; + + #[rustfmt::skip] + let _: Option = vec![1, 2, 3, 4, 5, 6] + .into_iter() + .filter_map(|x| { + if x == 2 { + Some(x * 2) + } else { + None + } + }) + .next(); +} + +pub fn manual_range_contains() { + x >= 8 && x < 12; +} + +pub fn use_self() { + struct Foo {} + + impl Foo { + fn new() -> Foo { + Foo {} + } + fn test() -> Foo { + Foo::new() + } + } +} + +fn replace_with_default() { + let mut s = String::from("foo"); + let _ = std::mem::replace(s, String::default()); +} + +fn map_unwrap_or() { + let opt = Some(1); + + // Check for `option.map(_).unwrap_or(_)` use. + // Single line case. + let _ = opt + .map(|x| x + 1) + // Should lint even though this call is on a separate line. + .unwrap_or(0); +} + fn main() { + filter_map_next(); + checked_conversion(); + redundant_fieldnames(); + redundant_static_lifetime(); option_as_ref_deref(); match_like_matches(); match_same_arms(); match_same_arms2(); manual_strip_msrv(); + manual_range_contains(); + use_self(); + replace_with_default(); + map_unwrap_or(); } mod meets_msrv { diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 3e1af046e7a..d3eafe7312f 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,37 +1,28 @@ -error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:60:24 - | -LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::manual-strip` implied by `-D warnings` -note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:59:9 - | -LL | if s.starts_with("hello, ") { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using the `strip_prefix` method - | -LL | if let Some() = s.strip_prefix("hello, ") { -LL | assert_eq!(.to_uppercase(), "WORLD!"); +error[E0425]: cannot find value `x` in this scope + --> $DIR/min_rust_version_attr.rs:77:5 | +LL | x >= 8 && x < 12; + | ^ not found in this scope -error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:72:24 +error[E0425]: cannot find value `x` in this scope + --> $DIR/min_rust_version_attr.rs:77:15 | -LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); - | ^^^^^^^^^^^^^^^^^^^^ - | -note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:71:9 - | -LL | if s.starts_with("hello, ") { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try using the `strip_prefix` method +LL | x >= 8 && x < 12; + | ^ not found in this scope + +error[E0308]: mismatched types + --> $DIR/min_rust_version_attr.rs:95:31 | -LL | if let Some() = s.strip_prefix("hello, ") { -LL | assert_eq!(.to_uppercase(), "WORLD!"); +LL | let _ = std::mem::replace(s, String::default()); + | ^ + | | + | expected `&mut _`, found struct `std::string::String` + | help: consider mutably borrowing here: `&mut s` | + = note: expected mutable reference `&mut _` + found struct `std::string::String` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From 0b145d688b293a92cd855000f249d83acae53f9d Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Sat, 12 Dec 2020 01:09:30 +0100 Subject: clone_double_ref: print reference type in lint message changelog: clone_double_ref: print the type of the reference in lint message --- clippy_lints/src/methods/mod.rs | 7 +++++-- tests/ui/unnecessary_clone.stderr | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5133f31e0e7..ce234e01a1b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2100,8 +2100,11 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp cx, CLONE_DOUBLE_REF, expr.span, - "using `clone` on a double-reference; \ - this will copy the reference instead of cloning the inner type", + &format!( + "using `clone` on a double-reference; \ + this will copy the reference of type `{}` instead of cloning the inner type", + ty + ), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5ffa6c4fd06..b908d0ce9c1 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -44,7 +44,7 @@ error: using `clone` on a `Copy` type LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); @@ -66,7 +66,7 @@ error: using `clone` on a `Copy` type LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` -error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:89:22 | LL | let _ = &mut encoded.clone(); @@ -81,7 +81,7 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let _ = &mut <&[u8]>::clone(encoded); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:90:18 | LL | let _ = &encoded.clone(); -- cgit 1.4.1-3-g733a5 From b2cb6ffbe3735ef8f137c9a6c1290c4a078793ef Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Sat, 12 Dec 2020 01:23:28 +0100 Subject: clone_on_copy: show the type in the lint message changelog: clone_on_copy: show the type in the lint message --- clippy_lints/src/methods/mod.rs | 16 +++++++++++----- tests/ui/clone_on_copy.stderr | 10 +++++----- tests/ui/unnecessary_clone.stderr | 6 +++--- 3 files changed, 19 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5133f31e0e7..03eaee35fc4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2174,11 +2174,17 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } else { snip = None; } - span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| { - if let Some((text, snip)) = snip { - diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); - } - }); + span_lint_and_then( + cx, + CLONE_ON_COPY, + expr.span, + &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), + |diag| { + if let Some((text, snip)) = snip { + diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); + } + }, + ); } } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index ec2faf4ab40..14a700886a7 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -1,4 +1,4 @@ -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:22:5 | LL | 42.clone(); @@ -6,25 +6,25 @@ LL | 42.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:26:5 | LL | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:29:5 | LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` -error: using `clone` on a `Copy` type +error: using `clone` on type `char` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:35:14 | LL | is_ascii('z'.clone()); | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` -error: using `clone` on a `Copy` type +error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:39:14 | LL | vec.push(42.clone()); diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5ffa6c4fd06..bb2dd998f27 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -30,7 +30,7 @@ error: using `.clone()` on a ref-counted pointer LL | let _: Arc = x.clone(); | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` -error: using `clone` on a `Copy` type +error: using `clone` on type `T` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:40:5 | LL | t.clone(); @@ -38,7 +38,7 @@ LL | t.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on a `Copy` type +error: using `clone` on type `std::option::Option` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); @@ -60,7 +60,7 @@ help: or try being explicit if you are sure, that you want to clone a reference LL | let z: &Vec<_> = <&std::vec::Vec>::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: using `clone` on a `Copy` type +error: using `clone` on type `many_derefs::E` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); -- cgit 1.4.1-3-g733a5 From a6aa0acbeaeb74a50e08bfa2b18df4e22dbd9894 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sun, 13 Dec 2020 06:32:41 +0200 Subject: Fix dogfood errors --- clippy_lints/src/manual_ok_or.rs | 3 ++- clippy_lints/src/methods/mod.rs | 10 +++++----- clippy_lints/src/ref_option_ref.rs | 3 ++- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 5 +++-- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index c99d2e35b94..b97d97ea1a5 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -8,6 +8,7 @@ use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// **What it does:** @@ -51,7 +52,7 @@ impl LateLintPass<'_> for ManualOkOr { if args.len() == 3; let method_receiver = &args[0]; let ty = cx.typeck_results().expr_ty(method_receiver); - if is_type_diagnostic_item(cx, ty, sym!(option_type)); + if is_type_diagnostic_item(cx, ty, sym::option_type); let or_expr = &args[1]; if is_ok_wrapping(cx, &args[2]); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5133f31e0e7..c5eab2a97fe 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1568,7 +1568,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); - if args.len() == 1 && method_call.ident.name == sym!(clone) { + if args.len() == 1 && method_call.ident.name == sym::clone { lint_clone_on_copy(cx, expr, &args[0], self_ty); lint_clone_on_ref_ptr(cx, expr, &args[0]); } @@ -1592,7 +1592,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } }, - ty::Ref(..) if method_call.ident.name == sym!(into_iter) => { + ty::Ref(..) if method_call.ident.name == sym::into_iter => { lint_into_iter(cx, expr, self_ty, *method_span); }, _ => (), @@ -2638,9 +2638,9 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { Some((EXPECT_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { Some((EXPECT_USED, "a Result", "Err")) } else { None @@ -3133,7 +3133,7 @@ fn lint_search_is_some<'tcx>( else if search_method == "find" { let is_string_or_str_slice = |e| { let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); - if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, self_ty, sym::string_type) { true } else { *self_ty.kind() == ty::Str diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index a914a77d48b..803ebada54b 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -2,6 +2,7 @@ use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; use if_chain::if_chain; use rustc_errors::Applicability; @@ -41,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if let Some(res) = last.res; if let Some(def_id) = res.opt_def_id(); - if cx.tcx.is_diagnostic_item(sym!(option_type), def_id); + if cx.tcx.is_diagnostic_item(sym::option_type, def_id); if let Some(ref params) = last_path_segment(qpath).args ; if !params.parenthesized; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 77e79073378..31dd5965473 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -372,7 +372,7 @@ impl LateLintPass<'_> for StringToString { if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; if path.ident.name == sym!(to_string); let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym!(string_type)); + if is_type_diagnostic_item(cx, ty, sym::string_type); then { span_lint_and_help( cx, diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index e763da593d4..5b9a80f92db 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -9,6 +9,7 @@ use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; use rustc_span::Span; declare_clippy_lint! { @@ -82,9 +83,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } } - let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::option_type) { ("Option", &paths::OPTION_SOME) - } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { ("Result", &paths::RESULT_OK) } else { return; -- cgit 1.4.1-3-g733a5 From 7871ebaab9af1fffc3e68bae9f95c9db1e3863e5 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 29 Dec 2020 16:04:31 -0600 Subject: Fix symbol string comparison dogfood --- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 ++-- clippy_lints/src/map_clone.rs | 2 +- clippy_lints/src/map_identity.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/minmax.rs | 4 ++-- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 3 ++- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/unnecessary_sort_by.rs | 2 +- clippy_lints/src/useless_conversion.rs | 4 ++-- clippy_lints/src/utils/attrs.rs | 9 +++++---- clippy_lints/src/utils/hir_utils.rs | 13 ++++++------- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 7 ++++--- 18 files changed, 34 insertions(+), 32 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 3edbe723922..9a00fc535fc 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -399,7 +399,7 @@ fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { if let Some(meta_item) = lint.meta_item(); if meta_item.path.segments.len() > 1; if let tool_name = meta_item.path.segments[0].ident; - if tool_name.as_str() == "clippy"; + if tool_name.name == sym::clippy; let lint_name = meta_item.path.segments.last().unwrap().ident.name; then { return Some(lint_name.as_str()); diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 2e55094d90c..58511c6d57c 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -145,7 +145,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind; - if path.ident.to_string() == "lock"; + if path.ident.as_str() == "lock"; let ty = cx.typeck_results().expr_ty(&args[0]); if is_type_diagnostic_item(cx, ty, sym!(mutex_type)); then { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 29439e52c48..89f5b2ff311 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -9,7 +9,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** It checks for manual implementations of `async` functions. @@ -137,7 +137,7 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t if let Some(args) = segment.args; if args.bindings.len() == 1; let binding = &args.bindings[0]; - if binding.ident.as_str() == "Output"; + if binding.ident.name == sym::Output; if let TypeBindingKind::Equality{ty: output} = binding.kind; then { return Some(output) diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 220240acb7a..1818836d5d5 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if_chain! { if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind; if args.len() == 2; - if method.ident.as_str() == "map"; + if method.ident.name == sym::map; let ty = cx.typeck_results().expr_ty(&args[0]); if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 6b782385a38..9f9c108a85a 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for MapIdentity { fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> { if_chain! { if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; - if args.len() == 2 && method.ident.as_str() == "map"; + if args.len() == 2 && method.ident.name == sym::map; let caller_ty = cx.typeck_results().expr_ty(&args[0]); if match_trait_method(cx, expr, &paths::ITERATOR) || is_type_diagnostic_item(cx, caller_ty, sym::result_type) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e99fe1b97ff..f13f2491d6e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3095,7 +3095,7 @@ fn lint_flat_map_identity<'tcx>( if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; if path.segments.len() == 1; - if path.segments[0].ident.as_str() == binding_ident.as_str(); + if path.segments[0].ident.name == binding_ident.name; then { apply_lint("called `flat_map(|x| x)` on an `Iterator`"); diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 004dd50a31b..8d0c3b8e0fe 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -89,9 +89,9 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons if let [obj, _] = args; if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); then { - if path.ident.as_str() == sym!(max).as_str() { + if path.ident.name == sym!(max) { fetch_const(cx, args, MinMax::Max) - } else if path.ident.as_str() == sym!(min).as_str() { + } else if path.ident.name == sym!(min) { fetch_const(cx, args, MinMax::Min) } else { None diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 27f1074a0dd..0e49eaab436 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -63,7 +63,7 @@ impl MissingDoc { if let Some(meta) = list.get(0); if let Some(name) = meta.ident(); then { - name.as_str() == "include" + name.name == sym::include } else { false } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5043b7b1fc3..1984942a914 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -13,6 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::kw; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; @@ -153,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // Ignore `self`s. if idx == 0 { if let PatKind::Binding(.., ident, _) = arg.pat.kind { - if ident.as_str() == "self" { + if ident.name == kw::SelfLower { continue; } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 681dbce9769..58c00541af7 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -66,7 +66,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); /// Returns true iff the given expression is the result of calling `Result::ok` fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { - path.ident.name.to_ident_string() == "ok" + path.ident.name.as_str() == "ok" && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type) } else { false diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index f8396592678..4ae22468f78 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -389,5 +389,5 @@ fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool { } fn path_eq_name(name: Symbol, path: &Path<'_>) -> bool { - !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.as_str() == name.as_str() + !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.name == name } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 386987eb181..699fd51ccc1 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -91,7 +91,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind; if rhs2.segments.len() == 1; - if ident.as_str() == rhs2.segments[0].ident.as_str(); + if ident.name == rhs2.segments[0].ident.name; if eq_expr_value(cx, tmp_init, lhs1); if eq_expr_value(cx, rhs1, lhs2); then { diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 0bccfc15678..9b45d38afd4 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -183,7 +183,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } ] = &closure_body.params; if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr], _) = &closure_body.value.kind; - if method_path.ident.name.to_ident_string() == "cmp"; + if method_path.ident.name == sym::cmp; then { let (closure_body, closure_arg, reverse) = if mirrored_exprs( &cx, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index efa9c3fab4a..c5334853986 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -80,10 +80,10 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" { + if match_trait_method(cx, e, &paths::INTO_ITERATOR) && name.ident.name == sym::into_iter { if let Some(parent_expr) = get_parent_expr(cx, e) { if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind { - if &*parent_name.ident.as_str() != "into_iter" { + if parent_name.ident.name != sym::into_iter { return; } } diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index 24052a243af..8d28421d70d 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -1,6 +1,7 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_session::Session; +use rustc_span::sym; use std::str::FromStr; /// Deprecation status of attributes known by Clippy. @@ -64,11 +65,11 @@ pub fn get_attr<'a>( return false; }; let attr_segments = &attr.path.segments; - if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" { + if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy { BUILTIN_ATTRIBUTES .iter() - .find_map(|(builtin_name, deprecation_status)| { - if *builtin_name == attr_segments[1].ident.to_string() { + .find_map(|&(builtin_name, ref deprecation_status)| { + if attr_segments[1].ident.name.as_str() == builtin_name { Some(deprecation_status) } else { None @@ -99,7 +100,7 @@ pub fn get_attr<'a>( }, DeprecationStatus::None => { diag.cancel(); - attr_segments[1].ident.to_string() == name + attr_segments[1].ident.name.as_str() == name }, } }, diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index a8fbb2ffaf0..8d8ad497be6 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { lb == rb && l_mut == r_mut && self.eq_expr(le, re) }, (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => { - both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str()) + both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) }, (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => { self.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) @@ -102,7 +102,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { }) }, (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => { - both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str()) + both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) && both(le, re, |l, r| self.eq_expr(l, r)) }, (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r), @@ -121,7 +121,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { }, (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node, (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => { - lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str()) + lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name) }, (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => { ls == rs @@ -188,7 +188,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool { let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right); - li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp) + li.name == ri.name && self.eq_pat(lp, rp) } /// Checks whether two patterns are the same. @@ -202,7 +202,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs }, (&PatKind::Binding(ref lb, .., ref li, ref lp), &PatKind::Binding(ref rb, .., ref ri, ref rp)) => { - lb == rb && li.name.as_str() == ri.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) + lb == rb && li.name == ri.name && both(lp, rp, |l, r| self.eq_pat(l, r)) }, (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r), (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), @@ -263,8 +263,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool { // The == of idents doesn't work with different contexts, // we have to be explicit about hygiene - left.ident.as_str() == right.ident.as_str() - && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r)) + left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r)) } pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 6249d7e867b..e632a7e57ee 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -158,7 +158,7 @@ fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Op ExprKind::Path(QPath::TypeRelative(ty, name)) if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type) => { - if name.ident.name.as_str() == "new" { + if name.ident.name == sym::new { return Some(VecInitKind::New); } else if name.ident.name.as_str() == "with_capacity" { return args.get(0).and_then(|arg| { diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5683a71efea..10005a7fc81 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -7,7 +7,8 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::BytePos; +use rustc_span::symbol::kw; +use rustc_span::{sym, BytePos}; declare_clippy_lint! { /// **What it does:** Checks for `use Enum::*`. @@ -198,12 +199,12 @@ impl WildcardImports { // Allow "...prelude::..::*" imports. // Many crates have a prelude, and it is imported as a glob by design. fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool { - segments.iter().any(|ps| ps.ident.as_str() == "prelude") + segments.iter().any(|ps| ps.ident.name == sym::prelude) } // Allow "super::*" imports in tests. fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool { - segments.len() == 1 && segments[0].ident.as_str() == "super" + segments.len() == 1 && segments[0].ident.name == kw::Super } fn is_test_module_or_function(item: &Item<'_>) -> bool { -- cgit 1.4.1-3-g733a5 From 3269070261e8324c2b3074cd491ddf2ac6cf19d3 Mon Sep 17 00:00:00 2001 From: nahuakang Date: Mon, 11 Jan 2021 23:56:12 +0100 Subject: Create new lint for the usage of inspect for each. --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/inspect_for_each.rs | 23 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 33 ++++++++++++++++++++++++++++ tests/ui/inspect_for_each.rs | 22 +++++++++++++++++++ tests/ui/inspect_for_each.stderr | 16 ++++++++++++++ 6 files changed, 98 insertions(+) create mode 100644 clippy_lints/src/methods/inspect_for_each.rs create mode 100644 tests/ui/inspect_for_each.rs create mode 100644 tests/ui/inspect_for_each.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 64864c2e278..a91b7c64770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1996,6 +1996,7 @@ Released 2018-09-13 [`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax [`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax [`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body +[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f12994c7a60..17662b81205 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -733,6 +733,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::FROM_ITER_INSTEAD_OF_COLLECT, &methods::GET_UNWRAP, &methods::INEFFICIENT_TO_STRING, + &methods::INSPECT_FOR_EACH, &methods::INTO_ITER_ON_REF, &methods::ITERATOR_STEP_BY_ZERO, &methods::ITER_CLONED_COLLECT, @@ -1507,6 +1508,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), + LintId::of(&methods::INSPECT_FOR_EACH), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), @@ -1807,6 +1809,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), + LintId::of(&methods::INSPECT_FOR_EACH), LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs new file mode 100644 index 00000000000..6d41ee38a27 --- /dev/null +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -0,0 +1,23 @@ +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use crate::utils::{match_trait_method, paths, span_lint_and_help}; + +use super::INSPECT_FOR_EACH; + +/// lint use of `inspect().for_each()` for `Iterators` +pub(super) fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + let msg = "called `inspect(..).for_each(..)` on an `Iterator`"; + let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`"; + span_lint_and_help( + cx, + INSPECT_FOR_EACH, + inspect_span.with_hi(expr.span.hi()), + msg, + None, + hint, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f13f2491d6e..018696ef0cf 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,6 @@ mod bind_instead_of_map; mod inefficient_to_string; +mod inspect_for_each; mod manual_saturating_arithmetic; mod option_map_unwrap_or; mod unnecessary_filter_map; @@ -1405,6 +1406,36 @@ declare_clippy_lint! { "use `.collect()` instead of `::from_iter()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `inspect().for_each()`. + /// + /// **Why is this bad?** It is the same as performing the computation + /// inside `inspect` at the beginning of the closure in `for_each`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// [1,2,3,4,5].iter() + /// .inspect(|&x| println!("inspect the number: {}", x)) + /// .for_each(|&x| { + /// assert!(x >= 0); + /// }); + /// ``` + /// Can be written as + /// ```rust + /// [1,2,3,4,5].iter() + /// .for_each(|&x| { + /// println!("inspect the number: {}", x); + /// assert!(x >= 0); + /// }); + /// ``` + pub INSPECT_FOR_EACH, + complexity, + "using `.inspect().for_each()`, which can be replaced with `.for_each()`" +} + pub struct Methods { msrv: Option, } @@ -1467,6 +1498,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_LAZY_EVALUATIONS, MAP_COLLECT_RESULT_UNIT, FROM_ITER_INSTEAD_OF_COLLECT, + INSPECT_FOR_EACH, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1553,6 +1585,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), + ["for_each", "inspect"] => inspect_for_each::lint(cx, expr, method_spans[1]), _ => {}, } diff --git a/tests/ui/inspect_for_each.rs b/tests/ui/inspect_for_each.rs new file mode 100644 index 00000000000..7fe45c83bca --- /dev/null +++ b/tests/ui/inspect_for_each.rs @@ -0,0 +1,22 @@ +#![warn(clippy::inspect_for_each)] + +fn main() { + let a: Vec = vec![1, 2, 3, 4, 5]; + + let mut b: Vec = Vec::new(); + a.into_iter().inspect(|x| assert!(*x > 0)).for_each(|x| { + let y = do_some(x); + let z = do_more(y); + b.push(z); + }); + + assert_eq!(b, vec![4, 5, 6, 7, 8]); +} + +fn do_some(a: usize) -> usize { + a + 1 +} + +fn do_more(a: usize) -> usize { + a + 2 +} diff --git a/tests/ui/inspect_for_each.stderr b/tests/ui/inspect_for_each.stderr new file mode 100644 index 00000000000..9f976bb7458 --- /dev/null +++ b/tests/ui/inspect_for_each.stderr @@ -0,0 +1,16 @@ +error: called `inspect(..).for_each(..)` on an `Iterator` + --> $DIR/inspect_for_each.rs:7:19 + | +LL | a.into_iter().inspect(|x| assert!(*x > 0)).for_each(|x| { + | ___________________^ +LL | | let y = do_some(x); +LL | | let z = do_more(y); +LL | | b.push(z); +LL | | }); + | |______^ + | + = note: `-D clippy::inspect-for-each` implied by `-D warnings` + = help: move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From e89ad4ba71816cbe6fb1f90743d9229fc824b1c0 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 14 Dec 2020 13:50:53 -0600 Subject: Fix comment --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 623554ea2d1..c8b69f4fbae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3059,7 +3059,7 @@ fn lint_filter_map_map<'tcx>( _filter_args: &'tcx [hir::Expr<'_>], _map_args: &'tcx [hir::Expr<'_>], ) { - // lint if caller of `.filter().map()` is an Iterator + // lint if caller of `.filter_map().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter_map(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; -- cgit 1.4.1-3-g733a5 From c92bdc4dbbd777f6933f7990f87066147a629c8d Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 1 Jan 2021 13:00:09 -0600 Subject: Split filter_map into manual_filter_map --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/mod.rs | 109 +++++++++++++++++++++++++++++++++----- tests/ui/filter_methods.stderr | 12 +---- tests/ui/manual_filter_map.fixed | 37 +++++++++++++ tests/ui/manual_filter_map.rs | 37 +++++++++++++ tests/ui/manual_filter_map.stderr | 22 ++++++++ 7 files changed, 198 insertions(+), 23 deletions(-) create mode 100644 tests/ui/manual_filter_map.fixed create mode 100644 tests/ui/manual_filter_map.rs create mode 100644 tests/ui/manual_filter_map.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 04f042b2deb..8feb1a148af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2035,6 +2035,7 @@ Released 2018-09-13 [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn +[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 53764bb7390..bde9c630c6c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -745,6 +745,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::ITER_NTH, &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, + &methods::MANUAL_FILTER_MAP, &methods::MANUAL_SATURATING_ARITHMETIC, &methods::MAP_COLLECT_RESULT_UNIT, &methods::MAP_FLATTEN, @@ -1526,6 +1527,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), + LintId::of(&methods::MANUAL_FILTER_MAP), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), LintId::of(&methods::NEW_RET_NO_SELF), @@ -1823,6 +1825,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INSPECT_FOR_EACH), + LintId::of(&methods::MANUAL_FILTER_MAP), LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c8b69f4fbae..518d2e67ad1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -15,7 +15,8 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{TraitItem, TraitItemKind}; +use rustc_hir::def::Res; +use rustc_hir::{Expr, ExprKind, PatKind, QPath, TraitItem, TraitItemKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; @@ -450,6 +451,32 @@ declare_clippy_lint! { "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.filter(_).map(_)` that can be written more simply + /// as `filter_map(_)`. + /// + /// **Why is this bad?** Redundant code in the `filter` and `map` operations is poor style and + /// less performant. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust + /// (0_i32..10) + /// .filter(|n| n.checked_add(1).is_some()) + /// .map(|n| n.checked_add(1).unwrap()); + /// ``` + /// + /// Good: + /// ```rust + /// (0_i32..10).filter_map(|n| n.checked_add(1)); + /// ``` + pub MANUAL_FILTER_MAP, + complexity, + "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter_map(_).next()`. /// @@ -1473,6 +1500,7 @@ impl_lint_pass!(Methods => [ FILTER_NEXT, SKIP_WHILE_NEXT, FILTER_MAP, + MANUAL_FILTER_MAP, FILTER_MAP_NEXT, FLAT_MAP_IDENTITY, FIND_MAP, @@ -1540,7 +1568,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), - ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), + ["map", "filter"] => lint_filter_map(cx, expr), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2989,17 +3017,72 @@ fn lint_skip_while_next<'tcx>( } /// lint use of `filter().map()` for `Iterators` -fn lint_filter_map<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { - // lint if caller of `.filter().map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(..).map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); +fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; + if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; + if match_trait_method(cx, expr, &paths::ITERATOR); + + // filter(|x| ...is_some())... + if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; + let filter_body = cx.tcx.hir().body(filter_body_id); + if let [filter_param] = filter_body.params; + // optional ref pattern: `filter(|&x| ..)` + let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + }; + // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; + if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind; + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) { + Some(false) + } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) { + Some(true) + } else { + None + }; + if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + + // ...map(|x| ...unwrap()) + if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind; + let map_body = cx.tcx.hir().body(map_body_id); + if let [map_param] = map_body.params; + if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + // closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind; + if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::UnDeref, expr_path) = a.kind; + then { expr_path } else { a } + }; + // let the filter closure arg and the map closure arg be equal + if_chain! { + if let ExprKind::Path(QPath::Resolved(None, a_path)) = a_path.kind; + if let ExprKind::Path(QPath::Resolved(None, b_path)) = b.kind; + if a_path.res == Res::Local(filter_param_id); + if b_path.res == Res::Local(map_param_id); + if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); + then { + return true; + } + } + false + }; + if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); + then { + let span = filter_span.to(map_span); + let msg = "`filter(..).map(..)` can be simplified as `filter_map(..)`"; + let to_opt = if is_result { ".ok()" } else { "" }; + let sugg = format!("filter_map(|{}| {}{})", map_param_ident, snippet(cx, map_arg.span, ".."), to_opt); + span_lint_and_sugg(cx, MANUAL_FILTER_MAP, span, msg, "try", sugg, Applicability::MachineApplicable); + } } } diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 11922681379..c7b4f28be3a 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,12 +1,3 @@ -error: called `filter(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:6:21 - | -LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::filter-map` implied by `-D warnings` - = help: this is more succinctly expressed by calling `.filter_map(..)` instead - error: called `filter(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:8:21 | @@ -17,6 +8,7 @@ LL | | .filter(|&x| x == 0) LL | | .flat_map(|x| x.checked_mul(2)) | |_______________________________________^ | + = note: `-D clippy::filter-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` error: called `filter_map(..).flat_map(..)` on an `Iterator` @@ -43,5 +35,5 @@ LL | | .map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by only calling `.filter_map(..)` instead -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed new file mode 100644 index 00000000000..fc8f58f8ea5 --- /dev/null +++ b/tests/ui/manual_filter_map.fixed @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] +#![warn(clippy::manual_filter_map)] +#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure + +fn main() { + // is_some(), unwrap() + let _ = (0..).filter_map(|a| to_opt(a)); + + // ref pattern, expect() + let _ = (0..).filter_map(|a| to_opt(a)); + + // is_ok(), unwrap_or() + let _ = (0..).filter_map(|a| to_res(a).ok()); +} + +fn no_lint() { + // no shared code + let _ = (0..).filter(|n| *n > 1).map(|n| n + 1); + + // very close but different since filter() provides a reference + let _ = (0..).filter(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap()); + + // similar but different + let _ = (0..).filter(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap()); + let _ = (0..) + .filter(|n| to_opt(n).map(|n| n + 1).is_some()) + .map(|a| to_opt(a).unwrap()); +} + +fn to_opt(_: T) -> Option { + unimplemented!() +} + +fn to_res(_: T) -> Result { + unimplemented!() +} diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs new file mode 100644 index 00000000000..3af4bbee3bf --- /dev/null +++ b/tests/ui/manual_filter_map.rs @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] +#![warn(clippy::manual_filter_map)] +#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure + +fn main() { + // is_some(), unwrap() + let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + + // ref pattern, expect() + let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + + // is_ok(), unwrap_or() + let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); +} + +fn no_lint() { + // no shared code + let _ = (0..).filter(|n| *n > 1).map(|n| n + 1); + + // very close but different since filter() provides a reference + let _ = (0..).filter(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap()); + + // similar but different + let _ = (0..).filter(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap()); + let _ = (0..) + .filter(|n| to_opt(n).map(|n| n + 1).is_some()) + .map(|a| to_opt(a).unwrap()); +} + +fn to_opt(_: T) -> Option { + unimplemented!() +} + +fn to_res(_: T) -> Result { + unimplemented!() +} diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr new file mode 100644 index 00000000000..4d4e2d5c12f --- /dev/null +++ b/tests/ui/manual_filter_map.stderr @@ -0,0 +1,22 @@ +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:8:19 + | +LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` + | + = note: `-D clippy::manual-filter-map` implied by `-D warnings` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:11:19 + | +LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:14:19 + | +LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From a752d31e0a8cd8c7d8549daf421a8b791d1325a4 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 14 Jan 2021 16:36:36 -0600 Subject: Replace find_map with manual_find_map --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/mod.rs | 64 ++++++++++++++++++++++++++--------------- tests/ui/find_map.stderr | 26 ----------------- tests/ui/manual_find_map.fixed | 37 ++++++++++++++++++++++++ tests/ui/manual_find_map.rs | 37 ++++++++++++++++++++++++ tests/ui/manual_find_map.stderr | 22 ++++++++++++++ 7 files changed, 141 insertions(+), 49 deletions(-) delete mode 100644 tests/ui/find_map.stderr create mode 100644 tests/ui/manual_find_map.fixed create mode 100644 tests/ui/manual_find_map.rs create mode 100644 tests/ui/manual_find_map.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 8feb1a148af..7f2de888d35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2036,6 +2036,7 @@ Released 2018-09-13 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map +[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bde9c630c6c..b22ddfacf86 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -746,6 +746,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, &methods::MANUAL_FILTER_MAP, + &methods::MANUAL_FIND_MAP, &methods::MANUAL_SATURATING_ARITHMETIC, &methods::MAP_COLLECT_RESULT_UNIT, &methods::MAP_FLATTEN, @@ -1528,6 +1529,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_FILTER_MAP), + LintId::of(&methods::MANUAL_FIND_MAP), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), LintId::of(&methods::NEW_RET_NO_SELF), @@ -1826,6 +1828,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INSPECT_FOR_EACH), LintId::of(&methods::MANUAL_FILTER_MAP), + LintId::of(&methods::MANUAL_FIND_MAP), LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 518d2e67ad1..9d078588746 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -477,6 +477,32 @@ declare_clippy_lint! { "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.find(_).map(_)` that can be written more simply + /// as `find_map(_)`. + /// + /// **Why is this bad?** Redundant code in the `find` and `map` operations is poor style and + /// less performant. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust + /// (0_i32..10) + /// .find(|n| n.checked_add(1).is_some()) + /// .map(|n| n.checked_add(1).unwrap()); + /// ``` + /// + /// Good: + /// ```rust + /// (0_i32..10).find_map(|n| n.checked_add(1)); + /// ``` + pub MANUAL_FIND_MAP, + complexity, + "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter_map(_).next()`. /// @@ -1501,6 +1527,7 @@ impl_lint_pass!(Methods => [ SKIP_WHILE_NEXT, FILTER_MAP, MANUAL_FILTER_MAP, + MANUAL_FIND_MAP, FILTER_MAP_NEXT, FLAT_MAP_IDENTITY, FIND_MAP, @@ -1568,10 +1595,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), - ["map", "filter"] => lint_filter_map(cx, expr), + ["map", "filter"] => lint_filter_map(cx, expr, false), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), - ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), + ["map", "find"] => lint_filter_map(cx, expr, true), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]), @@ -3016,12 +3043,12 @@ fn lint_skip_while_next<'tcx>( } } -/// lint use of `filter().map()` for `Iterators` -fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { +/// lint use of `filter().map()` or `find().map()` for `Iterators` +fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) { if_chain! { if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; - if match_trait_method(cx, expr, &paths::ITERATOR); + if match_trait_method(cx, map_recv, &paths::ITERATOR); // filter(|x| ...is_some())... if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; @@ -3078,10 +3105,16 @@ fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); then { let span = filter_span.to(map_span); - let msg = "`filter(..).map(..)` can be simplified as `filter_map(..)`"; + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) + } else { + ("filter", MANUAL_FILTER_MAP) + }; + let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name); let to_opt = if is_result { ".ok()" } else { "" }; - let sugg = format!("filter_map(|{}| {}{})", map_param_ident, snippet(cx, map_arg.span, ".."), to_opt); - span_lint_and_sugg(cx, MANUAL_FILTER_MAP, span, msg, "try", sugg, Applicability::MachineApplicable); + let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident, + snippet(cx, map_arg.span, ".."), to_opt); + span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); } } } @@ -3120,21 +3153,6 @@ fn lint_filter_map_next<'tcx>( } } -/// lint use of `find().map()` for `Iterators` -fn lint_find_map<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _find_args: &'tcx [hir::Expr<'_>], - map_args: &'tcx [hir::Expr<'_>], -) { - // lint if caller of `.filter().map()` is an Iterator - if match_trait_method(cx, &map_args[0], &paths::ITERATOR) { - let msg = "called `find(..).map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by calling `.find_map(..)` instead"; - span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint); - } -} - /// lint use of `filter_map().map()` for `Iterators` fn lint_filter_map_map<'tcx>( cx: &LateContext<'tcx>, diff --git a/tests/ui/find_map.stderr b/tests/ui/find_map.stderr deleted file mode 100644 index aea3cc62afc..00000000000 --- a/tests/ui/find_map.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: called `find(..).map(..)` on an `Iterator` - --> $DIR/find_map.rs:20:26 - | -LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s| s.parse().unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::find-map` implied by `-D warnings` - = help: this is more succinctly expressed by calling `.find_map(..)` instead - -error: called `find(..).map(..)` on an `Iterator` - --> $DIR/find_map.rs:23:29 - | -LL | let _: Option = desserts_of_the_week - | _____________________________^ -LL | | .iter() -LL | | .find(|dessert| match *dessert { -LL | | Dessert::Cake(_) => true, -... | -LL | | _ => unreachable!(), -LL | | }); - | |__________^ - | - = help: this is more succinctly expressed by calling `.find_map(..)` instead - -error: aborting due to 2 previous errors - diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed new file mode 100644 index 00000000000..95e97c4fd1f --- /dev/null +++ b/tests/ui/manual_find_map.fixed @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] +#![warn(clippy::manual_find_map)] +#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure + +fn main() { + // is_some(), unwrap() + let _ = (0..).find_map(|a| to_opt(a)); + + // ref pattern, expect() + let _ = (0..).find_map(|a| to_opt(a)); + + // is_ok(), unwrap_or() + let _ = (0..).find_map(|a| to_res(a).ok()); +} + +fn no_lint() { + // no shared code + let _ = (0..).filter(|n| *n > 1).map(|n| n + 1); + + // very close but different since filter() provides a reference + let _ = (0..).find(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap()); + + // similar but different + let _ = (0..).find(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap()); + let _ = (0..) + .find(|n| to_opt(n).map(|n| n + 1).is_some()) + .map(|a| to_opt(a).unwrap()); +} + +fn to_opt(_: T) -> Option { + unimplemented!() +} + +fn to_res(_: T) -> Result { + unimplemented!() +} diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs new file mode 100644 index 00000000000..cd3c82e3b25 --- /dev/null +++ b/tests/ui/manual_find_map.rs @@ -0,0 +1,37 @@ +// run-rustfix +#![allow(dead_code)] +#![warn(clippy::manual_find_map)] +#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure + +fn main() { + // is_some(), unwrap() + let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + + // ref pattern, expect() + let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + + // is_ok(), unwrap_or() + let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); +} + +fn no_lint() { + // no shared code + let _ = (0..).filter(|n| *n > 1).map(|n| n + 1); + + // very close but different since filter() provides a reference + let _ = (0..).find(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap()); + + // similar but different + let _ = (0..).find(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap()); + let _ = (0..) + .find(|n| to_opt(n).map(|n| n + 1).is_some()) + .map(|a| to_opt(a).unwrap()); +} + +fn to_opt(_: T) -> Option { + unimplemented!() +} + +fn to_res(_: T) -> Result { + unimplemented!() +} diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr new file mode 100644 index 00000000000..9e7f798df45 --- /dev/null +++ b/tests/ui/manual_find_map.stderr @@ -0,0 +1,22 @@ +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:8:19 + | +LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` + | + = note: `-D clippy::manual-find-map` implied by `-D warnings` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:11:19 + | +LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:14:19 + | +LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 82bab19a0105ff86176b79a5eae7a9ea7d300cb9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 14 Jan 2021 16:47:22 -0600 Subject: Deprecate find_map lint --- clippy_lints/src/deprecated_lints.rs | 5 +++++ clippy_lints/src/lib.rs | 6 ++++-- clippy_lints/src/methods/mod.rs | 23 ----------------------- 3 files changed, 9 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index bec0c9f93a0..ea386237f20 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -166,3 +166,8 @@ declare_deprecated_lint! { pub PANIC_PARAMS, "this lint has been uplifted to rustc and is now called `panic_fmt`" } + +declare_deprecated_lint! { + pub FIND_MAP, + "this lint is replaced by `manual_find_map`, a more specific lint" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b22ddfacf86..7097812e088 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -505,6 +505,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::panic_params", "this lint has been uplifted to rustc and is now called `panic_fmt`", ); + store.register_removed( + "clippy::find_map", + "this lint is replaced by `manual_find_map`, a more specific lint", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -732,7 +736,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::FILTER_MAP, &methods::FILTER_MAP_NEXT, &methods::FILTER_NEXT, - &methods::FIND_MAP, &methods::FLAT_MAP_IDENTITY, &methods::FROM_ITER_INSTEAD_OF_COLLECT, &methods::GET_UNWRAP, @@ -1333,7 +1336,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), - LintId::of(&methods::FIND_MAP), LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::MAP_FLATTEN), LintId::of(&methods::MAP_UNWRAP_OR), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9d078588746..7a459a440ca 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -547,28 +547,6 @@ declare_clippy_lint! { "call to `flat_map` where `flatten` is sufficient" } -declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.find(_).map(_)`. - /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.find_map(_)`. - /// - /// **Known problems:** Often requires a condition + Option/Iterator creation - /// inside the closure. - /// - /// **Example:** - /// ```rust - /// (0..3).find(|x| *x == 2).map(|x| x * 2); - /// ``` - /// Can be written as - /// ```rust - /// (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None }); - /// ``` - pub FIND_MAP, - pedantic, - "using a combination of `find` and `map` can usually be written as a single method call" -} - declare_clippy_lint! { /// **What it does:** Checks for an iterator or string search (such as `find()`, /// `position()`, or `rposition()`) followed by a call to `is_some()`. @@ -1530,7 +1508,6 @@ impl_lint_pass!(Methods => [ MANUAL_FIND_MAP, FILTER_MAP_NEXT, FLAT_MAP_IDENTITY, - FIND_MAP, MAP_FLATTEN, ITERATOR_STEP_BY_ZERO, ITER_NEXT_SLICE, -- cgit 1.4.1-3-g733a5 From 7825bf36d8dfee0099a23eb74451783da3ce261f Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 31 Jan 2021 21:43:35 +0100 Subject: Fix suggestions that need parens --- clippy_lints/src/methods/mod.rs | 9 +++++++-- tests/ui/from_iter_instead_of_collect.rs | 8 +++++++- tests/ui/from_iter_instead_of_collect.stderr | 14 +++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7a459a440ca..f53b2f67d1d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4094,14 +4094,19 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); then { // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); + let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); + let sugg = if higher::range(&args[0]).is_some() { + format!("{}.collect::<{}>()", iter_expr, ty) + } else { + format!("{}.collect()", iter_expr) + }; span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, "usage of `FromIterator::from_iter`", "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), + sugg, Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 045eb3133d3..6c81366c4df 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,6 +1,6 @@ #![warn(clippy::from_iter_instead_of_collect)] -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::iter::FromIterator; fn main() { @@ -10,4 +10,10 @@ fn main() { HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); Vec::from_iter(vec![42u32]); + + let a = vec![0, 1, 2]; + assert_eq!(a, Vec::from_iter(0..3)); + + let mut b = VecDeque::from_iter(0..3); + b.push_back(4); } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 46bdc2f4e19..e2161dd3b57 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -12,5 +12,17 @@ error: usage of `FromIterator::from_iter` LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` -error: aborting due to 2 previous errors +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:15:19 + | +LL | assert_eq!(a, Vec::from_iter(0..3)); + | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:17:17 + | +LL | let mut b = VecDeque::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 233fe11ce9711a3652141fbe7e9191314fd701d5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 4 Feb 2021 19:08:08 +0100 Subject: Set turbofish for every sugg and add more test cases --- clippy_lints/src/methods/mod.rs | 6 +--- tests/ui/from_iter_instead_of_collect.fixed | 34 ++++++++++++++++++++++ tests/ui/from_iter_instead_of_collect.rs | 21 ++++++++++++-- tests/ui/from_iter_instead_of_collect.stderr | 42 ++++++++++++++++++++++------ 4 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 tests/ui/from_iter_instead_of_collect.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f53b2f67d1d..3e356afa2a4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4095,11 +4095,7 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< then { // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let sugg = if higher::range(&args[0]).is_some() { - format!("{}.collect::<{}>()", iter_expr, ty) - } else { - format!("{}.collect()", iter_expr) - }; + let sugg = format!("{}.collect::<{}>()", iter_expr, ty); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed new file mode 100644 index 00000000000..96701e86395 --- /dev/null +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -0,0 +1,34 @@ +// run-rustfix + +#![warn(clippy::from_iter_instead_of_collect)] +#![allow(unused_imports)] + +use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; +use std::iter::FromIterator; + +fn main() { + let iter_expr = std::iter::repeat(5).take(5); + let _ = iter_expr.collect::>(); + + let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); + + Vec::from_iter(vec![42u32]); + + let a = vec![0, 1, 2]; + assert_eq!(a, (0..3).collect::>()); + + let mut b = (0..3).collect::>(); + b.push_back(4); + + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; + let bm = values.iter().cloned().collect::>(); + let mut bar = bm.range(0..2).collect::>(); + bar.insert(&4, &'e'); + + let mut bts = (0..3).collect::>(); + bts.insert(2); + { + use std::collections; + let _ = (0..3).collect::>(); + } +} diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 6c81366c4df..211f57bc537 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,13 +1,16 @@ +// run-rustfix + #![warn(clippy::from_iter_instead_of_collect)] +#![allow(unused_imports)] -use std::collections::{HashMap, VecDeque}; +use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; fn main() { let iter_expr = std::iter::repeat(5).take(5); - Vec::from_iter(iter_expr); + let _ = Vec::from_iter(iter_expr); - HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); Vec::from_iter(vec![42u32]); @@ -16,4 +19,16 @@ fn main() { let mut b = VecDeque::from_iter(0..3); b.push_back(4); + + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; + let bm = BTreeMap::from_iter(values.iter().cloned()); + let mut bar = BTreeMap::from_iter(bm.range(0..2)); + bar.insert(&4, &'e'); + + let mut bts = BTreeSet::from_iter(0..3); + bts.insert(2); + { + use std::collections; + let _ = collections::BTreeSet::from_iter(0..3); + } } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index e2161dd3b57..336e25a8adf 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,28 +1,52 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:8:5 + --> $DIR/from_iter_instead_of_collect.rs:11:13 | -LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()` +LL | let _ = Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:10:5 + --> $DIR/from_iter_instead_of_collect.rs:13:13 | -LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` +LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:15:19 + --> $DIR/from_iter_instead_of_collect.rs:18:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:17:17 + --> $DIR/from_iter_instead_of_collect.rs:20:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` -error: aborting due to 4 previous errors +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:24:14 + | +LL | let bm = BTreeMap::from_iter(values.iter().cloned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:25:19 + | +LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:28:19 + | +LL | let mut bts = BTreeSet::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:32:17 + | +LL | let _ = collections::BTreeSet::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 56f7fbb4ae67041fc1d2474da7fe52f5a2fd25a8 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 1 Feb 2021 19:22:31 -0600 Subject: Cleanup path to local checks --- clippy_lints/src/collapsible_match.rs | 22 ++- clippy_lints/src/eval_order_dependence.rs | 60 +++----- clippy_lints/src/functions.rs | 35 +++-- clippy_lints/src/let_if_seq.rs | 17 +-- clippy_lints/src/loops.rs | 168 +++++++-------------- clippy_lints/src/manual_ok_or.rs | 9 +- clippy_lints/src/manual_unwrap_or.rs | 8 +- clippy_lints/src/matches.rs | 15 +- clippy_lints/src/methods/mod.rs | 43 +++--- clippy_lints/src/methods/unnecessary_filter_map.rs | 14 +- clippy_lints/src/to_string_in_display.rs | 11 +- clippy_lints/src/utils/mod.rs | 29 +++- clippy_lints/src/utils/usage.rs | 34 +---- clippy_lints/src/utils/visitors.rs | 16 +- 14 files changed, 180 insertions(+), 301 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 604ba102046..834f294283e 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -1,10 +1,10 @@ use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{span_lint_and_then, SpanlessEq}; +use crate::utils::{path_to_local, span_lint_and_then, SpanlessEq}; use if_chain::if_chain; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{DefIdTree, TyCtxt}; +use rustc_middle::ty::{DefIdTree, TyCtxt, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{MultiSpan, Span}; @@ -72,7 +72,7 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { if arms_inner.iter().all(|arm| arm.guard.is_none()); // match expression must be a local binding // match { .. } - if let Some(binding_id) = addr_adjusted_binding(expr_in, cx); + if let Some(binding_id) = path_to_local(strip_ref_operators(expr_in, cx.typeck_results())); // one of the branches must be "wild-like" if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx)); let (wild_inner_arm, non_wild_inner_arm) = @@ -175,19 +175,15 @@ fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool { false } -/// Retrieves a binding ID with optional `&` and/or `*` operators removed. (e.g. `&**foo`) -/// Returns `None` if a non-reference type is de-referenced. -/// For example, if `Vec` is de-referenced to a slice, `None` is returned. -fn addr_adjusted_binding(mut expr: &Expr<'_>, cx: &LateContext<'_>) -> Option { +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. +fn strip_ref_operators<'hir>(mut expr: &'hir Expr<'hir>, typeck_results: &TypeckResults<'_>) -> &'hir Expr<'hir> { loop { match expr.kind { ExprKind::AddrOf(_, _, e) => expr = e, - ExprKind::Path(QPath::Resolved(None, path)) => match path.res { - Res::Local(binding_id) => break Some(binding_id), - _ => break None, - }, - ExprKind::Unary(UnOp::UnDeref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e, - _ => break None, + ExprKind::Unary(UnOp::UnDeref, e) if typeck_results.expr_ty(e).is_ref() => expr = e, + _ => break, } } + expr } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index bc2b2904698..83cee11c3a8 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,7 +1,6 @@ -use crate::utils::{get_parent_expr, span_lint, span_lint_and_note}; -use if_chain::if_chain; +use crate::utils::{get_parent_expr, path_to_local, path_to_local_id, span_lint, span_lint_and_note}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{def, BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, QPath, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; @@ -72,20 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { // Find a write to a local variable. match expr.kind { ExprKind::Assign(ref lhs, ..) | ExprKind::AssignOp(_, ref lhs, _) => { - if let ExprKind::Path(ref qpath) = lhs.kind { - if let QPath::Resolved(_, ref path) = *qpath { - if path.segments.len() == 1 { - if let def::Res::Local(var) = cx.qpath_res(qpath, lhs.hir_id) { - let mut visitor = ReadVisitor { - cx, - var, - write_expr: expr, - last_expr: expr, - }; - check_for_unsequenced_reads(&mut visitor); - } - } - } + if let Some(var) = path_to_local(lhs) { + let mut visitor = ReadVisitor { + cx, + var, + write_expr: expr, + last_expr: expr, + }; + check_for_unsequenced_reads(&mut visitor); } }, _ => {}, @@ -304,27 +297,20 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { return; } - match expr.kind { - ExprKind::Path(ref qpath) => { - if_chain! { - if let QPath::Resolved(None, ref path) = *qpath; - if path.segments.len() == 1; - if let def::Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id); - if local_id == self.var; - // Check that this is a read, not a write. - if !is_in_assignment_position(self.cx, expr); - then { - span_lint_and_note( - self.cx, - EVAL_ORDER_DEPENDENCE, - expr.span, - "unsequenced read of a variable", - Some(self.write_expr.span), - "whether read occurs before this write depends on evaluation order" - ); - } - } + if path_to_local_id(expr, self.var) { + // Check that this is a read, not a write. + if !is_in_assignment_position(self.cx, expr) { + span_lint_and_note( + self.cx, + EVAL_ORDER_DEPENDENCE, + expr.span, + "unsequenced read of a variable", + Some(self.write_expr.span), + "whether read occurs before this write depends on evaluation order", + ); } + } + match expr.kind { // We're about to descend a closure. Since we don't know when (or // if) the closure will be evaluated, any reads in it might not // occur here (or ever). Like above, bail to avoid false positives. diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 87954254610..8344d974728 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,7 +1,7 @@ use crate::utils::{ attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats, - last_path_segment, match_def_path, must_use_attr, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, + last_path_segment, match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint, + span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, }; use if_chain::if_chain; use rustc_ast::ast::Attribute; @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit; -use rustc_hir::{def::Res, def_id::DefId}; +use rustc_hir::{def::Res, def_id::DefId, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; @@ -658,16 +658,14 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { fn check_arg(&self, ptr: &hir::Expr<'_>) { - if let hir::ExprKind::Path(ref qpath) = ptr.kind { - if let Res::Local(id) = self.cx.qpath_res(qpath, ptr.hir_id) { - if self.ptrs.contains(&id) { - span_lint( - self.cx, - NOT_UNSAFE_PTR_ARG_DEREF, - ptr.span, - "this public function dereferences a raw pointer but is not marked `unsafe`", - ); - } + if let Some(id) = path_to_local(ptr) { + if self.ptrs.contains(&id) { + span_lint( + self.cx, + NOT_UNSAFE_PTR_ARG_DEREF, + ptr.span, + "this public function dereferences a raw pointer but is not marked `unsafe`", + ); } } } @@ -698,7 +696,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { arg.span, &mut tys, ) - && is_mutated_static(self.cx, arg) + && is_mutated_static(arg) { self.mutates_static = true; return; @@ -707,7 +705,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => { - self.mutates_static |= is_mutated_static(self.cx, target) + self.mutates_static |= is_mutated_static(target) }, _ => {}, } @@ -718,12 +716,13 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } } -fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { +fn is_mutated_static(e: &hir::Expr<'_>) -> bool { use hir::ExprKind::{Field, Index, Path}; match e.kind { - Path(ref qpath) => !matches!(cx.qpath_res(qpath, e.hir_id), Res::Local(_)), - Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner), + Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), + Path(_) => true, + Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(inner), _ => false, } } diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 5886c2360e3..6beaa51729a 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,8 +1,7 @@ -use crate::utils::{snippet, span_lint_and_then, visitors::LocalUsedVisitor}; +use crate::utils::{path_to_local_id, snippet, span_lint_and_then, visitors::LocalUsedVisitor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::BindingAnnotation; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -66,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind; if !LocalUsedVisitor::new(canonical_id).check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; - if let Some(value) = check_assign(cx, canonical_id, &*then); + if let Some(value) = check_assign(canonical_id, &*then); if !LocalUsedVisitor::new(canonical_id).check_expr(value); then { let span = stmt.span.to(if_.span); @@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let (default_multi_stmts, default) = if let Some(ref else_) = *else_ { if let hir::ExprKind::Block(ref else_, _) = else_.kind { - if let Some(default) = check_assign(cx, canonical_id, else_) { + if let Some(default) = check_assign(canonical_id, else_) { (else_.stmts.len() > 1, default) } else if let Some(ref default) = local.init { (true, &**default) @@ -134,19 +133,13 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { } } -fn check_assign<'tcx>( - cx: &LateContext<'tcx>, - decl: hir::HirId, - block: &'tcx hir::Block<'_>, -) -> Option<&'tcx hir::Expr<'tcx>> { +fn check_assign<'tcx>(decl: hir::HirId, block: &'tcx hir::Block<'_>) -> Option<&'tcx hir::Expr<'tcx>> { if_chain! { if block.expr.is_none(); if let Some(expr) = block.stmts.iter().last(); if let hir::StmtKind::Semi(ref expr) = expr.kind; if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind; - if let hir::ExprKind::Path(ref qpath) = var.kind; - if let Res::Local(local_id) = cx.qpath_res(qpath, var.hir_id); - if decl == local_id; + if path_to_local_id(var, decl); then { let mut v = LocalUsedVisitor::new(decl); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 663c2df23e2..d202072e920 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,14 +1,13 @@ use crate::consts::constant; -use crate::utils::paths; use crate::utils::sugg::Sugg; -use crate::utils::usage::{is_unused, mutated_variables}; +use crate::utils::usage::mutated_variables; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_ok_ctor, is_refutable, is_some_ctor, - is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, - single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, + is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, multispan_sugg, path_to_local, + path_to_local_id, paths, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -877,21 +876,6 @@ fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { } } -fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool { - if_chain! { - if let ExprKind::Path(qpath) = &expr.kind; - if let QPath::Resolved(None, path) = qpath; - if path.segments.len() == 1; - if let Res::Local(local_id) = cx.qpath_res(qpath, expr.hir_id); - then { - // our variable! - local_id == var - } else { - false - } - } -} - /// a wrapper of `Sugg`. Besides what `Sugg` do, this removes unnecessary `0`; /// and also, it avoids subtracting a variable from the same one by replacing it with `0`. /// it exists for the convenience of the overloaded operators while normal functions can do the @@ -1044,14 +1028,9 @@ fn get_details_from_idx<'tcx>( idx: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option<(StartKind<'tcx>, Offset)> { - fn get_start<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { - starts.iter().find_map(|start| { - if same_var(cx, e, start.id) { - Some(start.kind) - } else { - None - } - }) + fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { + let id = path_to_local(e)?; + starts.iter().find(|start| start.id == id).map(|start| start.kind) } fn get_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { @@ -1060,7 +1039,7 @@ fn get_details_from_idx<'tcx>( ast::LitKind::Int(x, _ty) => Some(Sugg::NonParen(x.to_string().into())), _ => None, }, - ExprKind::Path(..) if get_start(cx, e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), + ExprKind::Path(..) if get_start(e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), _ => None, } } @@ -1068,18 +1047,18 @@ fn get_details_from_idx<'tcx>( match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = get_start(cx, lhs, starts) + let offset_opt = get_start(lhs, starts) .and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o))) - .or_else(|| get_start(cx, rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); + .or_else(|| get_start(rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); offset_opt.map(|(s, o)| (s, Offset::positive(o))) }, BinOpKind::Sub => { - get_start(cx, lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) + get_start(lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) }, _ => None, }, - ExprKind::Path(..) => get_start(cx, idx, starts).map(|s| (s, Offset::empty())), + ExprKind::Path(..) => get_start(idx, starts).map(|s| (s, Offset::empty())), _ => None, } } @@ -1096,11 +1075,10 @@ fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx /// The returned iterator yields `None` if no assignment expressions are there, /// filtering out the increments of the given whitelisted loop counters; /// because its job is to make sure there's nothing other than assignments and the increments. -fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( - cx: &'a LateContext<'tcx>, +fn get_assignments<'a, 'tcx>( Block { stmts, expr, .. }: &'tcx Block<'tcx>, - loop_counters: &'c [Start<'tcx>], -) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'c { + loop_counters: &'a [Start<'tcx>], +) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'a { // As the `filter` and `map` below do different things, I think putting together // just increases complexity. (cc #3188 and #4193) stmts @@ -1112,12 +1090,14 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( .chain((*expr).into_iter()) .filter(move |e| { if let ExprKind::AssignOp(_, place, _) = e.kind { - !loop_counters - .iter() - // skip the first item which should be `StartKind::Range` - // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. - .skip(1) - .any(|counter| same_var(cx, place, counter.id)) + path_to_local(place).map_or(false, |id| { + !loop_counters + .iter() + // skip the first item which should be `StartKind::Range` + // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. + .skip(1) + .any(|counter| counter.id == id) + }) } else { true } @@ -1174,7 +1154,7 @@ fn build_manual_memcpy_suggestion<'tcx>( if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); - if var_def_id(cx, arg) == var_def_id(cx, base); + if path_to_local(arg) == path_to_local(base); then { if sugg.as_str() == end_str { sugg::EMPTY.into() @@ -1279,7 +1259,7 @@ fn detect_manual_memcpy<'tcx>( if let Some(loop_counters) = get_loop_counters(cx, block, expr) { starts.extend(loop_counters); } - iter_a = Some(get_assignments(cx, block, &starts)); + iter_a = Some(get_assignments(block, &starts)); } else { iter_b = Some(get_assignment(body)); } @@ -1301,7 +1281,7 @@ fn detect_manual_memcpy<'tcx>( if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts); // Source and destination must be different - if var_def_id(cx, base_left) != var_def_id(cx, base_right); + if path_to_local(base_left) != path_to_local(base_right); then { Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) @@ -2018,9 +1998,7 @@ fn check_manual_flatten<'tcx>( ) = inner_expr.kind; // Ensure match_expr in `if let` statement is the same as the pat from the for-loop if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; - if let ExprKind::Path(QPath::Resolved(None, match_expr_path)) = match_expr.kind; - if let Res::Local(match_expr_path_id) = match_expr_path.res; - if pat_hir_id == match_expr_path_id; + if path_to_local_id(match_expr, pat_hir_id); // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; let some_ctor = is_some_ctor(cx, path.res); @@ -2131,20 +2109,11 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option) { fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::Path(ref qpath) = bound.kind; - if let QPath::Resolved(None, _) = *qpath; + if let Some(hir_id) = path_to_local(bound); + if let Node::Binding(pat) = cx.tcx.hir().get(hir_id); + if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { - let res = cx.qpath_res(qpath, bound.hir_id); - if let Res::Local(hir_id) = res { - let node_str = cx.tcx.hir().get(hir_id); - if_chain! { - if let Node::Binding(pat) = node_str; - if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; - then { - return Some(hir_id); - } - } - } + return Some(hir_id); } } None @@ -2179,7 +2148,9 @@ fn check_for_mutation<'tcx>( fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { match *pat { PatKind::Wild => true, - PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => is_unused(&ident, body), + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { + !LocalUsedVisitor::new(id).check_expr(body) + }, _ => false, } } @@ -2215,7 +2186,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if let QPath::Resolved(None, ref seqvar) = *seqpath; if seqvar.segments.len() == 1; then { - let index_used_directly = same_var(self.cx, idx, self.var); + let index_used_directly = path_to_local_id(idx, self.var); let indexed_indirectly = { let mut used_visitor = LocalUsedVisitor::new(self.var); walk_expr(&mut used_visitor, idx); @@ -2286,17 +2257,14 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // directly using a variable - if let ExprKind::Path(ref qpath) = expr.kind; - if let QPath::Resolved(None, ref path) = *qpath; - if path.segments.len() == 1; + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind; + if let Res::Local(local_id) = path.res; then { - if let Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id) { - if local_id == self.var { - self.nonindex = true; - } else { - // not the correct variable, but still a variable - self.referenced.insert(path.segments[0].ident.name); - } + if local_id == self.var { + self.nonindex = true; + } else { + // not the correct variable, but still a variable + self.referenced.insert(path.segments[0].ident.name); } } } @@ -2354,7 +2322,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { } fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool { - let def_id = match var_def_id(cx, expr) { + let def_id = match path_to_local(expr) { Some(id) => id, None => return false, }; @@ -2367,12 +2335,11 @@ fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: } fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool { - let def_id = match var_def_id(cx, iter_expr) { + let def_id = match path_to_local(iter_expr) { Some(id) => id, None => return false, }; let mut visitor = VarUsedAfterLoopVisitor { - cx, def_id, iter_expr_id: iter_expr.hir_id, past_while_let: false, @@ -2384,20 +2351,19 @@ fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'t visitor.var_used_after_while_let } -struct VarUsedAfterLoopVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, +struct VarUsedAfterLoopVisitor { def_id: HirId, iter_expr_id: HirId, past_while_let: bool, var_used_after_while_let: bool, } -impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if self.past_while_let { - if Some(self.def_id) == var_def_id(self.cx, expr) { + if path_to_local_id(expr, self.def_id) { self.var_used_after_while_let = true; } } else if self.iter_expr_id == expr.hir_id { @@ -2519,7 +2485,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } // If node is a variable - if let Some(def_id) = var_def_id(self.cx, expr) { + if let Some(def_id) = path_to_local(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial); if *state == IncrementVisitorVarState::IncrOnce { @@ -2646,7 +2612,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } // If node is the desired variable, see how it's used - if var_def_id(self.cx, expr) == Some(self.var_id) { + if path_to_local_id(expr, self.var_id) { if self.past_loop { self.state = InitializeVisitorState::DontWarn; return; @@ -2693,16 +2659,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } -fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if let ExprKind::Path(ref qpath) = expr.kind { - let path_res = cx.qpath_res(qpath, expr.hir_id); - if let Res::Local(hir_id) = path_res { - return Some(hir_id); - } - } - None -} - fn is_loop(expr: &Expr<'_>) -> bool { matches!(expr.kind, ExprKind::Loop(..)) } @@ -2725,8 +2681,8 @@ fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { let mut id = loop_expr.hir_id; - let iter_name = if let Some(name) = path_name(iter_expr) { - name + let iter_id = if let Some(id) = path_to_local(iter_expr) { + id } else { return true; }; @@ -2744,7 +2700,7 @@ fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<' Some(Node::Block(block)) => { let mut block_visitor = LoopNestVisitor { hir_id: id, - iterator: iter_name, + iterator: iter_id, nesting: Unknown, }; walk_block(&mut block_visitor, block); @@ -2772,7 +2728,7 @@ use self::Nesting::{LookFurther, RuledOut, Unknown}; struct LoopNestVisitor { hir_id: HirId, - iterator: Symbol, + iterator: HirId, nesting: Nesting, } @@ -2797,7 +2753,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } match expr.kind { ExprKind::Assign(ref path, _, _) | ExprKind::AssignOp(_, ref path, _) => { - if match_var(path, self.iterator) { + if path_to_local_id(path, self.iterator) { self.nesting = RuledOut; } }, @@ -2809,8 +2765,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { if self.nesting != Unknown { return; } - if let PatKind::Binding(.., span_name, _) = pat.kind { - if self.iterator == span_name.name { + if let PatKind::Binding(_, id, ..) = pat.kind { + if id == self.iterator { self.nesting = RuledOut; return; } @@ -2823,16 +2779,6 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } } -fn path_name(e: &Expr<'_>) -> Option { - if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.kind { - let segments = &path.segments; - if segments.len() == 1 { - return Some(segments[0].ident.name); - } - }; - None -} - fn check_infinite_loop<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) { if constant(cx, cx.typeck_results(), cond).is_some() { // A pure constant condition (e.g., `while false`) is not linted. @@ -3194,7 +3140,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if same_var(self.cx, expr, self.id) { + if path_to_local_id(expr, self.id) { self.count += 1; } else { walk_expr(self, expr); diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 8c77e155b70..efb05b8ffdf 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,9 +1,10 @@ use crate::utils::{ - indent_of, is_type_diagnostic_item, match_qpath, paths, reindent_multiline, snippet_opt, span_lint_and_sugg, + indent_of, is_type_diagnostic_item, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, + span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, PatKind, QPath}; +use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -90,8 +91,6 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; if match_qpath(ok_path, &paths::RESULT_OK); - if let ExprKind::Path(QPath::Resolved(_, ok_arg_path)) = ok_arg.kind; - if let def::Res::Local(ok_arg_path_id) = ok_arg_path.res; - then { param_id == ok_arg_path_id } else { false } + then { path_to_local_id(ok_arg, param_id) } else { false } } } diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 9e2c6c7f231..b452225b5db 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,9 +1,9 @@ use crate::consts::constant_simple; use crate::utils; -use crate::utils::sugg; +use crate::utils::{path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Arm, Expr, ExprKind, Pat, PatKind, QPath}; +use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -83,9 +83,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if utils::match_qpath(unwrap_qpath, &utils::paths::OPTION_SOME) || utils::match_qpath(unwrap_qpath, &utils::paths::RESULT_OK); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; - if let ExprKind::Path(QPath::Resolved(_, body_path)) = unwrap_arm.body.kind; - if let def::Res::Local(body_path_hir_id) = body_path.res; - if body_path_hir_id == binding_hir_id; + if path_to_local_id(unwrap_arm.body, binding_hir_id); if !utils::usage::contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index ba7b9bd0424..c4aa2b30e7b 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,11 +1,12 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; -use crate::utils::usage::is_unused; +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - expr_block, get_arg_name, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, - is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, + expr_block, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, + is_type_diagnostic_item, is_wild, match_qpath, match_type, meets_msrv, multispan_sugg, path_to_local_id, peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, + strip_pat_refs, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -616,9 +617,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if let PatKind::TupleStruct( QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind; if args.len() == 1; - if let Some(arg) = get_arg_name(&args[0]); + if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind; let body = remove_blocks(&arms[0].body); - if match_var(body, arg); + if path_to_local_id(body, arg); then { let mut applicability = Applicability::MachineApplicable; @@ -922,8 +923,8 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { if !matching_wild { // Looking for unused bindings (i.e.: `_e`) inner.iter().for_each(|pat| { - if let PatKind::Binding(.., ident, None) = &pat.kind { - if ident.as_str().starts_with('_') && is_unused(ident, arm.body) { + if let PatKind::Binding(_, id, ident, None) = pat.kind { + if ident.as_str().starts_with('_') && !LocalUsedVisitor::new(id).check_expr(arm.body) { ident_bind_name = (&ident.name.as_str()).to_string(); matching_wild = true; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a17c5996293..3dc4cd278e6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -15,8 +15,7 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, PatKind, QPath, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::{Expr, ExprKind, PatKind, TraitItem, TraitItemKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; @@ -30,12 +29,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, - implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, - method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, - walk_ptrs_ty_depth, SpanlessEq, + contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, + in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, + match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, + remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, + SpanlessEq, }; declare_clippy_lint! { @@ -2396,11 +2395,12 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: if bin_op.node == op; // Extract the names of the two arguments to the closure - if let Some(first_arg_ident) = get_arg_name(&closure_body.params[0].pat); - if let Some(second_arg_ident) = get_arg_name(&closure_body.params[1].pat); + if let [param_a, param_b] = closure_body.params; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(¶m_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(¶m_b.pat).kind; - if match_var(&*left_expr, first_arg_ident); - if replacement_has_args || match_var(&*right_expr, second_arg_ident); + if path_to_local_id(left_expr, first_arg_id); + if replacement_has_args || path_to_local_id(right_expr, second_arg_id); then { let mut applicability = Applicability::MachineApplicable; @@ -3068,10 +3068,8 @@ fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_f }; // let the filter closure arg and the map closure arg be equal if_chain! { - if let ExprKind::Path(QPath::Resolved(None, a_path)) = a_path.kind; - if let ExprKind::Path(QPath::Resolved(None, b_path)) = b.kind; - if a_path.res == Res::Local(filter_param_id); - if b_path.res == Res::Local(map_param_id); + if path_to_local_id(a_path, filter_param_id); + if path_to_local_id(b, map_param_id); if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); then { return true; @@ -3255,8 +3253,9 @@ fn lint_search_is_some<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let Some(name) = get_arg_name(&closure_arg.pat) { - Some(search_snippet.replace(&format!("*{}", name), &name.as_str())) + } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind { + let name = &*ident.name.as_str(); + Some(search_snippet.replace(&format!("*{}", name), name)) } else { None } @@ -3688,9 +3687,7 @@ fn lint_option_as_ref_deref<'tcx>( hir::ExprKind::MethodCall(_, _, args, _) => { if_chain! { if args.len() == 1; - if let hir::ExprKind::Path(qpath) = &args[0].kind; - if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id); - if closure_body.params[0].pat.hir_id == local_id; + if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); let adj = cx .typeck_results() .expr_adjustments(&args[0]) @@ -3710,10 +3707,8 @@ fn lint_option_as_ref_deref<'tcx>( if_chain! { if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind; if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind; - if let hir::ExprKind::Path(ref qpath) = inner2.kind; - if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id); then { - closure_body.params[0].pat.hir_id == local_id + path_to_local_id(inner2, closure_body.params[0].pat.hir_id) } else { false } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index d98e6160d30..5691fcb88e9 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,8 +1,6 @@ -use crate::utils::paths; use crate::utils::usage::mutated_variables; -use crate::utils::{match_qpath, match_trait_method, span_lint}; +use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint}; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -59,14 +57,8 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc if let hir::ExprKind::Path(ref path) = func.kind; then { if match_qpath(path, &paths::OPTION_SOME) { - if_chain! { - if let hir::ExprKind::Path(path) = &args[0].kind; - if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id); - then { - if arg_id == *local { - return (false, false) - } - } + if path_to_local_id(&args[0], arg_id) { + return (false, false) } return (true, false); } diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index fa508df865e..fdd105e6246 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,6 +1,5 @@ -use crate::utils::{match_def_path, match_trait_method, paths, span_lint}; +use crate::utils::{match_def_path, match_trait_method, path_to_local_id, paths, span_lint}; use if_chain::if_chain; -use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -89,14 +88,12 @@ impl LateLintPass<'_> for ToStringInDisplay { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { + if self.in_display_impl; + if let Some(self_hir_id) = self.self_hir_id; if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); if match_trait_method(cx, expr, &paths::TO_STRING); - if self.in_display_impl; - if let ExprKind::Path(ref qpath) = args[0].kind; - if let Res::Local(hir_id) = cx.qpath_res(qpath, args[0].hir_id); - if let Some(self_hir_id) = self.self_hir_id; - if hir_id == self_hir_id; + if path_to_local_id(&args[0], self_hir_id); then { span_lint( cx, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index cf93ee0a7a5..15a254244c1 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -307,6 +307,22 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { .all(|(a, b)| a.ident.name.as_str() == *b) } +/// If the expression is a path to a local, returns the canonical `HirId` of the local. +pub fn path_to_local(expr: &Expr<'_>) -> Option { + if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { + if let Res::Local(id) = path.res { + return Some(id); + } + } + None +} + +/// Returns true if the expression is a path to a local with the specified `HirId`. +/// Use this function to see if an expression matches a function argument or a match binding. +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { + path_to_local(expr) == Some(id) +} + /// Gets the definition associated to a path. #[allow(clippy::shadow_unrelated)] // false positive #6563 pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { @@ -1135,9 +1151,7 @@ pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind; if match_qpath(path, &paths::RESULT_OK[1..]); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; - if let ExprKind::Path(QPath::Resolved(None, ref path)) = arm.body.kind; - if let Res::Local(lid) = path.res; - if lid == hir_id; + if path_to_local_id(arm.body, hir_id); then { return true; } @@ -1181,12 +1195,11 @@ pub fn is_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow } -pub fn get_arg_name(pat: &Pat<'_>) -> Option { - match pat.kind { - PatKind::Binding(.., ident, None) => Some(ident.name), - PatKind::Ref(ref subpat, _) => get_arg_name(subpat), - _ => None, +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> { + while let PatKind::Ref(subpat, _) = pat.kind { + pat = subpat; } + pat } pub fn int_bits(tcx: TyCtxt<'_>, ity: ty::IntTy) -> u64 { diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index fc0db7f64ec..7c7580a2c66 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,16 +1,14 @@ use crate::utils; -use crate::utils::match_var; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit; -use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_middle::ty; -use rustc_span::symbol::{Ident, Symbol}; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. @@ -81,36 +79,6 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { } } -pub struct UsedVisitor { - pub var: Symbol, // var to look for - pub used: bool, // has the var been used otherwise? -} - -impl<'tcx> Visitor<'tcx> for UsedVisitor { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if match_var(expr, self.var) { - self.used = true; - } else { - walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} - -pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool { - let mut visitor = UsedVisitor { - var: ident.name, - used: false, - }; - walk_expr(&mut visitor, body); - !visitor.used -} - pub struct ParamBindingIdCollector { binding_hir_ids: Vec, } diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index ebf69df31ca..a4064c3e705 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -1,7 +1,7 @@ +use crate::utils::path_to_local_id; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, QPath, Stmt}; +use rustc_hir::{Arm, Expr, HirId, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -168,15 +168,11 @@ impl<'v> Visitor<'v> for LocalUsedVisitor { type Map = Map<'v>; fn visit_expr(&mut self, expr: &'v Expr<'v>) { - if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { - if let Res::Local(id) = path.res { - if id == self.local_hir_id { - self.used = true; - return; - } - } + if path_to_local_id(expr, self.local_hir_id) { + self.used = true; + } else { + walk_expr(self, expr); } - walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { -- cgit 1.4.1-3-g733a5 From a60c143fe0cec1125e894f3d2d5008cc317fdacf Mon Sep 17 00:00:00 2001 From: Yusuke Tanaka Date: Wed, 3 Feb 2021 23:24:06 +0900 Subject: Add new lint `filter_map_identity` This commit adds a new lint named `filter_map_identity`. This lint is the same as `flat_map_identity` except that it checks for `filter_map`. Closes #6643 --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/filter_map_identity.rs | 56 +++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 30 ++++++++++++- tests/ui/filter_map_identity.fixed | 16 +++++++ tests/ui/filter_map_identity.rs | 16 +++++++ tests/ui/filter_map_identity.stderr | 22 ++++++++++ 7 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/filter_map_identity.rs create mode 100644 tests/ui/filter_map_identity.fixed create mode 100644 tests/ui/filter_map_identity.rs create mode 100644 tests/ui/filter_map_identity.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 45321751ba7..f32f5529751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1955,6 +1955,7 @@ Released 2018-09-13 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7f5c4f56f9e..760b490dc12 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -742,6 +742,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::EXPECT_USED, &methods::FILETYPE_IS_FILE, &methods::FILTER_MAP, + &methods::FILTER_MAP_IDENTITY, &methods::FILTER_MAP_NEXT, &methods::FILTER_NEXT, &methods::FLAT_MAP_IDENTITY, @@ -1531,6 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::CLONE_DOUBLE_REF), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::EXPECT_FUN_CALL), + LintId::of(&methods::FILTER_MAP_IDENTITY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), @@ -1838,6 +1840,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&methods::BIND_INSTEAD_OF_MAP), LintId::of(&methods::CLONE_ON_COPY), + LintId::of(&methods::FILTER_MAP_IDENTITY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INSPECT_FOR_EACH), diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs new file mode 100644 index 00000000000..d04e4be87ac --- /dev/null +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -0,0 +1,56 @@ +use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::FILTER_MAP_IDENTITY; + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + filter_map_args: &[hir::Expr<'_>], + filter_map_span: Span, +) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + let arg_node = &filter_map_args[1].kind; + + let apply_lint = |message: &str| { + span_lint_and_sugg( + cx, + FILTER_MAP_IDENTITY, + filter_map_span.with_hi(expr.span.hi()), + message, + "try", + "flatten()".to_string(), + Applicability::MachineApplicable, + ); + }; + + if_chain! { + if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; + let body = cx.tcx.hir().body(*body_id); + + if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; + + if path.segments.len() == 1; + if path.segments[0].ident.name == binding_ident.name; + + then { + apply_lint("called `filter_map(|x| x)` on an `Iterator`"); + } + } + + if_chain! { + if let hir::ExprKind::Path(ref qpath) = arg_node; + + if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); + + then { + apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); + } + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a17c5996293..2f68bc0121a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod filter_map_identity; mod inefficient_to_string; mod inspect_for_each; mod manual_saturating_arithmetic; @@ -1467,6 +1468,29 @@ declare_clippy_lint! { "using `.inspect().for_each()`, which can be replaced with `.for_each()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `filter_map(|x| x)`. + /// + /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # let iter = vec![Some(1)].into_iter(); + /// iter.filter_map(|x| x); + /// ``` + /// Use instead: + /// ```rust + /// # let iter = vec![Some(1)].into_iter(); + /// iter.flatten(); + /// ``` + pub FILTER_MAP_IDENTITY, + complexity, + "call to `filter_map` where `flatten` is sufficient" +} + pub struct Methods { msrv: Option, } @@ -1504,6 +1528,7 @@ impl_lint_pass!(Methods => [ FILTER_NEXT, SKIP_WHILE_NEXT, FILTER_MAP, + FILTER_MAP_IDENTITY, MANUAL_FILTER_MAP, MANUAL_FIND_MAP, FILTER_MAP_NEXT, @@ -1597,7 +1622,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), - ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), + ["filter_map", ..] => { + unnecessary_filter_map::lint(cx, expr, arg_lists[0]); + filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); + }, ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed new file mode 100644 index 00000000000..23ce28d8e9b --- /dev/null +++ b/tests/ui/filter_map_identity.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_imports)] +#![warn(clippy::filter_map_identity)] + +fn main() { + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); + + use std::convert::identity; + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); +} diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs new file mode 100644 index 00000000000..e698df13eea --- /dev/null +++ b/tests/ui/filter_map_identity.rs @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_imports)] +#![warn(clippy::filter_map_identity)] + +fn main() { + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(|x| x); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(std::convert::identity); + + use std::convert::identity; + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(identity); +} diff --git a/tests/ui/filter_map_identity.stderr b/tests/ui/filter_map_identity.stderr new file mode 100644 index 00000000000..596a6320608 --- /dev/null +++ b/tests/ui/filter_map_identity.stderr @@ -0,0 +1,22 @@ +error: called `filter_map(|x| x)` on an `Iterator` + --> $DIR/filter_map_identity.rs:8:22 + | +LL | let _ = iterator.filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` + | + = note: `-D clippy::filter-map-identity` implied by `-D warnings` + +error: called `filter_map(std::convert::identity)` on an `Iterator` + --> $DIR/filter_map_identity.rs:11:22 + | +LL | let _ = iterator.filter_map(std::convert::identity); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: called `filter_map(std::convert::identity)` on an `Iterator` + --> $DIR/filter_map_identity.rs:15:22 + | +LL | let _ = iterator.filter_map(identity); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 1c3033d5cf903d19d8f3dcdfc01ba1dc55debf71 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 8 Feb 2021 01:34:59 +0900 Subject: add a new lint `bytes_nth` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/bytes_nth.rs | 39 +++++++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 25 ++++++++++++++++++++++ tests/ui/bytes_nth.fixed | 9 ++++++++ tests/ui/bytes_nth.rs | 9 ++++++++ tests/ui/bytes_nth.stderr | 16 ++++++++++++++ 7 files changed, 102 insertions(+) create mode 100644 clippy_lints/src/methods/bytes_nth.rs create mode 100644 tests/ui/bytes_nth.fixed create mode 100644 tests/ui/bytes_nth.rs create mode 100644 tests/ui/bytes_nth.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index b74841c7794..7c79fe88816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1877,6 +1877,7 @@ Released 2018-09-13 [`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow +[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata [`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons [`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fe4aa584b18..22d91c9d40d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -734,6 +734,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &mem_replace::MEM_REPLACE_WITH_DEFAULT, &mem_replace::MEM_REPLACE_WITH_UNINIT, &methods::BIND_INSTEAD_OF_MAP, + &methods::BYTES_NTH, &methods::CHARS_LAST_CMP, &methods::CHARS_NEXT_CMP, &methods::CLONE_DOUBLE_REF, @@ -1531,6 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(&methods::BIND_INSTEAD_OF_MAP), + LintId::of(&methods::BYTES_NTH), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::CLONE_DOUBLE_REF), @@ -1749,6 +1751,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(&methods::BYTES_NTH), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs new file mode 100644 index 00000000000..4f38db06c0a --- /dev/null +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -0,0 +1,39 @@ +use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::BYTES_NTH; + +pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) { + if_chain! { + if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind; + let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs(); + let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) { + Some("String") + } else if ty.is_str() { + Some("str") + } else { + None + }; + if let Some(caller_type) = caller_type; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_NTH, + expr.span, + &format!("called `.byte().nth()` on a `{}`", caller_type), + "try calling `.as_bytes().get()`", + format!( + "{}.as_bytes().get({})", + snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[1].span, "..", &mut applicability) + ), + applicability, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3e34fc1aed1..4cb3a858511 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod bytes_nth; mod filter_map_identity; mod inefficient_to_string; mod inspect_for_each; @@ -1490,6 +1491,28 @@ declare_clippy_lint! { "call to `filter_map` where `flatten` is sufficient" } +declare_clippy_lint! { + /// **What it does:** Checks for the use of `.bytes().nth()`. + /// + /// **Why is this bad?** `.as_bytes().get()` is more efficient and more + /// readable. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let _ = "Hello".bytes().nth(3);; + /// + /// // Good + /// let _ = "Hello".as_bytes().get(3); + /// ``` + pub BYTES_NTH, + style, + "replace `.bytes().nth()` with `.as_bytes().get()`" +} + pub struct Methods { msrv: Option, } @@ -1537,6 +1560,7 @@ impl_lint_pass!(Methods => [ ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, + BYTES_NTH, ITER_SKIP_NEXT, GET_UNWRAP, STRING_EXTEND_CHARS, @@ -1614,6 +1638,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), + ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed new file mode 100644 index 00000000000..36bf8660a34 --- /dev/null +++ b/tests/ui/bytes_nth.fixed @@ -0,0 +1,9 @@ +// run-rustfix + +#![warn(clippy::bytes_nth)] + +fn main() { + let _ = "Hello".as_bytes().get(3); + + let _ = String::from("Hello").as_bytes().get(3); +} diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs new file mode 100644 index 00000000000..257344c2d32 --- /dev/null +++ b/tests/ui/bytes_nth.rs @@ -0,0 +1,9 @@ +// run-rustfix + +#![warn(clippy::bytes_nth)] + +fn main() { + let _ = "Hello".bytes().nth(3); + + let _ = String::from("Hello").bytes().nth(3); +} diff --git a/tests/ui/bytes_nth.stderr b/tests/ui/bytes_nth.stderr new file mode 100644 index 00000000000..b46a0736414 --- /dev/null +++ b/tests/ui/bytes_nth.stderr @@ -0,0 +1,16 @@ +error: called `.byte().nth()` on a `str` + --> $DIR/bytes_nth.rs:6:13 + | +LL | let _ = "Hello".bytes().nth(3); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `"Hello".as_bytes().get(3)` + | + = note: `-D clippy::bytes-nth` implied by `-D warnings` + +error: called `.byte().nth()` on a `String` + --> $DIR/bytes_nth.rs:8:13 + | +LL | let _ = String::from("Hello").bytes().nth(3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `String::from("Hello").as_bytes().get(3)` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 37555f8f73baf82b7761db56e7440c79a956b9ec Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 8 Feb 2021 09:50:13 -0600 Subject: Use path_to_local_id --- clippy_lints/src/methods/filter_map_identity.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index d04e4be87ac..9e646360a40 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -32,12 +32,8 @@ pub(super) fn check( if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; let body = cx.tcx.hir().body(*body_id); - if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; - - if path.segments.len() == 1; - if path.segments[0].ident.name == binding_ident.name; - + if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind; + if path_to_local_id(&body.value, binding_id); then { apply_lint("called `filter_map(|x| x)` on an `Iterator`"); } -- cgit 1.4.1-3-g733a5 From b932587c5d92bc7524ecd9d496f7081005299fa5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 9 Feb 2021 17:38:16 +0100 Subject: Add better turbofish extractor --- clippy_lints/src/methods/mod.rs | 35 ++++++++++++++- tests/ui/from_iter_instead_of_collect.fixed | 30 +++++++++---- tests/ui/from_iter_instead_of_collect.rs | 14 ++++++ tests/ui/from_iter_instead_of_collect.stderr | 64 ++++++++++++++++++++++------ 4 files changed, 120 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3e356afa2a4..d9f906619a0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4095,7 +4095,8 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< then { // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let sugg = format!("{}.collect::<{}>()", iter_expr, ty); + let turbofish = extract_turbofish(cx, expr, ty); + let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, @@ -4109,6 +4110,38 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< } } +fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + if_chain! { + let call_site = expr.span.source_callsite(); + if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); + let snippet_split = snippet.split("::").collect::>(); + if let Some((_, elements)) = snippet_split.split_last(); + + then { + // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) + format!("{}{}", without_ts.join("::"), type_specifier) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{}>", elements.join("::"), wildcards) + } + } else { + ty.to_string() + } + } +} + fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 96701e86395..b5f548810e6 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -8,27 +8,41 @@ use std::iter::FromIterator; fn main() { let iter_expr = std::iter::repeat(5).take(5); - let _ = iter_expr.collect::>(); + let _ = iter_expr.collect::>(); - let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); + let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); Vec::from_iter(vec![42u32]); let a = vec![0, 1, 2]; - assert_eq!(a, (0..3).collect::>()); + assert_eq!(a, (0..3).collect::>()); + assert_eq!(a, (0..3).collect::>()); - let mut b = (0..3).collect::>(); + let mut b = (0..3).collect::>(); b.push_back(4); + let mut b = (0..3).collect::>(); + b.push_back(4); + + { + use std::collections; + let mut b = (0..3).collect::>(); + b.push_back(4); + } + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; - let bm = values.iter().cloned().collect::>(); - let mut bar = bm.range(0..2).collect::>(); + let bm = values.iter().cloned().collect::>(); + let mut bar = bm.range(0..2).collect::>(); bar.insert(&4, &'e'); - let mut bts = (0..3).collect::>(); + let mut bts = (0..3).collect::>(); bts.insert(2); { use std::collections; - let _ = (0..3).collect::>(); + let _ = (0..3).collect::>(); + let _ = (0..3).collect::>(); } + + for _i in [1, 2, 3].iter().collect::>() {} + for _i in [1, 2, 3].iter().collect::>() {} } diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index 211f57bc537..b842b5451d1 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -16,10 +16,20 @@ fn main() { let a = vec![0, 1, 2]; assert_eq!(a, Vec::from_iter(0..3)); + assert_eq!(a, Vec::::from_iter(0..3)); let mut b = VecDeque::from_iter(0..3); b.push_back(4); + let mut b = VecDeque::::from_iter(0..3); + b.push_back(4); + + { + use std::collections; + let mut b = collections::VecDeque::::from_iter(0..3); + b.push_back(4); + } + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; let bm = BTreeMap::from_iter(values.iter().cloned()); let mut bar = BTreeMap::from_iter(bm.range(0..2)); @@ -30,5 +40,9 @@ fn main() { { use std::collections; let _ = collections::BTreeSet::from_iter(0..3); + let _ = collections::BTreeSet::::from_iter(0..3); } + + for _i in Vec::from_iter([1, 2, 3].iter()) {} + for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} } diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 336e25a8adf..434734c9a21 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -2,7 +2,7 @@ error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:11:13 | LL | let _ = Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` @@ -10,43 +10,79 @@ error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:13:13 | LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:18:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); - | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:20:17 + --> $DIR/from_iter_instead_of_collect.rs:19:19 + | +LL | assert_eq!(a, Vec::::from_iter(0..3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:21:17 | LL | let mut b = VecDeque::from_iter(0..3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:24:17 + | +LL | let mut b = VecDeque::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:29:21 + | +LL | let mut b = collections::VecDeque::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:24:14 + --> $DIR/from_iter_instead_of_collect.rs:34:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:25:19 + --> $DIR/from_iter_instead_of_collect.rs:35:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:28:19 + --> $DIR/from_iter_instead_of_collect.rs:38:19 | LL | let mut bts = BTreeSet::from_iter(0..3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:32:17 + --> $DIR/from_iter_instead_of_collect.rs:42:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:43:17 + | +LL | let _ = collections::BTreeSet::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:46:15 + | +LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:47:15 + | +LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors -- cgit 1.4.1-3-g733a5 From 932cc085e6ac277d58fbb6bebe05252b75d5dc54 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <41065217+TaKO8Ki@users.noreply.github.com> Date: Wed, 10 Feb 2021 15:49:07 +0900 Subject: Update clippy_lints/src/methods/bytes_nth.rs Co-authored-by: Phil Hansch --- clippy_lints/src/methods/bytes_nth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 4f38db06c0a..defc50ede22 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -26,7 +26,7 @@ pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' BYTES_NTH, expr.span, &format!("called `.byte().nth()` on a `{}`", caller_type), - "try calling `.as_bytes().get()`", + "try", format!( "{}.as_bytes().get({})", snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), -- cgit 1.4.1-3-g733a5 From 94b8f23baf045b16e2a8b2e2cdd7436724bbf8d5 Mon Sep 17 00:00:00 2001 From: alpaca-tc Date: Thu, 11 Feb 2021 00:45:28 +0900 Subject: Fix typo --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4cb3a858511..d3db9c666df 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1503,7 +1503,7 @@ declare_clippy_lint! { /// /// ```rust /// // Bad - /// let _ = "Hello".bytes().nth(3);; + /// let _ = "Hello".bytes().nth(3); /// /// // Good /// let _ = "Hello".as_bytes().get(3); -- cgit 1.4.1-3-g733a5 From 2f0e9f7d3afb3cb169e58d65261f04215b017561 Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Wed, 24 Feb 2021 21:06:26 +0100 Subject: or_fun_call: fix suggestion for `or_insert(vec![])` Applies for `std::collections::hash_map::Entry` and `std::collections::btree_map::Entry` Example: Previously, for the following code: `let _ = hash_map.entry("test".to_owned()).or_insert(vec![]);` clippy would suggest to use: `or_insert_with(vec![])`, which causes a compiler error (E0277). Now clippy suggests: `or_insert_with(Vec::new)` --- clippy_lints/src/methods/mod.rs | 16 +++++++++++++++- tests/ui/or_fun_call.fixed | 6 ++++++ tests/ui/or_fun_call.rs | 6 ++++++ tests/ui/or_fun_call.stderr | 26 +++++++++++++++++++------- 4 files changed, 46 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 433f513b1a8..26878d5bba9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2005,12 +2005,26 @@ fn lint_or_fun_call<'tcx>( if poss.contains(&name); then { + let macro_expanded_snipped; let sugg: Cow<'_, str> = { let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { (false, Some(fun_span)) => (fun_span, false), _ => (arg.span, true), }; - let snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + let snippet = { + let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + if not_macro_argument_snippet == "vec![]" { + macro_expanded_snipped = snippet(cx, snippet_span, ".."); + match macro_expanded_snipped.strip_prefix("$crate::vec::") { + Some(stripped) => Cow::from(stripped), + None => macro_expanded_snipped + } + } + else { + not_macro_argument_snippet + } + }; + if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; format!("|{}| {}", l_arg, snippet).into() diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 2a63318c8c7..64347cae5da 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -62,9 +62,15 @@ fn or_fun_call() { let mut map = HashMap::::new(); map.entry(42).or_insert_with(String::new); + let mut map_vec = HashMap::>::new(); + map_vec.entry(42).or_insert_with(Vec::new); + let mut btree = BTreeMap::::new(); btree.entry(42).or_insert_with(String::new); + let mut btree_vec = BTreeMap::>::new(); + btree_vec.entry(42).or_insert_with(Vec::new); + let stringy = Some(String::from("")); let _ = stringy.unwrap_or_else(|| "".to_owned()); diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 026ef437caa..7faab0017b2 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -62,9 +62,15 @@ fn or_fun_call() { let mut map = HashMap::::new(); map.entry(42).or_insert(String::new()); + let mut map_vec = HashMap::>::new(); + map_vec.entry(42).or_insert(vec![]); + let mut btree = BTreeMap::::new(); btree.entry(42).or_insert(String::new()); + let mut btree_vec = BTreeMap::>::new(); + btree_vec.entry(42).or_insert(vec![]); + let stringy = Some(String::from("")); let _ = stringy.unwrap_or("".to_owned()); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index fb8bf339828..1e2bfd490e0 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -67,40 +67,52 @@ LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:66:21 + --> $DIR/or_fun_call.rs:66:23 + | +LL | map_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)` + +error: use of `or_insert` followed by a function call + --> $DIR/or_fun_call.rs:69:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` +error: use of `or_insert` followed by a function call + --> $DIR/or_fun_call.rs:72:25 + | +LL | btree_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)` + error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:69:21 + --> $DIR/or_fun_call.rs:75:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:77:21 + --> $DIR/or_fun_call.rs:83:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:79:21 + --> $DIR/or_fun_call.rs:85:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:103:35 + --> $DIR/or_fun_call.rs:109:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:107:10 + --> $DIR/or_fun_call.rs:113:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 17 previous errors +error: aborting due to 19 previous errors -- cgit 1.4.1-3-g733a5 From 3d3cfd3754d616db959015eb7bd3c6238961320a Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Fri, 12 Feb 2021 04:27:04 +0000 Subject: added new lint `implicit_clone` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/implicit_clone.rs | 32 ++++++++ clippy_lints/src/methods/mod.rs | 32 ++++++++ clippy_utils/src/lib.rs | 16 ++++ tests/ui/cmp_owned/without_suggestion.rs | 1 + tests/ui/cmp_owned/without_suggestion.stderr | 6 +- tests/ui/implicit_clone.rs | 108 +++++++++++++++++++++++++++ tests/ui/implicit_clone.stderr | 64 ++++++++++++++++ tests/ui/redundant_clone.fixed | 1 + tests/ui/redundant_clone.rs | 1 + tests/ui/redundant_clone.stderr | 56 +++++++------- 12 files changed, 289 insertions(+), 31 deletions(-) create mode 100644 clippy_lints/src/methods/implicit_clone.rs create mode 100644 tests/ui/implicit_clone.rs create mode 100644 tests/ui/implicit_clone.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index d96c74b6e41..687f7447202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2104,6 +2104,7 @@ Released 2018-09-13 [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond +[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return [`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index faec9ec31f3..fa8f03eb445 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -769,6 +769,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::FLAT_MAP_IDENTITY, &methods::FROM_ITER_INSTEAD_OF_COLLECT, &methods::GET_UNWRAP, + &methods::IMPLICIT_CLONE, &methods::INEFFICIENT_TO_STRING, &methods::INSPECT_FOR_EACH, &methods::INTO_ITER_ON_REF, @@ -1380,6 +1381,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), + LintId::of(&methods::IMPLICIT_CLONE), LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::MAP_FLATTEN), LintId::of(&methods::MAP_UNWRAP_OR), diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs new file mode 100644 index 00000000000..a769493d11d --- /dev/null +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -0,0 +1,32 @@ +use crate::utils::span_lint_and_sugg; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::ExprKind; +use rustc_lint::LateContext; +use rustc_middle::ty::TyS; +use rustc_span::symbol::Symbol; + +use super::IMPLICIT_CLONE; +use clippy_utils::is_diagnostic_assoc_item; + +pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, trait_diagnostic: Symbol) { + if_chain! { + if let ExprKind::MethodCall(method_path, _, [arg], _) = &expr.kind; + let return_type = cx.typeck_results().expr_ty(&expr); + let input_type = cx.typeck_results().expr_ty(arg).peel_refs(); + if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); + if TyS::same_type(return_type, input_type); + if is_diagnostic_assoc_item(cx, expr_def_id, trait_diagnostic); + then { + span_lint_and_sugg( + cx,IMPLICIT_CLONE,method_path.ident.span, + &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_path.ident.name), + "consider using", + "clone".to_string(), + Applicability::MachineApplicable + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5fb3ae1890d..6f491144435 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,6 +1,7 @@ mod bind_instead_of_map; mod bytes_nth; mod filter_map_identity; +mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; mod manual_saturating_arithmetic; @@ -1513,6 +1514,32 @@ declare_clippy_lint! { "replace `.bytes().nth()` with `.as_bytes().get()`" } +declare_clippy_lint! { + /// **What it does:** Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer. + /// + /// **Why is this bad?** These methods do the same thing as `_.clone()` but may be confusing as + /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let a = vec![1, 2, 3]; + /// let b = a.to_vec(); + /// let c = a.to_owned(); + /// ``` + /// Use instead: + /// ```rust + /// let a = vec![1, 2, 3]; + /// let b = a.clone(); + /// let c = a.clone(); + /// ``` + pub IMPLICIT_CLONE, + pedantic, + "implicitly cloning a value by invoking a function on its dereferenced type" +} + pub struct Methods { msrv: Option, } @@ -1579,6 +1606,7 @@ impl_lint_pass!(Methods => [ MAP_COLLECT_RESULT_UNIT, FROM_ITER_INSTEAD_OF_COLLECT, INSPECT_FOR_EACH, + IMPLICIT_CLONE ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1670,6 +1698,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), ["for_each", "inspect"] => inspect_for_each::lint(cx, expr, method_spans[1]), + ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned), + ["to_os_string", ..] => implicit_clone::check(cx, expr, sym::OsStr), + ["to_path_buf", ..] => implicit_clone::check(cx, expr, sym::Path), + ["to_vec", ..] => implicit_clone::check(cx, expr, sym::slice), _ => {}, } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8e5cf5dc654..2380ea4c7bf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -237,6 +237,22 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } +/// Checks if the method call given in `expr` belongs to a trait or other container with a given +/// diagnostic item +pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { + cx.tcx + .opt_associated_item(def_id) + .and_then(|associated_item| match associated_item.container { + ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), + ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { + ty::Adt(adt, _) => Some(adt.did), + ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works + _ => None, + }, + }) + .map_or(false, |assoc_def_id| cx.tcx.is_diagnostic_item(diag_item, assoc_def_id)) +} + /// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { diff --git a/tests/ui/cmp_owned/without_suggestion.rs b/tests/ui/cmp_owned/without_suggestion.rs index 9ab8795474c..f44a3901fb4 100644 --- a/tests/ui/cmp_owned/without_suggestion.rs +++ b/tests/ui/cmp_owned/without_suggestion.rs @@ -1,4 +1,5 @@ #[allow(clippy::unnecessary_operation)] +#[allow(clippy::implicit_clone)] fn main() { let x = &Baz; diff --git a/tests/ui/cmp_owned/without_suggestion.stderr b/tests/ui/cmp_owned/without_suggestion.stderr index 6e8a5ad2a17..2ea3d8fac0d 100644 --- a/tests/ui/cmp_owned/without_suggestion.stderr +++ b/tests/ui/cmp_owned/without_suggestion.stderr @@ -1,5 +1,5 @@ error: this creates an owned instance just for comparison - --> $DIR/without_suggestion.rs:6:5 + --> $DIR/without_suggestion.rs:7:5 | LL | y.to_owned() == *x; | ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating @@ -7,13 +7,13 @@ LL | y.to_owned() == *x; = note: `-D clippy::cmp-owned` implied by `-D warnings` error: this creates an owned instance just for comparison - --> $DIR/without_suggestion.rs:10:5 + --> $DIR/without_suggestion.rs:11:5 | LL | y.to_owned() == **x; | ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating error: this creates an owned instance just for comparison - --> $DIR/without_suggestion.rs:17:9 + --> $DIR/without_suggestion.rs:18:9 | LL | self.to_owned() == *other | ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs new file mode 100644 index 00000000000..19101522163 --- /dev/null +++ b/tests/ui/implicit_clone.rs @@ -0,0 +1,108 @@ +#![warn(clippy::implicit_clone)] +#![allow(clippy::redundant_clone)] +use std::borrow::Borrow; +use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; + +fn return_owned_from_slice(slice: &[u32]) -> Vec { + slice.to_owned() +} + +pub fn own_same(v: T) -> T +where + T: ToOwned, +{ + v.to_owned() +} + +pub fn own_same_from_ref(v: &T) -> T +where + T: ToOwned, +{ + v.to_owned() +} + +pub fn own_different(v: T) -> U +where + T: ToOwned, +{ + v.to_owned() +} + +#[derive(Copy, Clone)] +struct Kitten {} +impl Kitten { + // badly named method + fn to_vec(self) -> Kitten { + Kitten {} + } +} +impl Borrow for Kitten { + fn borrow(&self) -> &BorrowedKitten { + static VALUE: BorrowedKitten = BorrowedKitten {}; + &VALUE + } +} + +struct BorrowedKitten {} +impl ToOwned for BorrowedKitten { + type Owned = Kitten; + fn to_owned(&self) -> Kitten { + Kitten {} + } +} + +mod weird { + #[allow(clippy::ptr_arg)] + pub fn to_vec(v: &Vec) -> Vec { + v.clone() + } +} + +fn main() { + let vec = vec![5]; + let _ = return_owned_from_slice(&vec); + let _ = vec.to_owned(); + let _ = vec.to_vec(); + + let vec_ref = &vec; + let _ = return_owned_from_slice(&vec_ref); + let _ = vec_ref.to_owned(); + let _ = vec_ref.to_vec(); + + // we expect no lint for this + let _ = weird::to_vec(&vec); + + // we expect no lints for this + let slice: &[u32] = &[1, 2, 3, 4, 5]; + let _ = return_owned_from_slice(slice); + let _ = slice.to_owned(); + let _ = slice.to_vec(); + + let str = "hello world".to_string(); + let _ = str.to_owned(); + + // testing w/ an arbitrary type + let kitten = Kitten {}; + let _ = kitten.to_owned(); + let _ = own_same_from_ref(&kitten); + // this shouln't lint + let _ = kitten.to_vec(); + + // we expect no lints for this + let borrowed = BorrowedKitten {}; + let _ = borrowed.to_owned(); + + let pathbuf = PathBuf::new(); + let _ = pathbuf.to_owned(); + let _ = pathbuf.to_path_buf(); + + let os_string = OsString::from("foo"); + let _ = os_string.to_owned(); + let _ = os_string.to_os_string(); + + // we expect no lints for this + let os_str = OsStr::new("foo"); + let _ = os_str.to_owned(); + let _ = os_str.to_os_string(); +} diff --git a/tests/ui/implicit_clone.stderr b/tests/ui/implicit_clone.stderr new file mode 100644 index 00000000000..e6f7527b672 --- /dev/null +++ b/tests/ui/implicit_clone.stderr @@ -0,0 +1,64 @@ +error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type + --> $DIR/implicit_clone.rs:65:17 + | +LL | let _ = vec.to_owned(); + | ^^^^^^^^ help: consider using: `clone` + | + = note: `-D clippy::implicit-clone` implied by `-D warnings` + +error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type + --> $DIR/implicit_clone.rs:66:17 + | +LL | let _ = vec.to_vec(); + | ^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type + --> $DIR/implicit_clone.rs:70:21 + | +LL | let _ = vec_ref.to_owned(); + | ^^^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type + --> $DIR/implicit_clone.rs:71:21 + | +LL | let _ = vec_ref.to_vec(); + | ^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type + --> $DIR/implicit_clone.rs:83:17 + | +LL | let _ = str.to_owned(); + | ^^^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type + --> $DIR/implicit_clone.rs:87:20 + | +LL | let _ = kitten.to_owned(); + | ^^^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type + --> $DIR/implicit_clone.rs:97:21 + | +LL | let _ = pathbuf.to_owned(); + | ^^^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type + --> $DIR/implicit_clone.rs:98:21 + | +LL | let _ = pathbuf.to_path_buf(); + | ^^^^^^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type + --> $DIR/implicit_clone.rs:101:23 + | +LL | let _ = os_string.to_owned(); + | ^^^^^^^^ help: consider using: `clone` + +error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type + --> $DIR/implicit_clone.rs:102:23 + | +LL | let _ = os_string.to_os_string(); + | ^^^^^^^^^^^^ help: consider using: `clone` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index cdeefda4c23..a5847e37c97 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -1,6 +1,7 @@ // run-rustfix // rustfix-only-machine-applicable +#![allow(clippy::implicit_clone)] use std::ffi::OsString; use std::path::Path; diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index acb7ffb305f..dab8d7fb1c7 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -1,6 +1,7 @@ // run-rustfix // rustfix-only-machine-applicable +#![allow(clippy::implicit_clone)] use std::ffi::OsString; use std::path::Path; diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index 89b39254299..87c219316ce 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -1,168 +1,168 @@ error: redundant clone - --> $DIR/redundant_clone.rs:8:42 + --> $DIR/redundant_clone.rs:9:42 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use - --> $DIR/redundant_clone.rs:8:14 + --> $DIR/redundant_clone.rs:9:14 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:11:15 + --> $DIR/redundant_clone.rs:12:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:11:14 + --> $DIR/redundant_clone.rs:12:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:14:15 + --> $DIR/redundant_clone.rs:15:15 | LL | let _s = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:14:14 + --> $DIR/redundant_clone.rs:15:14 | LL | let _s = s.to_string(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:17:15 + --> $DIR/redundant_clone.rs:18:15 | LL | let _s = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:17:14 + --> $DIR/redundant_clone.rs:18:14 | LL | let _s = s.to_owned(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:19:42 + --> $DIR/redundant_clone.rs:20:42 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:19:14 + --> $DIR/redundant_clone.rs:20:14 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:21:42 + --> $DIR/redundant_clone.rs:22:42 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:21:14 + --> $DIR/redundant_clone.rs:22:14 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:23:29 + --> $DIR/redundant_clone.rs:24:29 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:23:14 + --> $DIR/redundant_clone.rs:24:14 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:25:29 + --> $DIR/redundant_clone.rs:26:29 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:25:14 + --> $DIR/redundant_clone.rs:26:14 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:32:19 + --> $DIR/redundant_clone.rs:33:19 | LL | let _t = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:32:14 + --> $DIR/redundant_clone.rs:33:14 | LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:62:22 + --> $DIR/redundant_clone.rs:63:22 | LL | (a.clone(), a.clone()) | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:62:21 + --> $DIR/redundant_clone.rs:63:21 | LL | (a.clone(), a.clone()) | ^ error: redundant clone - --> $DIR/redundant_clone.rs:122:15 + --> $DIR/redundant_clone.rs:123:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:122:14 + --> $DIR/redundant_clone.rs:123:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:123:15 + --> $DIR/redundant_clone.rs:124:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:123:14 + --> $DIR/redundant_clone.rs:124:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:133:19 + --> $DIR/redundant_clone.rs:134:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:133:18 + --> $DIR/redundant_clone.rs:134:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:145:14 + --> $DIR/redundant_clone.rs:146:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> $DIR/redundant_clone.rs:145:13 + --> $DIR/redundant_clone.rs:146:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 51617b83a18b2a0b1f0f2cae8c43e42043a86b76 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 25 Feb 2021 23:06:50 +0900 Subject: new lint: iter_count --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/mod.rs | 62 ++++++++++++++++++++++++++++++++++++ tests/ui/auxiliary/option_helpers.rs | 4 +++ tests/ui/iter_count.fixed | 58 +++++++++++++++++++++++++++++++++ tests/ui/iter_count.rs | 58 +++++++++++++++++++++++++++++++++ tests/ui/iter_count.stderr | 52 ++++++++++++++++++++++++++++++ 7 files changed, 238 insertions(+) create mode 100644 tests/ui/iter_count.fixed create mode 100644 tests/ui/iter_count.rs create mode 100644 tests/ui/iter_count.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 687f7447202..41c334c6816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2135,6 +2135,7 @@ Released 2018-09-13 [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect +[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fa8f03eb445..1ace4c8a10c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -775,6 +775,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::INTO_ITER_ON_REF, &methods::ITERATOR_STEP_BY_ZERO, &methods::ITER_CLONED_COLLECT, + &methods::ITER_COUNT, &methods::ITER_NEXT_SLICE, &methods::ITER_NTH, &methods::ITER_NTH_ZERO, @@ -1577,6 +1578,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_COUNT), LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH), LintId::of(&methods::ITER_NTH_ZERO), @@ -1881,6 +1883,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INSPECT_FOR_EACH), + LintId::of(&methods::ITER_COUNT), LintId::of(&methods::MANUAL_FILTER_MAP), LintId::of(&methods::MANUAL_FIND_MAP), LintId::of(&methods::OPTION_AS_REF_DEREF), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6f491144435..17e7f6f662d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1540,6 +1540,32 @@ declare_clippy_lint! { "implicitly cloning a value by invoking a function on its dereferenced type" } +declare_clippy_lint! { + /// **What it does:** Checks for the use of `.iter().count()`. + /// + /// **Why is this bad?** `.len()` is more efficient and more + /// readable. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let some_vec = vec![0, 1, 2, 3]; + /// let _ = some_vec.iter().count(); + /// let _ = &some_vec[..].iter().count(); + /// + /// // Good + /// let some_vec = vec![0, 1, 2, 3]; + /// let _ = some_vec.len(); + /// let _ = &some_vec[..].len(); + /// ``` + pub ITER_COUNT, + complexity, + "replace `.iter().count()` with `.len()`" +} + pub struct Methods { msrv: Option, } @@ -1585,6 +1611,7 @@ impl_lint_pass!(Methods => [ MAP_FLATTEN, ITERATOR_STEP_BY_ZERO, ITER_NEXT_SLICE, + ITER_COUNT, ITER_NTH, ITER_NTH_ZERO, BYTES_NTH, @@ -1664,6 +1691,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), + ["count", "iter"] => lint_iter_count(cx, expr, &arg_lists[1], false), + ["count", "iter_mut"] => lint_iter_count(cx, expr, &arg_lists[1], true), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), @@ -2632,6 +2661,39 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ } } +fn lint_iter_count<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], is_mut: bool) { + let mut_str = if is_mut { "_mut" } else { "" }; + if_chain! { + let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { + Some("slice") + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { + Some("Vec") + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { + Some("VecDeque") + } else if match_trait_method(cx, expr, &paths::ITERATOR) { + Some("std::iter::Iterator") + } else { + None + }; + if let Some(caller_type) = caller_type; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_COUNT, + expr.span, + &format!("called `.iter{}().count()` on a `{}`", mut_str, caller_type), + "try", + format!( + "{}.len()", + snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + ), + applicability, + ); + } + } +} + fn lint_iter_nth<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, diff --git a/tests/ui/auxiliary/option_helpers.rs b/tests/ui/auxiliary/option_helpers.rs index ed11c41e21c..7dc3f4ebd4d 100644 --- a/tests/ui/auxiliary/option_helpers.rs +++ b/tests/ui/auxiliary/option_helpers.rs @@ -48,4 +48,8 @@ impl IteratorFalsePositives { pub fn skip_while(self) -> IteratorFalsePositives { self } + + pub fn count(self) -> usize { + self.foo as usize + } } diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed new file mode 100644 index 00000000000..14cae1cd73e --- /dev/null +++ b/tests/ui/iter_count.fixed @@ -0,0 +1,58 @@ +// run-rustfix +// aux-build:option_helpers.rs + +#![warn(clippy::iter_count)] +#![allow(unused_variables)] +#![allow(unused_mut)] + +extern crate option_helpers; + +use option_helpers::IteratorFalsePositives; +use std::collections::{HashSet, VecDeque}; + +/// 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 } + } +} + +fn main() { + 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(); + let mut some_hash_set = HashSet::new(); + some_hash_set.insert(1); + + { + // Make sure we lint `.iter()` for relevant types. + let bad_vec = some_vec.len(); + let bad_slice = &some_vec[..].len(); + let bad_boxed_slice = boxed_slice.len(); + let bad_vec_deque = some_vec_deque.len(); + let bad_hash_set = some_hash_set.len(); + } + + { + // Make sure we lint `.iter_mut()` for relevant types. + let bad_vec = some_vec.len(); + } + { + let bad_slice = &some_vec[..].len(); + } + { + let bad_vec_deque = some_vec_deque.len(); + } + + // Make sure we don't lint for non-relevant types. + let false_positive = HasIter; + let ok = false_positive.iter().count(); + let ok_mut = false_positive.iter_mut().count(); +} diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs new file mode 100644 index 00000000000..dfe02e5d53e --- /dev/null +++ b/tests/ui/iter_count.rs @@ -0,0 +1,58 @@ +// run-rustfix +// aux-build:option_helpers.rs + +#![warn(clippy::iter_count)] +#![allow(unused_variables)] +#![allow(unused_mut)] + +extern crate option_helpers; + +use option_helpers::IteratorFalsePositives; +use std::collections::{HashSet, VecDeque}; + +/// 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 } + } +} + +fn main() { + 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(); + let mut some_hash_set = HashSet::new(); + some_hash_set.insert(1); + + { + // Make sure we lint `.iter()` for relevant types. + let bad_vec = some_vec.iter().count(); + let bad_slice = &some_vec[..].iter().count(); + let bad_boxed_slice = boxed_slice.iter().count(); + let bad_vec_deque = some_vec_deque.iter().count(); + let bad_hash_set = some_hash_set.iter().count(); + } + + { + // Make sure we lint `.iter_mut()` for relevant types. + let bad_vec = some_vec.iter_mut().count(); + } + { + let bad_slice = &some_vec[..].iter_mut().count(); + } + { + let bad_vec_deque = some_vec_deque.iter_mut().count(); + } + + // Make sure we don't lint for non-relevant types. + let false_positive = HasIter; + let ok = false_positive.iter().count(); + let ok_mut = false_positive.iter_mut().count(); +} diff --git a/tests/ui/iter_count.stderr b/tests/ui/iter_count.stderr new file mode 100644 index 00000000000..a465d221994 --- /dev/null +++ b/tests/ui/iter_count.stderr @@ -0,0 +1,52 @@ +error: called `.iter().count()` on a `Vec` + --> $DIR/iter_count.rs:36:23 + | +LL | let bad_vec = some_vec.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec.len()` + | + = note: `-D clippy::iter-count` implied by `-D warnings` + +error: called `.iter().count()` on a `slice` + --> $DIR/iter_count.rs:37:26 + | +LL | let bad_slice = &some_vec[..].iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[..].len()` + +error: called `.iter().count()` on a `slice` + --> $DIR/iter_count.rs:38:31 + | +LL | let bad_boxed_slice = boxed_slice.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` + +error: called `.iter().count()` on a `VecDeque` + --> $DIR/iter_count.rs:39:29 + | +LL | let bad_vec_deque = some_vec_deque.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec_deque.len()` + +error: called `.iter().count()` on a `std::iter::Iterator` + --> $DIR/iter_count.rs:40:28 + | +LL | let bad_hash_set = some_hash_set.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_hash_set.len()` + +error: called `.iter_mut().count()` on a `Vec` + --> $DIR/iter_count.rs:45:23 + | +LL | let bad_vec = some_vec.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec.len()` + +error: called `.iter_mut().count()` on a `slice` + --> $DIR/iter_count.rs:48:26 + | +LL | let bad_slice = &some_vec[..].iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[..].len()` + +error: called `.iter_mut().count()` on a `VecDeque` + --> $DIR/iter_count.rs:51:29 + | +LL | let bad_vec_deque = some_vec_deque.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec_deque.len()` + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From 204b27937c488eb7c1b81c31d56779861ff488c3 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 01:54:51 +0900 Subject: lint for `into_iter().count()` --- clippy_lints/src/methods/mod.rs | 11 +++++-- tests/ui/iter_count.fixed | 58 +++++++++++++++++---------------- tests/ui/iter_count.rs | 58 +++++++++++++++++---------------- tests/ui/iter_count.stderr | 72 +++++++++++++++++++++++++---------------- 4 files changed, 116 insertions(+), 83 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 17e7f6f662d..e5509ee2c4e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1691,7 +1691,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), - ["count", "iter"] => lint_iter_count(cx, expr, &arg_lists[1], false), + ["count", "into_iter" | "iter"] => lint_iter_count(cx, expr, &arg_lists[1], false), ["count", "iter_mut"] => lint_iter_count(cx, expr, &arg_lists[1], true), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), @@ -2663,6 +2663,13 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ fn lint_iter_count<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], is_mut: bool) { let mut_str = if is_mut { "_mut" } else { "" }; + let iter_method = if method_chain_args(expr, &[format!("iter{}", mut_str).as_str(), "count"]).is_some() { + "iter" + } else if method_chain_args(expr, &["into_iter", "count"]).is_some() { + "into_iter" + } else { + return; + }; if_chain! { let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { Some("slice") @@ -2682,7 +2689,7 @@ fn lint_iter_count<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'t cx, ITER_COUNT, expr.span, - &format!("called `.iter{}().count()` on a `{}`", mut_str, caller_type), + &format!("called `.{}{}().count()` on a `{}`", iter_method, mut_str, caller_type), "try", format!( "{}.len()", diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed index 14cae1cd73e..c8f89640847 100644 --- a/tests/ui/iter_count.fixed +++ b/tests/ui/iter_count.fixed @@ -2,8 +2,13 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_count)] -#![allow(unused_variables)] -#![allow(unused_mut)] +#![allow( + unused_variables, + array_into_iter, + unused_mut, + clippy::into_iter_on_ref, + clippy::unnecessary_operation +)] extern crate option_helpers; @@ -22,37 +27,36 @@ impl HasIter { fn iter_mut(self) -> IteratorFalsePositives { IteratorFalsePositives { foo: 0 } } + + fn into_iter(self) -> IteratorFalsePositives { + IteratorFalsePositives { foo: 0 } + } } fn main() { - let mut some_vec = vec![0, 1, 2, 3]; + let mut 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(); - let mut some_hash_set = HashSet::new(); - some_hash_set.insert(1); - - { - // Make sure we lint `.iter()` for relevant types. - let bad_vec = some_vec.len(); - let bad_slice = &some_vec[..].len(); - let bad_boxed_slice = boxed_slice.len(); - let bad_vec_deque = some_vec_deque.len(); - let bad_hash_set = some_hash_set.len(); - } + let mut vec_deque: VecDeque<_> = vec.iter().cloned().collect(); + let mut hash_set = HashSet::new(); + hash_set.insert(1); - { - // Make sure we lint `.iter_mut()` for relevant types. - let bad_vec = some_vec.len(); - } - { - let bad_slice = &some_vec[..].len(); - } - { - let bad_vec_deque = some_vec_deque.len(); - } + &vec[..].len(); + vec.len(); + boxed_slice.len(); + vec_deque.len(); + hash_set.len(); + + vec.len(); + &vec[..].len(); + vec_deque.len(); + + &vec[..].len(); + vec.len(); + vec_deque.len(); // Make sure we don't lint for non-relevant types. let false_positive = HasIter; - let ok = false_positive.iter().count(); - let ok_mut = false_positive.iter_mut().count(); + false_positive.iter().count(); + false_positive.iter_mut().count(); + false_positive.into_iter().count(); } diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs index dfe02e5d53e..8ea17ef34fa 100644 --- a/tests/ui/iter_count.rs +++ b/tests/ui/iter_count.rs @@ -2,8 +2,13 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_count)] -#![allow(unused_variables)] -#![allow(unused_mut)] +#![allow( + unused_variables, + array_into_iter, + unused_mut, + clippy::into_iter_on_ref, + clippy::unnecessary_operation +)] extern crate option_helpers; @@ -22,37 +27,36 @@ impl HasIter { fn iter_mut(self) -> IteratorFalsePositives { IteratorFalsePositives { foo: 0 } } + + fn into_iter(self) -> IteratorFalsePositives { + IteratorFalsePositives { foo: 0 } + } } fn main() { - let mut some_vec = vec![0, 1, 2, 3]; + let mut 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(); - let mut some_hash_set = HashSet::new(); - some_hash_set.insert(1); - - { - // Make sure we lint `.iter()` for relevant types. - let bad_vec = some_vec.iter().count(); - let bad_slice = &some_vec[..].iter().count(); - let bad_boxed_slice = boxed_slice.iter().count(); - let bad_vec_deque = some_vec_deque.iter().count(); - let bad_hash_set = some_hash_set.iter().count(); - } + let mut vec_deque: VecDeque<_> = vec.iter().cloned().collect(); + let mut hash_set = HashSet::new(); + hash_set.insert(1); - { - // Make sure we lint `.iter_mut()` for relevant types. - let bad_vec = some_vec.iter_mut().count(); - } - { - let bad_slice = &some_vec[..].iter_mut().count(); - } - { - let bad_vec_deque = some_vec_deque.iter_mut().count(); - } + &vec[..].iter().count(); + vec.iter().count(); + boxed_slice.iter().count(); + vec_deque.iter().count(); + hash_set.iter().count(); + + vec.iter_mut().count(); + &vec[..].iter_mut().count(); + vec_deque.iter_mut().count(); + + &vec[..].into_iter().count(); + vec.into_iter().count(); + vec_deque.into_iter().count(); // Make sure we don't lint for non-relevant types. let false_positive = HasIter; - let ok = false_positive.iter().count(); - let ok_mut = false_positive.iter_mut().count(); + false_positive.iter().count(); + false_positive.iter_mut().count(); + false_positive.into_iter().count(); } diff --git a/tests/ui/iter_count.stderr b/tests/ui/iter_count.stderr index a465d221994..0820c001443 100644 --- a/tests/ui/iter_count.stderr +++ b/tests/ui/iter_count.stderr @@ -1,52 +1,70 @@ -error: called `.iter().count()` on a `Vec` - --> $DIR/iter_count.rs:36:23 +error: called `.iter().count()` on a `slice` + --> $DIR/iter_count.rs:43:6 | -LL | let bad_vec = some_vec.iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec.len()` +LL | &vec[..].iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` | = note: `-D clippy::iter-count` implied by `-D warnings` -error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:37:26 +error: called `.iter().count()` on a `Vec` + --> $DIR/iter_count.rs:44:5 | -LL | let bad_slice = &some_vec[..].iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[..].len()` +LL | vec.iter().count(); + | ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:38:31 + --> $DIR/iter_count.rs:45:5 | -LL | let bad_boxed_slice = boxed_slice.iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` +LL | boxed_slice.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` error: called `.iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:39:29 + --> $DIR/iter_count.rs:46:5 | -LL | let bad_vec_deque = some_vec_deque.iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec_deque.len()` +LL | vec_deque.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter().count()` on a `std::iter::Iterator` - --> $DIR/iter_count.rs:40:28 + --> $DIR/iter_count.rs:47:5 | -LL | let bad_hash_set = some_hash_set.iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_hash_set.len()` +LL | hash_set.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.iter_mut().count()` on a `Vec` - --> $DIR/iter_count.rs:45:23 + --> $DIR/iter_count.rs:49:5 | -LL | let bad_vec = some_vec.iter_mut().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec.len()` +LL | vec.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter_mut().count()` on a `slice` - --> $DIR/iter_count.rs:48:26 + --> $DIR/iter_count.rs:50:6 | -LL | let bad_slice = &some_vec[..].iter_mut().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[..].len()` +LL | &vec[..].iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.iter_mut().count()` on a `VecDeque` - --> $DIR/iter_count.rs:51:29 + --> $DIR/iter_count.rs:51:5 + | +LL | vec_deque.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` + +error: called `.into_iter().count()` on a `slice` + --> $DIR/iter_count.rs:53:6 + | +LL | &vec[..].into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` + +error: called `.into_iter().count()` on a `Vec` + --> $DIR/iter_count.rs:54:5 + | +LL | vec.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` + +error: called `.into_iter().count()` on a `VecDeque` + --> $DIR/iter_count.rs:55:5 | -LL | let bad_vec_deque = some_vec_deque.iter_mut().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec_deque.len()` +LL | vec_deque.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From 9958af4229d4bee06ee65b921ac11b1fe498e831 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 02:18:52 +0900 Subject: move `lints()` to `iter_count.rs` --- clippy_lints/src/methods/iter_count.rs | 51 ++++++++++++++++++ clippy_lints/src/methods/mod.rs | 97 ++++------------------------------ clippy_utils/src/lib.rs | 40 ++++++++++++++ 3 files changed, 100 insertions(+), 88 deletions(-) create mode 100644 clippy_lints/src/methods/iter_count.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs new file mode 100644 index 00000000000..ca8723cec94 --- /dev/null +++ b/clippy_lints/src/methods/iter_count.rs @@ -0,0 +1,51 @@ +use crate::utils::{ + derefs_to_slice, is_type_diagnostic_item, match_trait_method, method_chain_args, paths, snippet_with_applicability, + span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::ITER_COUNT; + +pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], is_mut: bool) { + let mut_str = if is_mut { "_mut" } else { "" }; + let iter_method = if method_chain_args(expr, &[format!("iter{}", mut_str).as_str(), "count"]).is_some() { + "iter" + } else if method_chain_args(expr, &["into_iter", "count"]).is_some() { + "into_iter" + } else { + return; + }; + if_chain! { + let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { + Some("slice") + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { + Some("Vec") + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { + Some("VecDeque") + } else if match_trait_method(cx, expr, &paths::ITERATOR) { + Some("std::iter::Iterator") + } else { + None + }; + if let Some(caller_type) = caller_type; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_COUNT, + expr.span, + &format!("called `.{}{}().count()` on a `{}`", iter_method, mut_str, caller_type), + "try", + format!( + "{}.len()", + snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + ), + applicability, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e5509ee2c4e..d2a926d0944 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4,6 +4,7 @@ mod filter_map_identity; mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; +mod iter_count; mod manual_saturating_arithmetic; mod option_map_unwrap_or; mod unnecessary_filter_map; @@ -32,12 +33,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, - match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, - remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, - SpanlessEq, + contains_return, contains_ty, derefs_to_slice, get_parent_expr, get_trait_def_id, has_iter_method, higher, + implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, + match_def_path, match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, + path_to_local_id, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, + sugg, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1691,8 +1692,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), - ["count", "into_iter" | "iter"] => lint_iter_count(cx, expr, &arg_lists[1], false), - ["count", "iter_mut"] => lint_iter_count(cx, expr, &arg_lists[1], true), + ["count", "into_iter" | "iter"] => iter_count::lints(cx, expr, &arg_lists[1], false), + ["count", "iter_mut"] => iter_count::lints(cx, expr, &arg_lists[1], true), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), @@ -2661,46 +2662,6 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ } } -fn lint_iter_count<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], is_mut: bool) { - let mut_str = if is_mut { "_mut" } else { "" }; - let iter_method = if method_chain_args(expr, &[format!("iter{}", mut_str).as_str(), "count"]).is_some() { - "iter" - } else if method_chain_args(expr, &["into_iter", "count"]).is_some() { - "into_iter" - } else { - return; - }; - if_chain! { - let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { - Some("slice") - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { - Some("Vec") - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { - Some("VecDeque") - } else if match_trait_method(cx, expr, &paths::ITERATOR) { - Some("std::iter::Iterator") - } else { - None - }; - if let Some(caller_type) = caller_type; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_COUNT, - expr.span, - &format!("called `.{}{}().count()` on a `{}`", iter_method, mut_str, caller_type), - "try", - format!( - "{}.len()", - snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), - ), - applicability, - ); - } - } -} - fn lint_iter_nth<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, @@ -2841,46 +2802,6 @@ fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[ } } -fn derefs_to_slice<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ty: Ty<'tcx>, -) -> Option<&'tcx hir::Expr<'tcx>> { - fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { - match ty.kind() { - ty::Slice(_) => true, - ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), - ty::Array(_, size) => size - .try_eval_usize(cx.tcx, cx.param_env) - .map_or(false, |size| size < 32), - ty::Ref(_, inner, _) => may_slice(cx, inner), - _ => false, - } - } - - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { - if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { - Some(&args[0]) - } else { - None - } - } else { - match ty.kind() { - ty::Slice(_) => Some(expr), - ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), - ty::Ref(_, inner, _) => { - if may_slice(cx, inner) { - Some(expr) - } else { - None - } - }, - _ => None, - } - } -} - /// lint use of `unwrap()` for `Option`s and `Result`s fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2380ea4c7bf..ec1b189bf77 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1802,6 +1802,46 @@ pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { false } +pub fn derefs_to_slice<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ty: Ty<'tcx>, +) -> Option<&'tcx hir::Expr<'tcx>> { + fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { + match ty.kind() { + ty::Slice(_) => true, + ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), + ty::Array(_, size) => size + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |size| size < 32), + ty::Ref(_, inner, _) => may_slice(cx, inner), + _ => false, + } + } + + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { + Some(&args[0]) + } else { + None + } + } else { + match ty.kind() { + ty::Slice(_) => Some(expr), + ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), + ty::Ref(_, inner, _) => { + if may_slice(cx, inner) { + Some(expr) + } else { + None + } + }, + _ => None, + } + } +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; -- cgit 1.4.1-3-g733a5 From cc2b00055ccc18f4b345a1f6d50865ada9093e88 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 04:11:01 +0900 Subject: return when the ty doesn't have `len()` --- clippy_lints/src/methods/iter_count.rs | 33 ++++++---- tests/ui/iter_count.fixed | 26 +++++++- tests/ui/iter_count.rs | 26 +++++++- tests/ui/iter_count.stderr | 110 +++++++++++++++++++++++++++++---- 4 files changed, 169 insertions(+), 26 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index ca8723cec94..1bcdb57ad29 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,7 +1,8 @@ use crate::utils::{ - derefs_to_slice, is_type_diagnostic_item, match_trait_method, method_chain_args, paths, snippet_with_applicability, + derefs_to_slice, is_type_diagnostic_item, match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_sugg, }; + use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::Expr; @@ -19,19 +20,29 @@ pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' } else { return; }; + let ty = cx.typeck_results().expr_ty(&iter_args[0]); if_chain! { - let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { - Some("slice") - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { - Some("Vec") - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { - Some("VecDeque") - } else if match_trait_method(cx, expr, &paths::ITERATOR) { - Some("std::iter::Iterator") + let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() { + "slice" + } else if is_type_diagnostic_item(cx, ty, sym::vec_type) { + "Vec" + } else if is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { + "VecDeque" + } else if is_type_diagnostic_item(cx, ty, sym!(hashset_type)) { + "HashSet" + } else if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { + "HashMap" + } else if match_type(cx, ty, &paths::BTREEMAP) { + "BTreeMap" + } else if match_type(cx, ty, &paths::BTREESET) { + "BTreeSet" + } else if match_type(cx, ty, &paths::LINKED_LIST) { + "LinkedList" + } else if match_type(cx, ty, &paths::BINARY_HEAP) { + "BinaryHeap" } else { - None + return }; - if let Some(caller_type) = caller_type; then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed index c8f89640847..b11dadda6c2 100644 --- a/tests/ui/iter_count.fixed +++ b/tests/ui/iter_count.fixed @@ -13,7 +13,7 @@ extern crate option_helpers; use option_helpers::IteratorFalsePositives; -use std::collections::{HashSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; /// Struct to generate false positives for things with `.iter()`. #[derive(Copy, Clone)] @@ -38,21 +38,45 @@ fn main() { let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); let mut vec_deque: VecDeque<_> = vec.iter().cloned().collect(); let mut hash_set = HashSet::new(); + let mut hash_map = HashMap::new(); + let mut b_tree_map = BTreeMap::new(); + let mut b_tree_set = BTreeSet::new(); + let mut linked_list = LinkedList::new(); + let mut binary_heap = BinaryHeap::new(); hash_set.insert(1); + hash_map.insert(1, 2); + b_tree_map.insert(1, 2); + b_tree_set.insert(1); + linked_list.push_back(1); + binary_heap.push(1); &vec[..].len(); vec.len(); boxed_slice.len(); vec_deque.len(); hash_set.len(); + hash_map.len(); + b_tree_map.len(); + b_tree_set.len(); + linked_list.len(); + binary_heap.len(); vec.len(); &vec[..].len(); vec_deque.len(); + hash_map.len(); + b_tree_map.len(); + linked_list.len(); &vec[..].len(); vec.len(); vec_deque.len(); + hash_set.len(); + hash_map.len(); + b_tree_map.len(); + b_tree_set.len(); + linked_list.len(); + binary_heap.len(); // Make sure we don't lint for non-relevant types. let false_positive = HasIter; diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs index 8ea17ef34fa..7d49c6a3dbb 100644 --- a/tests/ui/iter_count.rs +++ b/tests/ui/iter_count.rs @@ -13,7 +13,7 @@ extern crate option_helpers; use option_helpers::IteratorFalsePositives; -use std::collections::{HashSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; /// Struct to generate false positives for things with `.iter()`. #[derive(Copy, Clone)] @@ -38,21 +38,45 @@ fn main() { let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); let mut vec_deque: VecDeque<_> = vec.iter().cloned().collect(); let mut hash_set = HashSet::new(); + let mut hash_map = HashMap::new(); + let mut b_tree_map = BTreeMap::new(); + let mut b_tree_set = BTreeSet::new(); + let mut linked_list = LinkedList::new(); + let mut binary_heap = BinaryHeap::new(); hash_set.insert(1); + hash_map.insert(1, 2); + b_tree_map.insert(1, 2); + b_tree_set.insert(1); + linked_list.push_back(1); + binary_heap.push(1); &vec[..].iter().count(); vec.iter().count(); boxed_slice.iter().count(); vec_deque.iter().count(); hash_set.iter().count(); + hash_map.iter().count(); + b_tree_map.iter().count(); + b_tree_set.iter().count(); + linked_list.iter().count(); + binary_heap.iter().count(); vec.iter_mut().count(); &vec[..].iter_mut().count(); vec_deque.iter_mut().count(); + hash_map.iter_mut().count(); + b_tree_map.iter_mut().count(); + linked_list.iter_mut().count(); &vec[..].into_iter().count(); vec.into_iter().count(); vec_deque.into_iter().count(); + hash_set.into_iter().count(); + hash_map.into_iter().count(); + b_tree_map.into_iter().count(); + b_tree_set.into_iter().count(); + linked_list.into_iter().count(); + binary_heap.into_iter().count(); // Make sure we don't lint for non-relevant types. let false_positive = HasIter; diff --git a/tests/ui/iter_count.stderr b/tests/ui/iter_count.stderr index 0820c001443..f3fb98e65b9 100644 --- a/tests/ui/iter_count.stderr +++ b/tests/ui/iter_count.stderr @@ -1,5 +1,5 @@ error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:43:6 + --> $DIR/iter_count.rs:53:6 | LL | &vec[..].iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` @@ -7,64 +7,148 @@ LL | &vec[..].iter().count(); = note: `-D clippy::iter-count` implied by `-D warnings` error: called `.iter().count()` on a `Vec` - --> $DIR/iter_count.rs:44:5 + --> $DIR/iter_count.rs:54:5 | LL | vec.iter().count(); | ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:45:5 + --> $DIR/iter_count.rs:55:5 | LL | boxed_slice.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` error: called `.iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:46:5 + --> $DIR/iter_count.rs:56:5 | LL | vec_deque.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` -error: called `.iter().count()` on a `std::iter::Iterator` - --> $DIR/iter_count.rs:47:5 +error: called `.iter().count()` on a `HashSet` + --> $DIR/iter_count.rs:57:5 | LL | hash_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` +error: called `.iter().count()` on a `HashMap` + --> $DIR/iter_count.rs:58:5 + | +LL | hash_map.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` + +error: called `.iter().count()` on a `BTreeMap` + --> $DIR/iter_count.rs:59:5 + | +LL | b_tree_map.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` + +error: called `.iter().count()` on a `BTreeSet` + --> $DIR/iter_count.rs:60:5 + | +LL | b_tree_set.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` + +error: called `.iter().count()` on a `LinkedList` + --> $DIR/iter_count.rs:61:5 + | +LL | linked_list.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` + +error: called `.iter().count()` on a `BinaryHeap` + --> $DIR/iter_count.rs:62:5 + | +LL | binary_heap.iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` + error: called `.iter_mut().count()` on a `Vec` - --> $DIR/iter_count.rs:49:5 + --> $DIR/iter_count.rs:64:5 | LL | vec.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter_mut().count()` on a `slice` - --> $DIR/iter_count.rs:50:6 + --> $DIR/iter_count.rs:65:6 | LL | &vec[..].iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.iter_mut().count()` on a `VecDeque` - --> $DIR/iter_count.rs:51:5 + --> $DIR/iter_count.rs:66:5 | LL | vec_deque.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` +error: called `.iter_mut().count()` on a `HashMap` + --> $DIR/iter_count.rs:67:5 + | +LL | hash_map.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` + +error: called `.iter_mut().count()` on a `BTreeMap` + --> $DIR/iter_count.rs:68:5 + | +LL | b_tree_map.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` + +error: called `.iter_mut().count()` on a `LinkedList` + --> $DIR/iter_count.rs:69:5 + | +LL | linked_list.iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` + error: called `.into_iter().count()` on a `slice` - --> $DIR/iter_count.rs:53:6 + --> $DIR/iter_count.rs:71:6 | LL | &vec[..].into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.into_iter().count()` on a `Vec` - --> $DIR/iter_count.rs:54:5 + --> $DIR/iter_count.rs:72:5 | LL | vec.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.into_iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:55:5 + --> $DIR/iter_count.rs:73:5 | LL | vec_deque.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` -error: aborting due to 11 previous errors +error: called `.into_iter().count()` on a `HashSet` + --> $DIR/iter_count.rs:74:5 + | +LL | hash_set.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` + +error: called `.into_iter().count()` on a `HashMap` + --> $DIR/iter_count.rs:75:5 + | +LL | hash_map.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` + +error: called `.into_iter().count()` on a `BTreeMap` + --> $DIR/iter_count.rs:76:5 + | +LL | b_tree_map.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` + +error: called `.into_iter().count()` on a `BTreeSet` + --> $DIR/iter_count.rs:77:5 + | +LL | b_tree_set.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` + +error: called `.into_iter().count()` on a `LinkedList` + --> $DIR/iter_count.rs:78:5 + | +LL | linked_list.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` + +error: called `.into_iter().count()` on a `BinaryHeap` + --> $DIR/iter_count.rs:79:5 + | +LL | binary_heap.into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` + +error: aborting due to 25 previous errors -- cgit 1.4.1-3-g733a5 From 8bae2797067650071b69273ecfbf55240190db07 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 15:49:03 +0900 Subject: remove if_chain --- clippy_lints/src/methods/iter_count.rs | 72 ++++++++++++++++------------------ 1 file changed, 34 insertions(+), 38 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 1bcdb57ad29..06ce06126e6 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -21,42 +21,38 @@ pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' return; }; let ty = cx.typeck_results().expr_ty(&iter_args[0]); - if_chain! { - let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() { - "slice" - } else if is_type_diagnostic_item(cx, ty, sym::vec_type) { - "Vec" - } else if is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { - "VecDeque" - } else if is_type_diagnostic_item(cx, ty, sym!(hashset_type)) { - "HashSet" - } else if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { - "HashMap" - } else if match_type(cx, ty, &paths::BTREEMAP) { - "BTreeMap" - } else if match_type(cx, ty, &paths::BTREESET) { - "BTreeSet" - } else if match_type(cx, ty, &paths::LINKED_LIST) { - "LinkedList" - } else if match_type(cx, ty, &paths::BINARY_HEAP) { - "BinaryHeap" - } else { - return - }; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_COUNT, - expr.span, - &format!("called `.{}{}().count()` on a `{}`", iter_method, mut_str, caller_type), - "try", - format!( - "{}.len()", - snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), - ), - applicability, - ); - } - } + let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() { + "slice" + } else if is_type_diagnostic_item(cx, ty, sym::vec_type) { + "Vec" + } else if is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { + "VecDeque" + } else if is_type_diagnostic_item(cx, ty, sym!(hashset_type)) { + "HashSet" + } else if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { + "HashMap" + } else if match_type(cx, ty, &paths::BTREEMAP) { + "BTreeMap" + } else if match_type(cx, ty, &paths::BTREESET) { + "BTreeSet" + } else if match_type(cx, ty, &paths::LINKED_LIST) { + "LinkedList" + } else if match_type(cx, ty, &paths::BINARY_HEAP) { + "BinaryHeap" + } else { + return; + }; + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_COUNT, + expr.span, + &format!("called `.{}{}().count()` on a `{}`", iter_method, mut_str, caller_type), + "try", + format!( + "{}.len()", + snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + ), + applicability, + ); } -- cgit 1.4.1-3-g733a5 From 77907e6dab42dd0acc23c0cf1d540d2aa3e32bb8 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 16:21:43 +0900 Subject: receive iter method name as an argument --- clippy_lints/src/methods/iter_count.rs | 16 +++------------- clippy_lints/src/methods/mod.rs | 5 +++-- 2 files changed, 6 insertions(+), 15 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 06ce06126e6..ff3aa346e2d 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,9 +1,7 @@ use crate::utils::{ - derefs_to_slice, is_type_diagnostic_item, match_type, method_chain_args, paths, snippet_with_applicability, - span_lint_and_sugg, + derefs_to_slice, is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -11,15 +9,7 @@ use rustc_span::sym; use super::ITER_COUNT; -pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], is_mut: bool) { - let mut_str = if is_mut { "_mut" } else { "" }; - let iter_method = if method_chain_args(expr, &[format!("iter{}", mut_str).as_str(), "count"]).is_some() { - "iter" - } else if method_chain_args(expr, &["into_iter", "count"]).is_some() { - "into_iter" - } else { - return; - }; +pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], iter_method: &str) { let ty = cx.typeck_results().expr_ty(&iter_args[0]); let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() { "slice" @@ -47,7 +37,7 @@ pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' cx, ITER_COUNT, expr.span, - &format!("called `.{}{}().count()` on a `{}`", iter_method, mut_str, caller_type), + &format!("called `.{}().count()` on a `{}`", iter_method, caller_type), "try", format!( "{}.len()", diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d2a926d0944..f394e6673d4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1692,8 +1692,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), - ["count", "into_iter" | "iter"] => iter_count::lints(cx, expr, &arg_lists[1], false), - ["count", "iter_mut"] => iter_count::lints(cx, expr, &arg_lists[1], true), + ["count", "into_iter"] => iter_count::lints(cx, expr, &arg_lists[1], "into_iter"), + ["count", "iter"] => iter_count::lints(cx, expr, &arg_lists[1], "iter"), + ["count", "iter_mut"] => iter_count::lints(cx, expr, &arg_lists[1], "iter_mut"), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), -- cgit 1.4.1-3-g733a5 From c297174adf9468234d0eebad608514879a52b82b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 17:07:00 +0900 Subject: export `derefs_to_slice` from methods module --- clippy_lints/src/methods/iter_count.rs | 5 ++-- clippy_lints/src/methods/mod.rs | 52 ++++++++++++++++++++++++++++++---- clippy_utils/src/lib.rs | 40 -------------------------- 3 files changed, 48 insertions(+), 49 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index ff3aa346e2d..1b99bacc3f1 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - derefs_to_slice, is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg, -}; +use crate::methods::derefs_to_slice; +use crate::utils::{is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f394e6673d4..30830fb0af6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,12 +33,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, derefs_to_slice, get_parent_expr, get_trait_def_id, has_iter_method, higher, - implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, - path_to_local_id, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, - sugg, walk_ptrs_ty_depth, SpanlessEq, + contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, + in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, + match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, + remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, + SpanlessEq, }; declare_clippy_lint! { @@ -2803,6 +2803,46 @@ fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[ } } +pub(crate) fn derefs_to_slice<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ty: Ty<'tcx>, +) -> Option<&'tcx hir::Expr<'tcx>> { + fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { + match ty.kind() { + ty::Slice(_) => true, + ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), + ty::Array(_, size) => size + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |size| size < 32), + ty::Ref(_, inner, _) => may_slice(cx, inner), + _ => false, + } + } + + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { + Some(&args[0]) + } else { + None + } + } else { + match ty.kind() { + ty::Slice(_) => Some(expr), + ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), + ty::Ref(_, inner, _) => { + if may_slice(cx, inner) { + Some(expr) + } else { + None + } + }, + _ => None, + } + } +} + /// lint use of `unwrap()` for `Option`s and `Result`s fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index ec1b189bf77..2380ea4c7bf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1802,46 +1802,6 @@ pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { false } -pub fn derefs_to_slice<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ty: Ty<'tcx>, -) -> Option<&'tcx hir::Expr<'tcx>> { - fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { - match ty.kind() { - ty::Slice(_) => true, - ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), - ty::Array(_, size) => size - .try_eval_usize(cx.tcx, cx.param_env) - .map_or(false, |size| size < 32), - ty::Ref(_, inner, _) => may_slice(cx, inner), - _ => false, - } - } - - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { - if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { - Some(&args[0]) - } else { - None - } - } else { - match ty.kind() { - ty::Slice(_) => Some(expr), - ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), - ty::Ref(_, inner, _) => { - if may_slice(cx, inner) { - Some(expr) - } else { - None - } - }, - _ => None, - } - } -} - #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; -- cgit 1.4.1-3-g733a5 From 6041365f4bae6482467210ea1b60e18101ba6fd0 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 26 Feb 2021 17:38:21 +0900 Subject: remove pub(crate) --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 30830fb0af6..4a63de3cf48 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2803,7 +2803,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[ } } -pub(crate) fn derefs_to_slice<'tcx>( +fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, -- cgit 1.4.1-3-g733a5 From 8eb2bd13d0dd70131be1e21a0a0261c9dc69937a Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Wed, 24 Feb 2021 14:02:51 +0100 Subject: update the lint messages and tests --- clippy_lints/src/assign_ops.rs | 2 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 4 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 8 +-- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 12 ++-- clippy_lints/src/integer_division.rs | 2 +- clippy_lints/src/loops.rs | 19 +++---- clippy_lints/src/matches.rs | 4 +- clippy_lints/src/methods/mod.rs | 4 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/misc.rs | 4 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/ptr.rs | 8 +-- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/transmuting_null.rs | 2 +- clippy_lints/src/types.rs | 4 +- clippy_lints/src/zero_div_zero.rs | 2 +- tests/lint_message_convention.rs | 7 ++- tests/ui-toml/vec_box_sized/test.stderr | 6 +- tests/ui/assign_ops2.stderr | 18 +++--- tests/ui/await_holding_lock.stderr | 8 +-- tests/ui/await_holding_refcell_ref.stderr | 12 ++-- tests/ui/box_vec.stderr | 2 +- tests/ui/comparison_chain.stderr | 14 ++--- tests/ui/drop_forget_copy.stderr | 12 ++-- tests/ui/drop_ref.stderr | 18 +++--- tests/ui/explicit_counter_loop.stderr | 14 ++--- tests/ui/fallible_impl_from.stderr | 8 +-- tests/ui/filter_map_next.stderr | 2 +- tests/ui/filter_map_next_fixable.stderr | 2 +- tests/ui/for_loops_over_fallibles.stderr | 10 ++-- tests/ui/forget_ref.stderr | 18 +++--- tests/ui/indexing_slicing_index.stderr | 24 ++++---- tests/ui/indexing_slicing_slice.stderr | 48 ++++++++-------- tests/ui/integer_division.stderr | 6 +- tests/ui/methods.stderr | 2 +- tests/ui/methods_fixable.stderr | 2 +- tests/ui/mismatched_target_os_unix.stderr | 34 ++++++------ tests/ui/needless_collect_indirect.stderr | 10 ++-- tests/ui/needless_question_mark.stderr | 28 +++++----- tests/ui/needless_range_loop.stderr | 20 +++---- tests/ui/needless_range_loop2.stderr | 16 +++--- tests/ui/ptr_arg.stderr | 24 ++++---- tests/ui/suspicious_operation_groupings.stderr | 54 +++++++++--------- tests/ui/toplevel_ref_arg_non_rustfix.stderr | 4 +- tests/ui/transmuting_null.stderr | 6 +- tests/ui/unnecessary_lazy_eval.stderr | 64 +++++++++++----------- tests/ui/unnecessary_lazy_eval_unfixable.stderr | 6 +- tests/ui/used_underscore_binding.stderr | 12 ++-- tests/ui/vec_box_sized.stderr | 8 +-- tests/ui/wild_in_or_pats.stderr | 16 +++--- tests/ui/zero_div_zero.stderr | 8 +-- 54 files changed, 315 insertions(+), 315 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index b3185b88840..e13f62d0428 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -209,7 +209,7 @@ fn lint_misrefactored_assign_op( diag.span_suggestion( expr.span, &format!( - "Did you mean `{} = {} {} {}` or `{}`? Consider replacing it with", + "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with", snip_a, snip_a, op.node.as_str(), diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 652d1fa16b6..bb7be3d4724 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -639,7 +639,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); if !unix_suggested && is_unix(os) { - diag.help("Did you mean `unix`?"); + diag.help("did you mean `unix`?"); unix_suggested = true; } } diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index ae64c688744..fad3aff96cc 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -116,7 +116,7 @@ fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorType cx, AWAIT_HOLDING_LOCK, ty_cause.span, - "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.", + "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await", ty_cause.scope_span.or(Some(span)), "these are all the await points this lock is held through", ); @@ -126,7 +126,7 @@ fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorType cx, AWAIT_HOLDING_REFCELL_REF, ty_cause.span, - "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await.", + "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await", ty_cause.scope_span.or(Some(span)), "these are all the await points this ref is held through", ); diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 90d31dece13..e309db25995 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -117,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { expr.span, "`if` chain can be rewritten with `match`", None, - "Consider rewriting the `if` chain to use `cmp` and `match`.", + "consider rewriting the `if` chain to use `cmp` and `match`", ) } } diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index a84f9c46287..2aea00d883c 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -98,13 +98,13 @@ declare_clippy_lint! { } const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \ - Dropping a reference does nothing."; + Dropping a reference does nothing"; const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \ - Forgetting a reference does nothing."; + Forgetting a reference does nothing"; const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \ - Dropping a copy leaves the original intact."; + Dropping a copy leaves the original intact"; const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \ - Forgetting a copy leaves the original intact."; + Forgetting a copy leaves the original intact"; declare_lint_pass!(DropForgetRef => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY]); diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 6d522c7ef33..f466dddc13c 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -133,7 +133,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h move |diag| { diag.help( "`From` is intended for infallible conversions only. \ - Use `TryFrom` if there's a possibility for the conversion to fail."); + Use `TryFrom` if there's a possibility for the conversion to fail"); diag.span_note(fpu.result, "potential failure(s)"); }); } diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 741195f3b10..c919ec097a2 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -132,13 +132,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { } let help_msg = match (range.start, range.end) { - (None, Some(_)) => "Consider using `.get(..n)`or `.get_mut(..n)` instead", - (Some(_), None) => "Consider using `.get(n..)` or .get_mut(n..)` instead", - (Some(_), Some(_)) => "Consider using `.get(n..m)` or `.get_mut(n..m)` instead", + (None, Some(_)) => "consider using `.get(..n)`or `.get_mut(..n)` instead", + (Some(_), None) => "consider using `.get(n..)` or .get_mut(n..)` instead", + (Some(_), Some(_)) => "consider using `.get(n..m)` or `.get_mut(n..m)` instead", (None, None) => return, // [..] is ok. }; - span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", None, help_msg); + span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg); } else { // Catchall non-range index, i.e., [n] or [n << m] if let ty::Array(..) = ty.kind() { @@ -153,9 +153,9 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { cx, INDEXING_SLICING, expr.span, - "indexing may panic.", + "indexing may panic", None, - "Consider using `.get(n)` or `.get_mut(n)` instead", + "consider using `.get(n)` or `.get_mut(n)` instead", ); } } diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index 31181c10d23..39b4605e72f 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for IntegerDivision { expr.span, "integer division", None, - "division of integers may cause loss of precision. consider using floats.", + "division of integers may cause loss of precision. consider using floats", ); } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 1c9373a756c..3ff9e182121 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1625,10 +1625,7 @@ fn check_for_loop_range<'tcx>( cx, NEEDLESS_RANGE_LOOP, expr.span, - &format!( - "the loop variable `{}` is only used to index `{}`.", - ident.name, indexed - ), + &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed), |diag| { multispan_sugg( diag, @@ -1763,7 +1760,7 @@ fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { arg.span, &format!( "for loop over `{0}`, which is an `Option`. This is more readably written as an \ - `if let` statement.", + `if let` statement", snippet(cx, arg.span, "_") ), None, @@ -1780,7 +1777,7 @@ fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { arg.span, &format!( "for loop over `{0}`, which is a `Result`. This is more readably written as an \ - `if let` statement.", + `if let` statement", snippet(cx, arg.span, "_") ), None, @@ -1826,7 +1823,7 @@ fn check_for_loop_explicit_counter<'tcx>( cx, EXPLICIT_COUNTER_LOOP, for_span.with_hi(arg.span.hi()), - &format!("the variable `{}` is used as a loop counter.", name), + &format!("the variable `{}` is used as a loop counter", name), "consider using", format!( "for ({}, {}) in {}.enumerate()", @@ -3055,16 +3052,16 @@ impl IterFunction { fn get_suggestion_text(&self) -> &'static str { match &self.func { IterFunctionKind::IntoIter => { - "Use the original Iterator instead of collecting it and then producing a new one" + "use the original Iterator instead of collecting it and then producing a new one" }, IterFunctionKind::Len => { - "Take the original Iterator's count instead of collecting it and finding the length" + "take the original Iterator's count instead of collecting it and finding the length" }, IterFunctionKind::IsEmpty => { - "Check if the original Iterator has anything instead of collecting it and seeing if it's empty" + "check if the original Iterator has anything instead of collecting it and seeing if it's empty" }, IterFunctionKind::Contains(_) => { - "Check if the original Iterator contains an element instead of collecting then checking" + "check if the original Iterator contains an element instead of collecting then checking" }, } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index efc8b139425..0d79ffbe944 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1173,9 +1173,9 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) { cx, WILDCARD_IN_OR_PATTERNS, arm.pat.span, - "wildcard pattern covers any other pattern as it will match anyway.", + "wildcard pattern covers any other pattern as it will match anyway", None, - "Consider handling `_` separately.", + "consider handling `_` separately", ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6f491144435..f5c01ac7729 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3081,7 +3081,7 @@ fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, fil // lint if caller of `.filter().next()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find(..)` instead."; + `.find(..)` instead"; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { let iter_snippet = snippet(cx, filter_args[0].span, ".."); @@ -3209,7 +3209,7 @@ fn lint_filter_map_next<'tcx>( } let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find_map(..)` instead."; + `.find_map(..)` instead"; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { let iter_snippet = snippet(cx, filter_args[0].span, ".."); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a867bdb326d..40ccb8c80b3 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -50,7 +50,7 @@ pub(super) fn lint<'tcx>( UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, - &format!("Use `{}` instead", simplify_using), + &format!("use `{}` instead", simplify_using), format!( "{0}.{1}({2})", snippet(cx, args[0].span, ".."), diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 2ef5c6aa2a4..12f91d7bf63 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -292,7 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { TOPLEVEL_REF_ARG, arg.pat.span, "`ref` directly on a function argument is ignored. \ - Consider using a reference type instead.", + Consider using a reference type instead", ); } } @@ -422,7 +422,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { expr.span, &format!( "used binding `{}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used.", + underscore signals that a binding will not be used", binding ), ); diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index fe8d4d07abc..a3293f1b361 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -142,7 +142,7 @@ fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { cx, NEEDLESS_QUESTION_MARK, entire_expr.span, - "Question mark operator is useless here", + "question mark operator is useless here", "try", format!("{}", utils::snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index de2fb8decb7..5474fdf30bf 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -188,7 +188,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: PTR_ARG, arg.span, "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices.", + with non-Vec-based slices", |diag| { if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) { diag.span_suggestion( @@ -217,7 +217,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: cx, PTR_ARG, arg.span, - "writing `&String` instead of `&str` involves a new object where a slice will do.", + "writing `&String` instead of `&str` involves a new object where a slice will do", |diag| { diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified); for (clonespan, suggestion) in spans { @@ -239,7 +239,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: cx, PTR_ARG, arg.span, - "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.", + "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do", |diag| { diag.span_suggestion( arg.span, @@ -278,7 +278,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: cx, PTR_ARG, arg.span, - "using a reference to `Cow` is not recommended.", + "using a reference to `Cow` is not recommended", "change this to", "&".to_owned() + &r, Applicability::Unspecified, diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index cccd24ccf94..2ff30698043 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -261,7 +261,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit cx, SUSPICIOUS_OPERATION_GROUPINGS, span, - "This sequence of operators looks suspiciously like a bug.", + "this sequence of operators looks suspiciously like a bug", "I think you meant", sugg, applicability, diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 6b171a0fa1a..2ba2b646f00 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]); -const LINT_MSG: &str = "transmuting a known null pointer into a reference."; +const LINT_MSG: &str = "transmuting a known null pointer into a reference"; impl<'tcx> LateLintPass<'tcx> for TransmutingNull { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index af8d6865f93..a18cba6fb44 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -388,7 +388,7 @@ impl Types { hir_ty.span, "you seem to be trying to use `Box>`. Consider using just `Vec`", None, - "`Vec` is already on the heap, `Box>` makes an extra allocation.", + "`Vec` is already on the heap, `Box>` makes an extra allocation", ); return; // don't recurse into the type } @@ -554,7 +554,7 @@ impl Types { cx, VEC_BOX, hir_ty.span, - "`Vec` is already on the heap, the boxing is unnecessary.", + "`Vec` is already on the heap, the boxing is unnecessary", "try", format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), Applicability::MachineApplicable, diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 4b81a27632d..11d96e15ff1 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { "constant division of `0.0` with `0.0` will always result in NaN", None, &format!( - "Consider using `{}::NAN` if you would like a constant representing NaN", + "consider using `{}::NAN` if you would like a constant representing NaN", float_type, ), ); diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index 493bd3bf56b..e316a884996 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -38,8 +38,11 @@ impl Message { r".*the arguments may be inverted...", r".*Intel x86 assembly syntax used", r".*AT&T x86 assembly syntax used", - r".*remove .* the return type...", + r".*remove .*the return type...", r"note: Clippy version: .*", + r"the compiler unexpectedly panicked. this is a bug.", + r".*help: I think you meant: .*", + r"Iterator.* will panic at runtime", ]) .unwrap(); @@ -96,7 +99,7 @@ fn lint_message_convention() { eprintln!("\n\n\nLint message should not start with a capital letter and should not have punctuation at the end of the message unless multiple sentences are needed."); eprintln!("Check out the rustc-dev-guide for more information:"); - eprintln!("https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-structure"); + eprintln!("https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-structure\n\n\n"); assert!(bad_tests.is_empty()); } diff --git a/tests/ui-toml/vec_box_sized/test.stderr b/tests/ui-toml/vec_box_sized/test.stderr index 3bdeca0bc87..cf194de3c55 100644 --- a/tests/ui-toml/vec_box_sized/test.stderr +++ b/tests/ui-toml/vec_box_sized/test.stderr @@ -1,4 +1,4 @@ -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/test.rs:9:12 | LL | struct Foo(Vec>); @@ -6,13 +6,13 @@ LL | struct Foo(Vec>); | = note: `-D clippy::vec-box` implied by `-D warnings` -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/test.rs:10:12 | LL | struct Bar(Vec>); | ^^^^^^^^^^^^^ help: try: `Vec` -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/test.rs:13:18 | LL | struct FooBarBaz(Vec>); diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/assign_ops2.stderr index 70b15d18a56..e40668ed339 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/assign_ops2.stderr @@ -5,7 +5,7 @@ LL | a += a + 1; | ^^^^^^^^^^ | = note: `-D clippy::misrefactored-assign-op` implied by `-D warnings` -help: Did you mean `a = a + 1` or `a = a + a + 1`? Consider replacing it with +help: did you mean `a = a + 1` or `a = a + a + 1`? Consider replacing it with | LL | a += 1; | ^^^^^^ @@ -20,7 +20,7 @@ error: variable appears on both sides of an assignment operation LL | a += 1 + a; | ^^^^^^^^^^ | -help: Did you mean `a = a + 1` or `a = a + 1 + a`? Consider replacing it with +help: did you mean `a = a + 1` or `a = a + 1 + a`? Consider replacing it with | LL | a += 1; | ^^^^^^ @@ -35,7 +35,7 @@ error: variable appears on both sides of an assignment operation LL | a -= a - 1; | ^^^^^^^^^^ | -help: Did you mean `a = a - 1` or `a = a - (a - 1)`? Consider replacing it with +help: did you mean `a = a - 1` or `a = a - (a - 1)`? Consider replacing it with | LL | a -= 1; | ^^^^^^ @@ -50,7 +50,7 @@ error: variable appears on both sides of an assignment operation LL | a *= a * 99; | ^^^^^^^^^^^ | -help: Did you mean `a = a * 99` or `a = a * a * 99`? Consider replacing it with +help: did you mean `a = a * 99` or `a = a * a * 99`? Consider replacing it with | LL | a *= 99; | ^^^^^^^ @@ -65,7 +65,7 @@ error: variable appears on both sides of an assignment operation LL | a *= 42 * a; | ^^^^^^^^^^^ | -help: Did you mean `a = a * 42` or `a = a * 42 * a`? Consider replacing it with +help: did you mean `a = a * 42` or `a = a * 42 * a`? Consider replacing it with | LL | a *= 42; | ^^^^^^^ @@ -80,7 +80,7 @@ error: variable appears on both sides of an assignment operation LL | a /= a / 2; | ^^^^^^^^^^ | -help: Did you mean `a = a / 2` or `a = a / (a / 2)`? Consider replacing it with +help: did you mean `a = a / 2` or `a = a / (a / 2)`? Consider replacing it with | LL | a /= 2; | ^^^^^^ @@ -95,7 +95,7 @@ error: variable appears on both sides of an assignment operation LL | a %= a % 5; | ^^^^^^^^^^ | -help: Did you mean `a = a % 5` or `a = a % (a % 5)`? Consider replacing it with +help: did you mean `a = a % 5` or `a = a % (a % 5)`? Consider replacing it with | LL | a %= 5; | ^^^^^^ @@ -110,7 +110,7 @@ error: variable appears on both sides of an assignment operation LL | a &= a & 1; | ^^^^^^^^^^ | -help: Did you mean `a = a & 1` or `a = a & a & 1`? Consider replacing it with +help: did you mean `a = a & 1` or `a = a & a & 1`? Consider replacing it with | LL | a &= 1; | ^^^^^^ @@ -125,7 +125,7 @@ error: variable appears on both sides of an assignment operation LL | a *= a * a; | ^^^^^^^^^^ | -help: Did you mean `a = a * a` or `a = a * a * a`? Consider replacing it with +help: did you mean `a = a * a` or `a = a * a * a`? Consider replacing it with | LL | a *= a; | ^^^^^^ diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index 21bf49d16f0..a5fcff7e0e4 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,4 +1,4 @@ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await. +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await --> $DIR/await_holding_lock.rs:7:9 | LL | let guard = x.lock().unwrap(); @@ -13,7 +13,7 @@ LL | | baz().await LL | | } | |_^ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await. +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await --> $DIR/await_holding_lock.rs:28:9 | LL | let guard = x.lock().unwrap(); @@ -31,7 +31,7 @@ LL | | first + second + third LL | | } | |_^ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await. +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await --> $DIR/await_holding_lock.rs:41:13 | LL | let guard = x.lock().unwrap(); @@ -45,7 +45,7 @@ LL | | baz().await LL | | }; | |_____^ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await. +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await --> $DIR/await_holding_lock.rs:53:13 | LL | let guard = x.lock().unwrap(); diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index b504f045491..55e41dbca96 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -1,4 +1,4 @@ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await. +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await --> $DIR/await_holding_refcell_ref.rs:7:9 | LL | let b = x.borrow(); @@ -13,7 +13,7 @@ LL | | baz().await LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await. +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await --> $DIR/await_holding_refcell_ref.rs:12:9 | LL | let b = x.borrow_mut(); @@ -27,7 +27,7 @@ LL | | baz().await LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await. +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await --> $DIR/await_holding_refcell_ref.rs:33:9 | LL | let b = x.borrow_mut(); @@ -45,7 +45,7 @@ LL | | first + second + third LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await. +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await --> $DIR/await_holding_refcell_ref.rs:45:9 | LL | let b = x.borrow_mut(); @@ -63,7 +63,7 @@ LL | | first + second + third LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await. +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await --> $DIR/await_holding_refcell_ref.rs:60:13 | LL | let b = x.borrow_mut(); @@ -77,7 +77,7 @@ LL | | baz().await LL | | }; | |_____^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await. +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await --> $DIR/await_holding_refcell_ref.rs:72:13 | LL | let b = x.borrow_mut(); diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index fca12eddd57..9b789334bae 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -5,7 +5,7 @@ LL | pub fn test(foo: Box>) { | ^^^^^^^^^^^^^^ | = note: `-D clippy::box-vec` implied by `-D warnings` - = help: `Vec` is already on the heap, `Box>` makes an extra allocation. + = help: `Vec` is already on the heap, `Box>` makes an extra allocation error: aborting due to previous error diff --git a/tests/ui/comparison_chain.stderr b/tests/ui/comparison_chain.stderr index 69db88b03b5..be25a80dde0 100644 --- a/tests/ui/comparison_chain.stderr +++ b/tests/ui/comparison_chain.stderr @@ -9,7 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::comparison-chain` implied by `-D warnings` - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:27:5 @@ -23,7 +23,7 @@ LL | | c() LL | | } | |_____^ | - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:35:5 @@ -37,7 +37,7 @@ LL | | c() LL | | } | |_____^ | - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:43:5 @@ -51,7 +51,7 @@ LL | | c() LL | | } | |_____^ | - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:117:5 @@ -63,7 +63,7 @@ LL | | b() LL | | } | |_____^ | - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:123:5 @@ -77,7 +77,7 @@ LL | | c() LL | | } | |_____^ | - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:131:5 @@ -91,7 +91,7 @@ LL | | c() LL | | } | |_____^ | - = help: Consider rewriting the `if` chain to use `cmp` and `match`. + = help: consider rewriting the `if` chain to use `cmp` and `match` error: aborting due to 7 previous errors diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 82a4f047ba8..01de0be7cae 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -1,4 +1,4 @@ -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact. +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact --> $DIR/drop_forget_copy.rs:33:5 | LL | drop(s1); @@ -11,7 +11,7 @@ note: argument has type SomeStruct LL | drop(s1); | ^^ -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact. +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact --> $DIR/drop_forget_copy.rs:34:5 | LL | drop(s2); @@ -23,7 +23,7 @@ note: argument has type SomeStruct LL | drop(s2); | ^^ -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact. +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact --> $DIR/drop_forget_copy.rs:36:5 | LL | drop(s4); @@ -35,7 +35,7 @@ note: argument has type SomeStruct LL | drop(s4); | ^^ -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact. +error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact --> $DIR/drop_forget_copy.rs:39:5 | LL | forget(s1); @@ -48,7 +48,7 @@ note: argument has type SomeStruct LL | forget(s1); | ^^ -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact. +error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact --> $DIR/drop_forget_copy.rs:40:5 | LL | forget(s2); @@ -60,7 +60,7 @@ note: argument has type SomeStruct LL | forget(s2); | ^^ -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact. +error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact --> $DIR/drop_forget_copy.rs:42:5 | LL | forget(s4); diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr index 10087cb4820..531849f0680 100644 --- a/tests/ui/drop_ref.stderr +++ b/tests/ui/drop_ref.stderr @@ -1,4 +1,4 @@ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:11:5 | LL | drop(&SomeStruct); @@ -11,7 +11,7 @@ note: argument has type `&SomeStruct` LL | drop(&SomeStruct); | ^^^^^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:14:5 | LL | drop(&owned1); @@ -23,7 +23,7 @@ note: argument has type `&SomeStruct` LL | drop(&owned1); | ^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:15:5 | LL | drop(&&owned1); @@ -35,7 +35,7 @@ note: argument has type `&&SomeStruct` LL | drop(&&owned1); | ^^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:16:5 | LL | drop(&mut owned1); @@ -47,7 +47,7 @@ note: argument has type `&mut SomeStruct` LL | drop(&mut owned1); | ^^^^^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:20:5 | LL | drop(reference1); @@ -59,7 +59,7 @@ note: argument has type `&SomeStruct` LL | drop(reference1); | ^^^^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:23:5 | LL | drop(reference2); @@ -71,7 +71,7 @@ note: argument has type `&mut SomeStruct` LL | drop(reference2); | ^^^^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:26:5 | LL | drop(reference3); @@ -83,7 +83,7 @@ note: argument has type `&SomeStruct` LL | drop(reference3); | ^^^^^^^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:31:5 | LL | drop(&val); @@ -95,7 +95,7 @@ note: argument has type `&T` LL | drop(&val); | ^^^^ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing --> $DIR/drop_ref.rs:39:5 | LL | std::mem::drop(&SomeStruct); diff --git a/tests/ui/explicit_counter_loop.stderr b/tests/ui/explicit_counter_loop.stderr index 931af46efe6..4cbacffe87b 100644 --- a/tests/ui/explicit_counter_loop.stderr +++ b/tests/ui/explicit_counter_loop.stderr @@ -1,4 +1,4 @@ -error: the variable `_index` is used as a loop counter. +error: the variable `_index` is used as a loop counter --> $DIR/explicit_counter_loop.rs:6:5 | LL | for _v in &vec { @@ -6,37 +6,37 @@ LL | for _v in &vec { | = note: `-D clippy::explicit-counter-loop` implied by `-D warnings` -error: the variable `_index` is used as a loop counter. +error: the variable `_index` is used as a loop counter --> $DIR/explicit_counter_loop.rs:12:5 | LL | for _v in &vec { | ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()` -error: the variable `_index` is used as a loop counter. +error: the variable `_index` is used as a loop counter --> $DIR/explicit_counter_loop.rs:17:5 | LL | for _v in &mut vec { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter_mut().enumerate()` -error: the variable `_index` is used as a loop counter. +error: the variable `_index` is used as a loop counter --> $DIR/explicit_counter_loop.rs:22:5 | LL | for _v in vec { | ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()` -error: the variable `count` is used as a loop counter. +error: the variable `count` is used as a loop counter --> $DIR/explicit_counter_loop.rs:61:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` -error: the variable `count` is used as a loop counter. +error: the variable `count` is used as a loop counter --> $DIR/explicit_counter_loop.rs:72:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` -error: the variable `count` is used as a loop counter. +error: the variable `count` is used as a loop counter --> $DIR/explicit_counter_loop.rs:130:9 | LL | for _i in 3..10 { diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index f787b30bdab..a938d234fa0 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -13,7 +13,7 @@ note: the lint level is defined here | LL | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. + = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) --> $DIR/fallible_impl_from.rs:7:13 | @@ -32,7 +32,7 @@ LL | | } LL | | } | |_^ | - = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. + = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) --> $DIR/fallible_impl_from.rs:29:13 | @@ -52,7 +52,7 @@ LL | | } LL | | } | |_^ | - = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. + = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) --> $DIR/fallible_impl_from.rs:37:17 | @@ -79,7 +79,7 @@ LL | | } LL | | } | |_^ | - = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. + = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) --> $DIR/fallible_impl_from.rs:55:12 | diff --git a/tests/ui/filter_map_next.stderr b/tests/ui/filter_map_next.stderr index 45427684d96..ddc982c93fe 100644 --- a/tests/ui/filter_map_next.stderr +++ b/tests/ui/filter_map_next.stderr @@ -1,4 +1,4 @@ -error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. +error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead --> $DIR/filter_map_next.rs:7:26 | LL | let _: Option = vec![1, 2, 3, 4, 5, 6] diff --git a/tests/ui/filter_map_next_fixable.stderr b/tests/ui/filter_map_next_fixable.stderr index 6c2530e0379..3bb062ffd7a 100644 --- a/tests/ui/filter_map_next_fixable.stderr +++ b/tests/ui/filter_map_next_fixable.stderr @@ -1,4 +1,4 @@ -error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. +error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead --> $DIR/filter_map_next_fixable.rs:8:32 | LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); diff --git a/tests/ui/for_loops_over_fallibles.stderr b/tests/ui/for_loops_over_fallibles.stderr index bef228d4b93..52b94875aec 100644 --- a/tests/ui/for_loops_over_fallibles.stderr +++ b/tests/ui/for_loops_over_fallibles.stderr @@ -1,4 +1,4 @@ -error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement. +error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement --> $DIR/for_loops_over_fallibles.rs:9:14 | LL | for x in option { @@ -7,7 +7,7 @@ LL | for x in option { = note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings` = help: consider replacing `for x in option` with `if let Some(x) = option` -error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement. +error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement --> $DIR/for_loops_over_fallibles.rs:14:14 | LL | for x in result { @@ -15,7 +15,7 @@ LL | for x in result { | = help: consider replacing `for x in result` with `if let Ok(x) = result` -error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. +error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement --> $DIR/for_loops_over_fallibles.rs:18:14 | LL | for x in option.ok_or("x not found") { @@ -31,7 +31,7 @@ LL | for x in v.iter().next() { | = note: `#[deny(clippy::iter_next_loop)]` on by default -error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement. +error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement --> $DIR/for_loops_over_fallibles.rs:29:14 | LL | for x in v.iter().next().and(Some(0)) { @@ -39,7 +39,7 @@ LL | for x in v.iter().next().and(Some(0)) { | = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))` -error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. +error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement --> $DIR/for_loops_over_fallibles.rs:33:14 | LL | for x in v.iter().next().ok_or("x not found") { diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr index b2c7f2023bf..73409388ed1 100644 --- a/tests/ui/forget_ref.stderr +++ b/tests/ui/forget_ref.stderr @@ -1,4 +1,4 @@ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:10:5 | LL | forget(&SomeStruct); @@ -11,7 +11,7 @@ note: argument has type `&SomeStruct` LL | forget(&SomeStruct); | ^^^^^^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:13:5 | LL | forget(&owned); @@ -23,7 +23,7 @@ note: argument has type `&SomeStruct` LL | forget(&owned); | ^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:14:5 | LL | forget(&&owned); @@ -35,7 +35,7 @@ note: argument has type `&&SomeStruct` LL | forget(&&owned); | ^^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:15:5 | LL | forget(&mut owned); @@ -47,7 +47,7 @@ note: argument has type `&mut SomeStruct` LL | forget(&mut owned); | ^^^^^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:19:5 | LL | forget(&*reference1); @@ -59,7 +59,7 @@ note: argument has type `&SomeStruct` LL | forget(&*reference1); | ^^^^^^^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:22:5 | LL | forget(reference2); @@ -71,7 +71,7 @@ note: argument has type `&mut SomeStruct` LL | forget(reference2); | ^^^^^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:25:5 | LL | forget(reference3); @@ -83,7 +83,7 @@ note: argument has type `&SomeStruct` LL | forget(reference3); | ^^^^^^^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:30:5 | LL | forget(&val); @@ -95,7 +95,7 @@ note: argument has type `&T` LL | forget(&val); | ^^^^ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. +error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing --> $DIR/forget_ref.rs:38:5 | LL | std::mem::forget(&SomeStruct); diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 2f6c9e2f4e5..76ecec33484 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -1,51 +1,51 @@ -error: indexing may panic. +error: indexing may panic --> $DIR/indexing_slicing_index.rs:10:5 | LL | x[index]; | ^^^^^^^^ | = note: `-D clippy::indexing-slicing` implied by `-D warnings` - = help: Consider using `.get(n)` or `.get_mut(n)` instead + = help: consider using `.get(n)` or `.get_mut(n)` instead -error: indexing may panic. +error: indexing may panic --> $DIR/indexing_slicing_index.rs:22:5 | LL | v[0]; | ^^^^ | - = help: Consider using `.get(n)` or `.get_mut(n)` instead + = help: consider using `.get(n)` or `.get_mut(n)` instead -error: indexing may panic. +error: indexing may panic --> $DIR/indexing_slicing_index.rs:23:5 | LL | v[10]; | ^^^^^ | - = help: Consider using `.get(n)` or `.get_mut(n)` instead + = help: consider using `.get(n)` or `.get_mut(n)` instead -error: indexing may panic. +error: indexing may panic --> $DIR/indexing_slicing_index.rs:24:5 | LL | v[1 << 3]; | ^^^^^^^^^ | - = help: Consider using `.get(n)` or `.get_mut(n)` instead + = help: consider using `.get(n)` or `.get_mut(n)` instead -error: indexing may panic. +error: indexing may panic --> $DIR/indexing_slicing_index.rs:30:5 | LL | v[N]; | ^^^^ | - = help: Consider using `.get(n)` or `.get_mut(n)` instead + = help: consider using `.get(n)` or `.get_mut(n)` instead -error: indexing may panic. +error: indexing may panic --> $DIR/indexing_slicing_index.rs:31:5 | LL | v[M]; | ^^^^ | - = help: Consider using `.get(n)` or `.get_mut(n)` instead + = help: consider using `.get(n)` or `.get_mut(n)` instead error: aborting due to 6 previous errors diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr index 2231deee833..f70722b92a5 100644 --- a/tests/ui/indexing_slicing_slice.stderr +++ b/tests/ui/indexing_slicing_slice.stderr @@ -1,51 +1,51 @@ -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:12:6 | LL | &x[index..]; | ^^^^^^^^^^ | = note: `-D clippy::indexing-slicing` implied by `-D warnings` - = help: Consider using `.get(n..)` or .get_mut(n..)` instead + = help: consider using `.get(n..)` or .get_mut(n..)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:13:6 | LL | &x[..index]; | ^^^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:14:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead + = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:15:6 | LL | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:15:6 | LL | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. | ^^^^^^^^^^^^^^^ | - = help: Consider using `.get(n..)` or .get_mut(n..)` instead + = help: consider using `.get(n..)` or .get_mut(n..)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:16:6 | LL | &x[5..][..10]; // Two lint reports, one for out of bounds [5..] and another for slicing [..10]. | ^^^^^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds --> $DIR/indexing_slicing_slice.rs:16:8 @@ -55,21 +55,21 @@ LL | &x[5..][..10]; // Two lint reports, one for out of bounds [5..] and ano | = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:17:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:18:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds --> $DIR/indexing_slicing_slice.rs:25:12 @@ -83,21 +83,21 @@ error: range is out of bounds LL | &y[..=4]; | ^ -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:31:6 | LL | &v[10..100]; | ^^^^^^^^^^ | - = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead + = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:32:6 | LL | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. | ^^^^^^^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds --> $DIR/indexing_slicing_slice.rs:32:8 @@ -105,21 +105,21 @@ error: range is out of bounds LL | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. | ^^ -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:33:6 | LL | &v[10..]; | ^^^^^^^ | - = help: Consider using `.get(n..)` or .get_mut(n..)` instead + = help: consider using `.get(n..)` or .get_mut(n..)` instead -error: slicing may panic. +error: slicing may panic --> $DIR/indexing_slicing_slice.rs:34:6 | LL | &v[..100]; | ^^^^^^^^ | - = help: Consider using `.get(..n)`or `.get_mut(..n)` instead + = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: aborting due to 16 previous errors diff --git a/tests/ui/integer_division.stderr b/tests/ui/integer_division.stderr index 72a232ef3d7..cbb7f881424 100644 --- a/tests/ui/integer_division.stderr +++ b/tests/ui/integer_division.stderr @@ -5,7 +5,7 @@ LL | let n = 1 / 2; | ^^^^^ | = note: `-D clippy::integer-division` implied by `-D warnings` - = help: division of integers may cause loss of precision. consider using floats. + = help: division of integers may cause loss of precision. consider using floats error: integer division --> $DIR/integer_division.rs:6:13 @@ -13,7 +13,7 @@ error: integer division LL | let o = 1 / two; | ^^^^^^^ | - = help: division of integers may cause loss of precision. consider using floats. + = help: division of integers may cause loss of precision. consider using floats error: integer division --> $DIR/integer_division.rs:7:13 @@ -21,7 +21,7 @@ error: integer division LL | let p = two / 4; | ^^^^^^^ | - = help: division of integers may cause loss of precision. consider using floats. + = help: division of integers may cause loss of precision. consider using floats error: aborting due to 3 previous errors diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 33aba630a53..4643e09e270 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -8,7 +8,7 @@ LL | | } | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead --> $DIR/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| { diff --git a/tests/ui/methods_fixable.stderr b/tests/ui/methods_fixable.stderr index 70e7c3dea54..852f48e32d6 100644 --- a/tests/ui/methods_fixable.stderr +++ b/tests/ui/methods_fixable.stderr @@ -1,4 +1,4 @@ -error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead --> $DIR/methods_fixable.rs:10:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); diff --git a/tests/ui/mismatched_target_os_unix.stderr b/tests/ui/mismatched_target_os_unix.stderr index fe9aeedb59c..ea39f5b5577 100644 --- a/tests/ui/mismatched_target_os_unix.stderr +++ b/tests/ui/mismatched_target_os_unix.stderr @@ -7,7 +7,7 @@ LL | #[cfg(linux)] | help: try: `target_os = "linux"` | = note: `-D clippy::mismatched-target-os` implied by `-D warnings` - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:9:1 @@ -17,7 +17,7 @@ LL | #[cfg(freebsd)] | | | help: try: `target_os = "freebsd"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:12:1 @@ -27,7 +27,7 @@ LL | #[cfg(dragonfly)] | | | help: try: `target_os = "dragonfly"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:15:1 @@ -37,7 +37,7 @@ LL | #[cfg(openbsd)] | | | help: try: `target_os = "openbsd"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:18:1 @@ -47,7 +47,7 @@ LL | #[cfg(netbsd)] | | | help: try: `target_os = "netbsd"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:21:1 @@ -57,7 +57,7 @@ LL | #[cfg(macos)] | | | help: try: `target_os = "macos"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:24:1 @@ -67,7 +67,7 @@ LL | #[cfg(ios)] | | | help: try: `target_os = "ios"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:27:1 @@ -77,7 +77,7 @@ LL | #[cfg(android)] | | | help: try: `target_os = "android"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:30:1 @@ -87,7 +87,7 @@ LL | #[cfg(emscripten)] | | | help: try: `target_os = "emscripten"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:33:1 @@ -97,7 +97,7 @@ LL | #[cfg(fuchsia)] | | | help: try: `target_os = "fuchsia"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:36:1 @@ -107,7 +107,7 @@ LL | #[cfg(haiku)] | | | help: try: `target_os = "haiku"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:39:1 @@ -117,7 +117,7 @@ LL | #[cfg(illumos)] | | | help: try: `target_os = "illumos"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:42:1 @@ -127,7 +127,7 @@ LL | #[cfg(l4re)] | | | help: try: `target_os = "l4re"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:45:1 @@ -137,7 +137,7 @@ LL | #[cfg(redox)] | | | help: try: `target_os = "redox"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:48:1 @@ -147,7 +147,7 @@ LL | #[cfg(solaris)] | | | help: try: `target_os = "solaris"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:51:1 @@ -157,7 +157,7 @@ LL | #[cfg(vxworks)] | | | help: try: `target_os = "vxworks"` | - = help: Did you mean `unix`? + = help: did you mean `unix`? error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:55:1 @@ -165,7 +165,7 @@ error: operating system used in target family position LL | #[cfg(all(not(any(solaris, linux)), freebsd))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Did you mean `unix`? + = help: did you mean `unix`? help: try | LL | #[cfg(all(not(any(target_os = "solaris", linux)), freebsd))] diff --git a/tests/ui/needless_collect_indirect.stderr b/tests/ui/needless_collect_indirect.stderr index fb807da5f8a..76e789d9052 100644 --- a/tests/ui/needless_collect_indirect.stderr +++ b/tests/ui/needless_collect_indirect.stderr @@ -6,7 +6,7 @@ LL | | indirect_iter.into_iter().map(|x| (x, x + 1)).collect:: | |____^ | = note: `-D clippy::needless-collect` implied by `-D warnings` -help: Use the original Iterator instead of collecting it and then producing a new one +help: use the original Iterator instead of collecting it and then producing a new one | LL | LL | sample.iter().map(|x| (x, x + 1)).collect::>(); @@ -19,7 +19,7 @@ LL | / let indirect_len = sample.iter().collect::>(); LL | | indirect_len.len(); | |____^ | -help: Take the original Iterator's count instead of collecting it and finding the length +help: take the original Iterator's count instead of collecting it and finding the length | LL | LL | sample.iter().count(); @@ -32,7 +32,7 @@ LL | / let indirect_empty = sample.iter().collect::>(); LL | | indirect_empty.is_empty(); | |____^ | -help: Check if the original Iterator has anything instead of collecting it and seeing if it's empty +help: check if the original Iterator has anything instead of collecting it and seeing if it's empty | LL | LL | sample.iter().next().is_none(); @@ -45,7 +45,7 @@ LL | / let indirect_contains = sample.iter().collect::>(); LL | | indirect_contains.contains(&&5); | |____^ | -help: Check if the original Iterator contains an element instead of collecting then checking +help: check if the original Iterator contains an element instead of collecting then checking | LL | LL | sample.iter().any(|x| x == &5); @@ -58,7 +58,7 @@ LL | / let non_copy_contains = sample.into_iter().collect::>(); LL | | non_copy_contains.contains(&a); | |____^ | -help: Check if the original Iterator contains an element instead of collecting then checking +help: check if the original Iterator contains an element instead of collecting then checking | LL | LL | sample.into_iter().any(|x| x == a); diff --git a/tests/ui/needless_question_mark.stderr b/tests/ui/needless_question_mark.stderr index 567bc518a3f..983c56031d8 100644 --- a/tests/ui/needless_question_mark.stderr +++ b/tests/ui/needless_question_mark.stderr @@ -1,4 +1,4 @@ -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:23:12 | LL | return Some(to.magic?); @@ -6,79 +6,79 @@ LL | return Some(to.magic?); | = note: `-D clippy::needless-question-mark` implied by `-D warnings` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:31:12 | LL | return Some(to.magic?) | ^^^^^^^^^^^^^^^ help: try: `to.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:36:5 | LL | Some(to.magic?) | ^^^^^^^^^^^^^^^ help: try: `to.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:41:21 | LL | to.and_then(|t| Some(t.magic?)) | ^^^^^^^^^^^^^^ help: try: `t.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:50:9 | LL | Some(t.magic?) | ^^^^^^^^^^^^^^ help: try: `t.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:55:12 | LL | return Ok(tr.magic?); | ^^^^^^^^^^^^^ help: try: `tr.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:62:12 | LL | return Ok(tr.magic?) | ^^^^^^^^^^^^^ help: try: `tr.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:66:5 | LL | Ok(tr.magic?) | ^^^^^^^^^^^^^ help: try: `tr.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:70:21 | LL | tr.and_then(|t| Ok(t.magic?)) | ^^^^^^^^^^^^ help: try: `t.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:78:9 | LL | Ok(t.magic?) | ^^^^^^^^^^^^ help: try: `t.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:85:16 | LL | return Ok(t.magic?); | ^^^^^^^^^^^^ help: try: `t.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:138:9 | LL | Ok(to.magic?) // should be triggered | ^^^^^^^^^^^^^ help: try: `to.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:154:9 | LL | Some(to.magic?) // should be triggered | ^^^^^^^^^^^^^^^ help: try: `to.magic` -error: Question mark operator is useless here +error: question mark operator is useless here --> $DIR/needless_question_mark.rs:162:9 | LL | Ok(to.magic?) // should be triggered diff --git a/tests/ui/needless_range_loop.stderr b/tests/ui/needless_range_loop.stderr index c50c4931fb4..c898cd64a93 100644 --- a/tests/ui/needless_range_loop.stderr +++ b/tests/ui/needless_range_loop.stderr @@ -1,4 +1,4 @@ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:10:14 | LL | for i in 0..vec.len() { @@ -10,7 +10,7 @@ help: consider using an iterator LL | for in &vec { | ^^^^^^ ^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:19:14 | LL | for i in 0..vec.len() { @@ -21,7 +21,7 @@ help: consider using an iterator LL | for in &vec { | ^^^^^^ ^^^^ -error: the loop variable `j` is only used to index `STATIC`. +error: the loop variable `j` is only used to index `STATIC` --> $DIR/needless_range_loop.rs:24:14 | LL | for j in 0..4 { @@ -32,7 +32,7 @@ help: consider using an iterator LL | for in &STATIC { | ^^^^^^ ^^^^^^^ -error: the loop variable `j` is only used to index `CONST`. +error: the loop variable `j` is only used to index `CONST` --> $DIR/needless_range_loop.rs:28:14 | LL | for j in 0..4 { @@ -54,7 +54,7 @@ help: consider using an iterator LL | for (i, ) in vec.iter().enumerate() { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec2`. +error: the loop variable `i` is only used to index `vec2` --> $DIR/needless_range_loop.rs:40:14 | LL | for i in 0..vec.len() { @@ -65,7 +65,7 @@ help: consider using an iterator LL | for in vec2.iter().take(vec.len()) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:44:14 | LL | for i in 5..vec.len() { @@ -76,7 +76,7 @@ help: consider using an iterator LL | for in vec.iter().skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:48:14 | LL | for i in 0..MAX_LEN { @@ -87,7 +87,7 @@ help: consider using an iterator LL | for in vec.iter().take(MAX_LEN) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:52:14 | LL | for i in 0..=MAX_LEN { @@ -98,7 +98,7 @@ help: consider using an iterator LL | for in vec.iter().take(MAX_LEN + 1) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:56:14 | LL | for i in 5..10 { @@ -109,7 +109,7 @@ help: consider using an iterator LL | for in vec.iter().take(10).skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop.rs:60:14 | LL | for i in 5..=10 { diff --git a/tests/ui/needless_range_loop2.stderr b/tests/ui/needless_range_loop2.stderr index c54ab5ec980..2e1f0fd0299 100644 --- a/tests/ui/needless_range_loop2.stderr +++ b/tests/ui/needless_range_loop2.stderr @@ -1,4 +1,4 @@ -error: the loop variable `i` is only used to index `ns`. +error: the loop variable `i` is only used to index `ns` --> $DIR/needless_range_loop2.rs:10:14 | LL | for i in 3..10 { @@ -10,7 +10,7 @@ help: consider using an iterator LL | for in ns.iter().take(10).skip(3) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `ms`. +error: the loop variable `i` is only used to index `ms` --> $DIR/needless_range_loop2.rs:31:14 | LL | for i in 0..ms.len() { @@ -21,7 +21,7 @@ help: consider using an iterator LL | for in &mut ms { | ^^^^^^ ^^^^^^^ -error: the loop variable `i` is only used to index `ms`. +error: the loop variable `i` is only used to index `ms` --> $DIR/needless_range_loop2.rs:37:14 | LL | for i in 0..ms.len() { @@ -32,7 +32,7 @@ help: consider using an iterator LL | for in &mut ms { | ^^^^^^ ^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop2.rs:61:14 | LL | for i in x..x + 4 { @@ -43,7 +43,7 @@ help: consider using an iterator LL | for in vec.iter_mut().skip(x).take(4) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `vec`. +error: the loop variable `i` is only used to index `vec` --> $DIR/needless_range_loop2.rs:68:14 | LL | for i in x..=x + 4 { @@ -54,7 +54,7 @@ help: consider using an iterator LL | for in vec.iter_mut().skip(x).take(4 + 1) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `arr`. +error: the loop variable `i` is only used to index `arr` --> $DIR/needless_range_loop2.rs:74:14 | LL | for i in 0..3 { @@ -65,7 +65,7 @@ help: consider using an iterator LL | for in &arr { | ^^^^^^ ^^^^ -error: the loop variable `i` is only used to index `arr`. +error: the loop variable `i` is only used to index `arr` --> $DIR/needless_range_loop2.rs:78:14 | LL | for i in 0..2 { @@ -76,7 +76,7 @@ help: consider using an iterator LL | for in arr.iter().take(2) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^ -error: the loop variable `i` is only used to index `arr`. +error: the loop variable `i` is only used to index `arr` --> $DIR/needless_range_loop2.rs:82:14 | LL | for i in 1..3 { diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 708318bbe29..d302b16d4b7 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,4 +1,4 @@ -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices --> $DIR/ptr_arg.rs:7:14 | LL | fn do_vec(x: &Vec) { @@ -6,25 +6,25 @@ LL | fn do_vec(x: &Vec) { | = note: `-D clippy::ptr-arg` implied by `-D warnings` -error: writing `&String` instead of `&str` involves a new object where a slice will do. +error: writing `&String` instead of `&str` involves a new object where a slice will do --> $DIR/ptr_arg.rs:16:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` -error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do. +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do --> $DIR/ptr_arg.rs:25:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices --> $DIR/ptr_arg.rs:38:18 | LL | fn do_vec(x: &Vec); | ^^^^^^^^^ help: change this to: `&[i64]` -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices --> $DIR/ptr_arg.rs:51:14 | LL | fn cloned(x: &Vec) -> Vec { @@ -43,7 +43,7 @@ help: change `x.clone()` to LL | x.to_owned() | -error: writing `&String` instead of `&str` involves a new object where a slice will do. +error: writing `&String` instead of `&str` involves a new object where a slice will do --> $DIR/ptr_arg.rs:60:18 | LL | fn str_cloned(x: &String) -> String { @@ -66,7 +66,7 @@ help: change `x.clone()` to LL | x.to_string() | -error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do. +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do --> $DIR/ptr_arg.rs:68:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { @@ -89,7 +89,7 @@ help: change `x.clone()` to LL | x.to_path_buf() | -error: writing `&String` instead of `&str` involves a new object where a slice will do. +error: writing `&String` instead of `&str` involves a new object where a slice will do --> $DIR/ptr_arg.rs:76:44 | LL | fn false_positive_capacity(x: &Vec, y: &String) { @@ -108,13 +108,13 @@ help: change `y.as_str()` to LL | let c = y; | ^ -error: using a reference to `Cow` is not recommended. +error: using a reference to `Cow` is not recommended --> $DIR/ptr_arg.rs:90:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` -error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices --> $DIR/ptr_arg.rs:143:21 | LL | fn foo_vec(vec: &Vec) { @@ -133,7 +133,7 @@ help: change `vec.clone()` to LL | let _ = vec.to_owned().clone(); | ^^^^^^^^^^^^^^ -error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do. +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do --> $DIR/ptr_arg.rs:148:23 | LL | fn foo_path(path: &PathBuf) { @@ -152,7 +152,7 @@ help: change `path.clone()` to LL | let _ = path.to_path_buf().clone(); | ^^^^^^^^^^^^^^^^^^ -error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do. +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do --> $DIR/ptr_arg.rs:153:21 | LL | fn foo_str(str: &PathBuf) { diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr index ce7108217f1..2da05399575 100644 --- a/tests/ui/suspicious_operation_groupings.stderr +++ b/tests/ui/suspicious_operation_groupings.stderr @@ -1,4 +1,4 @@ -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:14:9 | LL | self.x == other.y && self.y == other.y && self.z == other.z @@ -6,157 +6,157 @@ LL | self.x == other.y && self.y == other.y && self.z == other.z | = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:14:9 | LL | self.x == other.y && self.y == other.y && self.z == other.z | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:27:20 | LL | s1.a < s2.a && s1.a < s2.b | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:75:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:80:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:80:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:85:19 | LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:90:19 | LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:95:5 | LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: I think you meant: `s1.a * s2.a` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:100:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:113:20 | LL | (s1.a * s2.a + s1.b * s1.b) | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:118:34 | LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:123:38 | LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:128:39 | LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:133:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:133:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:138:40 | LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:143:40 | LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:148:20 | LL | (s1.a * s2.a + s2.b * s2.b) / 2 | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:153:35 | LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:158:29 | LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:163:17 | LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:172:77 | LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: I think you meant: `(n1.inner.2).0 == (n2.inner.2).0` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:186:25 | LL | s1.a <= s2.a && s1.a <= s2.b | ^^^^^^^^^^^^ help: I think you meant: `s1.b <= s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:192:23 | LL | if s1.a < s2.a && s1.a < s2.b { | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:199:48 | LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) | ^^^^^^^^^^^^^ help: I think you meant: `-s1.c * -s2.c` -error: This sequence of operators looks suspiciously like a bug. +error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:204:27 | LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/tests/ui/toplevel_ref_arg_non_rustfix.stderr index 6c36141a58c..b8cfd987394 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -1,4 +1,4 @@ -error: `ref` directly on a function argument is ignored. Consider using a reference type instead. +error: `ref` directly on a function argument is ignored. Consider using a reference type instead --> $DIR/toplevel_ref_arg_non_rustfix.rs:9:15 | LL | fn the_answer(ref mut x: u8) { @@ -6,7 +6,7 @@ LL | fn the_answer(ref mut x: u8) { | = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` -error: `ref` directly on a function argument is ignored. Consider using a reference type instead. +error: `ref` directly on a function argument is ignored. Consider using a reference type instead --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24 | LL | fn fun_example(ref _x: usize) {} diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index 05f91ee2ada..1848fc2490a 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -1,4 +1,4 @@ -error: transmuting a known null pointer into a reference. +error: transmuting a known null pointer into a reference --> $DIR/transmuting_null.rs:10:23 | LL | let _: &u64 = std::mem::transmute(0 as *const u64); @@ -6,13 +6,13 @@ LL | let _: &u64 = std::mem::transmute(0 as *const u64); | = note: `-D clippy::transmuting-null` implied by `-D warnings` -error: transmuting a known null pointer into a reference. +error: transmuting a known null pointer into a reference --> $DIR/transmuting_null.rs:11:23 | LL | let _: &u64 = std::mem::transmute(std::ptr::null::()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: transmuting a known null pointer into a reference. +error: transmuting a known null pointer into a reference --> $DIR/transmuting_null.rs:21:23 | LL | let _: &u64 = std::mem::transmute(ZPTR); diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 44dcd0cafbb..cc94bd5cd9e 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -2,7 +2,7 @@ error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:35:13 | LL | let _ = opt.unwrap_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `opt.unwrap_or(2)` | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` @@ -10,187 +10,187 @@ error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:39:13 | LL | let _ = opt.and_then(|_| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `opt.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:40:13 | LL | let _ = opt.or_else(|| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `opt.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:41:13 | LL | let _ = opt.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)` + | ^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `opt.or(None)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:42:13 | LL | let _ = opt.get_or_insert_with(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `get_or_insert` instead: `opt.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:43:13 | LL | let _ = opt.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^ help: use `ok_or` instead: `opt.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:44:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:47:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Some(10).unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = Some(10).and_then(|_| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `Some(10).and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:49:28 | LL | let _: Option = None.or_else(|| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `None.or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = None.get_or_insert_with(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `get_or_insert` instead: `None.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:51:35 | LL | let _: Result = None.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `ok_or` instead: `None.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:52:28 | LL | let _: Option = None.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)` + | ^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `None.or(None)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `deep.0.unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = deep.0.and_then(|_| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `deep.0.and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = deep.0.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `deep.0.or(None)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `get_or_insert` instead: `deep.0.get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:59:13 | LL | let _ = deep.0.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `ok_or` instead: `deep.0.ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:79:28 | LL | let _: Option = None.or_else(|| Some(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `None.or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:80:13 | LL | let _ = deep.0.or_else(|| Some(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `deep.0.or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:81:13 | LL | let _ = opt.or_else(|| Some(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `opt.or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = res2.unwrap_or_else(|_| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `res2.unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:88:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:111:35 | LL | let _: Result = res.and_then(|_| Err(2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `res.and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:112:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `res.and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:113:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `res.and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:115:35 | LL | let _: Result = res.or_else(|_| Ok(2)); - | ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `res.or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:116:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `res.or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:117:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `res.or(Ok(ext_str.some_field))` error: aborting due to 32 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 581d641cbf5..75674b0a9d2 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -2,7 +2,7 @@ error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 | LL | let _ = Ok(1).unwrap_or_else(|()| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Ok(1).unwrap_or(2)` | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` @@ -10,13 +10,13 @@ error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Ok(1).unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Ok(1).unwrap_or(2)` error: aborting due to 3 previous errors diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 68e96148093..2cbfc5ca2e2 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,4 +1,4 @@ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:26:5 | LL | _foo + 1 @@ -6,31 +6,31 @@ LL | _foo + 1 | = note: `-D clippy::used-underscore-binding` implied by `-D warnings` -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:31:20 | LL | println!("{}", _foo); | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:32:16 | LL | assert_eq!(_foo, _foo); | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:32:22 | LL | assert_eq!(_foo, _foo); | ^^^^ -error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. +error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:45:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ -error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. +error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:100:16 | LL | uses_i(_i); diff --git a/tests/ui/vec_box_sized.stderr b/tests/ui/vec_box_sized.stderr index 57e2f1fdf9a..83435a40aa1 100644 --- a/tests/ui/vec_box_sized.stderr +++ b/tests/ui/vec_box_sized.stderr @@ -1,4 +1,4 @@ -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/vec_box_sized.rs:14:21 | LL | sized_type: Vec>, @@ -6,19 +6,19 @@ LL | sized_type: Vec>, | = note: `-D clippy::vec-box` implied by `-D warnings` -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/vec_box_sized.rs:17:14 | LL | struct A(Vec>); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec` -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/vec_box_sized.rs:18:18 | LL | struct B(Vec>>); | ^^^^^^^^^^^^^^^ help: try: `Vec` -error: `Vec` is already on the heap, the boxing is unnecessary. +error: `Vec` is already on the heap, the boxing is unnecessary --> $DIR/vec_box_sized.rs:46:23 | LL | pub fn f() -> Vec> { diff --git a/tests/ui/wild_in_or_pats.stderr b/tests/ui/wild_in_or_pats.stderr index 33c34cbbd40..45b87aa0f20 100644 --- a/tests/ui/wild_in_or_pats.stderr +++ b/tests/ui/wild_in_or_pats.stderr @@ -1,35 +1,35 @@ -error: wildcard pattern covers any other pattern as it will match anyway. +error: wildcard pattern covers any other pattern as it will match anyway --> $DIR/wild_in_or_pats.rs:8:9 | LL | "bar" | _ => { | ^^^^^^^^^ | = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings` - = help: Consider handling `_` separately. + = help: consider handling `_` separately -error: wildcard pattern covers any other pattern as it will match anyway. +error: wildcard pattern covers any other pattern as it will match anyway --> $DIR/wild_in_or_pats.rs:16:9 | LL | "bar" | "bar2" | _ => { | ^^^^^^^^^^^^^^^^^^ | - = help: Consider handling `_` separately. + = help: consider handling `_` separately -error: wildcard pattern covers any other pattern as it will match anyway. +error: wildcard pattern covers any other pattern as it will match anyway --> $DIR/wild_in_or_pats.rs:24:9 | LL | _ | "bar" | _ => { | ^^^^^^^^^^^^^ | - = help: Consider handling `_` separately. + = help: consider handling `_` separately -error: wildcard pattern covers any other pattern as it will match anyway. +error: wildcard pattern covers any other pattern as it will match anyway --> $DIR/wild_in_or_pats.rs:32:9 | LL | _ | "bar" => { | ^^^^^^^^^ | - = help: Consider handling `_` separately. + = help: consider handling `_` separately error: aborting due to 4 previous errors diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index d0e88f3c5a5..0931dd32e7a 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -13,7 +13,7 @@ LL | let nan = 0.0 / 0.0; | ^^^^^^^^^ | = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` - = help: Consider using `f64::NAN` if you would like a constant representing NaN + = help: consider using `f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:5:19 @@ -27,7 +27,7 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let f64_nan = 0.0 / 0.0f64; | ^^^^^^^^^^^^ | - = help: Consider using `f64::NAN` if you would like a constant representing NaN + = help: consider using `f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:6:25 @@ -41,7 +41,7 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let other_f64_nan = 0.0f64 / 0.0; | ^^^^^^^^^^^^ | - = help: Consider using `f64::NAN` if you would like a constant representing NaN + = help: consider using `f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:7:28 @@ -55,7 +55,7 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let one_more_f64_nan = 0.0f64 / 0.0f64; | ^^^^^^^^^^^^^^^ | - = help: Consider using `f64::NAN` if you would like a constant representing NaN + = help: consider using `f64::NAN` if you would like a constant representing NaN error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From e00b1cc73ada33c7ef72702810a74f5abd38b112 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Fri, 26 Feb 2021 15:49:18 +0100 Subject: change some lint messages and remove old entries from the ignorelist --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/types.rs | 2 +- tests/lint_message_convention.rs | 4 -- tests/ui/dlist.stderr | 12 ++--- tests/ui/iterator_step_by_zero.stderr | 14 +++--- tests/ui/suspicious_operation_groupings.stderr | 54 +++++++++++----------- 7 files changed, 43 insertions(+), 47 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f5c01ac7729..b0f8185e331 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2569,7 +2569,7 @@ fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx cx, ITERATOR_STEP_BY_ZERO, expr.span, - "Iterator::step_by(0) will panic at runtime", + "`Iterator::step_by(0)` will panic at runtime", ); } } diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 2ff30698043..44521885d20 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -262,7 +262,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit SUSPICIOUS_OPERATION_GROUPINGS, span, "this sequence of operators looks suspiciously like a bug", - "I think you meant", + "did you mean", sugg, applicability, ) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index a18cba6fb44..f71b1651bfe 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -578,7 +578,7 @@ impl Types { cx, LINKEDLIST, hir_ty.span, - "I see you're using a LinkedList! Perhaps you meant some other data structure?", + "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?", None, "a `VecDeque` might work", ); diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index 1606a7881c7..d45d93f8184 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -31,9 +31,7 @@ impl Message { // sometimes the first character is capitalized and it is legal (like in "Iterator...") or // we want to ask a question ending in "?" let exceptions_set: RegexSet = RegexSet::new(&[ - r".*error: I see you're using a LinkedList! Perhaps you meant some other data structure?", r".*C-like enum variant discriminant is not portable to 32-bit targets", - r".*Iterator::step_by(0) will panic at runtime", r".*did you mean `unix`?", r".*the arguments may be inverted...", r".*Intel x86 assembly syntax used", @@ -41,8 +39,6 @@ impl Message { r".*remove .*the return type...", r"note: Clippy version: .*", r"the compiler unexpectedly panicked. this is a bug.", - r".*help: I think you meant: .*", - r"Iterator.* will panic at runtime", ]) .unwrap(); diff --git a/tests/ui/dlist.stderr b/tests/ui/dlist.stderr index 64fde33c64f..234db33ba12 100644 --- a/tests/ui/dlist.stderr +++ b/tests/ui/dlist.stderr @@ -1,4 +1,4 @@ -error: I see you're using a LinkedList! Perhaps you meant some other data structure? +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/dlist.rs:9:16 | LL | type Baz = LinkedList; @@ -7,7 +7,7 @@ LL | type Baz = LinkedList; = note: `-D clippy::linkedlist` implied by `-D warnings` = help: a `VecDeque` might work -error: I see you're using a LinkedList! Perhaps you meant some other data structure? +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/dlist.rs:10:15 | LL | fn foo(_: LinkedList); @@ -15,7 +15,7 @@ LL | fn foo(_: LinkedList); | = help: a `VecDeque` might work -error: I see you're using a LinkedList! Perhaps you meant some other data structure? +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/dlist.rs:11:23 | LL | const BAR: Option>; @@ -23,7 +23,7 @@ LL | const BAR: Option>; | = help: a `VecDeque` might work -error: I see you're using a LinkedList! Perhaps you meant some other data structure? +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/dlist.rs:22:15 | LL | fn foo(_: LinkedList) {} @@ -31,7 +31,7 @@ LL | fn foo(_: LinkedList) {} | = help: a `VecDeque` might work -error: I see you're using a LinkedList! Perhaps you meant some other data structure? +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/dlist.rs:25:39 | LL | pub fn test(my_favourite_linked_list: LinkedList) { @@ -39,7 +39,7 @@ LL | pub fn test(my_favourite_linked_list: LinkedList) { | = help: a `VecDeque` might work -error: I see you're using a LinkedList! Perhaps you meant some other data structure? +error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/dlist.rs:29:29 | LL | pub fn test_ret() -> Option> { diff --git a/tests/ui/iterator_step_by_zero.stderr b/tests/ui/iterator_step_by_zero.stderr index c2c6803b3e6..d792aea11df 100644 --- a/tests/ui/iterator_step_by_zero.stderr +++ b/tests/ui/iterator_step_by_zero.stderr @@ -1,4 +1,4 @@ -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:3:13 | LL | let _ = vec!["A", "B", "B"].iter().step_by(0); @@ -6,37 +6,37 @@ LL | let _ = vec!["A", "B", "B"].iter().step_by(0); | = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:4:13 | LL | let _ = "XXX".chars().step_by(0); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:5:13 | LL | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:14:13 | LL | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:15:13 | LL | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:18:13 | LL | let _ = x.step_by(0); | ^^^^^^^^^^^^ -error: Iterator::step_by(0) will panic at runtime +error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:22:13 | LL | let _ = v1.iter().step_by(2 / 3); diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr index 2da05399575..96065699d32 100644 --- a/tests/ui/suspicious_operation_groupings.stderr +++ b/tests/ui/suspicious_operation_groupings.stderr @@ -2,7 +2,7 @@ error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:14:9 | LL | self.x == other.y && self.y == other.y && self.z == other.z - | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` + | ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x` | = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` @@ -10,157 +10,157 @@ error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:14:9 | LL | self.x == other.y && self.y == other.y && self.z == other.z - | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` + | ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:27:20 | LL | s1.a < s2.a && s1.a < s2.b - | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:75:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:80:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:80:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:85:19 | LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:90:19 | LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:95:5 | LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c - | ^^^^^^^^^^^ help: I think you meant: `s1.a * s2.a` + | ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:100:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:113:20 | LL | (s1.a * s2.a + s1.b * s1.b) - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:118:34 | LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:123:38 | LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:128:39 | LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:133:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:133:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:138:40 | LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:143:40 | LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) - | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:148:20 | LL | (s1.a * s2.a + s2.b * s2.b) / 2 - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:153:35 | LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) - | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:158:29 | LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d - | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` + | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:163:17 | LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d - | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` + | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:172:77 | LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: I think you meant: `(n1.inner.2).0 == (n2.inner.2).0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:186:25 | LL | s1.a <= s2.a && s1.a <= s2.b - | ^^^^^^^^^^^^ help: I think you meant: `s1.b <= s2.b` + | ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:192:23 | LL | if s1.a < s2.a && s1.a < s2.b { - | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` + | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:199:48 | LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) - | ^^^^^^^^^^^^^ help: I think you meant: `-s1.c * -s2.c` + | ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:204:27 | LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) - | ^^^^^^^^^^^^^ help: I think you meant: `-s1.b < -s2.b` + | ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b` error: aborting due to 27 previous errors -- cgit 1.4.1-3-g733a5 From e0f982bb3e975a3b5925e17790f6df70bad0c153 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 10 Mar 2021 00:02:24 +0900 Subject: Improve doc on `map_flatten` --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cc8dcacb1eb..612684dc4d8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -403,7 +403,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, + /// **What it does:** Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option` /// /// **Why is this bad?** Readability, this can be written more concisely as /// `_.flat_map(_)` -- cgit 1.4.1-3-g733a5 From 9c1dd0c22721029dc47e5fe73d85670abab9adfc Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 11 Mar 2021 10:57:49 +0100 Subject: Fix remaining dogfood errors (internal lints) --- clippy_lints/src/loops/explicit_iter_loop.rs | 8 ++++---- clippy_lints/src/loops/for_kv_map.rs | 3 ++- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/loops/needless_collect.rs | 6 +++--- clippy_lints/src/methods/iter_count.rs | 6 +++--- clippy_utils/src/eager_or_lazy.rs | 5 +++-- 6 files changed, 16 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 44d08916891..9683e59a396 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TyS}; -use rustc_span::symbol::sym; +use rustc_span::sym; use crate::utils::{is_type_diagnostic_item, match_type, paths}; @@ -55,9 +55,9 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { is_iterable_array(ty, cx) || is_type_diagnostic_item(cx, ty, sym::vec_type) || match_type(cx, ty, &paths::LINKED_LIST) || - is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || - is_type_diagnostic_item(cx, ty, sym!(hashset_type)) || - is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) || + is_type_diagnostic_item(cx, ty, sym::hashmap_type) || + is_type_diagnostic_item(cx, ty, sym::hashset_type) || + is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || match_type(cx, ty, &paths::BINARY_HEAP) || match_type(cx, ty, &paths::BTREEMAP) || match_type(cx, ty, &paths::BTREESET) diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index eb53c3179ca..6ee9b95a3b6 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -4,6 +4,7 @@ use crate::utils::{is_type_diagnostic_item, match_type, multispan_sugg, paths, s use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_span::sym; /// Checks for the `FOR_KV_MAP` lint. pub(super) fn check<'tcx>( @@ -35,7 +36,7 @@ pub(super) fn check<'tcx>( _ => arg, }; - if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || match_type(cx, ty, &paths::BTREEMAP) { + if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || match_type(cx, ty, &paths::BTREEMAP) { span_lint_and_then( cx, FOR_KV_MAP, diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index c41eb32f9d8..fad96c2d5c0 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -328,7 +328,7 @@ fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool { _ => false, }; - is_slice || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) + is_slice || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) } fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 6f271309105..92560c80629 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -29,9 +29,9 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont then { let ty = cx.typeck_results().node_type(ty.hir_id); if is_type_diagnostic_item(cx, ty, sym::vec_type) || - is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) || + is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || match_type(cx, ty, &paths::BTREEMAP) || - is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { + is_type_diagnostic_item(cx, ty, sym::hashmap_type) { if method.ident.name == sym!(len) { let span = shorten_needless_collect_span(expr); span_lint_and_sugg( @@ -99,7 +99,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); if let ty = cx.typeck_results().node_type(ty.hir_id); if is_type_diagnostic_item(cx, ty, sym::vec_type) || - is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) || + is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || match_type(cx, ty, &paths::LINKED_LIST); if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident); if iter_calls.len() == 1; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 1b99bacc3f1..71d65a01d3e 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -14,11 +14,11 @@ pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' "slice" } else if is_type_diagnostic_item(cx, ty, sym::vec_type) { "Vec" - } else if is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::vecdeque_type) { "VecDeque" - } else if is_type_diagnostic_item(cx, ty, sym!(hashset_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) { "HashSet" - } else if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::hashmap_type) { "HashMap" } else if match_type(cx, ty, &paths::BTREEMAP) { "BTreeMap" diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index f54a35a0a18..8013c4e4fcb 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -9,7 +9,7 @@ //! - or-fun-call //! - option-if-let-else -use crate::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths}; +use crate::{is_ctor_or_promotable_const_function, is_type_diagnostic_item}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -100,7 +100,8 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), ExprKind::Index(obj, _) => { let ty = self.cx.typeck_results().expr_ty(obj); - is_type_diagnostic_item(self.cx, ty, sym::hashmap_type) || match_type(self.cx, ty, &paths::BTREEMAP) + is_type_diagnostic_item(self.cx, ty, sym::hashmap_type) + || is_type_diagnostic_item(self.cx, ty, sym::BTreeMap) }, ExprKind::MethodCall(..) => true, _ => false, -- cgit 1.4.1-3-g733a5 From f0f07accbce24adb5706eeb4e14e0e1c6b2b973b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 00:14:38 +0900 Subject: move expect_used, filter_next, get_unwrap, ok_expect and unwrap_used to their own modules --- clippy_lints/src/methods/expect_used.rs | 30 +++ clippy_lints/src/methods/filter_next.rs | 31 +++ clippy_lints/src/methods/get_unwrap.rs | 84 +++++++++ clippy_lints/src/methods/mod.rs | 218 ++-------------------- clippy_lints/src/methods/ok_expect.rs | 45 +++++ clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/methods/unwrap_used.rs | 34 ++++ 8 files changed, 244 insertions(+), 202 deletions(-) create mode 100644 clippy_lints/src/methods/expect_used.rs create mode 100644 clippy_lints/src/methods/filter_next.rs create mode 100644 clippy_lints/src/methods/get_unwrap.rs create mode 100644 clippy_lints/src/methods/ok_expect.rs create mode 100644 clippy_lints/src/methods/unwrap_used.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs new file mode 100644 index 00000000000..90b781bd9d1 --- /dev/null +++ b/clippy_lints/src/methods/expect_used.rs @@ -0,0 +1,30 @@ +use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::EXPECT_USED; + +/// lint use of `expect()` for `Option`s and `Result`s +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { + let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); + + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { + Some((EXPECT_USED, "an Option", "None")) + } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { + Some((EXPECT_USED, "a Result", "Err")) + } else { + None + }; + + if let Some((lint, kind, none_value)) = mess { + span_lint_and_help( + cx, + lint, + expr.span, + &format!("used `expect()` on `{}` value", kind,), + None, + &format!("if this value is an `{}`, it will panic", none_value,), + ); + } +} diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs new file mode 100644 index 00000000000..81619e73017 --- /dev/null +++ b/clippy_lints/src/methods/filter_next.rs @@ -0,0 +1,31 @@ +use crate::utils::{match_trait_method, paths, snippet, span_lint, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::FILTER_NEXT; + +/// lint use of `filter().next()` for `Iterators` +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { + // lint if caller of `.filter().next()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find(..)` instead"; + let filter_snippet = snippet(cx, filter_args[1].span, ".."); + if filter_snippet.lines().count() <= 1 { + let iter_snippet = snippet(cx, filter_args[0].span, ".."); + // add note if not multi-line + span_lint_and_sugg( + cx, + FILTER_NEXT, + expr.span, + msg, + "try this", + format!("{}.find({})", iter_snippet, filter_snippet), + Applicability::MachineApplicable, + ); + } else { + span_lint(cx, FILTER_NEXT, expr.span, msg); + } + } +} diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs new file mode 100644 index 00000000000..2684c50e01b --- /dev/null +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -0,0 +1,84 @@ +use crate::methods::derefs_to_slice; +use crate::utils::{ + get_parent_expr, is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::GET_UNWRAP; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) { + // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`, + // because they do not implement `IndexMut` + let mut applicability = Applicability::MachineApplicable; + let expr_ty = cx.typeck_results().expr_ty(&get_args[0]); + let get_args_str = if get_args.len() > 1 { + snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability) + } else { + return; // not linting on a .get().unwrap() chain or variant + }; + let mut needs_ref; + let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() { + needs_ref = get_args_str.parse::().is_ok(); + "slice" + } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { + needs_ref = get_args_str.parse::().is_ok(); + "Vec" + } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) { + needs_ref = get_args_str.parse::().is_ok(); + "VecDeque" + } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym!(hashmap_type)) { + needs_ref = true; + "HashMap" + } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) { + needs_ref = true; + "BTreeMap" + } else { + return; // caller is not a type that we want to lint + }; + + let mut span = expr.span; + + // Handle the case where the result is immediately dereferenced + // by not requiring ref and pulling the dereference into the + // suggestion. + if_chain! { + if needs_ref; + if let Some(parent) = get_parent_expr(cx, expr); + if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind; + then { + needs_ref = false; + span = parent.span; + } + } + + let mut_str = if is_mut { "_mut" } else { "" }; + let borrow_str = if !needs_ref { + "" + } else if is_mut { + "&mut " + } else { + "&" + }; + + span_lint_and_sugg( + cx, + GET_UNWRAP, + span, + &format!( + "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", + mut_str, caller_type + ), + "try this", + format!( + "{}{}[{}]", + borrow_str, + snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability), + get_args_str + ), + applicability, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e8af9b3d7d9..71080e9bef0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,14 +1,19 @@ mod bind_instead_of_map; mod bytes_nth; +mod expect_used; mod filter_map_identity; +mod filter_next; +mod get_unwrap; mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; mod iter_count; mod manual_saturating_arithmetic; +mod ok_expect; mod option_map_unwrap_or; mod unnecessary_filter_map; mod unnecessary_lazy_eval; +mod unwrap_used; use std::borrow::Cow; use std::fmt; @@ -1649,15 +1654,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect(); match method_names.as_slice() { - ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false), - ["unwrap", "get_mut"] => lint_get_unwrap(cx, expr, arg_lists[1], true), - ["unwrap", ..] => lint_unwrap(cx, expr, arg_lists[0]), - ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]), - ["expect", ..] => lint_expect(cx, expr, arg_lists[0]), - ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), + ["unwrap", "get"] => get_unwrap::check(cx, expr, arg_lists[1], false), + ["unwrap", "get_mut"] => get_unwrap::check(cx, expr, arg_lists[1], true), + ["unwrap", ..] => unwrap_used::check(cx, expr, arg_lists[0]), + ["expect", "ok"] => ok_expect::check(cx, expr, arg_lists[1]), + ["expect", ..] => expect_used::check(cx, expr, arg_lists[0]), + ["unwrap_or", "map"] => option_map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"); + unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"); } }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), @@ -1665,15 +1670,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); if !biom_option_linted && !biom_result_linted { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and"); + unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "and"); } }, ["or_else", ..] => { if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) { - unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or"); + unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "or"); } }, - ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), + ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, false), @@ -1724,9 +1729,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["map", "as_mut"] => { lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) }, - ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), - ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), - ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), + ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"), + ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"), + ["ok_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "ok_or"), ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), ["for_each", "inspect"] => inspect_for_each::lint(cx, expr, method_spans[1]), ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned), @@ -2712,79 +2717,6 @@ fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_ar } } -fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) { - // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`, - // because they do not implement `IndexMut` - let mut applicability = Applicability::MachineApplicable; - let expr_ty = cx.typeck_results().expr_ty(&get_args[0]); - let get_args_str = if get_args.len() > 1 { - snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability) - } else { - return; // not linting on a .get().unwrap() chain or variant - }; - let mut needs_ref; - let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() { - needs_ref = get_args_str.parse::().is_ok(); - "slice" - } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { - needs_ref = get_args_str.parse::().is_ok(); - "Vec" - } else if is_type_diagnostic_item(cx, expr_ty, sym::vecdeque_type) { - needs_ref = get_args_str.parse::().is_ok(); - "VecDeque" - } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::hashmap_type) { - needs_ref = true; - "HashMap" - } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) { - needs_ref = true; - "BTreeMap" - } else { - return; // caller is not a type that we want to lint - }; - - let mut span = expr.span; - - // Handle the case where the result is immediately dereferenced - // by not requiring ref and pulling the dereference into the - // suggestion. - if_chain! { - if needs_ref; - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind; - then { - needs_ref = false; - span = parent.span; - } - } - - let mut_str = if is_mut { "_mut" } else { "" }; - let borrow_str = if !needs_ref { - "" - } else if is_mut { - "&mut " - } else { - "&" - }; - - span_lint_and_sugg( - cx, - GET_UNWRAP, - span, - &format!( - "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", - mut_str, caller_type - ), - "try this", - format!( - "{}{}[{}]", - borrow_str, - snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability), - get_args_str - ), - applicability, - ); -} - fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { // lint if caller of skip is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { @@ -2843,80 +2775,6 @@ fn derefs_to_slice<'tcx>( } } -/// lint use of `unwrap()` for `Option`s and `Result`s -fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { - let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); - - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { - Some((UNWRAP_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { - Some((UNWRAP_USED, "a Result", "Err")) - } else { - None - }; - - if let Some((lint, kind, none_value)) = mess { - span_lint_and_help( - cx, - lint, - expr.span, - &format!("used `unwrap()` on `{}` value", kind,), - None, - &format!( - "if you don't want to handle the `{}` case gracefully, consider \ - using `expect()` to provide a better panic message", - none_value, - ), - ); - } -} - -/// lint use of `expect()` for `Option`s and `Result`s -fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { - let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); - - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { - Some((EXPECT_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { - Some((EXPECT_USED, "a Result", "Err")) - } else { - None - }; - - if let Some((lint, kind, none_value)) = mess { - span_lint_and_help( - cx, - lint, - expr.span, - &format!("used `expect()` on `{}` value", kind,), - None, - &format!("if this value is an `{}`, it will panic", none_value,), - ); - } -} - -/// lint use of `ok().expect()` for `Result`s -fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) { - if_chain! { - // lint if the caller of `ok()` is a `Result` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type); - let result_type = cx.typeck_results().expr_ty(&ok_args[0]); - if let Some(error_type) = get_error_type(cx, result_type); - if has_debug_impl(error_type, cx); - - then { - span_lint_and_help( - cx, - OK_EXPECT, - expr.span, - "called `ok().expect()` on a `Result` value", - None, - "you can call `expect()` directly on the `Result`", - ); - } - } -} - /// lint use of `map().flatten()` for `Iterators` and 'Options' fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.map().flatten()` is an Iterator @@ -3107,31 +2965,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint use of `filter().next()` for `Iterators` -fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { - // lint if caller of `.filter().next()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find(..)` instead"; - let filter_snippet = snippet(cx, filter_args[1].span, ".."); - if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet(cx, filter_args[0].span, ".."); - // add note if not multi-line - span_lint_and_sugg( - cx, - FILTER_NEXT, - expr.span, - msg, - "try this", - format!("{}.find({})", iter_snippet, filter_snippet), - Applicability::MachineApplicable, - ); - } else { - span_lint(cx, FILTER_NEXT, expr.span, msg); - } - } -} - /// lint use of `skip_while().next()` for `Iterators` fn lint_skip_while_next<'tcx>( cx: &LateContext<'tcx>, @@ -3914,21 +3747,6 @@ fn lint_map_collect( } } -/// Given a `Result` type, return its error type (`E`). -fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { - match ty.kind() { - ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1), - _ => None, - } -} - -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::debug_trait) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} - enum Convention { Eq(&'static str), StartsWith(&'static str), diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs new file mode 100644 index 00000000000..c1706cc7cc7 --- /dev/null +++ b/clippy_lints/src/methods/ok_expect.rs @@ -0,0 +1,45 @@ +use crate::utils::{implements_trait, is_type_diagnostic_item, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; + +use super::OK_EXPECT; + +/// lint use of `ok().expect()` for `Result`s +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) { + if_chain! { + // lint if the caller of `ok()` is a `Result` + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type); + let result_type = cx.typeck_results().expr_ty(&ok_args[0]); + if let Some(error_type) = get_error_type(cx, result_type); + if has_debug_impl(error_type, cx); + + then { + span_lint_and_help( + cx, + OK_EXPECT, + expr.span, + "called `ok().expect()` on a `Result` value", + None, + "you can call `expect()` directly on the `Result`", + ); + } + } +} + +/// Given a `Result` type, return its error type (`E`). +fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { + match ty.kind() { + ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1), + _ => None, + } +} + +/// This checks whether a given type is known to implement Debug. +fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { + cx.tcx + .get_diagnostic_item(sym::debug_trait) + .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) +} diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 7763fd5f113..7cdd49bbf03 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -12,7 +12,7 @@ use rustc_span::{sym, Symbol}; use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or()` for `Option`s -pub(super) fn lint<'tcx>( +pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &rustc_hir::Expr<'_>, map_args: &'tcx [rustc_hir::Expr<'_>], diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 40ccb8c80b3..a17259d697f 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -9,7 +9,7 @@ use super::UNNECESSARY_LAZY_EVALUATIONS; /// lint use of `_else(simple closure)` for `Option`s and `Result`s that can be /// replaced with `(return value of simple closure)` -pub(super) fn lint<'tcx>( +pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs new file mode 100644 index 00000000000..094c3fc45c4 --- /dev/null +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -0,0 +1,34 @@ +use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNWRAP_USED; + +/// lint use of `unwrap()` for `Option`s and `Result`s +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { + let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); + + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { + Some((UNWRAP_USED, "an Option", "None")) + } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { + Some((UNWRAP_USED, "a Result", "Err")) + } else { + None + }; + + if let Some((lint, kind, none_value)) = mess { + span_lint_and_help( + cx, + lint, + expr.span, + &format!("used `unwrap()` on `{}` value", kind,), + None, + &format!( + "if you don't want to handle the `{}` case gracefully, consider \ + using `expect()` to provide a better panic message", + none_value, + ), + ); + } +} -- cgit 1.4.1-3-g733a5 From 483bac2dc0a47df87141a98df1d470b25cd2eda3 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 00:31:15 +0900 Subject: move skip_while_next to its own module --- clippy_lints/src/methods/mod.rs | 22 ++-------------------- clippy_lints/src/methods/skip_while_next.rs | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 clippy_lints/src/methods/skip_while_next.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 71080e9bef0..34def45a8dd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -11,6 +11,7 @@ mod iter_count; mod manual_saturating_arithmetic; mod ok_expect; mod option_map_unwrap_or; +mod skip_while_next; mod unnecessary_filter_map; mod unnecessary_lazy_eval; mod unwrap_used; @@ -1679,7 +1680,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } }, ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]), - ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), + ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, false), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2965,25 +2966,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint use of `skip_while().next()` for `Iterators` -fn lint_skip_while_next<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _skip_while_args: &'tcx [hir::Expr<'_>], -) { - // lint if caller of `.skip_while().next()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - span_lint_and_help( - cx, - SKIP_WHILE_NEXT, - expr.span, - "called `skip_while(

).next()` on an `Iterator`", - None, - "this is more succinctly expressed by calling `.find(!

)` instead", - ); - } -} - /// lint use of `filter().map()` or `find().map()` for `Iterators` fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) { if_chain! { diff --git a/clippy_lints/src/methods/skip_while_next.rs b/clippy_lints/src/methods/skip_while_next.rs new file mode 100644 index 00000000000..8ba6ae95200 --- /dev/null +++ b/clippy_lints/src/methods/skip_while_next.rs @@ -0,0 +1,20 @@ +use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::SKIP_WHILE_NEXT; + +/// lint use of `skip_while().next()` for `Iterators` +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, _skip_while_args: &'tcx [hir::Expr<'_>]) { + // lint if caller of `.skip_while().next()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + span_lint_and_help( + cx, + SKIP_WHILE_NEXT, + expr.span, + "called `skip_while(

).next()` on an `Iterator`", + None, + "this is more succinctly expressed by calling `.find(!

)` instead", + ); + } +} -- cgit 1.4.1-3-g733a5 From 110dac7f58257a0186daf13688aa8b02fba67bdb Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 00:43:27 +0900 Subject: move option_as_ref_deref to its own module --- clippy_lints/src/methods/mod.rs | 114 +--------------------- clippy_lints/src/methods/option_as_ref_deref.rs | 122 ++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 111 deletions(-) create mode 100644 clippy_lints/src/methods/option_as_ref_deref.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 34def45a8dd..c6b6ef34bc4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -10,6 +10,7 @@ mod inspect_for_each; mod iter_count; mod manual_saturating_arithmetic; mod ok_expect; +mod option_as_ref_deref; mod option_map_unwrap_or; mod skip_while_next; mod unnecessary_filter_map; @@ -1725,10 +1726,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), ["map", "as_ref"] => { - lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) + option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) }, ["map", "as_mut"] => { - lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) + option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) }, ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"), @@ -3584,115 +3585,6 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { ); } -const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - -/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s -fn lint_option_as_ref_deref<'tcx>( - cx: &LateContext<'tcx>, - expr: &hir::Expr<'_>, - as_ref_args: &[hir::Expr<'_>], - map_args: &[hir::Expr<'_>], - is_mut: bool, - msrv: Option<&RustcVersion>, -) { - if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { - return; - } - - let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); - - let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); - if !is_type_diagnostic_item(cx, option_ty, sym::option_type) { - return; - } - - let deref_aliases: [&[&str]; 9] = [ - &paths::DEREF_TRAIT_METHOD, - &paths::DEREF_MUT_TRAIT_METHOD, - &paths::CSTRING_AS_C_STR, - &paths::OS_STRING_AS_OS_STR, - &paths::PATH_BUF_AS_PATH, - &paths::STRING_AS_STR, - &paths::STRING_AS_MUT_STR, - &paths::VEC_AS_SLICE, - &paths::VEC_AS_MUT_SLICE, - ]; - - let is_deref = match map_args[1].kind { - hir::ExprKind::Path(ref expr_qpath) => cx - .qpath_res(expr_qpath, map_args[1].hir_id) - .opt_def_id() - .map_or(false, |fun_def_id| { - deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) - }), - hir::ExprKind::Closure(_, _, body_id, _, _) => { - let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); - - match &closure_expr.kind { - hir::ExprKind::MethodCall(_, _, args, _) => { - if_chain! { - if args.len() == 1; - if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); - let adj = cx - .typeck_results() - .expr_adjustments(&args[0]) - .iter() - .map(|x| &x.kind) - .collect::>(); - if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj; - then { - let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); - deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) - } else { - false - } - } - }, - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => { - if_chain! { - if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind; - if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind; - then { - path_to_local_id(inner2, closure_body.params[0].pat.hir_id) - } else { - false - } - } - }, - _ => false, - } - }, - _ => false, - }; - - if is_deref { - let current_method = if is_mut { - format!(".as_mut().map({})", snippet(cx, map_args[1].span, "..")) - } else { - format!(".as_ref().map({})", snippet(cx, map_args[1].span, "..")) - }; - let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; - let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint); - let suggestion = format!("try using {} instead", method_hint); - - let msg = format!( - "called `{0}` on an Option value. This can be done more directly \ - by calling `{1}` instead", - current_method, hint - ); - span_lint_and_sugg( - cx, - OPTION_AS_REF_DEREF, - expr.span, - &msg, - &suggestion, - hint, - Applicability::MachineApplicable, - ); - } -} - fn lint_map_collect( cx: &LateContext<'_>, expr: &hir::Expr<'_>, diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs new file mode 100644 index 00000000000..89067dbfe0e --- /dev/null +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -0,0 +1,122 @@ +use crate::utils::{ + is_type_diagnostic_item, match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet, + span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_semver::RustcVersion; +use rustc_span::sym; + +use super::OPTION_AS_REF_DEREF; + +const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); + +/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + as_ref_args: &[hir::Expr<'_>], + map_args: &[hir::Expr<'_>], + is_mut: bool, + msrv: Option<&RustcVersion>, +) { + if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { + return; + } + + let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); + + let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); + if !is_type_diagnostic_item(cx, option_ty, sym::option_type) { + return; + } + + let deref_aliases: [&[&str]; 9] = [ + &paths::DEREF_TRAIT_METHOD, + &paths::DEREF_MUT_TRAIT_METHOD, + &paths::CSTRING_AS_C_STR, + &paths::OS_STRING_AS_OS_STR, + &paths::PATH_BUF_AS_PATH, + &paths::STRING_AS_STR, + &paths::STRING_AS_MUT_STR, + &paths::VEC_AS_SLICE, + &paths::VEC_AS_MUT_SLICE, + ]; + + let is_deref = match map_args[1].kind { + hir::ExprKind::Path(ref expr_qpath) => cx + .qpath_res(expr_qpath, map_args[1].hir_id) + .opt_def_id() + .map_or(false, |fun_def_id| { + deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) + }), + hir::ExprKind::Closure(_, _, body_id, _, _) => { + let closure_body = cx.tcx.hir().body(body_id); + let closure_expr = remove_blocks(&closure_body.value); + + match &closure_expr.kind { + hir::ExprKind::MethodCall(_, _, args, _) => { + if_chain! { + if args.len() == 1; + if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); + let adj = cx + .typeck_results() + .expr_adjustments(&args[0]) + .iter() + .map(|x| &x.kind) + .collect::>(); + if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj; + then { + let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); + deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) + } else { + false + } + } + }, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => { + if_chain! { + if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind; + then { + path_to_local_id(inner2, closure_body.params[0].pat.hir_id) + } else { + false + } + } + }, + _ => false, + } + }, + _ => false, + }; + + if is_deref { + let current_method = if is_mut { + format!(".as_mut().map({})", snippet(cx, map_args[1].span, "..")) + } else { + format!(".as_ref().map({})", snippet(cx, map_args[1].span, "..")) + }; + let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; + let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint); + let suggestion = format!("try using {} instead", method_hint); + + let msg = format!( + "called `{0}` on an Option value. This can be done more directly \ + by calling `{1}` instead", + current_method, hint + ); + span_lint_and_sugg( + cx, + OPTION_AS_REF_DEREF, + expr.span, + &msg, + &suggestion, + hint, + Applicability::MachineApplicable, + ); + } +} -- cgit 1.4.1-3-g733a5 From 60a053725e5c5c3a78e3d0918ca00e9e98324a95 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 00:48:21 +0900 Subject: move suspicious_map to its own module --- clippy_lints/src/methods/mod.rs | 14 ++------------ clippy_lints/src/methods/suspicious_map.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 clippy_lints/src/methods/suspicious_map.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c6b6ef34bc4..a807afb6051 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -13,6 +13,7 @@ mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; mod skip_while_next; +mod suspicious_map; mod unnecessary_filter_map; mod unnecessary_lazy_eval; mod unwrap_used; @@ -1716,7 +1717,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { unnecessary_filter_map::lint(cx, expr, arg_lists[0]); filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); }, - ["count", "map"] => lint_suspicious_map(cx, expr), + ["count", "map"] => suspicious_map::check(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) @@ -3574,17 +3575,6 @@ fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } } -fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint_and_help( - cx, - SUSPICIOUS_MAP, - expr.span, - "this call to `map()` won't have an effect on the call to `count()`", - None, - "make sure you did not confuse `map` with `filter` or `for_each`", - ); -} - fn lint_map_collect( cx: &LateContext<'_>, expr: &hir::Expr<'_>, diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs new file mode 100644 index 00000000000..e135a826dc4 --- /dev/null +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -0,0 +1,16 @@ +use crate::utils::span_lint_and_help; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::SUSPICIOUS_MAP; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + span_lint_and_help( + cx, + SUSPICIOUS_MAP, + expr.span, + "this call to `map()` won't have an effect on the call to `count()`", + None, + "make sure you did not confuse `map` with `filter` or `for_each`", + ); +} -- cgit 1.4.1-3-g733a5 From 8623b331eebfa097bb33dff1df5efa324e6a780a Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 00:55:19 +0900 Subject: move filetype_is_file to its own module --- clippy_lints/src/methods/filetype_is_file.rs | 39 ++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 35 ++----------------------- 2 files changed, 41 insertions(+), 33 deletions(-) create mode 100644 clippy_lints/src/methods/filetype_is_file.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs new file mode 100644 index 00000000000..b03835f97e6 --- /dev/null +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -0,0 +1,39 @@ +use crate::utils::{get_parent_expr, match_type, paths, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::FILETYPE_IS_FILE; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let ty = cx.typeck_results().expr_ty(&args[0]); + + if !match_type(cx, ty, &paths::FILE_TYPE) { + return; + } + + let span: Span; + let verb: &str; + let lint_unary: &str; + let help_unary: &str; + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let hir::ExprKind::Unary(op, _) = parent.kind; + if op == hir::UnOp::Not; + then { + lint_unary = "!"; + verb = "denies"; + help_unary = ""; + span = parent.span; + } else { + lint_unary = ""; + verb = "covers"; + help_unary = "!"; + span = expr.span; + } + } + let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb); + let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary); + span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a807afb6051..54a6a4cf934 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,6 +1,7 @@ mod bind_instead_of_map; mod bytes_nth; mod expect_used; +mod filetype_is_file; mod filter_map_identity; mod filter_next; mod get_unwrap; @@ -1725,7 +1726,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { check_pointer_offset(cx, expr, arg_lists[0]) }, - ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), + ["is_file", ..] => filetype_is_file::check(cx, expr, arg_lists[0]), ["map", "as_ref"] => { option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) }, @@ -3859,38 +3860,6 @@ fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir: } } -fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let ty = cx.typeck_results().expr_ty(&args[0]); - - if !match_type(cx, ty, &paths::FILE_TYPE) { - return; - } - - let span: Span; - let verb: &str; - let lint_unary: &str; - let help_unary: &str; - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(op, _) = parent.kind; - if op == hir::UnOp::Not; - then { - lint_unary = "!"; - verb = "denies"; - help_unary = ""; - span = parent.span; - } else { - lint_unary = ""; - verb = "covers"; - help_unary = "!"; - span = expr.span; - } - } - let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb); - let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary); - span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); -} - fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); -- cgit 1.4.1-3-g733a5 From 35147d4cf342ee479d50afcb70aceab4ea506c2d Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 01:03:47 +0900 Subject: move uninit_assumed_init to its own module --- clippy_lints/src/methods/mod.rs | 31 ++-------------------- clippy_lints/src/methods/uninit_assumed_init.rs | 35 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 29 deletions(-) create mode 100644 clippy_lints/src/methods/uninit_assumed_init.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 54a6a4cf934..acb8318970e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -15,6 +15,7 @@ mod option_as_ref_deref; mod option_map_unwrap_or; mod skip_while_next; mod suspicious_map; +mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_lazy_eval; mod unwrap_used; @@ -1719,7 +1720,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); }, ["count", "map"] => suspicious_map::check(cx, expr), - ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), + ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) }, @@ -3548,34 +3549,6 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_ } } -/// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter) -fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::Call(ref callee, ref args) = expr.kind; - if args.is_empty(); - if let hir::ExprKind::Path(ref path) = callee.kind; - if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); - if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer)); - then { - span_lint( - cx, - UNINIT_ASSUMED_INIT, - outer.span, - "this call for this type may be undefined behavior" - ); - } - } -} - -fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component), - ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), - ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), - _ => false, - } -} - fn lint_map_collect( cx: &LateContext<'_>, expr: &hir::Expr<'_>, diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs new file mode 100644 index 00000000000..798b66192c8 --- /dev/null +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -0,0 +1,35 @@ +use crate::utils::{match_def_path, match_qpath, paths, span_lint}; +use if_chain::if_chain; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; + +use super::UNINIT_ASSUMED_INIT; + +/// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter) +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) { + if_chain! { + if let hir::ExprKind::Call(ref callee, ref args) = expr.kind; + if args.is_empty(); + if let hir::ExprKind::Path(ref path) = callee.kind; + if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); + if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer)); + then { + span_lint( + cx, + UNINIT_ASSUMED_INIT, + outer.span, + "this call for this type may be undefined behavior" + ); + } + } +} + +fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component), + ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), + ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), + _ => false, + } +} -- cgit 1.4.1-3-g733a5 From 45ee914df0c1d1a6a15272bd6833023dd4185b9b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 01:09:33 +0900 Subject: move iter_cloned_collect to its own module --- clippy_lints/src/methods/iter_cloned_collect.rs | 30 +++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 24 ++------------------ 2 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 clippy_lints/src/methods/iter_cloned_collect.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs new file mode 100644 index 00000000000..c3e48ffa5fa --- /dev/null +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -0,0 +1,30 @@ +use crate::methods::derefs_to_slice; +use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::ITER_CLONED_COLLECT; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { + if_chain! { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type); + if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])); + if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); + + then { + span_lint_and_sugg( + cx, + ITER_CLONED_COLLECT, + to_replace, + "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable", + "try", + ".to_vec()".to_string(), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index acb8318970e..92d8077c1ab 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -8,6 +8,7 @@ mod get_unwrap; mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; +mod iter_cloned_collect; mod iter_count; mod manual_saturating_arithmetic; mod ok_expect; @@ -1711,7 +1712,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), - ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]), + ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]), ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), @@ -2494,27 +2495,6 @@ fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_> } } -fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { - if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type); - if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])); - if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); - - then { - span_lint_and_sugg( - cx, - ITER_CLONED_COLLECT, - to_replace, - "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable", - "try", - ".to_vec()".to_string(), - Applicability::MachineApplicable, - ); - } - } -} - fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) { fn check_fold_with_op( cx: &LateContext<'_>, -- cgit 1.4.1-3-g733a5 From 6376da70be18d6cb9dbe22b5a661896cf916bc51 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 3 Mar 2021 01:16:16 +0900 Subject: replace `lints` and `lint` with `check` --- clippy_lints/src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/bytes_nth.rs | 2 +- clippy_lints/src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/inspect_for_each.rs | 2 +- clippy_lints/src/methods/iter_count.rs | 2 +- .../src/methods/manual_saturating_arithmetic.rs | 2 +- clippy_lints/src/methods/mod.rs | 22 +++++++++++----------- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 540a1484a85..5decb81d9f2 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -158,7 +158,7 @@ pub(crate) trait BindInsteadOfMap { } /// Lint use of `_.and_then(|x| Some(y))` for `Option`s - fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool { + fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool { if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) { return false; } diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index defc50ede22..71a7e195e41 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -7,7 +7,7 @@ use rustc_span::sym; use super::BYTES_NTH; -pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) { if_chain! { if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind; let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs(); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index c83b6f2c329..3045b09c238 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::sym; /// Checks for the `INEFFICIENT_TO_STRING` lint -pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { if_chain! { if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index 6d41ee38a27..959457a5bfc 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -7,7 +7,7 @@ use crate::utils::{match_trait_method, paths, span_lint_and_help}; use super::INSPECT_FOR_EACH; /// lint use of `inspect().for_each()` for `Iterators` -pub(super) fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) { if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `inspect(..).for_each(..)` on an `Iterator`"; let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`"; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 71d65a01d3e..869440e0165 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -8,7 +8,7 @@ use rustc_span::sym; use super::ITER_COUNT; -pub(crate) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], iter_method: &str) { +pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], iter_method: &str) { let ty = cx.typeck_results().expr_ty(&iter_args[0]); let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() { "slice" diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index eaa604c2ae6..0b414e0eb95 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_target::abi::LayoutOf; -pub fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>]], arith: &str) { +pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>]], arith: &str) { let unwrap_arg = &args[0][1]; let arith_lhs = &args[1][0]; let arith_rhs = &args[1][1]; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 92d8077c1ab..639d013f786 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1673,14 +1673,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => { - let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); - let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); + let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, arg_lists[0]); + let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, arg_lists[0]); if !biom_option_linted && !biom_result_linted { unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "and"); } }, ["or_else", ..] => { - if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) { + if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, arg_lists[0]) { unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "or"); } }, @@ -1703,12 +1703,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), - ["count", "into_iter"] => iter_count::lints(cx, expr, &arg_lists[1], "into_iter"), - ["count", "iter"] => iter_count::lints(cx, expr, &arg_lists[1], "iter"), - ["count", "iter_mut"] => iter_count::lints(cx, expr, &arg_lists[1], "iter_mut"), + ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), + ["count", "iter"] => iter_count::check(cx, expr, &arg_lists[1], "iter"), + ["count", "iter_mut"] => iter_count::check(cx, expr, &arg_lists[1], "iter_mut"), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), - ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), + ["nth", "bytes"] => bytes_nth::check(cx, expr, &arg_lists[1]), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), @@ -1717,13 +1717,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), ["filter_map", ..] => { - unnecessary_filter_map::lint(cx, expr, arg_lists[0]); + unnecessary_filter_map::check(cx, expr, arg_lists[0]); filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); }, ["count", "map"] => suspicious_map::check(cx, expr), ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { - manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) + manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..]) }, ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { check_pointer_offset(cx, expr, arg_lists[0]) @@ -1739,7 +1739,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "ok_or"), ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), - ["for_each", "inspect"] => inspect_for_each::lint(cx, expr, method_spans[1]), + ["for_each", "inspect"] => inspect_for_each::check(cx, expr, method_spans[1]), ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned), ["to_os_string", ..] => implicit_clone::check(cx, expr, sym::OsStr), ["to_path_buf", ..] => implicit_clone::check(cx, expr, sym::Path), @@ -1765,7 +1765,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { lint_clone_on_ref_ptr(cx, expr, &args[0]); } if args.len() == 1 && method_call.ident.name == sym!(to_string) { - inefficient_to_string::lint(cx, expr, &args[0], self_ty); + inefficient_to_string::check(cx, expr, &args[0], self_ty); } if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 5691fcb88e9..12b2cf0a165 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -9,7 +9,7 @@ use if_chain::if_chain; use super::UNNECESSARY_FILTER_MAP; -pub(super) fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if !match_trait_method(cx, expr, &paths::ITERATOR) { return; } -- cgit 1.4.1-3-g733a5 From 9b0a42b67d66cb79bdd09379d0b0e7959fc1505a Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 4 Mar 2021 19:46:44 +0900 Subject: move zst_offset to its own module --- clippy_lints/src/methods/mod.rs | 15 ++------------- clippy_lints/src/methods/zst_offset.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 clippy_lints/src/methods/zst_offset.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 639d013f786..c944568dc61 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -20,6 +20,7 @@ mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_lazy_eval; mod unwrap_used; +mod zst_offset; use std::borrow::Cow; use std::fmt; @@ -1726,7 +1727,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..]) }, ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { - check_pointer_offset(cx, expr, arg_lists[0]) + zst_offset::check(cx, expr, arg_lists[0]) }, ["is_file", ..] => filetype_is_file::check(cx, expr, arg_lists[0]), ["map", "as_ref"] => { @@ -3801,18 +3802,6 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } } -fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - if_chain! { - if args.len() == 2; - if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind(); - if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); - if layout.is_zst(); - then { - span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); - } - } -} - fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs new file mode 100644 index 00000000000..f1335726736 --- /dev/null +++ b/clippy_lints/src/methods/zst_offset.rs @@ -0,0 +1,19 @@ +use crate::utils::span_lint; +use if_chain::if_chain; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; + +use super::ZST_OFFSET; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + if_chain! { + if args.len() == 2; + if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind(); + if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); + if layout.is_zst(); + then { + span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); + } + } +} -- cgit 1.4.1-3-g733a5 From db91d9cf9a620cc258ab84a152a9333351ac166e Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 4 Mar 2021 19:47:06 +0900 Subject: move map_collect_result_unit to its own module --- .../src/methods/map_collect_result_unit.rs | 45 ++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 39 +------------------ 2 files changed, 47 insertions(+), 37 deletions(-) create mode 100644 clippy_lints/src/methods/map_collect_result_unit.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs new file mode 100644 index 00000000000..5b20e268d9f --- /dev/null +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -0,0 +1,45 @@ +use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +use super::MAP_COLLECT_RESULT_UNIT; + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + map_args: &[hir::Expr<'_>], + collect_args: &[hir::Expr<'_>], +) { + if_chain! { + // called on Iterator + if let [map_expr] = collect_args; + if match_trait_method(cx, map_expr, &paths::ITERATOR); + // return of collect `Result<(),_>` + let collect_ret_ty = cx.typeck_results().expr_ty(expr); + if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); + if let ty::Adt(_, substs) = collect_ret_ty.kind(); + if let Some(result_t) = substs.types().next(); + if result_t.is_unit(); + // get parts for snippet + if let [iter, map_fn] = map_args; + then { + span_lint_and_sugg( + cx, + MAP_COLLECT_RESULT_UNIT, + expr.span, + "`.map().collect()` can be replaced with `.try_for_each()`", + "try this", + format!( + "{}.try_for_each({})", + snippet(cx, iter.span, ".."), + snippet(cx, map_fn.span, "..") + ), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c944568dc61..baa342ab3bb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -11,6 +11,7 @@ mod inspect_for_each; mod iter_cloned_collect; mod iter_count; mod manual_saturating_arithmetic; +mod map_collect_result_unit; mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; @@ -1739,7 +1740,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "ok_or"), - ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), + ["collect", "map"] => map_collect_result_unit::check(cx, expr, arg_lists[1], arg_lists[0]), ["for_each", "inspect"] => inspect_for_each::check(cx, expr, method_spans[1]), ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned), ["to_os_string", ..] => implicit_clone::check(cx, expr, sym::OsStr), @@ -3530,42 +3531,6 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_ } } -fn lint_map_collect( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - map_args: &[hir::Expr<'_>], - collect_args: &[hir::Expr<'_>], -) { - if_chain! { - // called on Iterator - if let [map_expr] = collect_args; - if match_trait_method(cx, map_expr, &paths::ITERATOR); - // return of collect `Result<(),_>` - let collect_ret_ty = cx.typeck_results().expr_ty(expr); - if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); - if let ty::Adt(_, substs) = collect_ret_ty.kind(); - if let Some(result_t) = substs.types().next(); - if result_t.is_unit(); - // get parts for snippet - if let [iter, map_fn] = map_args; - then { - span_lint_and_sugg( - cx, - MAP_COLLECT_RESULT_UNIT, - expr.span, - "`.map().collect()` can be replaced with `.try_for_each()`", - "try this", - format!( - "{}.try_for_each({})", - snippet(cx, iter.span, ".."), - snippet(cx, map_fn.span, "..") - ), - Applicability::MachineApplicable, - ); - } - } -} - enum Convention { Eq(&'static str), StartsWith(&'static str), -- cgit 1.4.1-3-g733a5 From 3fe099ba8d2f6f4d085e7480f020f9f87e6b39e8 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 4 Mar 2021 22:50:53 +0900 Subject: move iter_next_slice to its own module --- clippy_lints/src/methods/iter_next_slice.rs | 68 +++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 66 +++------------------------- 2 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 clippy_lints/src/methods/iter_next_slice.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs new file mode 100644 index 00000000000..3c03a949cfe --- /dev/null +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -0,0 +1,68 @@ +use crate::methods::derefs_to_slice; +use crate::utils::{get_parent_expr, higher, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +use super::ITER_NEXT_SLICE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { + let caller_expr = &iter_args[0]; + + // Skip lint if the `iter().next()` expression is a for loop argument, + // since it is already covered by `&loops::ITER_NEXT_LOOP` + let mut parent_expr_opt = get_parent_expr(cx, expr); + while let Some(parent_expr) = parent_expr_opt { + if higher::for_loop(parent_expr).is_some() { + return; + } + parent_expr_opt = get_parent_expr(cx, parent_expr); + } + + if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() { + // caller is a Slice + if_chain! { + if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind; + if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) + = higher::range(index_expr); + if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; + if let ast::LitKind::Int(start_idx, _) = start_lit.node; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "using `.iter().next()` on a Slice without end index", + "try calling", + format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), + applicability, + ); + } + } + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type) + || matches!( + &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), + ty::Array(_, _) + ) + { + // caller is a Vec or an Array + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "using `.iter().next()` on an array", + "try calling", + format!( + "{}.get(0)", + snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability) + ), + applicability, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index baa342ab3bb..46c9524af55 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -10,6 +10,7 @@ mod inefficient_to_string; mod inspect_for_each; mod iter_cloned_collect; mod iter_count; +mod iter_next_slice; mod manual_saturating_arithmetic; mod map_collect_result_unit; mod ok_expect; @@ -46,9 +47,9 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, - match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, + contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, + is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, + match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, SpanlessEq, @@ -1688,7 +1689,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]), ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), - ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), + ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, false), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), @@ -2598,63 +2599,6 @@ fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx } } -fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { - let caller_expr = &iter_args[0]; - - // Skip lint if the `iter().next()` expression is a for loop argument, - // since it is already covered by `&loops::ITER_NEXT_LOOP` - let mut parent_expr_opt = get_parent_expr(cx, expr); - while let Some(parent_expr) = parent_expr_opt { - if higher::for_loop(parent_expr).is_some() { - return; - } - parent_expr_opt = get_parent_expr(cx, parent_expr); - } - - if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() { - // caller is a Slice - if_chain! { - if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind; - if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) - = higher::range(index_expr); - if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; - if let ast::LitKind::Int(start_idx, _) = start_lit.node; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_NEXT_SLICE, - expr.span, - "using `.iter().next()` on a Slice without end index", - "try calling", - format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), - applicability, - ); - } - } - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type) - || matches!( - &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), - ty::Array(_, _) - ) - { - // caller is a Vec or an Array - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_NEXT_SLICE, - expr.span, - "using `.iter().next()` on an array", - "try calling", - format!( - "{}.get(0)", - snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability) - ), - applicability, - ); - } -} - fn lint_iter_nth<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, -- cgit 1.4.1-3-g733a5 From 5912ca986c52041d01384393cbf2da10270738ee Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 4 Mar 2021 23:06:05 +0900 Subject: move iter_nth, iter_nth_zero and iterator_step_by_zero to their own module --- clippy_lints/src/methods/iter_nth.rs | 38 ++++++++++++ clippy_lints/src/methods/iter_nth_zero.rs | 27 +++++++++ clippy_lints/src/methods/iterator_step_by_zero.rs | 19 ++++++ clippy_lints/src/methods/mod.rs | 74 +++-------------------- 4 files changed, 91 insertions(+), 67 deletions(-) create mode 100644 clippy_lints/src/methods/iter_nth.rs create mode 100644 clippy_lints/src/methods/iter_nth_zero.rs create mode 100644 clippy_lints/src/methods/iterator_step_by_zero.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs new file mode 100644 index 00000000000..c8adea9536b --- /dev/null +++ b/clippy_lints/src/methods/iter_nth.rs @@ -0,0 +1,38 @@ +use crate::methods::derefs_to_slice; +use crate::methods::iter_nth_zero; +use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::ITER_NTH; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]], + is_mut: bool, +) { + let iter_args = nth_and_iter_args[1]; + let mut_str = if is_mut { "_mut" } else { "" }; + let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { + "slice" + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { + "Vec" + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { + "VecDeque" + } else { + let nth_args = nth_and_iter_args[0]; + iter_nth_zero::check(cx, expr, &nth_args); + return; // caller is not a type that we want to lint + }; + + span_lint_and_help( + cx, + ITER_NTH, + expr.span, + &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type), + None, + &format!("calling `.get{}()` is both faster and more readable", mut_str), + ); +} diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs new file mode 100644 index 00000000000..247192d81f3 --- /dev/null +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -0,0 +1,27 @@ +use crate::consts::{constant, Constant}; +use crate::utils::{match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::ITER_NTH_ZERO; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) { + if_chain! { + if match_trait_method(cx, expr, &paths::ITERATOR); + if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NTH_ZERO, + expr.span, + "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", + "try calling `.next()` instead of `.nth(0)`", + format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)), + applicability, + ); + } + } +} diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs new file mode 100644 index 00000000000..3e05d7f76b7 --- /dev/null +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -0,0 +1,19 @@ +use crate::consts::{constant, Constant}; +use crate::utils::{match_trait_method, paths, span_lint}; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::ITERATOR_STEP_BY_ZERO; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) { + span_lint( + cx, + ITERATOR_STEP_BY_ZERO, + expr.span, + "`Iterator::step_by(0)` will panic at runtime", + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 46c9524af55..259d370550c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -11,6 +11,9 @@ mod inspect_for_each; mod iter_cloned_collect; mod iter_count; mod iter_next_slice; +mod iter_nth; +mod iter_nth_zero; +mod iterator_step_by_zero; mod manual_saturating_arithmetic; mod map_collect_result_unit; mod ok_expect; @@ -43,7 +46,6 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol, SymbolStr}; use rustc_typeck::hir_ty_to_ty; -use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ @@ -1709,11 +1711,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), ["count", "iter"] => iter_count::check(cx, expr, &arg_lists[1], "iter"), ["count", "iter_mut"] => iter_count::check(cx, expr, &arg_lists[1], "iter_mut"), - ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), - ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), + ["nth", "iter"] => iter_nth::check(cx, expr, &arg_lists, false), + ["nth", "iter_mut"] => iter_nth::check(cx, expr, &arg_lists, true), ["nth", "bytes"] => bytes_nth::check(cx, expr, &arg_lists[1]), - ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), - ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), + ["nth", ..] => iter_nth_zero::check(cx, expr, arg_lists[0]), + ["step_by", ..] => iterator_step_by_zero::check(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]), ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), @@ -2586,68 +2588,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: } } -fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { - if match_trait_method(cx, expr, &paths::ITERATOR) { - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) { - span_lint( - cx, - ITERATOR_STEP_BY_ZERO, - expr.span, - "`Iterator::step_by(0)` will panic at runtime", - ); - } - } -} - -fn lint_iter_nth<'tcx>( - cx: &LateContext<'tcx>, - expr: &hir::Expr<'_>, - nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]], - is_mut: bool, -) { - let iter_args = nth_and_iter_args[1]; - let mut_str = if is_mut { "_mut" } else { "" }; - let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { - "slice" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { - "Vec" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vecdeque_type) { - "VecDeque" - } else { - let nth_args = nth_and_iter_args[0]; - lint_iter_nth_zero(cx, expr, &nth_args); - return; // caller is not a type that we want to lint - }; - - span_lint_and_help( - cx, - ITER_NTH, - expr.span, - &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type), - None, - &format!("calling `.get{}()` is both faster and more readable", mut_str), - ); -} - -fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) { - if_chain! { - if match_trait_method(cx, expr, &paths::ITERATOR); - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_NTH_ZERO, - expr.span, - "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", - "try calling `.next()` instead of `.nth(0)`", - format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)), - applicability, - ); - } - } -} - fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { // lint if caller of skip is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { -- cgit 1.4.1-3-g733a5 From b5d809a660240d5c826989839bd5eaab63fbb312 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 4 Mar 2021 23:47:30 +0900 Subject: move wrong_self_convention to its own module --- clippy_lints/src/methods/mod.rs | 81 +++-------------------- clippy_lints/src/methods/wrong_self_convention.rs | 76 +++++++++++++++++++++ 2 files changed, 86 insertions(+), 71 deletions(-) create mode 100644 clippy_lints/src/methods/wrong_self_convention.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 259d370550c..3cd720bc9ca 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -25,10 +25,10 @@ mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_lazy_eval; mod unwrap_used; +mod wrong_self_convention; mod zst_offset; use std::borrow::Cow; -use std::fmt; use std::iter; use bind_instead_of_map::BindInsteadOfMap; @@ -1868,7 +1868,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - lint_wrong_self_convention( + wrong_self_convention::check( cx, &name, item.vis.node.is_pub(), @@ -1924,7 +1924,14 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); then { - lint_wrong_self_convention(cx, &item.ident.name.as_str(), false, self_ty, first_arg_ty, first_arg_span); + wrong_self_convention::check( + cx, + &item.ident.name.as_str(), + false, + self_ty, + first_arg_ty, + first_arg_span + ); } } @@ -1949,39 +1956,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } -fn lint_wrong_self_convention<'tcx>( - cx: &LateContext<'tcx>, - item_name: &str, - is_pub: bool, - self_ty: &'tcx TyS<'tcx>, - first_arg_ty: &'tcx TyS<'tcx>, - first_arg_span: Span, -) { - let lint = if is_pub { - WRONG_PUB_SELF_CONVENTION - } else { - WRONG_SELF_CONVENTION - }; - if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) { - if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - span_lint( - cx, - lint, - first_arg_span, - &format!( - "methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, - &self_kinds - .iter() - .map(|k| k.description()) - .collect::>() - .join(" or ") - ), - ); - } - } -} - /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] fn lint_or_fun_call<'tcx>( @@ -3415,22 +3389,6 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_ } } -enum Convention { - Eq(&'static str), - StartsWith(&'static str), -} - -#[rustfmt::skip] -const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [ - (Convention::Eq("new"), &[SelfKind::No]), - (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), - (Convention::StartsWith("from_"), &[SelfKind::No]), - (Convention::StartsWith("into_"), &[SelfKind::Value]), - (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), - (Convention::Eq("to_mut"), &[SelfKind::RefMut]), - (Convention::StartsWith("to_"), &[SelfKind::Ref]), -]; - const FN_HEADER: hir::FnHeader = hir::FnHeader { unsafety: hir::Unsafety::Normal, constness: hir::Constness::NotConst, @@ -3602,25 +3560,6 @@ impl SelfKind { } } -impl Convention { - #[must_use] - fn check(&self, other: &str) -> bool { - match *self { - Self::Eq(this) => this == other, - Self::StartsWith(this) => other.starts_with(this) && this != other, - } - } -} - -impl fmt::Display for Convention { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match *self { - Self::Eq(this) => this.fmt(f), - Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), - } - } -} - #[derive(Clone, Copy)] enum OutType { Unit, diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs new file mode 100644 index 00000000000..90fab577436 --- /dev/null +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -0,0 +1,76 @@ +use crate::methods::SelfKind; +use crate::utils::span_lint; +use rustc_lint::LateContext; +use rustc_middle::ty::TyS; +use rustc_span::source_map::Span; +use std::fmt; + +use super::WRONG_PUB_SELF_CONVENTION; +use super::WRONG_SELF_CONVENTION; + +#[rustfmt::skip] +const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [ + (Convention::Eq("new"), &[SelfKind::No]), + (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), + (Convention::StartsWith("from_"), &[SelfKind::No]), + (Convention::StartsWith("into_"), &[SelfKind::Value]), + (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), + (Convention::Eq("to_mut"), &[SelfKind::RefMut]), + (Convention::StartsWith("to_"), &[SelfKind::Ref]), +]; +enum Convention { + Eq(&'static str), + StartsWith(&'static str), +} + +impl Convention { + #[must_use] + fn check(&self, other: &str) -> bool { + match *self { + Self::Eq(this) => this == other, + Self::StartsWith(this) => other.starts_with(this) && this != other, + } + } +} + +impl fmt::Display for Convention { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + match *self { + Self::Eq(this) => this.fmt(f), + Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), + } + } +} + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + item_name: &str, + is_pub: bool, + self_ty: &'tcx TyS<'tcx>, + first_arg_ty: &'tcx TyS<'tcx>, + first_arg_span: Span, +) { + let lint = if is_pub { + WRONG_PUB_SELF_CONVENTION + } else { + WRONG_SELF_CONVENTION + }; + if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) { + if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { + span_lint( + cx, + lint, + first_arg_span, + &format!( + "methods called `{}` usually take {}; consider choosing a less ambiguous name", + conv, + &self_kinds + .iter() + .map(|k| k.description()) + .collect::>() + .join(" or ") + ), + ); + } + } +} -- cgit 1.4.1-3-g733a5 From 2ade32ddf2ec13a6ec2e03c14e7393ce784d4d18 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 5 Mar 2021 00:16:43 +0900 Subject: move string_extend_chars and clone_on_ref_ptr to their own module --- clippy_lints/src/methods/clone_on_ref_ptr.rs | 36 +++++++++++++ clippy_lints/src/methods/mod.rs | 72 ++----------------------- clippy_lints/src/methods/string_extend_chars.rs | 42 +++++++++++++++ 3 files changed, 82 insertions(+), 68 deletions(-) create mode 100644 clippy_lints/src/methods/clone_on_ref_ptr.rs create mode 100644 clippy_lints/src/methods/string_extend_chars.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs new file mode 100644 index 00000000000..3d5a68d69d7 --- /dev/null +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -0,0 +1,36 @@ +use crate::utils::{is_type_diagnostic_item, match_type, paths, snippet_with_macro_callsite, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +use super::CLONE_ON_REF_PTR; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { + let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); + + if let ty::Adt(_, subst) = obj_ty.kind() { + let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { + "Rc" + } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) { + "Arc" + } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) { + "Weak" + } else { + return; + }; + + let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); + + span_lint_and_sugg( + cx, + CLONE_ON_REF_PTR, + expr.span, + "using `.clone()` on a ref-counted pointer", + "try this", + format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet), + Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3cd720bc9ca..480f32a4340 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,6 @@ mod bind_instead_of_map; mod bytes_nth; +mod clone_on_ref_ptr; mod expect_used; mod filetype_is_file; mod filter_map_identity; @@ -20,6 +21,7 @@ mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; mod skip_while_next; +mod string_extend_chars; mod suspicious_map; mod uninit_assumed_init; mod unnecessary_filter_map; @@ -1707,7 +1709,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["is_some", "rposition"] => { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, - ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), + ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]), ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), ["count", "iter"] => iter_count::check(cx, expr, &arg_lists[1], "iter"), ["count", "iter_mut"] => iter_count::check(cx, expr, &arg_lists[1], "iter_mut"), @@ -1767,7 +1769,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); if args.len() == 1 && method_call.ident.name == sym::clone { lint_clone_on_copy(cx, expr, &args[0], self_ty); - lint_clone_on_ref_ptr(cx, expr, &args[0]); + clone_on_ref_ptr::check(cx, expr, &args[0]); } if args.len() == 1 && method_call.ident.name == sym!(to_string) { inefficient_to_string::check(cx, expr, &args[0], self_ty); @@ -2408,72 +2410,6 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } } -fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); - - if let ty::Adt(_, subst) = obj_ty.kind() { - let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { - "Rc" - } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) { - "Arc" - } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) { - "Weak" - } else { - return; - }; - - let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); - - span_lint_and_sugg( - cx, - CLONE_ON_REF_PTR, - expr.span, - "using `.clone()` on a ref-counted pointer", - "try this", - format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet), - Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak - ); - } -} - -fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let arg = &args[1]; - if let Some(arglists) = method_chain_args(arg, &["chars"]) { - let target = &arglists[0][0]; - let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); - let ref_str = if *self_ty.kind() == ty::Str { - "" - } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { - "&" - } else { - return; - }; - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - STRING_EXTEND_CHARS, - expr.span, - "calling `.extend(_.chars())`", - "try this", - format!( - "{}.push_str({}{})", - snippet_with_applicability(cx, args[0].span, "..", &mut applicability), - ref_str, - snippet_with_applicability(cx, target.span, "..", &mut applicability) - ), - applicability, - ); - } -} - -fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); - if is_type_diagnostic_item(cx, obj_ty, sym::string_type) { - lint_string_extend(cx, expr, args); - } -} - fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) { fn check_fold_with_op( cx: &LateContext<'_>, diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs new file mode 100644 index 00000000000..0a08ea26175 --- /dev/null +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -0,0 +1,42 @@ +use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +use super::STRING_EXTEND_CHARS; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); + if is_type_diagnostic_item(cx, obj_ty, sym::string_type) { + let arg = &args[1]; + if let Some(arglists) = method_chain_args(arg, &["chars"]) { + let target = &arglists[0][0]; + let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); + let ref_str = if *self_ty.kind() == ty::Str { + "" + } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { + "&" + } else { + return; + }; + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + STRING_EXTEND_CHARS, + expr.span, + "calling `.extend(_.chars())`", + "try this", + format!( + "{}.push_str({}{})", + snippet_with_applicability(cx, args[0].span, "..", &mut applicability), + ref_str, + snippet_with_applicability(cx, target.span, "..", &mut applicability) + ), + applicability, + ); + } + } +} -- cgit 1.4.1-3-g733a5 From 8006dab817e6bfa0a71a593d46c5569e8a98a6b7 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 15:29:02 +0900 Subject: move single_char_insert_string to its own module --- clippy_lints/src/methods/mod.rs | 23 ++---------------- .../src/methods/single_char_insert_string.rs | 27 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 clippy_lints/src/methods/single_char_insert_string.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 480f32a4340..ef671e41cb5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -20,6 +20,7 @@ mod map_collect_result_unit; mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; +mod single_char_insert_string; mod skip_while_next; mod string_extend_chars; mod suspicious_map; @@ -1779,7 +1780,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { lint_single_char_push_string(cx, expr, args); } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { - lint_single_char_insert_string(cx, expr, args); + single_char_insert_string::check(cx, expr, args); } } @@ -3235,26 +3236,6 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args } } -/// lint for length-1 `str`s as argument for `insert_str` -fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { - let base_string_snippet = - snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); - let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability); - let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); - span_lint_and_sugg( - cx, - SINGLE_CHAR_ADD_STR, - expr.span, - "calling `insert_str()` using a single-character string literal", - "consider using `insert` with a character literal", - sugg, - applicability, - ); - } -} - /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs new file mode 100644 index 00000000000..0ce8b66978d --- /dev/null +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -0,0 +1,27 @@ +use crate::methods::get_hint_if_single_char_arg; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::SINGLE_CHAR_ADD_STR; + +/// lint for length-1 `str`s as argument for `insert_str` +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { + let base_string_snippet = + snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability); + let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `insert_str()` using a single-character string literal", + "consider using `insert` with a character literal", + sugg, + applicability, + ); + } +} -- cgit 1.4.1-3-g733a5 From 805aa47f43ab9b61a69f63682176604cdcda8fae Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 15:39:28 +0900 Subject: move single_char_push_string to its own module --- clippy_lints/src/methods/mod.rs | 22 ++---------------- .../src/methods/single_char_push_string.rs | 26 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 clippy_lints/src/methods/single_char_push_string.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ef671e41cb5..24d610cf5f8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -21,6 +21,7 @@ mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; mod single_char_insert_string; +mod single_char_push_string; mod skip_while_next; mod string_extend_chars; mod suspicious_map; @@ -1778,7 +1779,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { - lint_single_char_push_string(cx, expr, args); + single_char_push_string::check(cx, expr, args); } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { single_char_insert_string::check(cx, expr, args); } @@ -3217,25 +3218,6 @@ fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &h } } -/// lint for length-1 `str`s as argument for `push_str` -fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { - let base_string_snippet = - snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability); - let sugg = format!("{}.push({})", base_string_snippet, extension_string); - span_lint_and_sugg( - cx, - SINGLE_CHAR_ADD_STR, - expr.span, - "calling `push_str()` using a single-character string literal", - "consider using `push` with a character literal", - sugg, - applicability, - ); - } -} - /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs new file mode 100644 index 00000000000..deacc70b713 --- /dev/null +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -0,0 +1,26 @@ +use crate::methods::get_hint_if_single_char_arg; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::SINGLE_CHAR_ADD_STR; + +/// lint for length-1 `str`s as argument for `push_str` +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + let base_string_snippet = + snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability); + let sugg = format!("{}.push({})", base_string_snippet, extension_string); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `push_str()` using a single-character string literal", + "consider using `push` with a character literal", + sugg, + applicability, + ); + } +} -- cgit 1.4.1-3-g733a5 From 0c8d143515a19b04a404765ecb8145a183dc2186 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 17:28:14 +0900 Subject: move into_iter_on_ref and single_char_pattern to their own modules --- clippy_lints/src/methods/into_iter_on_ref.rs | 42 ++++++++++++++++ clippy_lints/src/methods/mod.rs | 67 ++++--------------------- clippy_lints/src/methods/single_char_pattern.rs | 23 +++++++++ 3 files changed, 74 insertions(+), 58 deletions(-) create mode 100644 clippy_lints/src/methods/into_iter_on_ref.rs create mode 100644 clippy_lints/src/methods/single_char_pattern.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs new file mode 100644 index 00000000000..d94b243404c --- /dev/null +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -0,0 +1,42 @@ +use crate::utils::{has_iter_method, match_trait_method, paths, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_span::source_map::Span; + +use super::INTO_ITER_ON_REF; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) { + if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) { + return; + } + if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) { + span_lint_and_sugg( + cx, + INTO_ITER_ON_REF, + method_span, + &format!( + "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", + method_name, kind, + ), + "call directly", + method_name.to_string(), + Applicability::MachineApplicable, + ); + } +} + +fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> { + has_iter_method(cx, self_ref_ty).map(|ty_name| { + let mutbl = match self_ref_ty.kind() { + ty::Ref(_, _, mutbl) => mutbl, + _ => unreachable!(), + }; + let method_name = match mutbl { + hir::Mutability::Not => "iter", + hir::Mutability::Mut => "iter_mut", + }; + (ty_name, method_name) + }) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 24d610cf5f8..28e2d896e6c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod get_unwrap; mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; +mod into_iter_on_ref; mod iter_cloned_collect; mod iter_count; mod iter_next_slice; @@ -21,6 +22,7 @@ mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; mod single_char_insert_string; +mod single_char_pattern; mod single_char_push_string; mod skip_while_next; mod string_extend_chars; @@ -53,12 +55,11 @@ use rustc_typeck::hir_ty_to_ty; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, - is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, - match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, - remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, - SpanlessEq, + contains_return, contains_ty, get_parent_expr, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, + is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, + match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty, + single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1789,12 +1790,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { for &(method, pos) in &PATTERN_METHODS { if method_call.ident.name.as_str() == method && args.len() > pos { - lint_single_char_pattern(cx, expr, &args[pos]); + single_char_pattern::check(cx, expr, &args[pos]); } } }, ty::Ref(..) if method_call.ident.name == sym::into_iter => { - lint_into_iter(cx, expr, self_ty, *method_span); + into_iter_on_ref::check(cx, expr, self_ty, *method_span); }, _ => (), } @@ -3202,22 +3203,6 @@ fn get_hint_if_single_char_arg( } } -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - let mut applicability = Applicability::MachineApplicable; - if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "try using a `char` instead", - hint, - applicability, - ); - } -} - /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" @@ -3254,40 +3239,6 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re } } -fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(Symbol, &'static str)> { - has_iter_method(cx, self_ref_ty).map(|ty_name| { - let mutbl = match self_ref_ty.kind() { - ty::Ref(_, _, mutbl) => mutbl, - _ => unreachable!(), - }; - let method_name = match mutbl { - hir::Mutability::Not => "iter", - hir::Mutability::Mut => "iter_mut", - }; - (ty_name, method_name) - }) -} - -fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) { - if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) { - return; - } - if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) { - span_lint_and_sugg( - cx, - INTO_ITER_ON_REF, - method_span, - &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", - method_name, kind, - ), - "call directly", - method_name.to_string(), - Applicability::MachineApplicable, - ); - } -} - const FN_HEADER: hir::FnHeader = hir::FnHeader { unsafety: hir::Unsafety::Normal, constness: hir::Constness::NotConst, diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs new file mode 100644 index 00000000000..61cbc9d2f0a --- /dev/null +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -0,0 +1,23 @@ +use crate::methods::get_hint_if_single_char_arg; +use crate::utils::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::SINGLE_CHAR_PATTERN; + +/// lint for length-1 `str`s for methods in `PATTERN_METHODS` +pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "try using a `char` instead", + hint, + applicability, + ); + } +} -- cgit 1.4.1-3-g733a5 From 2561b7ea062f0c07f27d9ebdf0c355ab29a4edf9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 17:46:50 +0900 Subject: move from_iter_insteam_of_collect to its own module --- .../src/methods/from_iter_instead_of_collect.rs | 67 ++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 62 +------------------- 2 files changed, 69 insertions(+), 60 deletions(-) create mode 100644 clippy_lints/src/methods/from_iter_instead_of_collect.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs new file mode 100644 index 00000000000..e50d0a33400 --- /dev/null +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -0,0 +1,67 @@ +use crate::utils::{get_trait_def_id, implements_trait, paths, span_lint_and_sugg, sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::Ty; + +use super::FROM_ITER_INSTEAD_OF_COLLECT; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let ty = cx.typeck_results().expr_ty(expr); + let arg_ty = cx.typeck_results().expr_ty(&args[0]); + + if_chain! { + if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); + if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); + + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + then { + // `expr` implements `FromIterator` trait + let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); + let turbofish = extract_turbofish(cx, expr, ty); + let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + sugg, + Applicability::MaybeIncorrect, + ); + } + } +} + +fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + if_chain! { + let call_site = expr.span.source_callsite(); + if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); + let snippet_split = snippet.split("::").collect::>(); + if let Some((_, elements)) = snippet_split.split_last(); + + then { + // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) + format!("{}{}", without_ts.join("::"), type_specifier) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{}>", elements.join("::"), wildcards) + } + } else { + ty.to_string() + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 28e2d896e6c..9a0ef6c01c1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5,6 +5,7 @@ mod expect_used; mod filetype_is_file; mod filter_map_identity; mod filter_next; +mod from_iter_instead_of_collect; mod get_unwrap; mod implicit_clone; mod inefficient_to_string; @@ -1761,7 +1762,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { hir::ExprKind::Call(ref func, ref args) => { if let hir::ExprKind::Path(path) = &func.kind { if match_qpath(path, &["from_iter"]) { - lint_from_iter(cx, expr, args); + from_iter_instead_of_collect::check(cx, expr, args); } } }, @@ -3440,65 +3441,6 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } } -fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let ty = cx.typeck_results().expr_ty(expr); - let arg_ty = cx.typeck_results().expr_ty(&args[0]); - - if_chain! { - if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); - if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); - - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); - then { - // `expr` implements `FromIterator` trait - let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let turbofish = extract_turbofish(cx, expr, ty); - let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); - span_lint_and_sugg( - cx, - FROM_ITER_INSTEAD_OF_COLLECT, - expr.span, - "usage of `FromIterator::from_iter`", - "use `.collect()` instead of `::from_iter()`", - sugg, - Applicability::MaybeIncorrect, - ); - } - } -} - -fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { - if_chain! { - let call_site = expr.span.source_callsite(); - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); - let snippet_split = snippet.split("::").collect::>(); - if let Some((_, elements)) = snippet_split.split_last(); - - then { - // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) - if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { - // remove the type specifier from the path elements - let without_ts = elements.iter().filter_map(|e| { - if e == type_specifier { None } else { Some((*e).to_string()) } - }).collect::>(); - // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) - format!("{}{}", without_ts.join("::"), type_specifier) - } else { - // type is not explicitly specified so wildcards are needed - // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` - let ty_str = ty.to_string(); - let start = ty_str.find('<').unwrap_or(0); - let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); - let nb_wildcard = ty_str[start..end].split(',').count(); - let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{}>", elements.join("::"), wildcards) - } - } else { - ty.to_string() - } - } -} - fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety -- cgit 1.4.1-3-g733a5 From 183daeb961c83d5be108cfa5ee463bba412dedc4 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 17:55:29 +0900 Subject: move filter_map to its own module --- clippy_lints/src/methods/filter_map.rs | 85 ++++++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 81 ++------------------------------ 2 files changed, 89 insertions(+), 77 deletions(-) create mode 100644 clippy_lints/src/methods/filter_map.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs new file mode 100644 index 00000000000..f559160004c --- /dev/null +++ b/clippy_lints/src/methods/filter_map.rs @@ -0,0 +1,85 @@ +use crate::utils::{match_trait_method, path_to_local_id, paths, snippet, span_lint_and_sugg, SpanlessEq}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::{Expr, ExprKind, PatKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty::TyS; +use rustc_span::symbol::sym; + +use super::MANUAL_FILTER_MAP; +use super::MANUAL_FIND_MAP; + +/// lint use of `filter().map()` or `find().map()` for `Iterators` +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) { + if_chain! { + if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; + if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; + if match_trait_method(cx, map_recv, &paths::ITERATOR); + + // filter(|x| ...is_some())... + if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; + let filter_body = cx.tcx.hir().body(filter_body_id); + if let [filter_param] = filter_body.params; + // optional ref pattern: `filter(|&x| ..)` + let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + }; + // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; + if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind; + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) { + Some(false) + } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) { + Some(true) + } else { + None + }; + if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + + // ...map(|x| ...unwrap()) + if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind; + let map_body = cx.tcx.hir().body(map_body_id); + if let [map_param] = map_body.params; + if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + // closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind; + if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; + then { expr_path } else { a } + }; + // let the filter closure arg and the map closure arg be equal + if_chain! { + if path_to_local_id(a_path, filter_param_id); + if path_to_local_id(b, map_param_id); + if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); + then { + return true; + } + } + false + }; + if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); + then { + let span = filter_span.to(map_span); + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) + } else { + ("filter", MANUAL_FILTER_MAP) + }; + let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name); + let to_opt = if is_result { ".ok()" } else { "" }; + let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident, + snippet(cx, map_arg.span, ".."), to_opt); + span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9a0ef6c01c1..61d562cbc28 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3,6 +3,7 @@ mod bytes_nth; mod clone_on_ref_ptr; mod expect_used; mod filetype_is_file; +mod filter_map; mod filter_map_identity; mod filter_next; mod from_iter_instead_of_collect; @@ -43,7 +44,7 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, PatKind, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::{PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; @@ -1698,10 +1699,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]), ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), - ["map", "filter"] => lint_filter_map(cx, expr, false), + ["map", "filter"] => filter_map::check(cx, expr, false), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), - ["map", "find"] => lint_filter_map(cx, expr, true), + ["map", "find"] => filter_map::check(cx, expr, true), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]), @@ -2750,80 +2751,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint use of `filter().map()` or `find().map()` for `Iterators` -fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) { - if_chain! { - if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; - if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; - if match_trait_method(cx, map_recv, &paths::ITERATOR); - - // filter(|x| ...is_some())... - if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; - let filter_body = cx.tcx.hir().body(filter_body_id); - if let [filter_param] = filter_body.params; - // optional ref pattern: `filter(|&x| ..)` - let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { - (ref_pat, true) - } else { - (filter_param.pat, false) - }; - // closure ends with is_some() or is_ok() - if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) { - Some(false) - } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) { - Some(true) - } else { - None - }; - if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; - - // ...map(|x| ...unwrap()) - if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind; - let map_body = cx.tcx.hir().body(map_body_id); - if let [map_param] = map_body.params; - if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; - // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); - - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; - // let the filter closure arg and the map closure arg be equal - if_chain! { - if path_to_local_id(a_path, filter_param_id); - if path_to_local_id(b, map_param_id); - if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); - then { - return true; - } - } - false - }; - if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); - then { - let span = filter_span.to(map_span); - let (filter_name, lint) = if is_find { - ("find", MANUAL_FIND_MAP) - } else { - ("filter", MANUAL_FILTER_MAP) - }; - let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name); - let to_opt = if is_result { ".ok()" } else { "" }; - let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident, - snippet(cx, map_arg.span, ".."), to_opt); - span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); - } - } -} - const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); /// lint use of `filter_map().next()` for `Iterators` -- cgit 1.4.1-3-g733a5 From 805dcd12d41e72c16bbca83496f4b89ba49eed64 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:05:15 +0900 Subject: move filter_map_map to its own module --- clippy_lints/src/methods/filter_map_map.rs | 20 ++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 18 ++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 clippy_lints/src/methods/filter_map_map.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_map.rs b/clippy_lints/src/methods/filter_map_map.rs new file mode 100644 index 00000000000..d015b4c7b38 --- /dev/null +++ b/clippy_lints/src/methods/filter_map_map.rs @@ -0,0 +1,20 @@ +use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::FILTER_MAP; + +/// lint use of `filter_map().map()` for `Iterators` +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + _filter_args: &'tcx [hir::Expr<'_>], + _map_args: &'tcx [hir::Expr<'_>], +) { + // lint if caller of `.filter_map().map()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + let msg = "called `filter_map(..).map(..)` on an `Iterator`"; + let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 61d562cbc28..2e5dc857b44 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5,6 +5,7 @@ mod expect_used; mod filetype_is_file; mod filter_map; mod filter_map_identity; +mod filter_map_map; mod filter_next; mod from_iter_instead_of_collect; mod get_unwrap; @@ -1700,7 +1701,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), ["map", "filter"] => filter_map::check(cx, expr, false), - ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), + ["map", "filter_map"] => filter_map_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => filter_map::check(cx, expr, true), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2785,21 +2786,6 @@ fn lint_filter_map_next<'tcx>( } } -/// lint use of `filter_map().map()` for `Iterators` -fn lint_filter_map_map<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { - // lint if caller of `.filter_map().map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(..).map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); - } -} - /// lint use of `filter().flat_map()` for `Iterators` fn lint_filter_flat_map<'tcx>( cx: &LateContext<'tcx>, -- cgit 1.4.1-3-g733a5 From 2baf043c374396dea3354eb8bc56af7539bf30b4 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:11:42 +0900 Subject: move filter_map_next to its own module --- clippy_lints/src/methods/filter_map_next.rs | 40 +++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 37 ++------------------------ 2 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 clippy_lints/src/methods/filter_map_next.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs new file mode 100644 index 00000000000..a789df922ff --- /dev/null +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -0,0 +1,40 @@ +use crate::utils::{match_trait_method, meets_msrv, paths, snippet, span_lint, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_semver::RustcVersion; + +use super::FILTER_MAP_NEXT; + +const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + filter_args: &'tcx [hir::Expr<'_>], + msrv: Option<&RustcVersion>, +) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { + return; + } + + let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find_map(..)` instead"; + let filter_snippet = snippet(cx, filter_args[1].span, ".."); + if filter_snippet.lines().count() <= 1 { + let iter_snippet = snippet(cx, filter_args[0].span, ".."); + span_lint_and_sugg( + cx, + FILTER_MAP_NEXT, + expr.span, + msg, + "try this", + format!("{}.find_map({})", iter_snippet, filter_snippet), + Applicability::MachineApplicable, + ); + } else { + span_lint(cx, FILTER_MAP_NEXT, expr.span, msg); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2e5dc857b44..fe1327564b2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -6,6 +6,7 @@ mod filetype_is_file; mod filter_map; mod filter_map_identity; mod filter_map_map; +mod filter_map_next; mod filter_next; mod from_iter_instead_of_collect; mod get_unwrap; @@ -1702,7 +1703,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), ["map", "filter"] => filter_map::check(cx, expr, false), ["map", "filter_map"] => filter_map_map::check(cx, expr, arg_lists[1], arg_lists[0]), - ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()), + ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => filter_map::check(cx, expr, true), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2752,40 +2753,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); - -/// lint use of `filter_map().next()` for `Iterators` -fn lint_filter_map_next<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - filter_args: &'tcx [hir::Expr<'_>], - msrv: Option<&RustcVersion>, -) { - if match_trait_method(cx, expr, &paths::ITERATOR) { - if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { - return; - } - - let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find_map(..)` instead"; - let filter_snippet = snippet(cx, filter_args[1].span, ".."); - if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet(cx, filter_args[0].span, ".."); - span_lint_and_sugg( - cx, - FILTER_MAP_NEXT, - expr.span, - msg, - "try this", - format!("{}.find_map({})", iter_snippet, filter_snippet), - Applicability::MachineApplicable, - ); - } else { - span_lint(cx, FILTER_MAP_NEXT, expr.span, msg); - } - } -} - /// lint use of `filter().flat_map()` for `Iterators` fn lint_filter_flat_map<'tcx>( cx: &LateContext<'tcx>, -- cgit 1.4.1-3-g733a5 From 6d941616f925298124eabe3ca10e48ec10bb33a9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:19:18 +0900 Subject: move filter_flat_map to its own module --- clippy_lints/src/methods/filter_flat_map.rs | 21 +++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 19 ++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 clippy_lints/src/methods/filter_flat_map.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_flat_map.rs b/clippy_lints/src/methods/filter_flat_map.rs new file mode 100644 index 00000000000..8da867fce51 --- /dev/null +++ b/clippy_lints/src/methods/filter_flat_map.rs @@ -0,0 +1,21 @@ +use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::FILTER_MAP; + +/// lint use of `filter().flat_map()` for `Iterators` +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + _filter_args: &'tcx [hir::Expr<'_>], + _map_args: &'tcx [hir::Expr<'_>], +) { + // lint if caller of `.filter().flat_map()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; + let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ + and filtering by returning `iter::empty()`"; + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fe1327564b2..3251a49da09 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3,6 +3,7 @@ mod bytes_nth; mod clone_on_ref_ptr; mod expect_used; mod filetype_is_file; +mod filter_flat_map; mod filter_map; mod filter_map_identity; mod filter_map_map; @@ -1705,7 +1706,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["map", "filter_map"] => filter_map_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => filter_map::check(cx, expr, true), - ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), + ["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]), ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), @@ -2753,22 +2754,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint use of `filter().flat_map()` for `Iterators` -fn lint_filter_flat_map<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { - // lint if caller of `.filter().flat_map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ - and filtering by returning `iter::empty()`"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); - } -} - /// lint use of `filter_map().flat_map()` for `Iterators` fn lint_filter_map_flat_map<'tcx>( cx: &LateContext<'tcx>, -- cgit 1.4.1-3-g733a5 From f430384f04ee3ee62156a9e3060ba4d9054278b5 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:22:15 +0900 Subject: move filter_map_flat_map to its own module --- clippy_lints/src/methods/filter_map_flat_map.rs | 21 +++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 19 ++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 clippy_lints/src/methods/filter_map_flat_map.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_flat_map.rs b/clippy_lints/src/methods/filter_map_flat_map.rs new file mode 100644 index 00000000000..a6db138623a --- /dev/null +++ b/clippy_lints/src/methods/filter_map_flat_map.rs @@ -0,0 +1,21 @@ +use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::FILTER_MAP; + +/// lint use of `filter_map().flat_map()` for `Iterators` +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + _filter_args: &'tcx [hir::Expr<'_>], + _map_args: &'tcx [hir::Expr<'_>], +) { + // lint if caller of `.filter_map().flat_map()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; + let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ + and filtering by returning `iter::empty()`"; + span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3251a49da09..34e1463f630 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5,6 +5,7 @@ mod expect_used; mod filetype_is_file; mod filter_flat_map; mod filter_map; +mod filter_map_flat_map; mod filter_map_identity; mod filter_map_map; mod filter_map_next; @@ -1707,7 +1708,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => filter_map::check(cx, expr, true), ["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), - ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), + ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]), ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), @@ -2754,22 +2755,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint use of `filter_map().flat_map()` for `Iterators` -fn lint_filter_map_flat_map<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { - // lint if caller of `.filter_map().flat_map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ - and filtering by returning `iter::empty()`"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); - } -} - /// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient fn lint_flat_map_identity<'tcx>( cx: &LateContext<'tcx>, -- cgit 1.4.1-3-g733a5 From 37ba779a532cd229a18e8a99342f351ba035aa30 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:30:40 +0900 Subject: move flat_map_identity to its own module --- clippy_lints/src/methods/flat_map_identity.rs | 57 +++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 52 +----------------------- 2 files changed, 59 insertions(+), 50 deletions(-) create mode 100644 clippy_lints/src/methods/flat_map_identity.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs new file mode 100644 index 00000000000..ce3194f8a23 --- /dev/null +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -0,0 +1,57 @@ +use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::FLAT_MAP_IDENTITY; + +/// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + flat_map_args: &'tcx [hir::Expr<'_>], + flat_map_span: Span, +) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + let arg_node = &flat_map_args[1].kind; + + let apply_lint = |message: &str| { + span_lint_and_sugg( + cx, + FLAT_MAP_IDENTITY, + flat_map_span.with_hi(expr.span.hi()), + message, + "try", + "flatten()".to_string(), + Applicability::MachineApplicable, + ); + }; + + if_chain! { + if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; + let body = cx.tcx.hir().body(*body_id); + + if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; + + if path.segments.len() == 1; + if path.segments[0].ident.name == binding_ident.name; + + then { + apply_lint("called `flat_map(|x| x)` on an `Iterator`"); + } + } + + if_chain! { + if let hir::ExprKind::Path(ref qpath) = arg_node; + + if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); + + then { + apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); + } + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 34e1463f630..6a425e6e3ed 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -10,6 +10,7 @@ mod filter_map_identity; mod filter_map_map; mod filter_map_next; mod filter_next; +mod flat_map_identity; mod from_iter_instead_of_collect; mod get_unwrap; mod implicit_clone; @@ -1709,7 +1710,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["map", "find"] => filter_map::check(cx, expr, true), ["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), - ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]), + ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), ["is_some", "position"] => { @@ -2755,55 +2756,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient -fn lint_flat_map_identity<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - flat_map_args: &'tcx [hir::Expr<'_>], - flat_map_span: Span, -) { - if match_trait_method(cx, expr, &paths::ITERATOR) { - let arg_node = &flat_map_args[1].kind; - - let apply_lint = |message: &str| { - span_lint_and_sugg( - cx, - FLAT_MAP_IDENTITY, - flat_map_span.with_hi(expr.span.hi()), - message, - "try", - "flatten()".to_string(), - Applicability::MachineApplicable, - ); - }; - - if_chain! { - if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; - let body = cx.tcx.hir().body(*body_id); - - if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; - - if path.segments.len() == 1; - if path.segments[0].ident.name == binding_ident.name; - - then { - apply_lint("called `flat_map(|x| x)` on an `Iterator`"); - } - } - - if_chain! { - if let hir::ExprKind::Path(ref qpath) = arg_node; - - if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); - - then { - apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); - } - } - } -} - /// lint searching an Iterator followed by `is_some()` /// or calling `find()` on a string followed by `is_some()` fn lint_search_is_some<'tcx>( -- cgit 1.4.1-3-g733a5 From 24909fabd27091a7b363dcbc549636e98ba4a898 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:41:43 +0900 Subject: move map_flatten and search_is_some to their own modules --- clippy_lints/src/methods/map_flatten.rs | 61 ++++++++++++ clippy_lints/src/methods/mod.rs | 150 ++--------------------------- clippy_lints/src/methods/search_is_some.rs | 101 +++++++++++++++++++ 3 files changed, 168 insertions(+), 144 deletions(-) create mode 100644 clippy_lints/src/methods/map_flatten.rs create mode 100644 clippy_lints/src/methods/search_is_some.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs new file mode 100644 index 00000000000..14a14e4f9ec --- /dev/null +++ b/clippy_lints/src/methods/map_flatten.rs @@ -0,0 +1,61 @@ +use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +use super::MAP_FLATTEN; + +/// lint use of `map().flatten()` for `Iterators` and 'Options' +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { + // lint if caller of `.map().flatten()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); + let is_map_to_option = match map_closure_ty.kind() { + ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { + let map_closure_sig = match map_closure_ty.kind() { + ty::Closure(_, substs) => substs.as_closure().sig(), + _ => map_closure_ty.fn_sig(cx.tcx), + }; + let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output()); + is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type) + }, + _ => false, + }; + + let method_to_use = if is_map_to_option { + // `(...).map(...)` has type `impl Iterator> + "filter_map" + } else { + // `(...).map(...)` has type `impl Iterator> + "flat_map" + }; + let func_snippet = snippet(cx, map_args[1].span, ".."); + let hint = format!(".{0}({1})", method_to_use, func_snippet); + span_lint_and_sugg( + cx, + MAP_FLATTEN, + expr.span.with_lo(map_args[0].span.hi()), + "called `map(..).flatten()` on an `Iterator`", + &format!("try using `{}` instead", method_to_use), + hint, + Applicability::MachineApplicable, + ); + } + + // lint if caller of `.map().flatten()` is an Option + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { + let func_snippet = snippet(cx, map_args[1].span, ".."); + let hint = format!(".and_then({})", func_snippet); + span_lint_and_sugg( + cx, + MAP_FLATTEN, + expr.span.with_lo(map_args[0].span.hi()), + "called `map(..).flatten()` on an `Option`", + "try using `and_then` instead", + hint, + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6a425e6e3ed..2b8bb0b4216 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -25,9 +25,11 @@ mod iter_nth_zero; mod iterator_step_by_zero; mod manual_saturating_arithmetic; mod map_collect_result_unit; +mod map_flatten; mod ok_expect; mod option_as_ref_deref; mod option_map_unwrap_or; +mod search_is_some; mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; @@ -1711,13 +1713,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), - ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), - ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), + ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]), + ["is_some", "find"] => search_is_some::check(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), ["is_some", "position"] => { - lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]) + search_is_some::check(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]) }, ["is_some", "rposition"] => { - lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) + search_is_some::check(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]), ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), @@ -2566,59 +2568,6 @@ fn derefs_to_slice<'tcx>( } } -/// lint use of `map().flatten()` for `Iterators` and 'Options' -fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { - // lint if caller of `.map().flatten()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); - let is_map_to_option = match map_closure_ty.kind() { - ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { - let map_closure_sig = match map_closure_ty.kind() { - ty::Closure(_, substs) => substs.as_closure().sig(), - _ => map_closure_ty.fn_sig(cx.tcx), - }; - let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output()); - is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type) - }, - _ => false, - }; - - let method_to_use = if is_map_to_option { - // `(...).map(...)` has type `impl Iterator> - "filter_map" - } else { - // `(...).map(...)` has type `impl Iterator> - "flat_map" - }; - let func_snippet = snippet(cx, map_args[1].span, ".."); - let hint = format!(".{0}({1})", method_to_use, func_snippet); - span_lint_and_sugg( - cx, - MAP_FLATTEN, - expr.span.with_lo(map_args[0].span.hi()), - "called `map(..).flatten()` on an `Iterator`", - &format!("try using `{}` instead", method_to_use), - hint, - Applicability::MachineApplicable, - ); - } - - // lint if caller of `.map().flatten()` is an Option - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { - let func_snippet = snippet(cx, map_args[1].span, ".."); - let hint = format!(".and_then({})", func_snippet); - span_lint_and_sugg( - cx, - MAP_FLATTEN, - expr.span.with_lo(map_args[0].span.hi()), - "called `map(..).flatten()` on an `Option`", - "try using `and_then` instead", - hint, - Applicability::MachineApplicable, - ); - } -} - const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s @@ -2756,93 +2705,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ); } -/// lint searching an Iterator followed by `is_some()` -/// or calling `find()` on a string followed by `is_some()` -fn lint_search_is_some<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - search_method: &str, - search_args: &'tcx [hir::Expr<'_>], - is_some_args: &'tcx [hir::Expr<'_>], - method_span: Span, -) { - // lint if caller of search is an Iterator - if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { - let msg = format!( - "called `is_some()` after searching an `Iterator` with `{}`", - search_method - ); - let hint = "this is more succinctly expressed by calling `any()`"; - let search_snippet = snippet(cx, search_args[1].span, ".."); - if search_snippet.lines().count() <= 1 { - // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` - // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` - let any_search_snippet = if_chain! { - if search_method == "find"; - if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind; - let closure_body = cx.tcx.hir().body(body_id); - if let Some(closure_arg) = closure_body.params.get(0); - then { - if let hir::PatKind::Ref(..) = closure_arg.pat.kind { - Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind { - let name = &*ident.name.as_str(); - Some(search_snippet.replace(&format!("*{}", name), name)) - } else { - None - } - } else { - None - } - }; - // add note if not multi-line - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - &msg, - "use `any()` instead", - format!( - "any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); - } else { - span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); - } - } - // lint if `find()` is called by `String` or `&str` - else if search_method == "find" { - let is_string_or_str_slice = |e| { - let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); - if is_type_diagnostic_item(cx, self_ty, sym::string_type) { - true - } else { - *self_ty.kind() == ty::Str - } - }; - if_chain! { - if is_string_or_str_slice(&search_args[0]); - if is_string_or_str_slice(&search_args[1]); - then { - let msg = "called `is_some()` after calling `find()` on a string"; - let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - msg, - "use `contains()` instead", - format!("contains({})", find_arg), - applicability, - ); - } - } - } -} - /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs new file mode 100644 index 00000000000..e9e65443220 --- /dev/null +++ b/clippy_lints/src/methods/search_is_some.rs @@ -0,0 +1,101 @@ +use crate::utils::{ + is_type_diagnostic_item, match_trait_method, paths, snippet, snippet_with_applicability, span_lint_and_help, + span_lint_and_sugg, strip_pat_refs, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::PatKind; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::source_map::Span; +use rustc_span::symbol::sym; + +use super::SEARCH_IS_SOME; + +/// lint searching an Iterator followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + search_method: &str, + search_args: &'tcx [hir::Expr<'_>], + is_some_args: &'tcx [hir::Expr<'_>], + method_span: Span, +) { + // lint if caller of search is an Iterator + if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { + let msg = format!( + "called `is_some()` after searching an `Iterator` with `{}`", + search_method + ); + let hint = "this is more succinctly expressed by calling `any()`"; + let search_snippet = snippet(cx, search_args[1].span, ".."); + if search_snippet.lines().count() <= 1 { + // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` + // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` + let any_search_snippet = if_chain! { + if search_method == "find"; + if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind; + let closure_body = cx.tcx.hir().body(body_id); + if let Some(closure_arg) = closure_body.params.get(0); + then { + if let hir::PatKind::Ref(..) = closure_arg.pat.kind { + Some(search_snippet.replacen('&', "", 1)) + } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind { + let name = &*ident.name.as_str(); + Some(search_snippet.replace(&format!("*{}", name), name)) + } else { + None + } + } else { + None + } + }; + // add note if not multi-line + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `any()` instead", + format!( + "any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); + } + } + // lint if `find()` is called by `String` or `&str` + else if search_method == "find" { + let is_string_or_str_slice = |e| { + let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); + if is_type_diagnostic_item(cx, self_ty, sym::string_type) { + true + } else { + *self_ty.kind() == ty::Str + } + }; + if_chain! { + if is_string_or_str_slice(&search_args[0]); + if is_string_or_str_slice(&search_args[1]); + then { + let msg = "called `is_some()` after calling `find()` on a string"; + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + msg, + "use `contains()` instead", + format!("contains({})", find_arg), + applicability, + ); + } + } + } +} -- cgit 1.4.1-3-g733a5 From 171c4c148540846c8aab4e1f0f491e8bfb892fcf Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:45:25 +0900 Subject: move iter_skip_next to its own module --- clippy_lints/src/methods/iter_skip_next.rs | 24 ++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 21 ++------------------- 2 files changed, 26 insertions(+), 19 deletions(-) create mode 100644 clippy_lints/src/methods/iter_skip_next.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs new file mode 100644 index 00000000000..5f5969134e4 --- /dev/null +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -0,0 +1,24 @@ +use crate::utils::{match_trait_method, paths, snippet, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::ITER_SKIP_NEXT; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { + // lint if caller of skip is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + if let [caller, n] = skip_args { + let hint = format!(".nth({})", snippet(cx, n.span, "..")); + span_lint_and_sugg( + cx, + ITER_SKIP_NEXT, + expr.span.trim_start(caller.span).unwrap(), + "called `skip(..).next()` on an iterator", + "use `nth` instead", + hint, + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2b8bb0b4216..927375f9e0b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -22,6 +22,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; +mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; mod map_collect_result_unit; @@ -1730,7 +1731,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["nth", "bytes"] => bytes_nth::check(cx, expr, &arg_lists[1]), ["nth", ..] => iter_nth_zero::check(cx, expr, arg_lists[0]), ["step_by", ..] => iterator_step_by_zero::check(cx, expr, arg_lists[0]), - ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), + ["next", "skip"] => iter_skip_next::check(cx, expr, arg_lists[1]), ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]), ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), @@ -2510,24 +2511,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: } } -fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { - // lint if caller of skip is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { - if let [caller, n] = skip_args { - let hint = format!(".nth({})", snippet(cx, n.span, "..")); - span_lint_and_sugg( - cx, - ITER_SKIP_NEXT, - expr.span.trim_start(caller.span).unwrap(), - "called `skip(..).next()` on an iterator", - "use `nth` instead", - hint, - Applicability::MachineApplicable, - ); - } - } -} - fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, -- cgit 1.4.1-3-g733a5 From caaba8270c7de1bf3446f3345e7e794295db59fd Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:53:31 +0900 Subject: move clone_on_copy to its own module --- clippy_lints/src/methods/clone_on_copy.rs | 109 ++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 106 +---------------------------- 2 files changed, 112 insertions(+), 103 deletions(-) create mode 100644 clippy_lints/src/methods/clone_on_copy.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs new file mode 100644 index 00000000000..4a130ed47db --- /dev/null +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -0,0 +1,109 @@ +use crate::utils::{is_copy, span_lint_and_then, sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use std::iter; + +use super::CLONE_DOUBLE_REF; +use super::CLONE_ON_COPY; + +/// Checks for the `CLONE_ON_COPY` lint. +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) { + let ty = cx.typeck_results().expr_ty(expr); + if let ty::Ref(_, inner, _) = arg_ty.kind() { + if let ty::Ref(_, innermost, _) = inner.kind() { + span_lint_and_then( + cx, + CLONE_DOUBLE_REF, + expr.span, + &format!( + "using `clone` on a double-reference; \ + this will copy the reference of type `{}` instead of cloning the inner type", + ty + ), + |diag| { + if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { + let mut ty = innermost; + let mut n = 0; + while let ty::Ref(_, inner, _) = ty.kind() { + ty = inner; + n += 1; + } + let refs: String = iter::repeat('&').take(n + 1).collect(); + let derefs: String = iter::repeat('*').take(n).collect(); + let explicit = format!("<{}{}>::clone({})", refs, ty, snip); + diag.span_suggestion( + expr.span, + "try dereferencing it", + format!("{}({}{}).clone()", refs, derefs, snip.deref()), + Applicability::MaybeIncorrect, + ); + diag.span_suggestion( + expr.span, + "or try being explicit if you are sure, that you want to clone a reference", + explicit, + Applicability::MaybeIncorrect, + ); + } + }, + ); + return; // don't report clone_on_copy + } + } + + if is_copy(cx, ty) { + let snip; + if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) { + let parent = cx.tcx.hir().get_parent_node(expr.hir_id); + match &cx.tcx.hir().get(parent) { + hir::Node::Expr(parent) => match parent.kind { + // &*x is a nop, &x.clone() is not + hir::ExprKind::AddrOf(..) => return, + // (*x).func() is useless, x.clone().func() can work in case func borrows mutably + hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => { + return; + }, + + _ => {}, + }, + hir::Node::Stmt(stmt) => { + if let hir::StmtKind::Local(ref loc) = stmt.kind { + if let hir::PatKind::Ref(..) = loc.pat.kind { + // let ref y = *x borrows x, let ref y = x.clone() does not + return; + } + } + }, + _ => {}, + } + + // x.clone() might have dereferenced x, possibly through Deref impls + if cx.typeck_results().expr_ty(arg) == ty { + snip = Some(("try removing the `clone` call", format!("{}", snippet))); + } else { + let deref_count = cx + .typeck_results() + .expr_adjustments(arg) + .iter() + .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) + .count(); + let derefs: String = iter::repeat('*').take(deref_count).collect(); + snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet))); + } + } else { + snip = None; + } + span_lint_and_then( + cx, + CLONE_ON_COPY, + expr.span, + &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), + |diag| { + if let Some((text, snip)) = snip { + diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); + } + }, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 927375f9e0b..f248a09e18e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,6 @@ mod bind_instead_of_map; mod bytes_nth; +mod clone_on_copy; mod clone_on_ref_ptr; mod expect_used; mod filetype_is_file; @@ -45,7 +46,6 @@ mod wrong_self_convention; mod zst_offset; use std::borrow::Cow; -use std::iter; use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; @@ -69,7 +69,7 @@ use crate::utils::{ is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, SpanlessEq, + span_lint_and_help, span_lint_and_sugg, strip_pat_refs, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1781,7 +1781,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); if args.len() == 1 && method_call.ident.name == sym::clone { - lint_clone_on_copy(cx, expr, &args[0], self_ty); + clone_on_copy::check(cx, expr, &args[0], self_ty); clone_on_ref_ptr::check(cx, expr, &args[0]); } if args.len() == 1 && method_call.ident.name == sym!(to_string) { @@ -2323,106 +2323,6 @@ fn lint_expect_fun_call( ); } -/// Checks for the `CLONE_ON_COPY` lint. -fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) { - let ty = cx.typeck_results().expr_ty(expr); - if let ty::Ref(_, inner, _) = arg_ty.kind() { - if let ty::Ref(_, innermost, _) = inner.kind() { - span_lint_and_then( - cx, - CLONE_DOUBLE_REF, - expr.span, - &format!( - "using `clone` on a double-reference; \ - this will copy the reference of type `{}` instead of cloning the inner type", - ty - ), - |diag| { - if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { - let mut ty = innermost; - let mut n = 0; - while let ty::Ref(_, inner, _) = ty.kind() { - ty = inner; - n += 1; - } - let refs: String = iter::repeat('&').take(n + 1).collect(); - let derefs: String = iter::repeat('*').take(n).collect(); - let explicit = format!("<{}{}>::clone({})", refs, ty, snip); - diag.span_suggestion( - expr.span, - "try dereferencing it", - format!("{}({}{}).clone()", refs, derefs, snip.deref()), - Applicability::MaybeIncorrect, - ); - diag.span_suggestion( - expr.span, - "or try being explicit if you are sure, that you want to clone a reference", - explicit, - Applicability::MaybeIncorrect, - ); - } - }, - ); - return; // don't report clone_on_copy - } - } - - if is_copy(cx, ty) { - let snip; - if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) { - let parent = cx.tcx.hir().get_parent_node(expr.hir_id); - match &cx.tcx.hir().get(parent) { - hir::Node::Expr(parent) => match parent.kind { - // &*x is a nop, &x.clone() is not - hir::ExprKind::AddrOf(..) => return, - // (*x).func() is useless, x.clone().func() can work in case func borrows mutably - hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => { - return; - }, - - _ => {}, - }, - hir::Node::Stmt(stmt) => { - if let hir::StmtKind::Local(ref loc) = stmt.kind { - if let hir::PatKind::Ref(..) = loc.pat.kind { - // let ref y = *x borrows x, let ref y = x.clone() does not - return; - } - } - }, - _ => {}, - } - - // x.clone() might have dereferenced x, possibly through Deref impls - if cx.typeck_results().expr_ty(arg) == ty { - snip = Some(("try removing the `clone` call", format!("{}", snippet))); - } else { - let deref_count = cx - .typeck_results() - .expr_adjustments(arg) - .iter() - .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) - .count(); - let derefs: String = iter::repeat('*').take(deref_count).collect(); - snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet))); - } - } else { - snip = None; - } - span_lint_and_then( - cx, - CLONE_ON_COPY, - expr.span, - &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), - |diag| { - if let Some((text, snip)) = snip { - diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); - } - }, - ); - } -} - fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) { fn check_fold_with_op( cx: &LateContext<'_>, -- cgit 1.4.1-3-g733a5 From 78e572c62782b4bd027c23b9d56a14b0b42ba93a Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 18:59:35 +0900 Subject: move useless_asref to its own module --- clippy_lints/src/methods/mod.rs | 45 ++++--------------------------- clippy_lints/src/methods/useless_asref.rs | 45 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 clippy_lints/src/methods/useless_asref.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f248a09e18e..eaf247536b6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -42,6 +42,7 @@ mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_lazy_eval; mod unwrap_used; +mod useless_asref; mod wrong_self_convention; mod zst_offset; @@ -65,11 +66,11 @@ use rustc_typeck::hir_ty_to_ty; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, get_parent_expr, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, + contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, strip_pat_refs, walk_ptrs_ty_depth, SpanlessEq, + span_lint_and_help, span_lint_and_sugg, strip_pat_refs, SpanlessEq, }; declare_clippy_lint! { @@ -1733,8 +1734,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["step_by", ..] => iterator_step_by_zero::check(cx, expr, arg_lists[0]), ["next", "skip"] => iter_skip_next::check(cx, expr, arg_lists[1]), ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]), - ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), - ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), + ["as_ref"] => useless_asref::check(cx, expr, "as_ref", arg_lists[0]), + ["as_mut"] => useless_asref::check(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), ["filter_map", ..] => { unnecessary_filter_map::check(cx, expr, arg_lists[0]); @@ -2751,42 +2752,6 @@ fn get_hint_if_single_char_arg( } } -/// Checks for the `USELESS_ASREF` lint. -fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { - // when we get here, we've already checked that the call name is "as_ref" or "as_mut" - // check if the call is to the actual `AsRef` or `AsMut` trait - if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) { - // check if the type after `as_ref` or `as_mut` is the same as before - let recvr = &as_ref_args[0]; - let rcv_ty = cx.typeck_results().expr_ty(recvr); - let res_ty = cx.typeck_results().expr_ty(expr); - let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty); - let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty); - if base_rcv_ty == base_res_ty && rcv_depth >= res_depth { - // allow the `as_ref` or `as_mut` if it is followed by another method call - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::MethodCall(_, ref span, _, _) = parent.kind; - if span != &expr.span; - then { - return; - } - } - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - USELESS_ASREF, - expr.span, - &format!("this call to `{}` does nothing", call_name), - "try this", - snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), - applicability, - ); - } - } -} - const FN_HEADER: hir::FnHeader = hir::FnHeader { unsafety: hir::Unsafety::Normal, constness: hir::Constness::NotConst, diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs new file mode 100644 index 00000000000..e4554f8d489 --- /dev/null +++ b/clippy_lints/src/methods/useless_asref.rs @@ -0,0 +1,45 @@ +use crate::utils::{ + get_parent_expr, match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty_depth, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::USELESS_ASREF; + +/// Checks for the `USELESS_ASREF` lint. +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { + // when we get here, we've already checked that the call name is "as_ref" or "as_mut" + // check if the call is to the actual `AsRef` or `AsMut` trait + if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) { + // check if the type after `as_ref` or `as_mut` is the same as before + let recvr = &as_ref_args[0]; + let rcv_ty = cx.typeck_results().expr_ty(recvr); + let res_ty = cx.typeck_results().expr_ty(expr); + let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty); + let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty); + if base_rcv_ty == base_res_ty && rcv_depth >= res_depth { + // allow the `as_ref` or `as_mut` if it is followed by another method call + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let hir::ExprKind::MethodCall(_, ref span, _, _) = parent.kind; + if span != &expr.span; + then { + return; + } + } + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + USELESS_ASREF, + expr.span, + &format!("this call to `{}` does nothing", call_name), + "try this", + snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), + applicability, + ); + } + } +} -- cgit 1.4.1-3-g733a5 From bbed852f6fb82aa85f72fc8b2aeffdb90f409495 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 19:05:51 +0900 Subject: unnecessary_fold to its own module --- clippy_lints/src/methods/mod.rs | 100 ++------------------------ clippy_lints/src/methods/unnecessary_fold.rs | 101 +++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 94 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_fold.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index eaf247536b6..702c8e76f49 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -40,6 +40,7 @@ mod string_extend_chars; mod suspicious_map; mod uninit_assumed_init; mod unnecessary_filter_map; +mod unnecessary_fold; mod unnecessary_lazy_eval; mod unwrap_used; mod useless_asref; @@ -53,7 +54,7 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{PatKind, TraitItem, TraitItemKind}; +use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; @@ -67,10 +68,9 @@ use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, - is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, - match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty, - single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, strip_pat_refs, SpanlessEq, + is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_type, meets_msrv, + method_calls, method_chain_args, paths, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; declare_clippy_lint! { @@ -1736,7 +1736,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]), ["as_ref"] => useless_asref::check(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => useless_asref::check(cx, expr, "as_mut", arg_lists[0]), - ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), + ["fold", ..] => unnecessary_fold::check(cx, expr, arg_lists[0], method_spans[0]), ["filter_map", ..] => { unnecessary_filter_map::check(cx, expr, arg_lists[0]); filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); @@ -2324,94 +2324,6 @@ fn lint_expect_fun_call( ); } -fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) { - fn check_fold_with_op( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - fold_args: &[hir::Expr<'_>], - fold_span: Span, - op: hir::BinOpKind, - replacement_method_name: &str, - replacement_has_args: bool, - ) { - if_chain! { - // Extract the body of the closure passed to fold - if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind; - let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); - - // Check if the closure body is of the form `acc some_expr(x)` - if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind; - if bin_op.node == op; - - // Extract the names of the two arguments to the closure - if let [param_a, param_b] = closure_body.params; - if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(¶m_a.pat).kind; - if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(¶m_b.pat).kind; - - if path_to_local_id(left_expr, first_arg_id); - if replacement_has_args || path_to_local_id(right_expr, second_arg_id); - - then { - let mut applicability = Applicability::MachineApplicable; - let sugg = if replacement_has_args { - format!( - "{replacement}(|{s}| {r})", - replacement = replacement_method_name, - s = second_arg_ident, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!( - "{replacement}()", - replacement = replacement_method_name, - ) - }; - - span_lint_and_sugg( - cx, - UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), - // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) - "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, - ); - } - } - } - - // Check that this is a call to Iterator::fold rather than just some function called fold - if !match_trait_method(cx, expr, &paths::ITERATOR) { - return; - } - - assert!( - fold_args.len() == 3, - "Expected fold_args to have three entries - the receiver, the initial value and the closure" - ); - - // Check if the first argument to .fold is a suitable literal - if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind { - match lit.node { - ast::LitKind::Bool(false) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true) - }, - ast::LitKind::Bool(true) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true) - }, - ast::LitKind::Int(0, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false) - }, - ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false) - }, - _ => (), - } - } -} - fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs new file mode 100644 index 00000000000..a26443f4ee9 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -0,0 +1,101 @@ +use crate::utils::{ + match_trait_method, path_to_local_id, paths, remove_blocks, snippet_with_applicability, span_lint_and_sugg, + strip_pat_refs, +}; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::PatKind; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::UNNECESSARY_FOLD; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) { + fn check_fold_with_op( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + fold_args: &[hir::Expr<'_>], + fold_span: Span, + op: hir::BinOpKind, + replacement_method_name: &str, + replacement_has_args: bool, + ) { + if_chain! { + // Extract the body of the closure passed to fold + if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind; + let closure_body = cx.tcx.hir().body(body_id); + let closure_expr = remove_blocks(&closure_body.value); + + // Check if the closure body is of the form `acc some_expr(x)` + if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind; + if bin_op.node == op; + + // Extract the names of the two arguments to the closure + if let [param_a, param_b] = closure_body.params; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(¶m_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(¶m_b.pat).kind; + + if path_to_local_id(left_expr, first_arg_id); + if replacement_has_args || path_to_local_id(right_expr, second_arg_id); + + then { + let mut applicability = Applicability::MachineApplicable; + let sugg = if replacement_has_args { + format!( + "{replacement}(|{s}| {r})", + replacement = replacement_method_name, + s = second_arg_ident, + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), + ) + } else { + format!( + "{replacement}()", + replacement = replacement_method_name, + ) + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FOLD, + fold_span.with_hi(expr.span.hi()), + // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) + "this `.fold` can be written more succinctly using another method", + "try", + sugg, + applicability, + ); + } + } + } + + // Check that this is a call to Iterator::fold rather than just some function called fold + if !match_trait_method(cx, expr, &paths::ITERATOR) { + return; + } + + assert!( + fold_args.len() == 3, + "Expected fold_args to have three entries - the receiver, the initial value and the closure" + ); + + // Check if the first argument to .fold is a suitable literal + if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind { + match lit.node { + ast::LitKind::Bool(false) => { + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true) + }, + ast::LitKind::Bool(true) => { + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true) + }, + ast::LitKind::Int(0, _) => { + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false) + }, + ast::LitKind::Int(1, _) => { + check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false) + }, + _ => (), + } + } +} -- cgit 1.4.1-3-g733a5 From 5557596926b493f1fdb85aef6bd78941f231f962 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 19:11:52 +0900 Subject: move option_map_or_none to its own module --- clippy_lints/src/methods/mod.rs | 73 +----------------------- clippy_lints/src/methods/option_map_or_none.rs | 78 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 71 deletions(-) create mode 100644 clippy_lints/src/methods/option_map_or_none.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 702c8e76f49..0c67c3b892b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -30,6 +30,7 @@ mod map_collect_result_unit; mod map_flatten; mod ok_expect; mod option_as_ref_deref; +mod option_map_or_none; mod option_map_unwrap_or; mod search_is_some; mod single_char_insert_string; @@ -1692,7 +1693,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"); } }, - ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), + ["map_or", ..] => option_map_or_none::check(cx, expr, arg_lists[0]), ["and_then", ..] => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, arg_lists[0]); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, arg_lists[0]); @@ -2431,76 +2432,6 @@ fn lint_map_unwrap_or_else<'tcx>( false } -/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s -fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type); - - // There are two variants of this `map_or` lint: - // (1) using `map_or` as an adapter from `Result` to `Option` - // (2) using `map_or` as a combinator instead of `and_then` - // - // (For this lint) we don't care if any other type calls `map_or` - if !is_option && !is_result { - return; - } - - let (lint_name, msg, instead, hint) = { - let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind { - match_qpath(qpath, &paths::OPTION_NONE) - } else { - return; - }; - - if !default_arg_is_none { - // nothing to lint! - return; - } - - let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind { - match_qpath(qpath, &paths::OPTION_SOME) - } else { - false - }; - - if is_option { - let self_snippet = snippet(cx, map_or_args[0].span, ".."); - let func_snippet = snippet(cx, map_or_args[2].span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `and_then(..)` instead"; - ( - OPTION_MAP_OR_NONE, - msg, - "try using `and_then` instead", - format!("{0}.and_then({1})", self_snippet, func_snippet), - ) - } else if f_arg_is_some { - let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ - `ok()` instead"; - let self_snippet = snippet(cx, map_or_args[0].span, ".."); - ( - RESULT_MAP_OR_INTO_OPTION, - msg, - "try using `ok` instead", - format!("{0}.ok()", self_snippet), - ) - } else { - // nothing to lint! - return; - } - }; - - span_lint_and_sugg( - cx, - lint_name, - expr.span, - msg, - instead, - hint, - Applicability::MachineApplicable, - ); -} - /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs new file mode 100644 index 00000000000..64f6ebc5062 --- /dev/null +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -0,0 +1,78 @@ +use crate::utils::{is_type_diagnostic_item, match_qpath, paths, snippet, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::OPTION_MAP_OR_NONE; +use super::RESULT_MAP_OR_INTO_OPTION; + +/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) { + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type); + + // There are two variants of this `map_or` lint: + // (1) using `map_or` as an adapter from `Result` to `Option` + // (2) using `map_or` as a combinator instead of `and_then` + // + // (For this lint) we don't care if any other type calls `map_or` + if !is_option && !is_result { + return; + } + + let (lint_name, msg, instead, hint) = { + let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind { + match_qpath(qpath, &paths::OPTION_NONE) + } else { + return; + }; + + if !default_arg_is_none { + // nothing to lint! + return; + } + + let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind { + match_qpath(qpath, &paths::OPTION_SOME) + } else { + false + }; + + if is_option { + let self_snippet = snippet(cx, map_or_args[0].span, ".."); + let func_snippet = snippet(cx, map_or_args[2].span, ".."); + let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ + `and_then(..)` instead"; + ( + OPTION_MAP_OR_NONE, + msg, + "try using `and_then` instead", + format!("{0}.and_then({1})", self_snippet, func_snippet), + ) + } else if f_arg_is_some { + let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ + `ok()` instead"; + let self_snippet = snippet(cx, map_or_args[0].span, ".."); + ( + RESULT_MAP_OR_INTO_OPTION, + msg, + "try using `ok` instead", + format!("{0}.ok()", self_snippet), + ) + } else { + // nothing to lint! + return; + } + }; + + span_lint_and_sugg( + cx, + lint_name, + expr.span, + msg, + instead, + hint, + Applicability::MachineApplicable, + ); +} -- cgit 1.4.1-3-g733a5 From b0824bf75fba159f40e498dd88386174feea5cf5 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 19:31:46 +0900 Subject: move map_unwrap_or to its own module --- clippy_lints/src/methods/map_unwrap_or.rs | 76 +++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 75 ++---------------------------- 2 files changed, 80 insertions(+), 71 deletions(-) create mode 100644 clippy_lints/src/methods/map_unwrap_or.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs new file mode 100644 index 00000000000..63b2cf87f32 --- /dev/null +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -0,0 +1,76 @@ +use crate::utils::usage::mutated_variables; +use crate::utils::{is_type_diagnostic_item, meets_msrv, snippet, span_lint, span_lint_and_sugg}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_semver::RustcVersion; +use rustc_span::symbol::sym; + +use super::MAP_UNWRAP_OR; + +const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); + +/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s +/// Return true if lint triggered +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + map_args: &'tcx [hir::Expr<'_>], + unwrap_args: &'tcx [hir::Expr<'_>], + msrv: Option<&RustcVersion>, +) -> bool { + if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { + return false; + } + // lint if the caller of `map()` is an `Option` + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); + + if is_option || is_result { + // Don't make a suggestion that may fail to compile due to mutably borrowing + // the same variable twice. + let map_mutated_vars = mutated_variables(&map_args[0], cx); + let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx); + if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { + if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { + return false; + } + } else { + return false; + } + + // lint message + let msg = if is_option { + "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling \ + `map_or_else(, )` instead" + } else { + "called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling \ + `.map_or_else(, )` instead" + }; + // get snippets for args to map() and unwrap_or_else() + let map_snippet = snippet(cx, map_args[1].span, ".."); + let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or_else() have the same span + let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; + let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt(); + if same_span && !multiline { + let var_snippet = snippet(cx, map_args[0].span, ".."); + span_lint_and_sugg( + cx, + MAP_UNWRAP_OR, + expr.span, + msg, + "try this", + format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet), + Applicability::MachineApplicable, + ); + return true; + } else if same_span && multiline { + span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); + return true; + } + } + + false +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0c67c3b892b..5f62942530c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -28,6 +28,7 @@ mod iterator_step_by_zero; mod manual_saturating_arithmetic; mod map_collect_result_unit; mod map_flatten; +mod map_unwrap_or; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -66,11 +67,10 @@ use rustc_span::symbol::{sym, Symbol, SymbolStr}; use rustc_typeck::hir_ty_to_ty; use crate::utils::eager_or_lazy::is_lazyness_candidate; -use crate::utils::usage::mutated_variables; use crate::utils::{ contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, - is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_type, meets_msrv, - method_calls, method_chain_args, paths, return_ty, single_segment_path, snippet, snippet_with_applicability, + is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_type, method_calls, + method_chain_args, paths, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; @@ -1689,7 +1689,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["expect", ..] => expect_used::check(cx, expr, arg_lists[0]), ["unwrap_or", "map"] => option_map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => { - if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) { + if !map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) { unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"); } }, @@ -2365,73 +2365,6 @@ fn derefs_to_slice<'tcx>( } } -const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); - -/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s -/// Return true if lint triggered -fn lint_map_unwrap_or_else<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - map_args: &'tcx [hir::Expr<'_>], - unwrap_args: &'tcx [hir::Expr<'_>], - msrv: Option<&RustcVersion>, -) -> bool { - if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { - return false; - } - // lint if the caller of `map()` is an `Option` - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); - - if is_option || is_result { - // Don't make a suggestion that may fail to compile due to mutably borrowing - // the same variable twice. - let map_mutated_vars = mutated_variables(&map_args[0], cx); - let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx); - if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { - if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { - return false; - } - } else { - return false; - } - - // lint message - let msg = if is_option { - "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling \ - `map_or_else(, )` instead" - } else { - "called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling \ - `.map_or_else(, )` instead" - }; - // get snippets for args to map() and unwrap_or_else() - let map_snippet = snippet(cx, map_args[1].span, ".."); - let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or_else() have the same span - let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt(); - if same_span && !multiline { - let var_snippet = snippet(cx, map_args[0].span, ".."); - span_lint_and_sugg( - cx, - MAP_UNWRAP_OR, - expr.span, - msg, - "try this", - format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet), - Applicability::MachineApplicable, - ); - return true; - } else if same_span && multiline { - span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); - return true; - } - } - - false -} - /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { -- cgit 1.4.1-3-g733a5 From f49349bf333001166e3a215b7b2eb5b5cb1c9989 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 19:40:34 +0900 Subject: move or_fun_call to its own module --- clippy_lints/src/methods/mod.rs | 168 +------------------------------ clippy_lints/src/methods/or_fun_call.rs | 173 ++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 163 deletions(-) create mode 100644 clippy_lints/src/methods/or_fun_call.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5f62942530c..857c1bf0ec0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,6 +33,7 @@ mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; mod option_map_unwrap_or; +mod or_fun_call; mod search_is_some; mod single_char_insert_string; mod single_char_pattern; @@ -66,12 +67,11 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol, SymbolStr}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::{ contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, - is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_type, method_calls, - method_chain_args, paths, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, + is_type_diagnostic_item, iter_input_pats, match_def_path, match_qpath, method_calls, method_chain_args, paths, + return_ty, single_segment_path, snippet, snippet_with_applicability, span_lint, span_lint_and_help, + span_lint_and_sugg, SpanlessEq, }; declare_clippy_lint! { @@ -1778,7 +1778,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { - lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); + or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); @@ -1973,164 +1973,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } -/// Checks for the `OR_FUN_CALL` lint. -#[allow(clippy::too_many_lines)] -fn lint_or_fun_call<'tcx>( - cx: &LateContext<'tcx>, - expr: &hir::Expr<'_>, - method_span: Span, - name: &str, - args: &'tcx [hir::Expr<'_>], -) { - /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. - fn check_unwrap_or_default( - cx: &LateContext<'_>, - name: &str, - fun: &hir::Expr<'_>, - self_expr: &hir::Expr<'_>, - arg: &hir::Expr<'_>, - or_has_args: bool, - span: Span, - ) -> bool { - if_chain! { - if !or_has_args; - if name == "unwrap_or"; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - let path = &*last_path_segment(qpath).ident.as_str(); - if ["default", "new"].contains(&path); - let arg_ty = cx.typeck_results().expr_ty(arg); - if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); - if implements_trait(cx, arg_ty, default_trait_id, &[]); - - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - OR_FUN_CALL, - span, - &format!("use of `{}` followed by a call to `{}`", name, path), - "try this", - format!( - "{}.unwrap_or_default()", - snippet_with_applicability(cx, self_expr.span, "..", &mut applicability) - ), - applicability, - ); - - true - } else { - false - } - } - } - - /// Checks for `*or(foo())`. - #[allow(clippy::too_many_arguments)] - fn check_general_case<'tcx>( - cx: &LateContext<'tcx>, - name: &str, - method_span: Span, - self_expr: &hir::Expr<'_>, - arg: &'tcx hir::Expr<'_>, - span: Span, - // None if lambda is required - fun_span: Option, - ) { - // (path, fn_has_argument, methods, suffix) - static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ - (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else"), - ]; - - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { - if path.ident.as_str() == "len" { - let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); - - match ty.kind() { - ty::Slice(_) | ty::Array(_, _) => return, - _ => (), - } - - if is_type_diagnostic_item(cx, ty, sym::vec_type) { - return; - } - } - } - - if_chain! { - if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); - - if is_lazyness_candidate(cx, arg); - if !contains_return(&arg); - - let self_ty = cx.typeck_results().expr_ty(self_expr); - - if let Some(&(_, fn_has_arguments, poss, suffix)) = - KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); - - if poss.contains(&name); - - then { - let macro_expanded_snipped; - let sugg: Cow<'_, str> = { - let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { - (false, Some(fun_span)) => (fun_span, false), - _ => (arg.span, true), - }; - let snippet = { - let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); - if not_macro_argument_snippet == "vec![]" { - macro_expanded_snipped = snippet(cx, snippet_span, ".."); - match macro_expanded_snipped.strip_prefix("$crate::vec::") { - Some(stripped) => Cow::from(stripped), - None => macro_expanded_snipped - } - } - else { - not_macro_argument_snippet - } - }; - - if use_lambda { - let l_arg = if fn_has_arguments { "_" } else { "" }; - format!("|{}| {}", l_arg, snippet).into() - } else { - snippet - } - }; - let span_replace_word = method_span.with_hi(span.hi()); - span_lint_and_sugg( - cx, - OR_FUN_CALL, - span_replace_word, - &format!("use of `{}` followed by a function call", name), - "try this", - format!("{}_{}({})", name, suffix, sugg), - Applicability::HasPlaceholders, - ); - } - } - } - - if args.len() == 2 { - match args[1].kind { - hir::ExprKind::Call(ref fun, ref or_args) => { - let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { - let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); - } - }, - hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); - }, - _ => {}, - } - } -} - /// Checks for the `EXPECT_FUN_CALL` lint. #[allow(clippy::too_many_lines)] fn lint_expect_fun_call( diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs new file mode 100644 index 00000000000..5f7fc431d22 --- /dev/null +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -0,0 +1,173 @@ +use crate::utils::eager_or_lazy::is_lazyness_candidate; +use crate::utils::{ + contains_return, get_trait_def_id, implements_trait, is_type_diagnostic_item, last_path_segment, match_type, paths, + snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::source_map::Span; +use rustc_span::symbol::sym; +use std::borrow::Cow; + +use super::OR_FUN_CALL; + +/// Checks for the `OR_FUN_CALL` lint. +#[allow(clippy::too_many_lines)] +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + method_span: Span, + name: &str, + args: &'tcx [hir::Expr<'_>], +) { + /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + fn check_unwrap_or_default( + cx: &LateContext<'_>, + name: &str, + fun: &hir::Expr<'_>, + self_expr: &hir::Expr<'_>, + arg: &hir::Expr<'_>, + or_has_args: bool, + span: Span, + ) -> bool { + if_chain! { + if !or_has_args; + if name == "unwrap_or"; + if let hir::ExprKind::Path(ref qpath) = fun.kind; + let path = &*last_path_segment(qpath).ident.as_str(); + if ["default", "new"].contains(&path); + let arg_ty = cx.typeck_results().expr_ty(arg); + if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); + if implements_trait(cx, arg_ty, default_trait_id, &[]); + + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + OR_FUN_CALL, + span, + &format!("use of `{}` followed by a call to `{}`", name, path), + "try this", + format!( + "{}.unwrap_or_default()", + snippet_with_applicability(cx, self_expr.span, "..", &mut applicability) + ), + applicability, + ); + + true + } else { + false + } + } + } + + /// Checks for `*or(foo())`. + #[allow(clippy::too_many_arguments)] + fn check_general_case<'tcx>( + cx: &LateContext<'tcx>, + name: &str, + method_span: Span, + self_expr: &hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, + span: Span, + // None if lambda is required + fun_span: Option, + ) { + // (path, fn_has_argument, methods, suffix) + static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&paths::RESULT, true, &["or", "unwrap_or"], "else"), + ]; + + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { + if path.ident.as_str() == "len" { + let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); + + match ty.kind() { + ty::Slice(_) | ty::Array(_, _) => return, + _ => (), + } + + if is_type_diagnostic_item(cx, ty, sym::vec_type) { + return; + } + } + } + + if_chain! { + if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); + + if is_lazyness_candidate(cx, arg); + if !contains_return(&arg); + + let self_ty = cx.typeck_results().expr_ty(self_expr); + + if let Some(&(_, fn_has_arguments, poss, suffix)) = + KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); + + if poss.contains(&name); + + then { + let macro_expanded_snipped; + let sugg: Cow<'_, str> = { + let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { + (false, Some(fun_span)) => (fun_span, false), + _ => (arg.span, true), + }; + let snippet = { + let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + if not_macro_argument_snippet == "vec![]" { + macro_expanded_snipped = snippet(cx, snippet_span, ".."); + match macro_expanded_snipped.strip_prefix("$crate::vec::") { + Some(stripped) => Cow::from(stripped), + None => macro_expanded_snipped + } + } + else { + not_macro_argument_snippet + } + }; + + if use_lambda { + let l_arg = if fn_has_arguments { "_" } else { "" }; + format!("|{}| {}", l_arg, snippet).into() + } else { + snippet + } + }; + let span_replace_word = method_span.with_hi(span.hi()); + span_lint_and_sugg( + cx, + OR_FUN_CALL, + span_replace_word, + &format!("use of `{}` followed by a function call", name), + "try this", + format!("{}_{}({})", name, suffix, sugg), + Applicability::HasPlaceholders, + ); + } + } + } + + if args.len() == 2 { + match args[1].kind { + hir::ExprKind::Call(ref fun, ref or_args) => { + let or_has_args = !or_args.is_empty(); + if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { + let fun_span = if or_has_args { None } else { Some(fun.span) }; + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); + } + }, + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + }, + _ => {}, + } + } +} -- cgit 1.4.1-3-g733a5 From c711de28ee903c78ad465f6af99afdb977ab8dfe Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 6 Mar 2021 22:26:29 +0900 Subject: move expect_fun_call to its own module --- clippy_lints/src/methods/expect_fun_call.rs | 199 +++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 206 +--------------------------- 2 files changed, 204 insertions(+), 201 deletions(-) create mode 100644 clippy_lints/src/methods/expect_fun_call.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs new file mode 100644 index 00000000000..6866e9c652a --- /dev/null +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -0,0 +1,199 @@ +use crate::utils::{is_expn_of, is_type_diagnostic_item, snippet, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::source_map::Span; +use rustc_span::symbol::sym; +use std::borrow::Cow; + +use super::EXPECT_FUN_CALL; + +/// Checks for the `EXPECT_FUN_CALL` lint. +#[allow(clippy::too_many_lines)] +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Span, name: &str, args: &[hir::Expr<'_>]) { + // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or + // `&str` + fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + let mut arg_root = arg; + loop { + arg_root = match &arg_root.kind { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, + hir::ExprKind::MethodCall(method_name, _, call_args, _) => { + if call_args.len() == 1 + && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref)) + && { + let arg_type = cx.typeck_results().expr_ty(&call_args[0]); + let base_type = arg_type.peel_refs(); + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type) + } + { + &call_args[0] + } else { + break; + } + }, + _ => break, + }; + } + arg_root + } + + // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be + // converted to string. + fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { + let arg_ty = cx.typeck_results().expr_ty(arg); + if is_type_diagnostic_item(cx, arg_ty, sym::string_type) { + return false; + } + if let ty::Ref(_, ty, ..) = arg_ty.kind() { + if *ty.kind() == ty::Str && can_be_static_str(cx, arg) { + return false; + } + }; + true + } + + // Check if an expression could have type `&'static str`, knowing that it + // has type `&str` for some lifetime. + fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { + match arg.kind { + hir::ExprKind::Lit(_) => true, + hir::ExprKind::Call(fun, _) => { + if let hir::ExprKind::Path(ref p) = fun.kind { + match cx.qpath_res(p, fun.hir_id) { + hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( + cx.tcx.fn_sig(def_id).output().skip_binder().kind(), + ty::Ref(ty::ReStatic, ..) + ), + _ => false, + } + } else { + false + } + }, + hir::ExprKind::MethodCall(..) => { + cx.typeck_results() + .type_dependent_def_id(arg.hir_id) + .map_or(false, |method_id| { + matches!( + cx.tcx.fn_sig(method_id).output().skip_binder().kind(), + ty::Ref(ty::ReStatic, ..) + ) + }) + }, + hir::ExprKind::Path(ref p) => matches!( + cx.qpath_res(p, arg.hir_id), + hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) + ), + _ => false, + } + } + + fn generate_format_arg_snippet( + cx: &LateContext<'_>, + a: &hir::Expr<'_>, + applicability: &mut Applicability, + ) -> Vec { + if_chain! { + if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind; + if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind; + if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind; + + then { + format_arg_expr_tup + .iter() + .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned()) + .collect() + } else { + unreachable!() + } + } + } + + fn is_call(node: &hir::ExprKind<'_>) -> bool { + match node { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => { + is_call(&expr.kind) + }, + hir::ExprKind::Call(..) + | hir::ExprKind::MethodCall(..) + // These variants are debatable or require further examination + | hir::ExprKind::If(..) + | hir::ExprKind::Match(..) + | hir::ExprKind::Block{ .. } => true, + _ => false, + } + } + + if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) { + return; + } + + let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); + let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) { + "||" + } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) { + "|_|" + } else { + return; + }; + + let arg_root = get_arg_root(cx, &args[1]); + + let span_replace_word = method_span.with_hi(expr.span.hi()); + + let mut applicability = Applicability::MachineApplicable; + + //Special handling for `format!` as arg_root + if_chain! { + if let hir::ExprKind::Block(block, None) = &arg_root.kind; + if block.stmts.len() == 1; + if let hir::StmtKind::Local(local) = &block.stmts[0].kind; + if let Some(arg_root) = &local.init; + if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind; + if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1; + if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind; + then { + let fmt_spec = &format_args[0]; + let fmt_args = &format_args[1]; + + let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()]; + + args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability)); + + let sugg = args.join(", "); + + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + &format!("use of `{}` followed by a function call", name), + "try this", + format!("unwrap_or_else({} panic!({}))", closure_args, sugg), + applicability, + ); + + return; + } + } + + let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability); + if requires_to_string(cx, arg_root) { + arg_root_snippet.to_mut().push_str(".to_string()"); + } + + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + &format!("use of `{}` followed by a function call", name), + "try this", + format!( + "unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", + closure_args, arg_root_snippet + ), + applicability, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 857c1bf0ec0..180620e860a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2,6 +2,7 @@ mod bind_instead_of_map; mod bytes_nth; mod clone_on_copy; mod clone_on_ref_ptr; +mod expect_fun_call; mod expect_used; mod filetype_is_file; mod filter_flat_map; @@ -50,8 +51,6 @@ mod useless_asref; mod wrong_self_convention; mod zst_offset; -use std::borrow::Cow; - use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; use rustc_ast::ast; @@ -68,10 +67,9 @@ use rustc_span::symbol::{sym, Symbol, SymbolStr}; use rustc_typeck::hir_ty_to_ty; use crate::utils::{ - contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, - is_type_diagnostic_item, iter_input_pats, match_def_path, match_qpath, method_calls, method_chain_args, paths, - return_ty, single_segment_path, snippet, snippet_with_applicability, span_lint, span_lint_and_help, - span_lint_and_sugg, SpanlessEq, + contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_type_diagnostic_item, + iter_input_pats, match_def_path, match_qpath, method_calls, method_chain_args, paths, return_ty, + single_segment_path, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; declare_clippy_lint! { @@ -1779,7 +1777,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); - lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); + expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); if args.len() == 1 && method_call.ident.name == sym::clone { @@ -1973,200 +1971,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } -/// Checks for the `EXPECT_FUN_CALL` lint. -#[allow(clippy::too_many_lines)] -fn lint_expect_fun_call( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - method_span: Span, - name: &str, - args: &[hir::Expr<'_>], -) { - // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or - // `&str` - fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - let mut arg_root = arg; - loop { - arg_root = match &arg_root.kind { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, - hir::ExprKind::MethodCall(method_name, _, call_args, _) => { - if call_args.len() == 1 - && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref)) - && { - let arg_type = cx.typeck_results().expr_ty(&call_args[0]); - let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type) - } - { - &call_args[0] - } else { - break; - } - }, - _ => break, - }; - } - arg_root - } - - // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be - // converted to string. - fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { - let arg_ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, arg_ty, sym::string_type) { - return false; - } - if let ty::Ref(_, ty, ..) = arg_ty.kind() { - if *ty.kind() == ty::Str && can_be_static_str(cx, arg) { - return false; - } - }; - true - } - - // Check if an expression could have type `&'static str`, knowing that it - // has type `&str` for some lifetime. - fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { - match arg.kind { - hir::ExprKind::Lit(_) => true, - hir::ExprKind::Call(fun, _) => { - if let hir::ExprKind::Path(ref p) = fun.kind { - match cx.qpath_res(p, fun.hir_id) { - hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( - cx.tcx.fn_sig(def_id).output().skip_binder().kind(), - ty::Ref(ty::ReStatic, ..) - ), - _ => false, - } - } else { - false - } - }, - hir::ExprKind::MethodCall(..) => { - cx.typeck_results() - .type_dependent_def_id(arg.hir_id) - .map_or(false, |method_id| { - matches!( - cx.tcx.fn_sig(method_id).output().skip_binder().kind(), - ty::Ref(ty::ReStatic, ..) - ) - }) - }, - hir::ExprKind::Path(ref p) => matches!( - cx.qpath_res(p, arg.hir_id), - hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) - ), - _ => false, - } - } - - fn generate_format_arg_snippet( - cx: &LateContext<'_>, - a: &hir::Expr<'_>, - applicability: &mut Applicability, - ) -> Vec { - if_chain! { - if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind; - if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind; - if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind; - - then { - format_arg_expr_tup - .iter() - .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned()) - .collect() - } else { - unreachable!() - } - } - } - - fn is_call(node: &hir::ExprKind<'_>) -> bool { - match node { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => { - is_call(&expr.kind) - }, - hir::ExprKind::Call(..) - | hir::ExprKind::MethodCall(..) - // These variants are debatable or require further examination - | hir::ExprKind::If(..) - | hir::ExprKind::Match(..) - | hir::ExprKind::Block{ .. } => true, - _ => false, - } - } - - if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) { - return; - } - - let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); - let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) { - "||" - } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) { - "|_|" - } else { - return; - }; - - let arg_root = get_arg_root(cx, &args[1]); - - let span_replace_word = method_span.with_hi(expr.span.hi()); - - let mut applicability = Applicability::MachineApplicable; - - //Special handling for `format!` as arg_root - if_chain! { - if let hir::ExprKind::Block(block, None) = &arg_root.kind; - if block.stmts.len() == 1; - if let hir::StmtKind::Local(local) = &block.stmts[0].kind; - if let Some(arg_root) = &local.init; - if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind; - if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1; - if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind; - then { - let fmt_spec = &format_args[0]; - let fmt_args = &format_args[1]; - - let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()]; - - args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability)); - - let sugg = args.join(", "); - - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - &format!("use of `{}` followed by a function call", name), - "try this", - format!("unwrap_or_else({} panic!({}))", closure_args, sugg), - applicability, - ); - - return; - } - } - - let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability); - if requires_to_string(cx, arg_root) { - arg_root_snippet.to_mut().push_str(".to_string()"); - } - - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - &format!("use of `{}` followed by a function call", name), - "try this", - format!( - "unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", - closure_args, arg_root_snippet - ), - applicability, - ); -} - fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, -- cgit 1.4.1-3-g733a5 From 99f860768cdd71c371cdaf7827c377dbaa4fe396 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 11 Mar 2021 20:02:29 +0900 Subject: remove unused imports --- clippy_lints/src/methods/into_iter_on_ref.rs | 3 ++- clippy_lints/src/methods/mod.rs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index d94b243404c..1e8315dbee2 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; +use rustc_span::symbol::Symbol; use super::INTO_ITER_ON_REF; @@ -27,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty< } } -fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> { +fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(Symbol, &'static str)> { has_iter_method(cx, self_ref_ty).map(|ty_name| { let mutbl = match self_ref_ty.kind() { ty::Ref(_, _, mutbl) => mutbl, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 180620e860a..7fd14c4f9b1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -62,8 +62,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; -use rustc_span::symbol::{sym, Symbol, SymbolStr}; +use rustc_span::symbol::{sym, SymbolStr}; use rustc_typeck::hir_ty_to_ty; use crate::utils::{ -- cgit 1.4.1-3-g733a5 From 83a955335f986c503ac114cf5009ff965bb21741 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 11 Mar 2021 20:18:33 +0900 Subject: fix interning-defined-symbol error --- clippy_lints/src/methods/get_unwrap.rs | 4 ++-- clippy_lints/src/methods/iter_nth.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index 2684c50e01b..e157db2712a 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -27,10 +27,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { needs_ref = get_args_str.parse::().is_ok(); "Vec" - } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) { + } else if is_type_diagnostic_item(cx, expr_ty, sym::vecdeque_type) { needs_ref = get_args_str.parse::().is_ok(); "VecDeque" - } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym!(hashmap_type)) { + } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::hashmap_type) { needs_ref = true; "HashMap" } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) { diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index c8adea9536b..cc3e56ea872 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( "slice" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { "Vec" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vecdeque_type) { "VecDeque" } else { let nth_args = nth_and_iter_args[0]; -- cgit 1.4.1-3-g733a5 From 2547edb84272aeb3d01e2b61640a9107c01b281b Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Thu, 11 Mar 2021 23:47:15 -0800 Subject: wrong_self_convention: fix lint in case of `to_*_mut` method When a method starts with `to_` and ends with `_mut`, it should expect a `&mut self` parameter, otherwise `&self`. --- clippy_lints/src/methods/mod.rs | 15 ++-- clippy_lints/src/methods/wrong_self_convention.rs | 72 +++++++++++++---- tests/ui/def_id_nocore.stderr | 3 +- tests/ui/wrong_self_convention.stderr | 95 +++++++++++++++++------ tests/ui/wrong_self_conventions_mut.rs | 30 +++++++ tests/ui/wrong_self_conventions_mut.stderr | 19 +++++ 6 files changed, 189 insertions(+), 45 deletions(-) create mode 100644 tests/ui/wrong_self_conventions_mut.rs create mode 100644 tests/ui/wrong_self_conventions_mut.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7fd14c4f9b1..16d5e3bb43f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -191,13 +191,14 @@ declare_clippy_lint! { /// **What it does:** Checks for methods with certain name prefixes and which /// doesn't match how self is taken. The actual rules are: /// - /// |Prefix |`self` taken | - /// |-------|----------------------| - /// |`as_` |`&self` or `&mut self`| - /// |`from_`| none | - /// |`into_`|`self` | - /// |`is_` |`&self` or none | - /// |`to_` |`&self` | + /// |Prefix |Postfix |`self` taken | + /// |-------|------------|----------------------| + /// |`as_` | none |`&self` or `&mut self`| + /// |`from_`| none | none | + /// |`into_`| none |`self` | + /// |`is_` | none |`&self` or none | + /// |`to_` | `_mut` |`&mut &self` | + /// |`to_` | not `_mut` |`&self` | /// /// **Why is this bad?** Consistency breeds readability. If you follow the /// conventions, your users won't be surprised that they, e.g., need to supply a diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 90fab577436..c8bcad7be3e 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -1,5 +1,5 @@ use crate::methods::SelfKind; -use crate::utils::span_lint; +use crate::utils::span_lint_and_help; use rustc_lint::LateContext; use rustc_middle::ty::TyS; use rustc_span::source_map::Span; @@ -9,18 +9,22 @@ use super::WRONG_PUB_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION; #[rustfmt::skip] -const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [ - (Convention::Eq("new"), &[SelfKind::No]), - (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), - (Convention::StartsWith("from_"), &[SelfKind::No]), - (Convention::StartsWith("into_"), &[SelfKind::Value]), - (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), - (Convention::Eq("to_mut"), &[SelfKind::RefMut]), - (Convention::StartsWith("to_"), &[SelfKind::Ref]), +const CONVENTIONS: [(&[Convention], &[SelfKind]); 8] = [ + (&[Convention::Eq("new")], &[SelfKind::No]), + (&[Convention::StartsWith("as_")], &[SelfKind::Ref, SelfKind::RefMut]), + (&[Convention::StartsWith("from_")], &[SelfKind::No]), + (&[Convention::StartsWith("into_")], &[SelfKind::Value]), + (&[Convention::StartsWith("is_")], &[SelfKind::Ref, SelfKind::No]), + (&[Convention::Eq("to_mut")], &[SelfKind::RefMut]), + (&[Convention::StartsWith("to_"), Convention::EndsWith("_mut")], &[SelfKind::RefMut]), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut")], &[SelfKind::Ref]), ]; + enum Convention { Eq(&'static str), StartsWith(&'static str), + EndsWith(&'static str), + NotEndsWith(&'static str), } impl Convention { @@ -29,6 +33,8 @@ impl Convention { match *self { Self::Eq(this) => this == other, Self::StartsWith(this) => other.starts_with(this) && this != other, + Self::EndsWith(this) => other.ends_with(this) && this != other, + Self::NotEndsWith(this) => !Self::EndsWith(this).check(other), } } } @@ -38,6 +44,8 @@ impl fmt::Display for Convention { match *self { Self::Eq(this) => this.fmt(f), Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), + Self::EndsWith(this) => '*'.fmt(f).and_then(|_| this.fmt(f)), + Self::NotEndsWith(this) => '~'.fmt(f).and_then(|_| this.fmt(f)), } } } @@ -55,21 +63,59 @@ pub(super) fn check<'tcx>( } else { WRONG_SELF_CONVENTION }; - if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) { + if let Some((conventions, self_kinds)) = &CONVENTIONS + .iter() + .find(|(convs, _)| convs.iter().all(|conv| conv.check(item_name))) + { if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { - span_lint( + let suggestion = { + if conventions.len() > 1 { + let special_case = { + // Don't mention `NotEndsWith` when there is also `StartsWith` convention present + if conventions.len() == 2 { + match conventions { + [Convention::StartsWith(starts_with), Convention::NotEndsWith(_)] + | [Convention::NotEndsWith(_), Convention::StartsWith(starts_with)] => { + Some(format!("methods called `{}`", Convention::StartsWith(starts_with))) + }, + _ => None, + } + } else { + None + } + }; + + if let Some(suggestion) = special_case { + suggestion + } else { + let s = conventions + .iter() + .map(|c| format!("`{}`", &c.to_string())) + .collect::>() + .join(" and "); + + format!("methods called like this: ({})", &s) + } + } else { + format!("methods called `{}`", &conventions[0]) + } + }; + + span_lint_and_help( cx, lint, first_arg_span, &format!( - "methods called `{}` usually take {}; consider choosing a less ambiguous name", - conv, + "{} usually take {}", + suggestion, &self_kinds .iter() .map(|k| k.description()) .collect::>() .join(" or ") ), + None, + "consider choosing a less ambiguous name", ); } } diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index ed87a50547d..a3e9cc75b08 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,10 +1,11 @@ -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take self by reference or self by mutable reference --> $DIR/def_id_nocore.rs:26:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name error: aborting due to previous error diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 32bd9075bd5..f43fea0d513 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,148 +1,195 @@ -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:18:17 | LL | fn from_i32(self) {} | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:24:21 | LL | pub fn from_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take self by reference or self by mutable reference --> $DIR/wrong_self_convention.rs:36:15 | LL | fn as_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take self by value --> $DIR/wrong_self_convention.rs:38:17 | LL | fn into_i32(&self) {} | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take self by reference or no self --> $DIR/wrong_self_convention.rs:40:15 | LL | fn is_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name +error: methods called `to_*` usually take self by reference --> $DIR/wrong_self_convention.rs:42:15 | LL | fn to_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:44:17 | LL | fn from_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take self by reference or self by mutable reference --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn as_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take self by value --> $DIR/wrong_self_convention.rs:47:21 | LL | pub fn into_i64(&self) {} | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take self by reference or no self --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn is_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name +error: methods called `to_*` usually take self by reference --> $DIR/wrong_self_convention.rs:49:19 | LL | pub fn to_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:50:21 | LL | pub fn from_i64(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take self by reference or self by mutable reference --> $DIR/wrong_self_convention.rs:95:19 | LL | fn as_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take self by value --> $DIR/wrong_self_convention.rs:98:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take self by reference or no self --> $DIR/wrong_self_convention.rs:100:19 | LL | fn is_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name +error: methods called `to_*` usually take self by reference --> $DIR/wrong_self_convention.rs:102:19 | LL | fn to_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:104:21 | LL | fn from_i32(self) {} | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name +error: methods called `as_*` usually take self by reference or self by mutable reference --> $DIR/wrong_self_convention.rs:119:19 | LL | fn as_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take self by value --> $DIR/wrong_self_convention.rs:122:25 | LL | fn into_i32_ref(&self); | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name +error: methods called `is_*` usually take self by reference or no self --> $DIR/wrong_self_convention.rs:124:19 | LL | fn is_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name +error: methods called `to_*` usually take self by reference --> $DIR/wrong_self_convention.rs:126:19 | LL | fn to_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:128:21 | LL | fn from_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name +error: methods called `into_*` usually take self by value --> $DIR/wrong_self_convention.rs:146:25 | LL | fn into_i32_ref(&self); | ^^^^^ + | + = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self; consider choosing a less ambiguous name +error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:152:21 | LL | fn from_i32(self); | ^^^^ + | + = help: consider choosing a less ambiguous name error: aborting due to 24 previous errors diff --git a/tests/ui/wrong_self_conventions_mut.rs b/tests/ui/wrong_self_conventions_mut.rs new file mode 100644 index 00000000000..486a0d77235 --- /dev/null +++ b/tests/ui/wrong_self_conventions_mut.rs @@ -0,0 +1,30 @@ +// edition:2018 +#![warn(clippy::wrong_self_convention)] +#![allow(dead_code)] + +fn main() {} + +mod issue6758 { + pub enum Test { + One(T), + Many(Vec), + } + + impl Test { + // If a method starts with `to_` and not ends with `_mut` it should expect `&self` + pub fn to_many(&mut self) -> Option<&mut [T]> { + match self { + Self::Many(data) => Some(data), + _ => None, + } + } + + // If a method starts with `to_` and ends with `_mut` it should expect `&mut self` + pub fn to_many_mut(&self) -> Option<&[T]> { + match self { + Self::Many(data) => Some(data), + _ => None, + } + } + } +} diff --git a/tests/ui/wrong_self_conventions_mut.stderr b/tests/ui/wrong_self_conventions_mut.stderr new file mode 100644 index 00000000000..7662b38e67d --- /dev/null +++ b/tests/ui/wrong_self_conventions_mut.stderr @@ -0,0 +1,19 @@ +error: methods called `to_*` usually take self by reference + --> $DIR/wrong_self_conventions_mut.rs:15:24 + | +LL | pub fn to_many(&mut self) -> Option<&mut [T]> { + | ^^^^^^^^^ + | + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name + +error: methods called like this: (`to_*` and `*_mut`) usually take self by mutable reference + --> $DIR/wrong_self_conventions_mut.rs:23:28 + | +LL | pub fn to_many_mut(&self) -> Option<&[T]> { + | ^^^^^ + | + = help: consider choosing a less ambiguous name + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 93ee80ac3e9ecc3eee4246c56fce5582a6e1a15f Mon Sep 17 00:00:00 2001 From: Yoshitomo Nakanishi Date: Sat, 13 Mar 2021 02:09:19 +0900 Subject: Use sym::Iterator instead of paths::ITERATOR --- clippy_lints/src/blocks_in_if_conditions.rs | 7 ++++--- clippy_lints/src/copy_iterator.rs | 21 +++++++++++++-------- clippy_lints/src/loops/iter_next_loop.rs | 6 ++++-- clippy_lints/src/loops/needless_collect.rs | 6 +++--- clippy_lints/src/loops/utils.rs | 7 +++---- clippy_lints/src/loops/while_let_on_iterator.rs | 8 ++++---- clippy_lints/src/map_clone.rs | 5 ++--- clippy_lints/src/map_identity.rs | 4 ++-- clippy_lints/src/matches.rs | 4 ++-- clippy_lints/src/methods/filter_flat_map.rs | 5 +++-- clippy_lints/src/methods/filter_map.rs | 4 ++-- clippy_lints/src/methods/filter_map_flat_map.rs | 5 +++-- clippy_lints/src/methods/filter_map_identity.rs | 6 +++--- clippy_lints/src/methods/filter_map_map.rs | 5 +++-- clippy_lints/src/methods/filter_map_next.rs | 5 +++-- clippy_lints/src/methods/filter_next.rs | 5 +++-- clippy_lints/src/methods/flat_map_identity.rs | 6 +++--- .../src/methods/from_iter_instead_of_collect.rs | 3 ++- clippy_lints/src/methods/inspect_for_each.rs | 6 +++--- clippy_lints/src/methods/iter_nth_zero.rs | 5 +++-- clippy_lints/src/methods/iter_skip_next.rs | 5 +++-- clippy_lints/src/methods/iterator_step_by_zero.rs | 5 +++-- clippy_lints/src/methods/map_collect_result_unit.rs | 4 ++-- clippy_lints/src/methods/map_flatten.rs | 4 ++-- clippy_lints/src/methods/search_is_some.rs | 4 ++-- clippy_lints/src/methods/skip_while_next.rs | 5 +++-- clippy_lints/src/methods/unnecessary_filter_map.rs | 5 +++-- clippy_lints/src/methods/unnecessary_fold.rs | 7 +++---- clippy_utils/src/lib.rs | 8 ++++++++ clippy_utils/src/paths.rs | 1 - 30 files changed, 97 insertions(+), 74 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index b53f80fd8bc..59bddb8473b 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,6 +1,6 @@ use crate::utils::{ - differing_macro_contexts, get_parent_expr, get_trait_def_id, implements_trait, paths, - snippet_block_with_applicability, span_lint, span_lint_and_sugg, + differing_macro_contexts, get_parent_expr, implements_trait, snippet_block_with_applicability, span_lint, + span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `if` conditions that use blocks containing an @@ -61,7 +62,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { if let Some(parent) = get_parent_expr(self.cx, expr); if let ExprKind::MethodCall(_, _, args, _) = parent.kind; let caller = self.cx.typeck_results().expr_ty(&args[0]); - if let Some(iter_id) = get_trait_def_id(self.cx, &paths::ITERATOR); + if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(self.cx, caller, iter_id, &[]); then { return; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 004bce5f62a..0502f725efb 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -1,7 +1,10 @@ -use crate::utils::{is_copy, match_path, paths, span_lint_and_note}; +use crate::utils::{is_copy, span_lint_and_note}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +use if_chain::if_chain; declare_clippy_lint! { /// **What it does:** Checks for types that implement `Copy` as well as @@ -33,14 +36,16 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for CopyIterator { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Impl(Impl { - of_trait: Some(ref trait_ref), - .. - }) = item.kind - { + if_chain! { + if let ItemKind::Impl(Impl { + of_trait: Some(ref trait_ref), + .. + }) = item.kind; let ty = cx.tcx.type_of(item.def_id); - - if is_copy(cx, ty) && match_path(&trait_ref.path, &paths::ITERATOR) { + if is_copy(cx, ty); + if let Some(trait_id) = trait_ref.trait_def_id(); + if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id); + then { span_lint_and_note( cx, COPY_ITERATOR, diff --git a/clippy_lints/src/loops/iter_next_loop.rs b/clippy_lints/src/loops/iter_next_loop.rs index cf78bbc49a3..d6b40fa9fa8 100644 --- a/clippy_lints/src/loops/iter_next_loop.rs +++ b/clippy_lints/src/loops/iter_next_loop.rs @@ -1,10 +1,12 @@ use super::ITER_NEXT_LOOP; -use crate::utils::{match_trait_method, paths, span_lint}; use rustc_hir::Expr; use rustc_lint::LateContext; +use rustc_span::sym; + +use crate::utils::{is_trait_method, span_lint}; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, expr: &Expr<'_>) -> bool { - if match_trait_method(cx, arg, &paths::ITERATOR) { + if is_trait_method(cx, arg, sym::Iterator) { span_lint( cx, ITER_NEXT_LOOP, diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 92560c80629..f8432abfa8a 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -1,7 +1,7 @@ use super::NEEDLESS_COLLECT; use crate::utils::sugg::Sugg; use crate::utils::{ - is_type_diagnostic_item, match_trait_method, match_type, path_to_local_id, paths, snippet, span_lint_and_sugg, + is_trait_method, is_type_diagnostic_item, match_type, path_to_local_id, paths, snippet, span_lint_and_sugg, span_lint_and_then, }; use if_chain::if_chain; @@ -23,7 +23,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if_chain! { if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; if let ExprKind::MethodCall(ref chain_method, _, _, _) = args[0].kind; - if chain_method.ident.name == sym!(collect) && match_trait_method(cx, &args[0], &paths::ITERATOR); + if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); if let Some(ref generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); then { @@ -94,7 +94,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo init: Some(ref init_expr), .. } ) = stmt.kind; if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind; - if method_name.ident.name == sym!(collect) && match_trait_method(cx, &init_expr, &paths::ITERATOR); + if method_name.ident.name == sym!(collect) && is_trait_method(cx, &init_expr, sym::Iterator); if let Some(ref generic_args) = method_name.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); if let ty = cx.typeck_results().node_type(ty.hir_id); diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 9e38e17719a..e62b2ab16d1 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -1,6 +1,5 @@ use crate::utils::{ - get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, is_integer_const, path_to_local, - path_to_local_id, paths, sugg, + get_parent_expr, has_iter_method, implements_trait, is_integer_const, path_to_local, path_to_local_id, sugg, }; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; @@ -10,7 +9,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, P use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use std::iter::Iterator; #[derive(Debug, PartialEq)] @@ -316,7 +315,7 @@ pub(super) fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the /// actual `Iterator` that the loop uses. pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String { - let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |id| { + let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[]) }); if impls_iterator { diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index e5a47694faa..f3b8d0da9cd 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -2,8 +2,8 @@ use super::utils::{LoopNestVisitor, Nesting}; use super::WHILE_LET_ON_ITERATOR; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_enclosing_block, get_trait_def_id, implements_trait, is_refutable, last_path_segment, match_trait_method, - path_to_local, path_to_local_id, paths, snippet_with_applicability, span_lint_and_sugg, + get_enclosing_block, implements_trait, is_refutable, is_trait_method, last_path_segment, path_to_local, + path_to_local_id, snippet_with_applicability, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -27,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Don't lint when the iterator is recreated on every iteration if_chain! { if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind; - if let Some(iter_def_id) = get_trait_def_id(cx, &paths::ITERATOR); + if let Some(iter_def_id) = cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]); then { return; @@ -36,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let lhs_constructor = last_path_segment(qpath); if method_path.ident.name == sym::next - && match_trait_method(cx, match_expr, &paths::ITERATOR) + && is_trait_method(cx, match_expr, sym::Iterator) && lhs_constructor.ident.name == sym::Some && (pat_args.is_empty() || !is_refutable(cx, &pat_args[0]) diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 4b685c09a05..61cf768bcab 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,6 +1,5 @@ -use crate::utils::paths; use crate::utils::{ - is_copy, is_type_diagnostic_item, match_trait_method, remove_blocks, snippet_with_applicability, span_lint_and_sugg, + is_copy, is_trait_method, is_type_diagnostic_item, remove_blocks, snippet_with_applicability, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -55,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if args.len() == 2; if method.ident.name == sym::map; let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR); + if is_type_diagnostic_item(cx, ty, sym::option_type) || is_trait_method(cx, e, sym::Iterator); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 9f9c108a85a..7202a29edd9 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks, + is_adjusted, is_trait_method, is_type_diagnostic_item, match_path, match_var, paths, remove_blocks, span_lint_and_sugg, }; use if_chain::if_chain; @@ -65,7 +65,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; if args.len() == 2 && method.ident.name == sym::map; let caller_ty = cx.typeck_results().expr_ty(&args[0]); - if match_trait_method(cx, expr, &paths::ITERATOR) + if is_trait_method(cx, expr, sym::Iterator) || is_type_diagnostic_item(cx, caller_ty, sym::result_type) || is_type_diagnostic_item(cx, caller_ty, sym::option_type); then { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 1d5a6e7fcc5..e6c2885eb4d 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1614,7 +1614,7 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; + use crate::utils::{is_trait_method, match_qpath, paths, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -1679,7 +1679,7 @@ mod redundant_pattern_match { if keyword == "while"; if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; if method_path.ident.name == sym::next; - if match_trait_method(cx, op, &paths::ITERATOR); + if is_trait_method(cx, op, sym::Iterator); then { return; } diff --git a/clippy_lints/src/methods/filter_flat_map.rs b/clippy_lints/src/methods/filter_flat_map.rs index 8da867fce51..42f05aa0b3a 100644 --- a/clippy_lints/src/methods/filter_flat_map.rs +++ b/clippy_lints/src/methods/filter_flat_map.rs @@ -1,6 +1,7 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use crate::utils::{is_trait_method, span_lint_and_help}; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_MAP; @@ -12,7 +13,7 @@ pub(super) fn check<'tcx>( _map_args: &'tcx [hir::Expr<'_>], ) { // lint if caller of `.filter().flat_map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index f559160004c..91c11afcaaf 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_trait_method, path_to_local_id, paths, snippet, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{is_trait_method, path_to_local_id, snippet, span_lint_and_sugg, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_ if_chain! { if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; - if match_trait_method(cx, map_recv, &paths::ITERATOR); + if is_trait_method(cx, map_recv, sym::Iterator); // filter(|x| ...is_some())... if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; diff --git a/clippy_lints/src/methods/filter_map_flat_map.rs b/clippy_lints/src/methods/filter_map_flat_map.rs index a6db138623a..e113f3f71b1 100644 --- a/clippy_lints/src/methods/filter_map_flat_map.rs +++ b/clippy_lints/src/methods/filter_map_flat_map.rs @@ -1,6 +1,7 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use crate::utils::{is_trait_method, span_lint_and_help}; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_MAP; @@ -12,7 +13,7 @@ pub(super) fn check<'tcx>( _map_args: &'tcx [hir::Expr<'_>], ) { // lint if caller of `.filter_map().flat_map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 9e646360a40..5f627b42abc 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,9 +1,9 @@ -use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint_and_sugg}; +use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; use super::FILTER_MAP_IDENTITY; @@ -13,7 +13,7 @@ pub(super) fn check( filter_map_args: &[hir::Expr<'_>], filter_map_span: Span, ) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let arg_node = &filter_map_args[1].kind; let apply_lint = |message: &str| { diff --git a/clippy_lints/src/methods/filter_map_map.rs b/clippy_lints/src/methods/filter_map_map.rs index d015b4c7b38..2e704c4c555 100644 --- a/clippy_lints/src/methods/filter_map_map.rs +++ b/clippy_lints/src/methods/filter_map_map.rs @@ -1,6 +1,7 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use crate::utils::{is_trait_method, span_lint_and_help}; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_MAP; @@ -12,7 +13,7 @@ pub(super) fn check<'tcx>( _map_args: &'tcx [hir::Expr<'_>], ) { // lint if caller of `.filter_map().map()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter_map(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index a789df922ff..9019202df0c 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,8 +1,9 @@ -use crate::utils::{match_trait_method, meets_msrv, paths, snippet, span_lint, span_lint_and_sugg}; +use crate::utils::{is_trait_method, meets_msrv, snippet, span_lint, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_semver::RustcVersion; +use rustc_span::sym; use super::FILTER_MAP_NEXT; @@ -14,7 +15,7 @@ pub(super) fn check<'tcx>( filter_args: &'tcx [hir::Expr<'_>], msrv: Option<&RustcVersion>, ) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { return; } diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 81619e73017..34787b9a828 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,14 +1,15 @@ -use crate::utils::{match_trait_method, paths, snippet, span_lint, span_lint_and_sugg}; +use crate::utils::{is_trait_method, snippet, span_lint, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::FILTER_NEXT; /// lint use of `filter().next()` for `Iterators` pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.filter().next()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; let filter_snippet = snippet(cx, filter_args[1].span, ".."); diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index ce3194f8a23..19ddceeccce 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,9 +1,9 @@ -use crate::utils::{match_qpath, match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{is_trait_method, match_qpath, paths, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; use super::FLAT_MAP_IDENTITY; @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>( flat_map_args: &'tcx [hir::Expr<'_>], flat_map_span: Span, ) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let arg_node = &flat_map_args[1].kind; let apply_lint = |message: &str| { diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index e50d0a33400..a5c5bc0e4e2 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -4,6 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Ty; +use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; @@ -13,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp if_chain! { if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); - if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); + if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); then { diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index 959457a5bfc..e7c3a433fe1 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -1,14 +1,14 @@ use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use crate::utils::{is_trait_method, span_lint_and_help}; use super::INSPECT_FOR_EACH; /// lint use of `inspect().for_each()` for `Iterators` pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `inspect(..).for_each(..)` on an `Iterator`"; let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`"; span_lint_and_help( diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index 247192d81f3..ca2e5db4382 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,15 +1,16 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{is_trait_method, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::ITER_NTH_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) { if_chain! { - if match_trait_method(cx, expr, &paths::ITERATOR); + if is_trait_method(cx, expr, sym::Iterator); if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index 5f5969134e4..bdfa133b9e2 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -1,13 +1,14 @@ -use crate::utils::{match_trait_method, paths, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::ITER_SKIP_NEXT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { // lint if caller of skip is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { if let [caller, n] = skip_args { let hint = format!(".nth({})", snippet(cx, n.span, "..")); span_lint_and_sugg( diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 3e05d7f76b7..019a08f746e 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,12 +1,13 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_trait_method, paths, span_lint}; +use crate::utils::{is_trait_method, span_lint}; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) { span_lint( cx, diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index 5b20e268d9f..8f4de00a2b7 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,4 +1,4 @@ -use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, is_type_diagnostic_item, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -17,7 +17,7 @@ pub(super) fn check( if_chain! { // called on Iterator if let [map_expr] = collect_args; - if match_trait_method(cx, map_expr, &paths::ITERATOR); + if is_trait_method(cx, map_expr, sym::Iterator); // return of collect `Result<(),_>` let collect_ret_ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 14a14e4f9ec..afd76e8b959 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,4 +1,4 @@ -use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, is_type_diagnostic_item, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -10,7 +10,7 @@ use super::MAP_FLATTEN; /// lint use of `map().flatten()` for `Iterators` and 'Options' pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.map().flatten()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); let is_map_to_option = match map_closure_ty.kind() { ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index e9e65443220..eb3dc308722 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_type_diagnostic_item, match_trait_method, paths, snippet, snippet_with_applicability, span_lint_and_help, + is_trait_method, is_type_diagnostic_item, snippet, snippet_with_applicability, span_lint_and_help, span_lint_and_sugg, strip_pat_refs, }; use if_chain::if_chain; @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( method_span: Span, ) { // lint if caller of search is an Iterator - if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { + if is_trait_method(cx, &is_some_args[0], sym::Iterator) { let msg = format!( "called `is_some()` after searching an `Iterator` with `{}`", search_method diff --git a/clippy_lints/src/methods/skip_while_next.rs b/clippy_lints/src/methods/skip_while_next.rs index 8ba6ae95200..a9ff78c3260 100644 --- a/clippy_lints/src/methods/skip_while_next.rs +++ b/clippy_lints/src/methods/skip_while_next.rs @@ -1,13 +1,14 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_help}; +use crate::utils::{is_trait_method, span_lint_and_help}; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::SKIP_WHILE_NEXT; /// lint use of `skip_while().next()` for `Iterators` pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, _skip_while_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.skip_while().next()` is an Iterator - if match_trait_method(cx, expr, &paths::ITERATOR) { + if is_trait_method(cx, expr, sym::Iterator) { span_lint_and_help( cx, SKIP_WHILE_NEXT, diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 12b2cf0a165..686874c0a24 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,16 +1,17 @@ use crate::utils::usage::mutated_variables; -use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint}; +use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths, span_lint}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; +use rustc_span::sym; use if_chain::if_chain; use super::UNNECESSARY_FILTER_MAP; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - if !match_trait_method(cx, expr, &paths::ITERATOR) { + if !is_trait_method(cx, expr, sym::Iterator) { return; } diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index a26443f4ee9..9aa53f02ef0 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,6 +1,5 @@ use crate::utils::{ - match_trait_method, path_to_local_id, paths, remove_blocks, snippet_with_applicability, span_lint_and_sugg, - strip_pat_refs, + is_trait_method, path_to_local_id, remove_blocks, snippet_with_applicability, span_lint_and_sugg, strip_pat_refs, }; use if_chain::if_chain; use rustc_ast::ast; @@ -8,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{source_map::Span, sym}; use super::UNNECESSARY_FOLD; @@ -71,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir } // Check that this is a call to Iterator::fold rather than just some function called fold - if !match_trait_method(cx, expr, &paths::ITERATOR) { + if !is_trait_method(cx, expr, sym::Iterator) { return; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e17af49f618..3dad21d2028 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -273,6 +273,7 @@ pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { } /// Checks if the method call given in `expr` belongs to the given trait. +/// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); let trt_id = cx.tcx.trait_of_item(def_id); @@ -295,6 +296,13 @@ pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: .map_or(false, |assoc_def_id| cx.tcx.is_diagnostic_item(diag_item, assoc_def_id)) } +/// Checks if the method call given in `expr` belongs to the given trait. +pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { + cx.typeck_results() + .type_dependent_def_id(expr.hir_id) + .map_or(false, |did| is_diagnostic_assoc_item(cx, did, diag_item)) +} + /// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 560614efc74..11a446e42a4 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -61,7 +61,6 @@ pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; -pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"]; #[cfg(feature = "internal-lints")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; #[cfg(feature = "internal-lints")] -- cgit 1.4.1-3-g733a5 From ecf0c76c369a80c1a2de61e25c94b7df5dc7d164 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 25 Mar 2020 21:13:24 -0400 Subject: Fix suspicious_map false positives --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/suspicious_map.rs | 45 ++++++++++++++++----- clippy_utils/src/lib.rs | 64 ++++++++++++++++++++++++++++-- tests/ui/suspicious_map.rs | 27 +++++++++++++ tests/ui/suspicious_map.stderr | 10 ++++- 5 files changed, 132 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7fd14c4f9b1..45e906cf468 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1739,7 +1739,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { unnecessary_filter_map::check(cx, expr, arg_lists[0]); filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); }, - ["count", "map"] => suspicious_map::check(cx, expr), + ["count", "map"] => suspicious_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..]) diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index e135a826dc4..0ffa71de30c 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -1,16 +1,41 @@ -use crate::utils::span_lint_and_help; +use crate::utils::usage::mutated_variables; +use crate::utils::{expr_or_init, is_trait_method, span_lint_and_help}; +use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::SUSPICIOUS_MAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint_and_help( - cx, - SUSPICIOUS_MAP, - expr.span, - "this call to `map()` won't have an effect on the call to `count()`", - None, - "make sure you did not confuse `map` with `filter` or `for_each`", - ); +pub fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + map_args: &[hir::Expr<'_>], + count_args: &[hir::Expr<'_>], +) { + if_chain! { + if let [count_recv] = count_args; + if let [_, map_arg] = map_args; + if is_trait_method(cx, count_recv, sym::Iterator); + let closure = expr_or_init(cx, map_arg); + if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id); + let closure_body = cx.tcx.hir().body(body_id); + if !cx.typeck_results().expr_ty(&closure_body.value).is_unit(); + then { + if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) { + // A variable is used mutably inside of the closure. Suppress the lint. + if !map_mutated_vars.is_empty() { + return; + } + } + span_lint_and_help( + cx, + SUSPICIOUS_MAP, + expr.span, + "this call to `map()` won't have an effect on the call to `count()`", + None, + "make sure you did not confuse `map` with `filter` or `for_each`", + ); + } + } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 0ddc915862c..98cdeae739f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -62,10 +62,10 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{ - def, Arm, Block, Body, Constness, CrateItem, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs, GenericParam, HirId, - Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Local, MacroDef, MatchSource, Node, Param, Pat, - PatKind, Path, PathSegment, QPath, Stmt, StructField, TraitItem, TraitItemKind, TraitRef, TyKind, Unsafety, - Variant, Visibility, + def, Arm, BindingAnnotation, Block, Body, Constness, CrateItem, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs, + GenericParam, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Local, MacroDef, + MatchSource, Node, Param, Pat, PatKind, Path, PathSegment, QPath, Stmt, StructField, TraitItem, TraitItemKind, + TraitRef, TyKind, Unsafety, Variant, Visibility, }; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -138,6 +138,62 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.ctxt() != lhs.ctxt() } +/// If the given expression is a local binding, find the initializer expression. +/// If that initializer expression is another local binding, find its initializer again. +/// This process repeats as long as possible (but usually no more than once). Initializer +/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`] +/// instead. +/// +/// Examples: +/// ```ignore +/// let abc = 1; +/// // ^ output +/// let def = abc; +/// dbg!(def) +/// // ^^^ input +/// +/// // or... +/// let abc = 1; +/// let def = abc + 2; +/// // ^^^^^^^ output +/// dbg!(def) +/// // ^^^ input +/// ``` +pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> { + while let Some(init) = path_to_local(expr) + .and_then(|id| find_binding_init(cx, id)) + .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty()) + { + expr = init; + } + expr +} + +/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable. +/// By only considering immutable bindings, we guarantee that the returned expression represents the +/// value of the binding wherever it is referenced. +/// +/// Example: +/// ```ignore +/// let abc = 1; +/// // ^ output +/// dbg!(abc) +/// // ^^^ input +/// ``` +pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { + let hir = cx.tcx.hir(); + if_chain! { + if let Some(Node::Binding(pat)) = hir.find(hir_id); + if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..)); + let parent = hir.get_parent_node(hir_id); + if let Some(Node::Local(local)) = hir.find(parent); + then { + return local.init; + } + } + None +} + /// Returns `true` if the given `NodeId` is inside a constant context /// /// # Example diff --git a/tests/ui/suspicious_map.rs b/tests/ui/suspicious_map.rs index d838d8fde21..3a2a10cf09e 100644 --- a/tests/ui/suspicious_map.rs +++ b/tests/ui/suspicious_map.rs @@ -2,4 +2,31 @@ fn main() { let _ = (0..3).map(|x| x + 2).count(); + + let f = |x| x + 1; + let _ = (0..3).map(f).count(); +} + +fn negative() { + // closure with side effects + let mut sum = 0; + let _ = (0..3).map(|x| sum += x).count(); + + // closure variable with side effects + let ext_closure = |x| sum += x; + let _ = (0..3).map(ext_closure).count(); + + // closure that returns unit + let _ = (0..3) + .map(|x| { + // do nothing + }) + .count(); + + // external function + let _ = (0..3).map(do_something).count(); +} + +fn do_something(t: T) -> String { + unimplemented!() } diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr index e1b4ba40376..8c3f36584a5 100644 --- a/tests/ui/suspicious_map.stderr +++ b/tests/ui/suspicious_map.stderr @@ -7,5 +7,13 @@ LL | let _ = (0..3).map(|x| x + 2).count(); = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: make sure you did not confuse `map` with `filter` or `for_each` -error: aborting due to previous error +error: this call to `map()` won't have an effect on the call to `count()` + --> $DIR/suspicious_map.rs:7:13 + | +LL | let _ = (0..3).map(f).count(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: make sure you did not confuse `map` with `filter` or `for_each` + +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From eb7f8d6089e2dba4006f0452ab25262735bbbf61 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sat, 13 Mar 2021 17:01:03 -0600 Subject: Move some utils to ty_utils --- clippy_lints/src/assign_ops.rs | 5 +- clippy_lints/src/async_yields_async.rs | 3 +- clippy_lints/src/blocks_in_if_conditions.rs | 4 +- clippy_lints/src/booleans.rs | 4 +- clippy_lints/src/bytecount.rs | 3 +- clippy_lints/src/casts/cast_lossless.rs | 3 +- clippy_lints/src/casts/cast_possible_truncation.rs | 3 +- clippy_lints/src/casts/cast_possible_wrap.rs | 3 +- clippy_lints/src/casts/cast_precision_loss.rs | 3 +- clippy_lints/src/cognitive_complexity.rs | 3 +- clippy_lints/src/comparison_chain.rs | 5 +- clippy_lints/src/copy_iterator.rs | 3 +- clippy_lints/src/dereference.rs | 3 +- clippy_lints/src/derive.rs | 5 +- clippy_lints/src/doc.rs | 4 +- clippy_lints/src/drop_forget_ref.rs | 3 +- clippy_lints/src/duration_subsec.rs | 3 +- clippy_lints/src/entry.rs | 3 +- clippy_lints/src/eq_op.rs | 5 +- clippy_lints/src/escape.rs | 3 +- clippy_lints/src/eta_reduction.rs | 10 +- clippy_lints/src/fallible_impl_from.rs | 3 +- clippy_lints/src/format.rs | 4 +- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions.rs | 7 +- clippy_lints/src/get_last_with_len.rs | 3 +- clippy_lints/src/if_let_mutex.rs | 3 +- clippy_lints/src/if_let_some_result.rs | 3 +- clippy_lints/src/infinite_iter.rs | 3 +- clippy_lints/src/inherent_to_string.rs | 6 +- clippy_lints/src/let_underscore.rs | 3 +- clippy_lints/src/loops/explicit_iter_loop.rs | 4 +- clippy_lints/src/loops/for_kv_map.rs | 3 +- clippy_lints/src/loops/for_loops_over_fallibles.rs | 3 +- clippy_lints/src/loops/manual_memcpy.rs | 5 +- clippy_lints/src/loops/needless_collect.rs | 6 +- clippy_lints/src/loops/needless_range_loop.rs | 5 +- clippy_lints/src/loops/same_item_push.rs | 3 +- clippy_lints/src/loops/utils.rs | 5 +- clippy_lints/src/loops/while_let_on_iterator.rs | 6 +- clippy_lints/src/manual_map.rs | 6 +- clippy_lints/src/manual_ok_or.rs | 4 +- clippy_lints/src/manual_unwrap_or.rs | 5 +- clippy_lints/src/map_clone.rs | 6 +- clippy_lints/src/map_identity.rs | 6 +- clippy_lints/src/map_unit_fn.rs | 3 +- clippy_lints/src/match_on_vec_items.rs | 3 +- clippy_lints/src/matches.rs | 10 +- clippy_lints/src/mem_discriminant.rs | 4 +- clippy_lints/src/methods/bind_instead_of_map.rs | 3 +- clippy_lints/src/methods/bytes_nth.rs | 3 +- clippy_lints/src/methods/clone_on_copy.rs | 3 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 3 +- clippy_lints/src/methods/expect_fun_call.rs | 3 +- clippy_lints/src/methods/expect_used.rs | 3 +- clippy_lints/src/methods/filetype_is_file.rs | 3 +- .../src/methods/from_iter_instead_of_collect.rs | 3 +- clippy_lints/src/methods/get_unwrap.rs | 5 +- clippy_lints/src/methods/inefficient_to_string.rs | 5 +- clippy_lints/src/methods/into_iter_on_ref.rs | 3 +- clippy_lints/src/methods/iter_cloned_collect.rs | 3 +- clippy_lints/src/methods/iter_count.rs | 4 +- clippy_lints/src/methods/iter_next_slice.rs | 3 +- clippy_lints/src/methods/iter_nth.rs | 3 +- .../src/methods/map_collect_result_unit.rs | 3 +- clippy_lints/src/methods/map_flatten.rs | 3 +- clippy_lints/src/methods/map_unwrap_or.rs | 3 +- clippy_lints/src/methods/mod.rs | 7 +- clippy_lints/src/methods/ok_expect.rs | 3 +- clippy_lints/src/methods/option_as_ref_deref.rs | 6 +- clippy_lints/src/methods/option_map_or_none.rs | 3 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 3 +- clippy_lints/src/methods/or_fun_call.rs | 5 +- clippy_lints/src/methods/search_is_some.rs | 4 +- clippy_lints/src/methods/string_extend_chars.rs | 3 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 3 +- clippy_lints/src/methods/unwrap_used.rs | 3 +- clippy_lints/src/methods/useless_asref.rs | 5 +- clippy_lints/src/misc.rs | 7 +- clippy_lints/src/missing_const_for_fn.rs | 5 +- clippy_lints/src/mut_mutex_lock.rs | 3 +- clippy_lints/src/mutex_atomic.rs | 3 +- clippy_lints/src/needless_pass_by_value.rs | 6 +- clippy_lints/src/needless_question_mark.rs | 9 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 5 +- clippy_lints/src/no_effect.rs | 3 +- clippy_lints/src/open_options.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 3 +- clippy_lints/src/panic_in_result_fn.rs | 3 +- clippy_lints/src/pass_by_ref_or_value.rs | 3 +- clippy_lints/src/path_buf_push_overwrite.rs | 3 +- clippy_lints/src/ptr.rs | 6 +- clippy_lints/src/question_mark.rs | 6 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/redundant_slicing.rs | 3 +- clippy_lints/src/repeat_once.rs | 3 +- clippy_lints/src/strings.rs | 15 +- clippy_lints/src/swap.rs | 5 +- clippy_lints/src/transmute/utils.rs | 3 +- clippy_lints/src/try_err.rs | 5 +- clippy_lints/src/types/mod.rs | 7 +- clippy_lints/src/undropped_manually_drops.rs | 3 +- clippy_lints/src/unnecessary_sort_by.rs | 3 +- clippy_lints/src/unwrap.rs | 5 +- clippy_lints/src/unwrap_in_result.rs | 8 +- clippy_lints/src/useless_conversion.rs | 5 +- clippy_lints/src/utils/internal_lints.rs | 5 +- clippy_lints/src/vec.rs | 3 +- clippy_lints/src/vec_init_then_push.rs | 5 +- clippy_lints/src/verbose_file_reads.rs | 3 +- clippy_lints/src/zero_sized_map_values.rs | 3 +- clippy_utils/src/eager_or_lazy.rs | 3 +- clippy_utils/src/lib.rs | 323 ++------------------- clippy_utils/src/ty.rs | 296 +++++++++++++++++++ 114 files changed, 578 insertions(+), 509 deletions(-) create mode 100644 clippy_utils/src/ty.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index e13f62d0428..ae300324158 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - eq_expr_value, get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, -}; +use crate::utils::{eq_expr_value, get_trait_def_id, snippet_opt, span_lint_and_then, trait_ref_of_method}; use crate::utils::{higher, sugg}; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 869a5c28d05..1e185e97df6 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -1,4 +1,5 @@ -use crate::utils::{implements_trait, snippet, span_lint_and_then}; +use crate::utils::{snippet, span_lint_and_then}; +use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 59bddb8473b..222bb39f89c 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,7 +1,7 @@ use crate::utils::{ - differing_macro_contexts, get_parent_expr, implements_trait, snippet_block_with_applicability, span_lint, - span_lint_and_sugg, + differing_macro_contexts, get_parent_expr, snippet_block_with_applicability, span_lint, span_lint_and_sugg, }; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 0713303ec4b..affc7d2c93f 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,7 +1,7 @@ use crate::utils::{ - eq_expr_value, get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, - span_lint_and_sugg, span_lint_and_then, + eq_expr_value, get_trait_def_id, in_macro, paths, snippet_opt, span_lint_and_sugg, span_lint_and_then, }; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index eb5dc7ceecd..67cca8dcadb 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,6 +1,7 @@ use crate::utils::{ - contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, + contains_name, get_pat_name, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, }; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 478832a5164..902fb423ff1 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,9 +1,10 @@ +use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{in_constant, is_isize_or_usize, snippet_opt, span_lint_and_sugg}; +use crate::utils::{in_constant, snippet_opt, span_lint_and_sugg}; use super::{utils, CAST_LOSSLESS}; diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 33b06b8fe7c..522ef5348be 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,8 +1,9 @@ +use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{is_isize_or_usize, span_lint}; +use crate::utils::span_lint; use super::{utils, CAST_POSSIBLE_TRUNCATION}; diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 56d301ed3e1..931252415ad 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -1,8 +1,9 @@ +use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use crate::utils::{is_isize_or_usize, span_lint}; +use crate::utils::span_lint; use super::{utils, CAST_POSSIBLE_WRAP}; diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index a1c3900ce1f..b6905c21c78 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -1,8 +1,9 @@ +use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{is_isize_or_usize, span_lint}; +use crate::utils::span_lint; use super::{utils, CAST_PRECISION_LOSS}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 658d445dfec..3d842a46813 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; @@ -9,7 +10,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; -use crate::utils::{is_type_diagnostic_item, snippet_opt, span_lint_and_help, LimitStack}; +use crate::utils::{snippet_opt, span_lint_and_help, LimitStack}; declare_clippy_lint! { /// **What it does:** Checks for methods with high cognitive complexity. diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index e309db25995..9843033a2e0 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - get_trait_def_id, if_sequence, implements_trait, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq, -}; +use crate::utils::{get_trait_def_id, if_sequence, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq}; +use clippy_utils::ty::implements_trait; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 0502f725efb..434d8958da5 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_copy, span_lint_and_note}; +use crate::utils::span_lint_and_note; +use clippy_utils::ty::is_copy; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 40ed6d8d154..8842ea9628d 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_node, in_macro, is_allowed, peel_mid_ty_refs, snippet_with_context, span_lint_and_sugg}; +use crate::utils::{get_parent_node, in_macro, is_allowed, snippet_with_context, span_lint_and_sugg}; +use clippy_utils::ty::peel_mid_ty_refs; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 6d3094ed6bf..460fe385272 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,8 +1,9 @@ use crate::utils::paths; use crate::utils::{ - get_trait_def_id, is_allowed, is_automatically_derived, is_copy, match_def_path, span_lint_and_help, - span_lint_and_note, span_lint_and_then, + get_trait_def_id, is_allowed, is_automatically_derived, match_def_path, span_lint_and_help, span_lint_and_note, + span_lint_and_then, }; +use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 90b02d52f8a..4f3c573691e 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,7 +1,7 @@ use crate::utils::{ - implements_trait, is_entrypoint_fn, is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args, - return_ty, span_lint, span_lint_and_note, + is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty, span_lint, span_lint_and_note, }; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind}; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 2aea00d883c..dd145ba6867 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_copy, match_def_path, paths, span_lint_and_note}; +use crate::utils::{match_def_path, paths, span_lint_and_note}; +use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index c0529a34cc4..c97392e3385 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -7,7 +8,7 @@ use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 55575969927..68363e53f0e 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,6 +1,7 @@ use crate::utils::SpanlessEq; -use crate::utils::{get_item_name, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; +use crate::utils::{get_item_name, paths, snippet, snippet_opt}; use crate::utils::{snippet_with_applicability, span_lint_and_then}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 6308f6e2e7e..fa19f16074d 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,7 +1,8 @@ use crate::utils::{ - ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, - multispan_sugg, snippet, span_lint, span_lint_and_then, + ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, multispan_sugg, snippet, + span_lint, span_lint_and_then, }; +use clippy_utils::ty::{implements_trait, is_copy}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index f8ef2a464d5..a7258eea0ad 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::contains_ty; use rustc_hir::intravisit; use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node}; use rustc_infer::infer::TyCtxtInferExt; @@ -10,7 +11,7 @@ use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; -use crate::utils::{contains_ty, span_lint}; +use crate::utils::span_lint; #[derive(Copy, Clone)] pub struct BoxedLocal { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index c461732fd36..d93c32c179f 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,3 +1,6 @@ +use clippy_utils::higher; +use clippy_utils::higher::VecArgs; +use clippy_utils::ty::{implements_trait, type_is_unsafe_function}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; @@ -6,12 +9,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{ - implements_trait, is_adjusted, iter_input_pats, snippet_opt, span_lint_and_sugg, span_lint_and_then, - type_is_unsafe_function, -}; -use clippy_utils::higher; -use clippy_utils::higher::VecArgs; +use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for closures which just call another function where diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index f466dddc13c..cc4e570956b 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args, span_lint_and_then}; +use crate::utils::{is_expn_of, match_panic_def_id, method_chain_args, span_lint_and_then}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index fd6bf19db94..b6209f815bc 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,8 +1,8 @@ use crate::utils::paths; use crate::utils::{ - is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet, snippet_opt, - span_lint_and_then, + is_expn_of, last_path_segment, match_def_path, match_function_call, snippet, snippet_opt, span_lint_and_then, }; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 0933f983014..b92c8ccfb1b 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind}; @@ -6,7 +7,6 @@ use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; -use crate::utils::is_type_diagnostic_item; use crate::utils::span_lint_and_sugg; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index c474db06fe3..349cd39ffb6 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,8 +1,9 @@ use crate::utils::{ - attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats, - match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, + attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr, + path_to_local, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, span_lint_and_then, + trait_ref_of_method, }; +use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, type_is_unsafe_function}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index cdd8a42e7cd..478008ea48c 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -1,6 +1,7 @@ //! lint on using `x.get(x.len() - 1)` instead of `x.last()` -use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 58511c6d57c..f53d1b1cf3b 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_help, SpanlessEq}; +use crate::utils::{span_lint_and_help, SpanlessEq}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir::intravisit::{self as visit, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, MatchSource}; diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 1194bd7e55e..0cd44a1c3a0 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath}; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 7040ac3191f..6bce205ec3a 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,8 +1,9 @@ +use clippy_utils::ty::{implements_trait, match_type}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint}; +use crate::utils::{get_trait_def_id, higher, match_qpath, paths, span_lint}; declare_clippy_lint! { /// **What it does:** Checks for iteration that is guaranteed to be infinite. diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index c1f3e1d9d68..9207413cd69 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -1,13 +1,11 @@ +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir::{ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::{ - get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, - trait_ref_of_method, -}; +use crate::utils::{get_trait_def_id, paths, return_ty, span_lint_and_help, trait_ref_of_method}; declare_clippy_lint! { /// **What it does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 7e96dfcc7da..2da7137b48b 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::{is_must_use_ty, match_type}; use if_chain::if_chain; use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -5,7 +6,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; +use crate::utils::{is_must_use_func_call, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 9683e59a396..b70585015ca 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,12 +1,12 @@ use super::EXPLICIT_ITER_LOOP; -use crate::utils::{match_trait_method, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TyS}; use rustc_span::sym; -use crate::utils::{is_type_diagnostic_item, match_type, paths}; +use crate::utils::{match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) { let should_lint = match method_name { diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 6ee9b95a3b6..aef21886803 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,6 +1,7 @@ use super::FOR_KV_MAP; use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{is_type_diagnostic_item, match_type, multispan_sugg, paths, snippet, span_lint_and_then, sugg}; +use crate::utils::{multispan_sugg, paths, snippet, span_lint_and_then, sugg}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; diff --git a/clippy_lints/src/loops/for_loops_over_fallibles.rs b/clippy_lints/src/loops/for_loops_over_fallibles.rs index db22d90a304..063078adcd1 100644 --- a/clippy_lints/src/loops/for_loops_over_fallibles.rs +++ b/clippy_lints/src/loops/for_loops_over_fallibles.rs @@ -1,5 +1,6 @@ use super::FOR_LOOPS_OVER_FALLIBLES; -use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_help}; +use crate::utils::{snippet, span_lint_and_help}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::{Expr, Pat}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index fad96c2d5c0..362124c082a 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -1,8 +1,7 @@ use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; use crate::utils::sugg::Sugg; -use crate::utils::{ - get_enclosing_block, higher, is_type_diagnostic_item, path_to_local, snippet, span_lint_and_sugg, sugg, -}; +use crate::utils::{get_enclosing_block, higher, path_to_local, snippet, span_lint_and_sugg, sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index f8432abfa8a..f4d3b9eb272 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -1,9 +1,7 @@ use super::NEEDLESS_COLLECT; use crate::utils::sugg::Sugg; -use crate::utils::{ - is_trait_method, is_type_diagnostic_item, match_type, path_to_local_id, paths, snippet, span_lint_and_sugg, - span_lint_and_then, -}; +use crate::utils::{is_trait_method, path_to_local_id, paths, snippet, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 5f02e4b9d87..6d498149166 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -1,9 +1,10 @@ use super::NEEDLESS_RANGE_LOOP; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - contains_name, has_iter_method, higher, is_integer_const, match_trait_method, multispan_sugg, path_to_local_id, - paths, snippet, span_lint_and_then, sugg, SpanlessEq, + contains_name, higher, is_integer_const, match_trait_method, multispan_sugg, path_to_local_id, paths, snippet, + span_lint_and_then, sugg, SpanlessEq, }; +use clippy_utils::ty::has_iter_method; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index f3585830e4a..f891f7b8a1f 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -1,5 +1,6 @@ use super::SAME_ITEM_PUSH; -use crate::utils::{implements_trait, is_type_diagnostic_item, snippet_with_macro_callsite, span_lint_and_help}; +use crate::utils::{snippet_with_macro_callsite, span_lint_and_help}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index e62b2ab16d1..b85676570b4 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - get_parent_expr, has_iter_method, implements_trait, is_integer_const, path_to_local, path_to_local_id, sugg, -}; +use crate::utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; +use clippy_utils::ty::{has_iter_method, implements_trait}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index f3b8d0da9cd..619fd1554f0 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -2,16 +2,16 @@ use super::utils::{LoopNestVisitor, Nesting}; use super::WHILE_LET_ON_ITERATOR; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_enclosing_block, implements_trait, is_refutable, is_trait_method, last_path_segment, path_to_local, - path_to_local_id, snippet_with_applicability, span_lint_and_sugg, + get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, + snippet_with_applicability, span_lint_and_sugg, }; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; - use rustc_span::symbol::sym; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index ea4cedc6754..7c89359f2d9 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -2,11 +2,11 @@ use crate::{ map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF, utils::{ - can_partially_move_ty, is_allowed, is_type_diagnostic_item, match_def_path, match_var, paths, - peel_hir_expr_refs, peel_mid_ty_refs_is_mutable, snippet_with_applicability, snippet_with_context, - span_lint_and_sugg, + is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs, snippet_with_applicability, + snippet_with_context, span_lint_and_sugg, }, }; +use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index efb05b8ffdf..b08829a8bbf 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,7 +1,7 @@ use crate::utils::{ - indent_of, is_type_diagnostic_item, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, - span_lint_and_sugg, + indent_of, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, span_lint_and_sugg, }; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind}; diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index b452225b5db..3a1bde9540d 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,6 +1,7 @@ use crate::consts::constant_simple; use crate::utils; use crate::utils::{path_to_local_id, sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; @@ -96,9 +97,9 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym::option_type) { + if let Some(case) = if is_type_diagnostic_item(cx, ty, sym::option_type) { Some(Case::Option) - } else if utils::is_type_diagnostic_item(cx, ty, sym::result_type) { + } else if is_type_diagnostic_item(cx, ty, sym::result_type) { Some(Case::Result) } else { None diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 61cf768bcab..73d924cd51e 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,6 +1,6 @@ -use crate::utils::{ - is_copy, is_trait_method, is_type_diagnostic_item, remove_blocks, snippet_with_applicability, span_lint_and_sugg, -}; +use crate::utils::is_trait_method; +use crate::utils::{remove_blocks, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 7202a29edd9..79570367ed9 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - is_adjusted, is_trait_method, is_type_diagnostic_item, match_path, match_var, paths, remove_blocks, - span_lint_and_sugg, -}; +use crate::utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 01126e86199..6f4ce87ea5c 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, iter_input_pats, method_chain_args, snippet, span_lint_and_then}; +use crate::utils::{iter_input_pats, method_chain_args, snippet, span_lint_and_then}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 086dae9422f..65afd691d62 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg}; +use crate::utils::{snippet, span_lint_and_sugg}; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource}; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index e6c2885eb4d..4689974e850 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,13 +2,13 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - expr_block, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, - is_type_diagnostic_item, is_wild, match_qpath, match_type, meets_msrv, multispan_sugg, path_to_local, - path_to_local_id, peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, - snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, strip_pat_refs, + expr_block, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, + meets_msrv, multispan_sugg, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, + remove_blocks, snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, + span_lint_and_note, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index c71c2ee7d70..d9d86ac9912 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -1,10 +1,10 @@ -use crate::utils::{match_def_path, paths, snippet, span_lint_and_then, walk_ptrs_ty_depth}; +use crate::utils::{match_def_path, paths, snippet, span_lint_and_then}; +use clippy_utils::ty::walk_ptrs_ty_depth; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; - use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 5decb81d9f2..073d684dbe3 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,8 +1,9 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use crate::utils::{ - in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, + in_macro, match_qpath, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, }; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 71a7e195e41..a695c27f11b 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 4a130ed47db..954d589a47e 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_copy, span_lint_and_then, sugg}; +use crate::utils::{span_lint_and_then, sugg}; +use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 3d5a68d69d7..7bc4ed622dc 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, match_type, paths, snippet_with_macro_callsite, span_lint_and_sugg}; +use crate::utils::{paths, snippet_with_macro_callsite, span_lint_and_sugg}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 6866e9c652a..3de35c930ea 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, is_type_diagnostic_item, snippet, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{is_expn_of, snippet, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 90b781bd9d1..37c41194b4a 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use crate::utils::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index b03835f97e6..791fe3647cb 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_expr, match_type, paths, span_lint_and_help}; +use crate::utils::{get_parent_expr, paths, span_lint_and_help}; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index a5c5bc0e4e2..9b46adaac58 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, implements_trait, paths, span_lint_and_sugg, sugg}; +use crate::utils::{get_trait_def_id, paths, span_lint_and_sugg, sugg}; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index e157db2712a..35071a25cec 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -1,7 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{ - get_parent_expr, is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg, -}; +use crate::utils::{get_parent_expr, paths, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 3045b09c238..42ba62cd4e7 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,7 +1,6 @@ use super::INEFFICIENT_TO_STRING; -use crate::utils::{ - is_type_diagnostic_item, match_def_path, paths, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty_depth, -}; +use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_then}; +use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 1e8315dbee2..f28f082e6fc 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{has_iter_method, match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{match_trait_method, paths, span_lint_and_sugg}; +use clippy_utils::ty::has_iter_method; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index c3e48ffa5fa..1e1d3fdcf70 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 869440e0165..320fd15d6f8 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,6 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg}; - +use crate::utils::{paths, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index 3c03a949cfe..736148d4fb8 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, higher, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, higher, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index cc3e56ea872..17600bb8153 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,6 +1,7 @@ use crate::methods::derefs_to_slice; use crate::methods::iter_nth_zero; -use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use crate::utils::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index 8f4de00a2b7..0a8837be752 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, is_type_diagnostic_item, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index afd76e8b959..3d1c6408dea 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, is_type_diagnostic_item, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 63b2cf87f32..4346869ae0d 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,6 @@ use crate::utils::usage::mutated_variables; -use crate::utils::{is_type_diagnostic_item, meets_msrv, snippet, span_lint, span_lint_and_sugg}; +use crate::utils::{meets_msrv, snippet, span_lint, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 45e906cf468..3e78b662b89 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -52,6 +52,7 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -66,9 +67,9 @@ use rustc_span::symbol::{sym, SymbolStr}; use rustc_typeck::hir_ty_to_ty; use crate::utils::{ - contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_type_diagnostic_item, - iter_input_pats, match_def_path, match_qpath, method_calls, method_chain_args, paths, return_ty, - single_segment_path, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, + contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls, + method_chain_args, paths, return_ty, single_segment_path, snippet_with_applicability, span_lint, + span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; declare_clippy_lint! { diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index c1706cc7cc7..2618d04b242 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -1,4 +1,5 @@ -use crate::utils::{implements_trait, is_type_diagnostic_item, span_lint_and_help}; +use crate::utils::span_lint_and_help; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 89067dbfe0e..17444336a5e 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - is_type_diagnostic_item, match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet, - span_lint_and_sugg, -}; +use crate::utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 64f6ebc5062..5bd4a5bfe21 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, match_qpath, paths, snippet, span_lint_and_sugg}; +use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 7cdd49bbf03..d1c78b3a833 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,6 @@ use crate::utils::{differing_macro_contexts, snippet_with_applicability, span_lint_and_then}; -use crate::utils::{is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::is_copy; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 5f7fc431d22..9f24fe79089 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,8 +1,9 @@ use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::{ - contains_return, get_trait_def_id, implements_trait, is_type_diagnostic_item, last_path_segment, match_type, paths, - snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint_and_sugg, + contains_return, get_trait_def_id, last_path_segment, paths, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint_and_sugg, }; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index eb3dc308722..d903f1e74d3 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,7 +1,7 @@ use crate::utils::{ - is_trait_method, is_type_diagnostic_item, snippet, snippet_with_applicability, span_lint_and_help, - span_lint_and_sugg, strip_pat_refs, + is_trait_method, snippet, snippet_with_applicability, span_lint_and_help, span_lint_and_sugg, strip_pat_refs, }; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 0a08ea26175..5b8cca34931 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a17259d697f..d260a771c01 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,5 +1,6 @@ use crate::utils::{eager_or_lazy, usage}; -use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg}; +use crate::utils::{snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 094c3fc45c4..efe43a6a952 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_help}; +use crate::utils::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index e4554f8d489..e6b1789a4a8 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - get_parent_expr, match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty_depth, -}; +use crate::utils::{get_parent_expr, match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::walk_ptrs_ty_depth; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index acdc245456b..5c4d4401cd9 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -17,9 +18,9 @@ use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; use crate::utils::sugg::Sugg; use crate::utils::{ - get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_diagnostic_assoc_item, is_integer_const, - iter_input_pats, last_path_segment, match_qpath, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, unsext, SpanlessEq, + get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, + last_path_segment, match_qpath, snippet, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then, + span_lint_hir_and_then, unsext, SpanlessEq, }; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index b0998a80128..4cc20b8d38c 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,6 @@ use crate::utils::qualify_min_const_fn::is_min_const_fn; -use crate::utils::{ - fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method, -}; +use crate::utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method}; +use clippy_utils::ty::has_drop; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs index df1cecb328c..e4a57661f97 100644 --- a/clippy_lints/src/mut_mutex_lock.rs +++ b/clippy_lints/src/mut_mutex_lock.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability}; diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 40b236493a3..9f746ce2e1a 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -2,7 +2,8 @@ //! //! This lint is **warn** by default -use crate::utils::{is_type_diagnostic_item, span_lint}; +use crate::utils::span_lint; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index cac4b207511..14989283681 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,8 +1,6 @@ use crate::utils::ptr::get_spans; -use crate::utils::{ - get_trait_def_id, implements_trait, is_copy, is_self, is_type_diagnostic_item, multispan_sugg, paths, snippet, - snippet_opt, span_lint_and_then, -}; +use crate::utils::{get_trait_def_id, is_self, multispan_sugg, paths, snippet, snippet_opt, span_lint_and_then}; +use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index a3293f1b361..d616290ee9c 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -175,8 +176,8 @@ fn is_some_or_ok_call<'a>( let outer_ty = cx.typeck_results().expr_ty(expr); // Check if outer and inner type are Option - let outer_is_some = utils::is_type_diagnostic_item(cx, outer_ty, sym::option_type); - let inner_is_some = utils::is_type_diagnostic_item(cx, inner_ty, sym::option_type); + let outer_is_some = is_type_diagnostic_item(cx, outer_ty, sym::option_type); + let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type); // Check for Option MSRV let meets_option_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV); @@ -185,8 +186,8 @@ fn is_some_or_ok_call<'a>( } // Check if outer and inner type are Result - let outer_is_result = utils::is_type_diagnostic_item(cx, outer_ty, sym::result_type); - let inner_is_result = utils::is_type_diagnostic_item(cx, inner_ty, sym::result_type); + let outer_is_result = is_type_diagnostic_item(cx, outer_ty, sym::result_type); + let inner_is_result = is_type_diagnostic_item(cx, inner_ty, sym::result_type); // Additional check: if the error type of the Result can be converted // via the From trait, then don't match diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index ec0ad58ca9c..67d49f06ad9 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -60,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { let implements_ord = { if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) { - utils::implements_trait(cx, ty, id, &[]) + implements_trait(cx, ty, id, &[]) } else { return; } @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { let implements_partial_ord = { if let Some(id) = cx.tcx.lang_items().partial_ord_trait() { - utils::implements_trait(cx, ty, id, &[]) + implements_trait(cx, ty, id, &[]) } else { return; } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 69302d695ce..c377d373ad6 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,4 +1,5 @@ -use crate::utils::{has_drop, snippet_opt, span_lint, span_lint_and_sugg}; +use crate::utils::{snippet_opt, span_lint, span_lint_and_sugg}; +use clippy_utils::ty::has_drop; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 07ca196990d..71e77932f7a 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_type, paths, span_lint}; +use crate::utils::{paths, span_lint}; +use clippy_utils::ty::match_type; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9ef0d267b0b..8a6d257848f 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,7 +1,8 @@ use crate::utils; use crate::utils::eager_or_lazy; use crate::utils::sugg::Sugg; -use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg}; +use crate::utils::{paths, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 207423a1861..1821e2611ff 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,4 +1,5 @@ -use crate::utils::{find_macro_calls, is_type_diagnostic_item, return_ty, span_lint_and_then}; +use crate::utils::{find_macro_calls, return_ty, span_lint_and_then}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index ff700aa5146..c9b59b89306 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,6 +1,7 @@ use std::cmp; -use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg}; +use crate::utils::{is_self_ty, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_ast::attr; use rustc_errors::Applicability; diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 4a7b0ad07aa..46533682d42 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 6ea2d8b06d8..c2649a135eb 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,10 +1,8 @@ //! Checks for usage of `&Vec[_]` and `&String`. use crate::utils::ptr::get_spans; -use crate::utils::{ - is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, walk_ptrs_hir_ty, -}; +use crate::utils::{is_allowed, match_qpath, paths, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 6c480d48c75..dc00aaffa58 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -7,10 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use crate::utils::sugg::Sugg; -use crate::utils::{ - eq_expr_value, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, - span_lint_and_sugg, -}; +use crate::utils::{eq_expr_value, match_def_path, match_qpath, paths, snippet_with_applicability, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for expressions that could be replaced by the question mark operator. diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index c57e1d0ba77..d2e5a5db372 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,7 +1,7 @@ use crate::utils::{ - fn_has_unsatisfiable_preds, has_drop, is_copy, is_type_diagnostic_item, match_def_path, paths, snippet_opt, - span_lint_hir, span_lint_hir_and_then, walk_ptrs_ty_depth, + fn_has_unsatisfiable_preds, match_def_path, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then, }; +use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth}; use if_chain::if_chain; use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index e5ced13514f..992d1901584 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; @@ -5,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::{lint::in_external_macro, ty::TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_type_lang_item, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for redundant slicing expressions which use the full range, and diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index d34e744eb94..7d668739c5a 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg}; +use crate::utils::{in_macro, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 31dd5965473..62b4b40df45 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,3 +1,10 @@ +use crate::utils::SpanlessEq; +use crate::utils::{ + get_parent_expr, is_allowed, match_function_call, method_calls, paths, span_lint, span_lint_and_help, + span_lint_and_sugg, +}; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -7,14 +14,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use rustc_span::sym; -use if_chain::if_chain; - -use crate::utils::SpanlessEq; -use crate::utils::{ - get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, - span_lint_and_help, span_lint_and_sugg, -}; - declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without /// `let`!). diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 9d8a0c24833..ba2d73a8228 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,7 +1,6 @@ use crate::utils::sugg::Sugg; -use crate::utils::{ - differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, -}; +use crate::utils::{differing_macro_contexts, eq_expr_value, snippet_with_applicability, span_lint_and_then}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 55008d8ec3f..f4b0f205993 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_normalizable, last_path_segment, snippet}; +use crate::utils::{last_path_segment, snippet}; +use clippy_utils::ty::is_normalizable; use if_chain::if_chain; use rustc_hir::{Expr, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 73e3a04aec9..bdb81ea32d7 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,7 +1,8 @@ use crate::utils::{ - differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, + differing_macro_contexts, in_macro, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, + span_lint_and_sugg, }; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 13da768b0ca..fcd38718b9b 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -13,6 +13,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; +use clippy_utils::ty::{is_isize_or_usize, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -37,9 +38,9 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, indent_of, int_bits, is_isize_or_usize, - is_type_diagnostic_item, match_path, multispan_sugg, reindent_multiline, sext, snippet, snippet_opt, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_then, unsext, + clip, comparisons, differing_macro_contexts, higher, indent_of, int_bits, match_path, multispan_sugg, + reindent_multiline, sext, snippet, snippet_opt, snippet_with_macro_callsite, span_lint, span_lint_and_help, + span_lint_and_then, unsext, }; declare_clippy_lint! { diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index 5443f1601fc..8c34ca16e6f 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_type_lang_item, match_function_call, paths, span_lint_and_help}; +use crate::utils::{match_function_call, paths, span_lint_and_help}; +use clippy_utils::ty::is_type_lang_item; use rustc_hir::{lang_items, Expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 00a707107bc..7e385b00646 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,6 @@ use crate::utils; use crate::utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; @@ -176,7 +177,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 2fb0463c5a6..43b5f138a42 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - differing_macro_contexts, is_type_diagnostic_item, span_lint_and_then, usage::is_potentially_mutated, -}; +use crate::utils::{differing_macro_contexts, span_lint_and_then, usage::is_potentially_mutated}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp}; diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 8cb7429849d..6a8f8211566 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,6 +1,9 @@ -use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then}; +use crate::utils::{method_chain_args, return_ty, span_lint_and_then}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; @@ -66,9 +69,6 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { } } -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ImplItemKind}; - struct FindExpectUnwrap<'a, 'tcx> { lcx: &'a LateContext<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c5334853986..23032c74f9a 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,8 +1,9 @@ use crate::utils::sugg::Sugg; use crate::utils::{ - get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, - snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg, + get_parent_expr, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite, + span_lint_and_help, span_lint_and_sugg, }; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 0a347516c3a..2f4bc74ef64 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,8 +1,9 @@ use crate::consts::{constant_simple, Constant}; use crate::utils::{ - is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, run_lints, snippet, - span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, + is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, snippet, span_lint, + span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; use rustc_ast::visit::FnKind; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index c132e4de4f6..682cc35a7d7 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,6 +1,7 @@ use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; -use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{higher, snippet_with_applicability, span_lint_and_sugg}; +use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 8d111f98add..b3262a253e7 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - is_type_diagnostic_item, match_def_path, path_to_local, path_to_local_id, paths, snippet, span_lint_and_sugg, -}; +use crate::utils::{match_def_path, path_to_local, path_to_local_id, paths, snippet, span_lint_and_sugg}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 32574d9d6c9..079a4279c60 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_type, paths, span_lint_and_help}; +use crate::utils::{paths, span_lint_and_help}; +use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index adf7077e650..ab27b60cfa4 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,3 +1,4 @@ +use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -7,7 +8,7 @@ use rustc_span::sym; use rustc_target::abi::LayoutOf as _; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{is_normalizable, is_type_diagnostic_item, match_type, paths, span_lint_and_help}; +use crate::utils::{paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for maps with zero-sized value types anywhere in the code. diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 8013c4e4fcb..88b115a63d7 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -9,7 +9,8 @@ //! - or-fun-call //! - option-if-let-else -use crate::{is_ctor_or_promotable_const_function, is_type_diagnostic_item}; +use crate::is_ctor_or_promotable_const_function; +use crate::ty::is_type_diagnostic_item; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 5b2529b4930..366962d8b77 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -42,6 +42,7 @@ pub mod paths; pub mod ptr; pub mod qualify_min_const_fn; pub mod sugg; +pub mod ty; pub mod usage; pub mod visitors; @@ -54,7 +55,7 @@ use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use if_chain::if_chain; -use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind, Mutability}; +use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir as hir; @@ -65,14 +66,13 @@ use rustc_hir::{ def, Arm, BindingAnnotation, Block, Body, Constness, CrateItem, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs, GenericParam, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Local, MacroDef, MatchSource, Node, Param, Pat, PatKind, Path, PathSegment, QPath, Stmt, StructField, TraitItem, TraitItemKind, - TraitRef, TyKind, Unsafety, Variant, Visibility, + TraitRef, TyKind, Variant, Visibility, }; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, layout::IntegerExt, DefIdTree, IntTy, Ty, TyCtxt, TypeFoldable, UintTy}; +use rustc_middle::ty as rustc_ty; +use rustc_middle::ty::{layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_semver::RustcVersion; use rustc_session::Session; use rustc_span::hygiene::{self, ExpnKind, MacroKind}; @@ -81,11 +81,10 @@ use rustc_span::sym; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{BytePos, Pos, Span, SyntaxContext, DUMMY_SP}; use rustc_target::abi::Integer; -use rustc_trait_selection::traits::query::normalize::AtExt; use smallvec::SmallVec; use crate::consts::{constant, Constant}; -use std::collections::HashMap; +use crate::ty::is_recursively_primitive_type; pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { if let Ok(version) = RustcVersion::parse(msrv) { @@ -256,35 +255,6 @@ pub fn is_wild<'tcx>(pat: &impl std::ops::Deref>) -> bool { matches!(pat.kind, PatKind::Wild) } -/// Checks if type is struct, enum or union type with the given def path. -/// -/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead. -/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` -pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { - match ty.kind() { - ty::Adt(adt, _) => match_def_path(cx, adt.did, path), - _ => false, - } -} - -/// Checks if the type is equal to a diagnostic item -/// -/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` -pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { - match ty.kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), - _ => false, - } -} - -/// Checks if the type is equal to a lang item -pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { - match ty.kind() { - ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did, - _ => false, - } -} - /// Checks if the first type parameter is a lang item. pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> { let ty = get_qpath_generic_tys(qpath).next()?; @@ -319,11 +289,6 @@ pub fn is_ty_param_diagnostic_item( } } -/// Return `true` if the passed `typ` is `isize` or `usize`. -pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { - matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) -} - /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { @@ -338,10 +303,10 @@ pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: cx.tcx .opt_associated_item(def_id) .and_then(|associated_item| match associated_item.container { - ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), - ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { - ty::Adt(adt, _) => Some(adt.did), - ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works + rustc_ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), + rustc_ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { + rustc_ty::Adt(adt, _) => Some(adt.did), + rustc_ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works _ => None, }, }) @@ -540,26 +505,6 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option { } } -/// Checks whether a type implements a trait. -/// See also `get_trait_def_id`. -pub fn implements_trait<'tcx>( - cx: &LateContext<'tcx>, - ty: Ty<'tcx>, - trait_id: DefId, - ty_params: &[GenericArg<'tcx>], -) -> bool { - // Do not check on infer_types to avoid panic in evaluate_obligation. - if ty.has_infer_types() { - return false; - } - let ty = cx.tcx.erase_regions(ty); - if ty.has_escaping_bound_vars() { - return false; - } - let ty_params = cx.tcx.mk_substs(ty_params.iter()); - cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) -} - /// Gets the `hir::TraitRef` of the trait the given method is implemented for. /// /// Use this if you want to find the `TraitRef` of the `Add` trait in this example: @@ -587,26 +532,6 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio None } -/// Checks whether this type implements `Drop`. -pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.ty_adt_def() { - Some(def) => def.has_dtor(cx.tcx), - None => false, - } -} - -/// Checks whether a type can be partially moved. -pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if has_drop(cx, ty) || is_copy(cx, ty) { - return false; - } - match ty.kind() { - ty::Param(_) => false, - ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))), - _ => true, - } -} - /// Returns the method names and argument list of nested method call expressions that make up /// `expr`. method/span lists are sorted with the most recent call first. pub fn method_calls<'tcx>( @@ -1155,26 +1080,6 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { } } -/// Returns the base type for HIR references and pointers. -pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - match ty.kind { - TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), - _ => ty, - } -} - -/// Returns the base type for references and raw pointers, and count reference -/// depth. -pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { - fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { - match ty.kind() { - ty::Ref(_, ty, _) => inner(ty, depth + 1), - _ => (ty, depth), - } - } - inner(ty, 0) -} - /// Checks whether the given expression is a constant integer of the given value. /// unlike `is_integer_literal`, this version does const folding pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool { @@ -1270,26 +1175,6 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> cx.tcx.erase_late_bound_regions(ret_ty) } -/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` -pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { - ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) -} - -/// Returns `true` if the given type is an `unsafe` function. -pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe, - _ => false, - } -} - -pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env) -} - /// Checks if an expression is constructing a tuple-like enum variant or struct pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::Call(ref fun, _) = expr.kind { @@ -1338,11 +1223,13 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, PatKind::Slice(ref head, ref middle, ref tail) => { match &cx.typeck_results().node_type(pat.hir_id).kind() { - ty::Slice(..) => { + rustc_ty::Slice(..) => { // [..] is the only irrefutable slice pattern. !head.is_empty() || middle.is_none() || !tail.is_empty() }, - ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)), + rustc_ty::Array(..) => { + are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)) + }, _ => { // unreachable!() true @@ -1454,26 +1341,26 @@ pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> { pat } -pub fn int_bits(tcx: TyCtxt<'_>, ity: ty::IntTy) -> u64 { +pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 { Integer::from_int_ty(&tcx, ity).size().bits() } #[allow(clippy::cast_possible_wrap)] /// Turn a constant int byte representation into an i128 -pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: ty::IntTy) -> i128 { +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 { let amt = 128 - int_bits(tcx, ity); ((u as i128) << amt) >> amt } #[allow(clippy::cast_sign_loss)] /// clip unused bytes -pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: ty::IntTy) -> u128 { +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 { let amt = 128 - int_bits(tcx, ity); ((u as u128) << amt) >> amt } /// clip unused bytes -pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: ty::UintTy) -> u128 { +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 { let bits = Integer::from_uint_ty(&tcx, ity).size().bits(); let amt = 128 - bits; (u << amt) >> amt @@ -1526,47 +1413,6 @@ pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool false } -/// Returns true if ty has `iter` or `iter_mut` methods -pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option { - // FIXME: instead of this hard-coded list, we should check if `::iter` - // exists and has the desired signature. Unfortunately FnCtxt is not exported - // so we can't use its `lookup_method` method. - let into_iter_collections: &[Symbol] = &[ - sym::vec_type, - sym::option_type, - sym::result_type, - sym::BTreeMap, - sym::BTreeSet, - sym::vecdeque_type, - sym::LinkedList, - sym::BinaryHeap, - sym::hashset_type, - sym::hashmap_type, - sym::PathBuf, - sym::Path, - sym::Receiver, - ]; - - let ty_to_check = match probably_ref_ty.kind() { - ty::Ref(_, ty_to_check, _) => ty_to_check, - _ => probably_ref_ty, - }; - - let def_id = match ty_to_check.kind() { - ty::Array(..) => return Some(sym::array), - ty::Slice(..) => return Some(sym::slice), - ty::Adt(adt, _) => adt.did, - _ => return None, - }; - - for &name in into_iter_collections { - if cx.tcx.is_diagnostic_item(name, def_id) { - return Some(cx.tcx.item_name(def_id)); - } - } - None -} - /// Matches a function call with the given path and returns the arguments. /// /// Usage: @@ -1591,51 +1437,6 @@ pub fn match_function_call<'tcx>( None } -// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize -// this function can be removed once the `normalizie` method does not panic when normalization does -// not succeed -/// Checks if `Ty` is normalizable. This function is useful -/// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - is_normalizable_helper(cx, param_env, ty, &mut HashMap::new()) -} - -fn is_normalizable_helper<'tcx>( - cx: &LateContext<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - cache: &mut HashMap, bool>, -) -> bool { - if let Some(&cached_result) = cache.get(ty) { - return cached_result; - } - // prevent recursive loops, false-negative is better than endless loop leading to stack overflow - cache.insert(ty, false); - let result = cx.tcx.infer_ctxt().enter(|infcx| { - let cause = rustc_middle::traits::ObligationCause::dummy(); - if infcx.at(&cause, param_env).normalize(ty).is_ok() { - match ty.kind() { - ty::Adt(def, substs) => def.variants.iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) - }), - _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { - GenericArgKind::Type(inner_ty) if inner_ty != ty => { - is_normalizable_helper(cx, param_env, inner_ty, cache) - }, - _ => true, // if inner_ty == ty, we've already checked it - }), - } - } else { - false - } - }); - cache.insert(ty, result); - result -} - pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { // We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path` // accepts only that. We should probably move to Symbols in Clippy as well. @@ -1721,44 +1522,6 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { attr_by_name(attrs, "must_use") } -// Returns whether the type has #[must_use] attribute -pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), - ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), - ty::Slice(ref ty) - | ty::Array(ref ty, _) - | ty::RawPtr(ty::TypeAndMut { ref ty, .. }) - | ty::Ref(_, ref ty, _) => { - // for the Array case we don't need to care for the len == 0 case - // because we don't want to lint functions returning empty arrays - is_must_use_ty(cx, *ty) - }, - ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), - ty::Opaque(ref def_id, _) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { - if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { - if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { - return true; - } - } - } - false - }, - ty::Dynamic(binder, _) => { - for predicate in binder.iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { - return true; - } - } - } - false - }, - _ => false, - } -} - // check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { @@ -1853,18 +1616,6 @@ pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bo }) } -/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point -/// number type, a str, or an array, slice, or tuple of those types). -pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, - ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), - ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), - _ => false, - } -} - /// Returns Option where String is a textual representation of the type encapsulated in the /// slice iff the given expression is a slice of primitives (as defined in the /// `is_recursively_primitive_type` function) and None otherwise. @@ -1872,9 +1623,9 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option is_recursively_primitive_type(element_type), - ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &ty::Slice(_)) => { - if let ty::Slice(element_type) = inner_ty.kind() { + rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type), + rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => { + if let rustc_ty::Slice(element_type) = inner_ty.kind() { is_recursively_primitive_type(element_type) } else { unreachable!() @@ -1887,9 +1638,9 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option return Some("slice".into()), - ty::Array(..) => return Some("array".into()), - ty::Tuple(..) => return Some("tuple".into()), + rustc_ty::Slice(..) => return Some("slice".into()), + rustc_ty::Array(..) => return Some("array".into()), + rustc_ty::Tuple(..) => return Some("tuple".into()), _ => { // is_recursively_primitive_type() should have taken care // of the rest and we can rely on the type that is found @@ -1973,32 +1724,6 @@ pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { f(expr, 0) } -/// Peels off all references on the type. Returns the underlying type and the number of references -/// removed. -pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { - fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(ty, count + 1) - } else { - (ty, count) - } - } - peel(ty, 0) -} - -/// Peels off all references on the type.Returns the underlying type, the number of references -/// removed, and whether the pointer is ultimately mutable or not. -pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { - fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) { - match ty.kind() { - ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability), - ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not), - _ => (ty, count, mutability), - } - } - f(ty, 0, Mutability::Mut) -} - #[macro_export] macro_rules! unwrap_cargo_metadata { ($cx: ident, $lint: ident, $deps: expr) => {{ diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs new file mode 100644 index 00000000000..f4a1ae67da3 --- /dev/null +++ b/clippy_utils/src/ty.rs @@ -0,0 +1,296 @@ +//! Util methods for [`rustc_middle::ty`] + +#![allow(clippy::module_name_repetitions)] + +use std::collections::HashMap; + +use rustc_ast::ast::Mutability; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::{TyKind, Unsafety}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_lint::LateContext; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, IntTy, Ty, TypeFoldable, UintTy}; +use rustc_span::sym; +use rustc_span::symbol::Symbol; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::normalize::AtExt; + +use crate::{match_def_path, must_use_attr}; + +pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env) +} + +/// Checks whether a type can be partially moved. +pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + if has_drop(cx, ty) || is_copy(cx, ty) { + return false; + } + match ty.kind() { + ty::Param(_) => false, + ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))), + _ => true, + } +} + +/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` +pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + +/// Returns true if ty has `iter` or `iter_mut` methods +pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option { + // FIXME: instead of this hard-coded list, we should check if `::iter` + // exists and has the desired signature. Unfortunately FnCtxt is not exported + // so we can't use its `lookup_method` method. + let into_iter_collections: &[Symbol] = &[ + sym::vec_type, + sym::option_type, + sym::result_type, + sym::BTreeMap, + sym::BTreeSet, + sym::vecdeque_type, + sym::LinkedList, + sym::BinaryHeap, + sym::hashset_type, + sym::hashmap_type, + sym::PathBuf, + sym::Path, + sym::Receiver, + ]; + + let ty_to_check = match probably_ref_ty.kind() { + ty::Ref(_, ty_to_check, _) => ty_to_check, + _ => probably_ref_ty, + }; + + let def_id = match ty_to_check.kind() { + ty::Array(..) => return Some(sym::array), + ty::Slice(..) => return Some(sym::slice), + ty::Adt(adt, _) => adt.did, + _ => return None, + }; + + for &name in into_iter_collections { + if cx.tcx.is_diagnostic_item(name, def_id) { + return Some(cx.tcx.item_name(def_id)); + } + } + None +} + +/// Checks whether a type implements a trait. +/// See also `get_trait_def_id`. +pub fn implements_trait<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + trait_id: DefId, + ty_params: &[GenericArg<'tcx>], +) -> bool { + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + let ty = cx.tcx.erase_regions(ty); + if ty.has_escaping_bound_vars() { + return false; + } + let ty_params = cx.tcx.mk_substs(ty_params.iter()); + cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) +} + +/// Checks whether this type implements `Drop`. +pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.ty_adt_def() { + Some(def) => def.has_dtor(cx.tcx), + None => false, + } +} + +// Returns whether the type has #[must_use] attribute +pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), + ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), + ty::Slice(ref ty) + | ty::Array(ref ty, _) + | ty::RawPtr(ty::TypeAndMut { ref ty, .. }) + | ty::Ref(_, ref ty, _) => { + // for the Array case we don't need to care for the len == 0 case + // because we don't want to lint functions returning empty arrays + is_must_use_ty(cx, *ty) + }, + ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), + ty::Opaque(ref def_id, _) => { + for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { + if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { + return true; + } + } + } + false + }, + ty::Dynamic(binder, _) => { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { + return true; + } + } + } + false + }, + _ => false, + } +} + +// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize +// this function can be removed once the `normalizie` method does not panic when normalization does +// not succeed +/// Checks if `Ty` is normalizable. This function is useful +/// to avoid crashes on `layout_of`. +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { + is_normalizable_helper(cx, param_env, ty, &mut HashMap::new()) +} + +fn is_normalizable_helper<'tcx>( + cx: &LateContext<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + cache: &mut HashMap, bool>, +) -> bool { + if let Some(&cached_result) = cache.get(ty) { + return cached_result; + } + // prevent recursive loops, false-negative is better than endless loop leading to stack overflow + cache.insert(ty, false); + let result = cx.tcx.infer_ctxt().enter(|infcx| { + let cause = rustc_middle::traits::ObligationCause::dummy(); + if infcx.at(&cause, param_env).normalize(ty).is_ok() { + match ty.kind() { + ty::Adt(def, substs) => def.variants.iter().all(|variant| { + variant + .fields + .iter() + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + }), + _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { + GenericArgKind::Type(inner_ty) if inner_ty != ty => { + is_normalizable_helper(cx, param_env, inner_ty, cache) + }, + _ => true, // if inner_ty == ty, we've already checked it + }), + } + } else { + false + } + }); + cache.insert(ty, result); + result +} + +/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point +/// number type, a str, or an array, slice, or tuple of those types). +pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, + ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, + ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), + _ => false, + } +} + +/// Checks if the type is equal to a diagnostic item +/// +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` +pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { + match ty.kind() { + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), + _ => false, + } +} + +/// Checks if the type is equal to a lang item +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { + match ty.kind() { + ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did, + _ => false, + } +} + +/// Return `true` if the passed `typ` is `isize` or `usize`. +pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { + matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) +} + +/// Checks if type is struct, enum or union type with the given def path. +/// +/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead. +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` +pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { + match ty.kind() { + ty::Adt(adt, _) => match_def_path(cx, adt.did, path), + _ => false, + } +} + +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { + fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { + if let ty::Ref(_, ty, _) = ty.kind() { + peel(ty, count + 1) + } else { + (ty, count) + } + } + peel(ty, 0) +} + +/// Peels off all references on the type.Returns the underlying type, the number of references +/// removed, and whether the pointer is ultimately mutable or not. +pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { + fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) { + match ty.kind() { + ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability), + ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not), + _ => (ty, count, mutability), + } + } + f(ty, 0, Mutability::Mut) +} + +/// Returns `true` if the given type is an `unsafe` function. +pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe, + _ => false, + } +} + +/// Returns the base type for HIR references and pointers. +pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { + match ty.kind { + TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), + _ => ty, + } +} + +/// Returns the base type for references and raw pointers, and count reference +/// depth. +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { + fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { + match ty.kind() { + ty::Ref(_, ty, _) => inner(ty, depth + 1), + _ => (ty, depth), + } + } + inner(ty, 0) +} -- cgit 1.4.1-3-g733a5 From 6fc52a63d19c85e952fc81298e7dd2289a774ac6 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 14 Mar 2021 18:17:44 -0500 Subject: Move some utils to clippy_utils::source module --- clippy_lints/src/assertions_on_constants.rs | 3 +- clippy_lints/src/assign_ops.rs | 3 +- clippy_lints/src/async_yields_async.rs | 3 +- clippy_lints/src/attrs.rs | 6 +- clippy_lints/src/blocks_in_if_conditions.rs | 5 +- clippy_lints/src/booleans.rs | 5 +- clippy_lints/src/bytecount.rs | 5 +- clippy_lints/src/casts/cast_lossless.rs | 3 +- clippy_lints/src/casts/char_lit_as_u8.rs | 6 +- clippy_lints/src/casts/fn_to_numeric_cast.rs | 4 +- .../casts/fn_to_numeric_cast_with_truncation.rs | 4 +- clippy_lints/src/casts/unnecessary_cast.rs | 6 +- clippy_lints/src/checked_conversions.rs | 3 +- clippy_lints/src/cognitive_complexity.rs | 3 +- clippy_lints/src/collapsible_if.rs | 5 +- clippy_lints/src/create_dir.rs | 3 +- clippy_lints/src/dbg_macro.rs | 3 +- clippy_lints/src/default.rs | 5 +- clippy_lints/src/default_numeric_fallback.rs | 6 +- clippy_lints/src/dereference.rs | 3 +- clippy_lints/src/double_comparison.rs | 3 +- clippy_lints/src/duration_subsec.rs | 3 +- clippy_lints/src/entry.rs | 5 +- clippy_lints/src/enum_variants.rs | 3 +- clippy_lints/src/eq_op.rs | 5 +- clippy_lints/src/eta_reduction.rs | 3 +- clippy_lints/src/exhaustive_items.rs | 5 +- clippy_lints/src/format.rs | 5 +- clippy_lints/src/formatting.rs | 3 +- clippy_lints/src/functions.rs | 4 +- clippy_lints/src/get_last_with_len.rs | 3 +- clippy_lints/src/identity_op.rs | 3 +- clippy_lints/src/if_let_some_result.rs | 3 +- clippy_lints/src/if_then_some_else_none.rs | 5 +- clippy_lints/src/implicit_return.rs | 3 +- .../src/inconsistent_struct_constructor.rs | 6 +- clippy_lints/src/int_plus_one.rs | 3 +- clippy_lints/src/large_enum_variant.rs | 3 +- clippy_lints/src/large_stack_arrays.rs | 6 +- clippy_lints/src/len_zero.rs | 6 +- clippy_lints/src/let_if_seq.rs | 3 +- clippy_lints/src/literal_representation.rs | 3 +- clippy_lints/src/loops/explicit_counter_loop.rs | 3 +- clippy_lints/src/loops/explicit_into_iter_loop.rs | 3 +- clippy_lints/src/loops/explicit_iter_loop.rs | 4 +- clippy_lints/src/loops/for_kv_map.rs | 3 +- clippy_lints/src/loops/for_loops_over_fallibles.rs | 6 +- clippy_lints/src/loops/manual_memcpy.rs | 3 +- clippy_lints/src/loops/needless_collect.rs | 3 +- clippy_lints/src/loops/needless_range_loop.rs | 3 +- clippy_lints/src/loops/same_item_push.rs | 3 +- clippy_lints/src/loops/single_element_loop.rs | 3 +- clippy_lints/src/loops/while_let_loop.rs | 3 +- clippy_lints/src/loops/while_let_on_iterator.rs | 3 +- clippy_lints/src/macro_use.rs | 3 +- clippy_lints/src/main_recursion.rs | 5 +- clippy_lints/src/manual_async_fn.rs | 3 +- clippy_lints/src/manual_map.rs | 6 +- clippy_lints/src/manual_non_exhaustive.rs | 3 +- clippy_lints/src/manual_ok_or.rs | 5 +- clippy_lints/src/manual_strip.rs | 6 +- clippy_lints/src/manual_unwrap_or.rs | 7 +- clippy_lints/src/map_clone.rs | 3 +- clippy_lints/src/map_unit_fn.rs | 3 +- clippy_lints/src/match_on_vec_items.rs | 3 +- clippy_lints/src/matches.rs | 9 +- clippy_lints/src/mem_discriminant.rs | 3 +- clippy_lints/src/mem_replace.rs | 8 +- clippy_lints/src/methods/bind_instead_of_map.rs | 5 +- clippy_lints/src/methods/bytes_nth.rs | 3 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 3 +- clippy_lints/src/methods/expect_fun_call.rs | 3 +- clippy_lints/src/methods/filter_map.rs | 3 +- clippy_lints/src/methods/filter_map_next.rs | 3 +- clippy_lints/src/methods/filter_next.rs | 3 +- clippy_lints/src/methods/get_unwrap.rs | 3 +- clippy_lints/src/methods/inefficient_to_string.rs | 3 +- clippy_lints/src/methods/iter_count.rs | 3 +- clippy_lints/src/methods/iter_next_slice.rs | 3 +- clippy_lints/src/methods/iter_nth_zero.rs | 3 +- clippy_lints/src/methods/iter_skip_next.rs | 3 +- .../src/methods/manual_saturating_arithmetic.rs | 3 +- .../src/methods/map_collect_result_unit.rs | 3 +- clippy_lints/src/methods/map_flatten.rs | 3 +- clippy_lints/src/methods/map_unwrap_or.rs | 3 +- clippy_lints/src/methods/mod.rs | 5 +- clippy_lints/src/methods/option_as_ref_deref.rs | 3 +- clippy_lints/src/methods/option_map_or_none.rs | 3 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 3 +- clippy_lints/src/methods/or_fun_call.rs | 6 +- clippy_lints/src/methods/search_is_some.rs | 5 +- .../src/methods/single_char_insert_string.rs | 3 +- .../src/methods/single_char_push_string.rs | 3 +- clippy_lints/src/methods/string_extend_chars.rs | 3 +- clippy_lints/src/methods/unnecessary_fold.rs | 5 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 3 +- clippy_lints/src/methods/useless_asref.rs | 3 +- clippy_lints/src/misc.rs | 5 +- clippy_lints/src/misc_early.rs | 3 +- clippy_lints/src/needless_bool.rs | 3 +- clippy_lints/src/needless_borrow.rs | 3 +- clippy_lints/src/needless_borrowed_ref.rs | 3 +- clippy_lints/src/needless_continue.rs | 3 +- clippy_lints/src/needless_pass_by_value.rs | 3 +- clippy_lints/src/needless_question_mark.rs | 3 +- clippy_lints/src/no_effect.rs | 3 +- clippy_lints/src/pass_by_ref_or_value.rs | 3 +- clippy_lints/src/precedence.rs | 3 +- clippy_lints/src/ptr.rs | 3 +- clippy_lints/src/ptr_eq.rs | 5 +- clippy_lints/src/ptr_offset_with_cast.rs | 3 +- clippy_lints/src/question_mark.rs | 3 +- clippy_lints/src/ranges.rs | 5 +- clippy_lints/src/redundant_clone.rs | 5 +- clippy_lints/src/redundant_closure_call.rs | 3 +- clippy_lints/src/redundant_slicing.rs | 3 +- clippy_lints/src/redundant_static_lifetimes.rs | 3 +- clippy_lints/src/ref_option_ref.rs | 8 +- clippy_lints/src/reference.rs | 3 +- clippy_lints/src/repeat_once.rs | 3 +- clippy_lints/src/returns.rs | 3 +- clippy_lints/src/self_assignment.rs | 3 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 3 +- clippy_lints/src/shadow.rs | 3 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 3 +- clippy_lints/src/swap.rs | 3 +- clippy_lints/src/to_digit_is_some.rs | 3 +- clippy_lints/src/trait_bounds.rs | 3 +- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 3 +- clippy_lints/src/transmute/utils.rs | 3 +- clippy_lints/src/try_err.rs | 6 +- clippy_lints/src/types/borrowed_box.rs | 7 +- clippy_lints/src/types/mod.rs | 6 +- clippy_lints/src/types/rc_buffer.rs | 5 +- clippy_lints/src/types/redundant_allocation.rs | 6 +- clippy_lints/src/types/vec_box.rs | 6 +- clippy_lints/src/unicode.rs | 3 +- clippy_lints/src/unnecessary_wraps.rs | 4 +- clippy_lints/src/unused_unit.rs | 3 +- clippy_lints/src/use_self.rs | 3 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_lints/src/utils/internal_lints.rs | 3 +- clippy_lints/src/vec.rs | 3 +- clippy_lints/src/vec_init_then_push.rs | 3 +- clippy_lints/src/wildcard_imports.rs | 3 +- clippy_lints/src/write.rs | 3 +- clippy_utils/src/hir_utils.rs | 3 +- clippy_utils/src/lib.rs | 416 +------------------- clippy_utils/src/ptr.rs | 3 +- clippy_utils/src/source.rs | 420 +++++++++++++++++++++ clippy_utils/src/sugg.rs | 3 +- 152 files changed, 753 insertions(+), 649 deletions(-) create mode 100644 clippy_utils/src/source.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 77b26faaa58..3b6f64e7769 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, snippet_opt, span_lint_and_help}; +use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, span_lint_and_help}; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index ae300324158..031827e7e89 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,5 +1,6 @@ -use crate::utils::{eq_expr_value, get_trait_def_id, snippet_opt, span_lint_and_then, trait_ref_of_method}; +use crate::utils::{eq_expr_value, get_trait_def_id, span_lint_and_then, trait_ref_of_method}; use crate::utils::{higher, sugg}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 1e185e97df6..a5ed6016874 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet, span_lint_and_then}; +use crate::utils::span_lint_and_then; +use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 6250810bc42..04b0e71e4a3 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,9 +1,7 @@ //! checks for attributes -use crate::utils::{ - first_line_of_span, is_present_in_source, match_panic_def_id, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_sugg, span_lint_and_then, without_block_comments, -}; +use crate::utils::{match_panic_def_id, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 222bb39f89c..f43f98d1dc0 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - differing_macro_contexts, get_parent_expr, snippet_block_with_applicability, span_lint, span_lint_and_sugg, -}; +use crate::utils::{differing_macro_contexts, get_parent_expr, span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index affc7d2c93f..12a07c60438 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - eq_expr_value, get_trait_def_id, in_macro, paths, snippet_opt, span_lint_and_sugg, span_lint_and_then, -}; +use crate::utils::{eq_expr_value, get_trait_def_id, in_macro, paths, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 67cca8dcadb..d02861b1b1e 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - contains_name, get_pat_name, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, -}; +use crate::utils::{contains_name, get_pat_name, paths, single_segment_path, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 902fb423ff1..62ba19c0e16 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,10 +1,11 @@ +use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{in_constant, snippet_opt, span_lint_and_sugg}; +use crate::utils::{in_constant, span_lint_and_sugg}; use super::{utils, CAST_LOSSLESS}; diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index ccaad1b8f2a..75aa559359c 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -1,12 +1,12 @@ +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, UintTy}; -use if_chain::if_chain; - -use crate::utils::{snippet_with_applicability, span_lint_and_then}; +use crate::utils::span_lint_and_then; use super::CHAR_LIT_AS_U8; diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index a8d508585b5..723bfa5befe 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -1,10 +1,10 @@ +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, UintTy}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; - use super::{utils, FN_TO_NUMERIC_CAST}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 0085c7b27b2..a3108f8a983 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -1,10 +1,10 @@ +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; - use super::{utils, FN_TO_NUMERIC_CAST_WITH_TRUNCATION}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index c43bbf32949..eb0ee012e6c 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,3 +1,5 @@ +use clippy_utils::source::snippet_opt; +use if_chain::if_chain; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit, UnOp}; @@ -5,9 +7,7 @@ use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; -use if_chain::if_chain; - -use crate::utils::{numeric_literal::NumericLiteral, snippet_opt, span_lint_and_sugg}; +use crate::utils::{numeric_literal::NumericLiteral, span_lint_and_sugg}; use super::UNNECESSARY_CAST; diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 54bc69e058b..4f3daa427e3 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,5 +1,6 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -9,7 +10,7 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{meets_msrv, snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{meets_msrv, span_lint_and_sugg, SpanlessEq}; const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 3d842a46813..5b8ef01505b 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; @@ -10,7 +11,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; -use crate::utils::{snippet_opt, span_lint_and_help, LimitStack}; +use crate::utils::{span_lint_and_help, LimitStack}; declare_clippy_lint! { /// **What it does:** Checks for methods with high cognitive complexity. diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 34f0e6ab027..c866f18ef3e 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -12,14 +12,15 @@ //! //! This lint is **warn** by default +use clippy_utils::source::{snippet_block, snippet_block_with_applicability}; use if_chain::if_chain; use rustc_ast::ast; +use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::sugg::Sugg; -use crate::utils::{snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then}; -use rustc_errors::Applicability; +use crate::utils::{span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for nested `if` statements which can be collapsed diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 200b6a565cc..0785e25b0a2 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg}; +use crate::utils::{match_def_path, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index e513dcce64e..3171a945eb0 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint_and_help, span_lint_and_sugg}; +use crate::utils::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; use rustc_ast::ast; use rustc_ast::tokenstream::TokenStream; use rustc_errors::Applicability; diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 6fa1378b8c7..7d975b5a3d9 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,6 @@ -use crate::utils::{ - any_parent_is_automatically_derived, contains_name, match_def_path, paths, snippet_with_macro_callsite, -}; +use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; use crate::utils::{span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_macro_callsite; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 369efacc9bc..e58dcb942c6 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -1,3 +1,5 @@ +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{ @@ -11,9 +13,7 @@ use rustc_middle::{ }; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use if_chain::if_chain; - -use crate::utils::{snippet, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 8842ea9628d..e112338dfea 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_node, in_macro, is_allowed, snippet_with_context, span_lint_and_sugg}; +use crate::utils::{get_parent_node, in_macro, is_allowed, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::peel_mid_ty_refs; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 19f56195ec1..3de027b2cc6 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,12 +1,13 @@ //! Lint on unnecessary double comparisons. Some examples: +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::utils::{eq_expr_value, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{eq_expr_value, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for double comparisons that could be simplified to a single expression. diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index c97392e3385..195143d720d 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; @@ -8,7 +9,7 @@ use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 68363e53f0e..93723219594 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,6 +1,7 @@ +use crate::utils::span_lint_and_then; use crate::utils::SpanlessEq; -use crate::utils::{get_item_name, paths, snippet, snippet_opt}; -use crate::utils::{snippet_with_applicability, span_lint_and_then}; +use crate::utils::{get_item_name, paths}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 67a46353856..660131cf176 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,7 +1,8 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use crate::utils::{camel_case, is_present_in_source}; +use crate::utils::camel_case; use crate::utils::{span_lint, span_lint_and_help}; +use clippy_utils::source::is_present_in_source; use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index fa19f16074d..0a5917c10ea 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,7 +1,8 @@ use crate::utils::{ - ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, multispan_sugg, snippet, - span_lint, span_lint_and_then, + ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, multispan_sugg, span_lint, + span_lint_and_then, }; +use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index d93c32c179f..e8d5b992b63 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,5 +1,6 @@ use clippy_utils::higher; use clippy_utils::higher::VecArgs; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, type_is_unsafe_function}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -9,7 +10,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{is_adjusted, iter_input_pats, span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for closures which just call another function where diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 316f7484862..5e31072523d 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -1,11 +1,14 @@ -use crate::utils::{indent_of, span_lint_and_then}; +use clippy_utils::source::indent_of; use if_chain::if_chain; + use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; +use crate::utils::span_lint_and_then; + declare_clippy_lint! { /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` /// diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index b6209f815bc..c0048bb2175 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,7 +1,6 @@ use crate::utils::paths; -use crate::utils::{ - is_expn_of, last_path_segment, match_def_path, match_function_call, snippet, snippet_opt, span_lint_and_then, -}; +use crate::utils::{is_expn_of, last_path_segment, match_def_path, match_function_call, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 1bd16e6cce5..590de04717a 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, snippet_opt, span_lint_and_help, span_lint_and_note}; +use crate::utils::{differing_macro_contexts, span_lint_and_help, span_lint_and_note}; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 349cd39ffb6..104c692dcec 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,8 +1,8 @@ use crate::utils::{ attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr, - path_to_local, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, span_lint_and_then, - trait_ref_of_method, + path_to_local, return_ty, span_lint, span_lint_and_help, span_lint_and_then, trait_ref_of_method, }; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, type_is_unsafe_function}; use if_chain::if_chain; use rustc_ast::ast::Attribute; diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 478008ea48c..875cd33bc8f 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -1,6 +1,7 @@ //! lint on using `x.get(x.len() - 1)` instead of `x.last()` -use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{span_lint_and_sugg, SpanlessEq}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 8501d347702..fc93864c74a 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -6,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::{clip, snippet, span_lint, unsext}; +use crate::utils::{clip, span_lint, unsext}; declare_clippy_lint! { /// **What it does:** Checks for identity operations, e.g., `x + 0`. diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 0cd44a1c3a0..9f7ca95a8f3 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,4 +1,5 @@ -use crate::utils::{method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{method_chain_args, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index a527f51b1fd..7e1807786ee 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,4 +1,5 @@ use crate::utils; +use clippy_utils::source::snippet_with_macro_callsite; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -82,13 +83,13 @@ impl LateLintPass<'_> for IfThenSomeElseNone { if let ExprKind::Path(ref els_call_qpath) = els_expr.kind; if utils::match_qpath(els_call_qpath, &utils::paths::OPTION_NONE); then { - let cond_snip = utils::snippet_with_macro_callsite(cx, cond.span, "[condition]"); + let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { format!("({})", cond_snip) } else { cond_snip.into_owned() }; - let arg_snip = utils::snippet_with_macro_callsite(cx, then_arg.span, ""); + let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); let closure_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index b4f814e1dcc..e86bd49251d 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_panic_def_id, snippet_opt, span_lint_and_then}; +use crate::utils::{match_panic_def_id, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 49c17a12102..4762d5d40f3 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,3 +1,5 @@ +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -5,9 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; -use if_chain::if_chain; - -use crate::utils::{snippet, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for struct constructors where all fields are shorthand and diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 260b8988d37..9eae653dd67 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,11 +1,12 @@ //! lint on blocks unnecessarily using >= with a + 1 or - 1 +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{snippet_opt, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index ab4cb33612d..cbb5192bfd9 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,6 +1,7 @@ //! lint when there is a large size difference between variants on an enum -use crate::utils::{snippet_opt, span_lint_and_then}; +use crate::utils::span_lint_and_then; +use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 9a448ab1256..ceae4243e63 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,13 +1,13 @@ +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use if_chain::if_chain; - use crate::rustc_target::abi::LayoutOf; -use crate::utils::{snippet, span_lint_and_help}; +use crate::utils::span_lint_and_help; declare_clippy_lint! { /// **What it does:** Checks for local arrays that may be too large. diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 1e1023b2743..e758a269fbe 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - get_item_name, get_parent_as_impl, is_allowed, snippet_with_applicability, span_lint, span_lint_and_sugg, - span_lint_and_then, -}; +use crate::utils::{get_item_name, get_parent_as_impl, is_allowed, span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 5863eef8a26..7059ba21207 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,4 +1,5 @@ -use crate::utils::{path_to_local_id, snippet, span_lint_and_then, visitors::LocalUsedVisitor}; +use crate::utils::{path_to_local_id, span_lint_and_then, visitors::LocalUsedVisitor}; +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 87a957a9bd2..8bc7bf37ef1 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -4,8 +4,9 @@ use crate::utils::{ in_macro, numeric_literal::{NumericLiteral, Radix}, - snippet_opt, span_lint_and_sugg, + span_lint_and_sugg, }; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 8d98b940c66..1f6d48fe915 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,7 +1,8 @@ use super::{ get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP, }; -use crate::utils::{get_enclosing_block, is_integer_const, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{get_enclosing_block, is_integer_const, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index 1d778205a2a..e5b3dc7aad7 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,5 +1,6 @@ use super::EXPLICIT_INTO_ITER_LOOP; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index b70585015ca..d2000d80ac1 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,4 +1,6 @@ use super::EXPLICIT_ITER_LOOP; +use crate::utils::{match_trait_method, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -6,8 +8,6 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TyS}; use rustc_span::sym; -use crate::utils::{match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; - pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) { let should_lint = match method_name { "iter" | "iter_mut" => is_ref_iterable_type(cx, &args[0]), diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index aef21886803..19a68dd78d1 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,6 +1,7 @@ use super::FOR_KV_MAP; use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{multispan_sugg, paths, snippet, span_lint_and_then, sugg}; +use crate::utils::{multispan_sugg, paths, span_lint_and_then, sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/for_loops_over_fallibles.rs b/clippy_lints/src/loops/for_loops_over_fallibles.rs index 063078adcd1..5140448592d 100644 --- a/clippy_lints/src/loops/for_loops_over_fallibles.rs +++ b/clippy_lints/src/loops/for_loops_over_fallibles.rs @@ -1,6 +1,8 @@ -use super::FOR_LOOPS_OVER_FALLIBLES; -use crate::utils::{snippet, span_lint_and_help}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; + +use super::FOR_LOOPS_OVER_FALLIBLES; +use crate::utils::span_lint_and_help; use rustc_hir::{Expr, Pat}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 362124c082a..c9c25641160 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -1,6 +1,7 @@ use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; use crate::utils::sugg::Sugg; -use crate::utils::{get_enclosing_block, higher, path_to_local, snippet, span_lint_and_sugg, sugg}; +use crate::utils::{get_enclosing_block, higher, path_to_local, span_lint_and_sugg, sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index f4d3b9eb272..59f7b23af75 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -1,6 +1,7 @@ use super::NEEDLESS_COLLECT; use crate::utils::sugg::Sugg; -use crate::utils::{is_trait_method, path_to_local_id, paths, snippet, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{is_trait_method, path_to_local_id, paths, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 6d498149166..674cb34c37b 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -1,9 +1,10 @@ use super::NEEDLESS_RANGE_LOOP; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - contains_name, higher, is_integer_const, match_trait_method, multispan_sugg, path_to_local_id, paths, snippet, + contains_name, higher, is_integer_const, match_trait_method, multispan_sugg, path_to_local_id, paths, span_lint_and_then, sugg, SpanlessEq, }; +use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index f891f7b8a1f..255d6de4a36 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -1,5 +1,6 @@ use super::SAME_ITEM_PUSH; -use crate::utils::{snippet_with_macro_callsite, span_lint_and_help}; +use crate::utils::span_lint_and_help; +use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 38400c93c9a..4f83191d919 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,5 +1,6 @@ use super::{get_span_of_entire_for_loop, SINGLE_ELEMENT_LOOP}; -use crate::utils::{indent_of, single_segment_path, snippet, span_lint_and_sugg}; +use crate::utils::{single_segment_path, span_lint_and_sugg}; +use clippy_utils::source::{indent_of, snippet}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind}; diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index 65d8f2f1111..dbd9126861f 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -1,5 +1,6 @@ use super::WHILE_LET_LOOP; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, StmtKind}; use rustc_lint::{LateContext, LintContext}; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 619fd1554f0..ccabe586c2b 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -3,8 +3,9 @@ use super::WHILE_LET_ON_ITERATOR; use crate::utils::usage::mutated_variables; use crate::utils::{ get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, - snippet_with_applicability, span_lint_and_sugg, + span_lint_and_sugg, }; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 6d9c78393c8..637f10f6609 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, snippet, span_lint_and_sugg}; +use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 1b274c79d38..5db2968e42c 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -1,9 +1,10 @@ +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_hir::{Crate, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{is_entrypoint_fn, is_no_std_crate, snippet, span_lint_and_help}; -use if_chain::if_chain; +use crate::utils::{is_entrypoint_fn, is_no_std_crate, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for recursion using the entrypoint. diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 2e2e693592c..ebc493c0f7e 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,6 @@ use crate::utils::paths::FUTURE_FROM_GENERATOR; -use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then}; +use crate::utils::{match_function_call, span_lint_and_then}; +use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 7c89359f2d9..3896645ca7d 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -1,11 +1,9 @@ use crate::{ map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF, - utils::{ - is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs, snippet_with_applicability, - snippet_with_context, span_lint_and_sugg, - }, + utils::{is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs, span_lint_and_sugg}, }; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 91849e74887..0b8c049b466 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,4 +1,5 @@ -use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then}; +use crate::utils::{meets_msrv, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index b08829a8bbf..f436eccc0dc 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - indent_of, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, span_lint_and_sugg, -}; +use crate::utils::{match_qpath, path_to_local_id, paths, span_lint_and_sugg}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 42a92104a49..3bfca8bea40 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,9 +1,7 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; -use crate::utils::{ - eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, snippet, span_lint_and_then, -}; - +use crate::utils::{eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, span_lint_and_then}; +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 3a1bde9540d..7a4040539e3 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,6 +1,7 @@ use crate::consts::constant_simple; use crate::utils; use crate::utils::{path_to_local_id, sugg}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -105,12 +106,12 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { None }; if let Some(or_arm) = applicable_or_arm(match_arms); - if let Some(or_body_snippet) = utils::snippet_opt(cx, or_arm.body.span); - if let Some(indent) = utils::indent_of(cx, expr.span); + if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span); + if let Some(indent) = indent_of(cx, expr.span); if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some(); then { let reindented_or_body = - utils::reindent_multiline(or_body_snippet.into(), true, Some(indent)); + reindent_multiline(or_body_snippet.into(), true, Some(indent)); utils::span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 73d924cd51e..e10d7647bcf 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,5 +1,6 @@ use crate::utils::is_trait_method; -use crate::utils::{remove_blocks, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{remove_blocks, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 6f4ce87ea5c..24bcc808585 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,4 +1,5 @@ -use crate::utils::{iter_input_pats, method_chain_args, snippet, span_lint_and_then}; +use crate::utils::{iter_input_pats, method_chain_args, span_lint_and_then}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 65afd691d62..57dcd8709b8 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 4689974e850..4ae1ce977f4 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,12 +2,12 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - expr_block, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, - meets_msrv, multispan_sugg, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, - remove_blocks, snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, + get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, multispan_sugg, + path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, remove_blocks, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -1614,7 +1614,8 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{is_trait_method, match_qpath, paths, snippet, span_lint_and_then}; + use crate::utils::{is_trait_method, match_qpath, paths, span_lint_and_then}; + use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index d9d86ac9912..fbdc0cdb2d8 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, snippet, span_lint_and_then}; +use crate::utils::{match_def_path, paths, span_lint_and_then}; +use clippy_utils::source::snippet; use clippy_utils::ty::walk_ptrs_ty_depth; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 13f9c9b71f3..bf3f6f7f830 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,9 @@ use crate::utils::{ - in_macro, match_def_path, match_qpath, meets_msrv, paths, snippet, snippet_with_applicability, span_lint_and_help, - span_lint_and_sugg, span_lint_and_then, + in_macro, match_def_path, match_qpath, meets_msrv, paths, span_lint_and_help, span_lint_and_sugg, + span_lint_and_then, }; +use clippy_utils::is_diagnostic_assoc_item; +use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -13,8 +15,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; -use clippy_utils::is_diagnostic_assoc_item; - declare_clippy_lint! { /// **What it does:** Checks for `mem::replace()` on an `Option` with /// `None`. diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 073d684dbe3..99b3be67f18 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,8 +1,9 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use crate::utils::{ - in_macro, match_qpath, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, + in_macro, match_qpath, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, span_lint_and_sugg, + span_lint_and_then, visitors::find_all_ret_expressions, }; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index a695c27f11b..f81e9a8c524 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 7bc4ed622dc..90ecb2382e7 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,4 +1,5 @@ -use crate::utils::{paths, snippet_with_macro_callsite, span_lint_and_sugg}; +use crate::utils::{paths, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 3de35c930ea..9e96d571337 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, snippet, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{is_expn_of, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 91c11afcaaf..964c4903ed2 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, path_to_local_id, snippet, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{is_trait_method, path_to_local_id, span_lint_and_sugg, SpanlessEq}; +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 9019202df0c..ed75315b52c 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, meets_msrv, snippet, span_lint, span_lint_and_sugg}; +use crate::utils::{is_trait_method, meets_msrv, span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 34787b9a828..097f9fdf2c4 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, snippet, span_lint, span_lint_and_sugg}; +use crate::utils::{is_trait_method, span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index 35071a25cec..b9d34b402bb 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, paths, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 42ba62cd4e7..19d05b5c693 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,5 +1,6 @@ use super::INEFFICIENT_TO_STRING; -use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_then}; +use crate::utils::{match_def_path, paths, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 320fd15d6f8..0f393423b7d 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{paths, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{paths, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index 736148d4fb8..f79942576da 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, higher, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, higher, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index ca2e5db4382..98ddfdfdf9c 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_trait_method, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{is_trait_method, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index bdfa133b9e2..d191ea0a831 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, span_lint_and_sugg}; +use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 0b414e0eb95..d090a35a3cf 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_qpath, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{match_qpath, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index 0a8837be752..349b26b9d58 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 3d1c6408dea..56719b3cff2 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, snippet, span_lint_and_sugg}; +use crate::utils::{is_trait_method, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 4346869ae0d..96dbc7ddc63 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,6 @@ use crate::utils::usage::mutated_variables; -use crate::utils::{meets_msrv, snippet, span_lint, span_lint_and_sugg}; +use crate::utils::{meets_msrv, span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3e78b662b89..6e0ae9416ff 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -52,6 +52,7 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_ast::ast; @@ -68,8 +69,8 @@ use rustc_typeck::hir_ty_to_ty; use crate::utils::{ contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls, - method_chain_args, paths, return_ty, single_segment_path, snippet_with_applicability, span_lint, - span_lint_and_help, span_lint_and_sugg, SpanlessEq, + method_chain_args, paths, return_ty, single_segment_path, span_lint, span_lint_and_help, span_lint_and_sugg, + SpanlessEq, }; declare_clippy_lint! { diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 17444336a5e..6597e9f96a8 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet, span_lint_and_sugg}; +use crate::utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 5bd4a5bfe21..eed71d02467 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg}; +use crate::utils::{match_qpath, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index d1c78b3a833..398d8f13bd4 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, snippet_with_applicability, span_lint_and_then}; +use crate::utils::{differing_macro_contexts, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 9f24fe79089..634feebe54a 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,8 +1,6 @@ use crate::utils::eager_or_lazy::is_lazyness_candidate; -use crate::utils::{ - contains_return, get_trait_def_id, last_path_segment, paths, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint_and_sugg, -}; +use crate::utils::{contains_return, get_trait_def_id, last_path_segment, paths, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index d903f1e74d3..6054579d988 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - is_trait_method, snippet, snippet_with_applicability, span_lint_and_help, span_lint_and_sugg, strip_pat_refs, -}; +use crate::utils::{is_trait_method, span_lint_and_help, span_lint_and_sugg, strip_pat_refs}; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 0ce8b66978d..ff67564b39d 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,5 +1,6 @@ use crate::methods::get_hint_if_single_char_arg; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index deacc70b713..18df90c1ab3 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,5 +1,6 @@ use crate::methods::get_hint_if_single_char_arg; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 5b8cca34931..1b26e8314af 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -1,4 +1,5 @@ -use crate::utils::{method_chain_args, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{method_chain_args, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 9aa53f02ef0..4d5cbdd619d 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - is_trait_method, path_to_local_id, remove_blocks, snippet_with_applicability, span_lint_and_sugg, strip_pat_refs, -}; +use crate::utils::{is_trait_method, path_to_local_id, remove_blocks, span_lint_and_sugg, strip_pat_refs}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index d260a771c01..444abde3d0f 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,5 +1,6 @@ +use crate::utils::span_lint_and_sugg; use crate::utils::{eager_or_lazy, usage}; -use crate::utils::{snippet, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index e6b1789a4a8..c6d84aedc0a 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_expr, match_trait_method, paths, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, match_trait_method, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 5c4d4401cd9..f161054cc8c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -19,8 +20,8 @@ use crate::consts::{constant, Constant}; use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, - last_path_segment, match_qpath, snippet, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then, - span_lint_hir_and_then, unsext, SpanlessEq, + last_path_segment, match_qpath, span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then, unsext, + SpanlessEq, }; declare_clippy_lint! { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 84a0df92f5b..6ec523498e1 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{ BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, NodeId, Pat, PatKind, UnOp, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index f283ff1715f..22adbdf09a6 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -3,7 +3,8 @@ //! This lint is **warn** by default use crate::utils::sugg::Sugg; -use crate::utils::{is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg}; +use crate::utils::{is_expn_of, parent_node_is_if_expr, span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 1aadcfd87b6..d8b574af1fe 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -2,7 +2,8 @@ //! //! This lint is **warn** by default -use crate::utils::{is_automatically_derived, snippet_opt, span_lint_and_then}; +use crate::utils::{is_automatically_derived, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind}; diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index f449f397e7d..5ee71f25694 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint_and_then}; +use crate::utils::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 30fe2d6225c..4ff90704207 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -33,13 +33,14 @@ //! ``` //! //! This lint is **warn** by default. +use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; -use crate::utils::{indent_of, snippet, snippet_block, span_lint_and_help}; +use crate::utils::span_lint_and_help; declare_clippy_lint! { /// **What it does:** The lint checks for `if`-statements appearing in loops diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 14989283681..6f7a5d85480 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,5 +1,6 @@ use crate::utils::ptr::get_spans; -use crate::utils::{get_trait_def_id, is_self, multispan_sugg, paths, snippet, snippet_opt, span_lint_and_then}; +use crate::utils::{get_trait_def_id, is_self, multispan_sugg, paths, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_ast::ast::Attribute; diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index d616290ee9c..bcc39ff855c 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; @@ -145,7 +146,7 @@ fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { entire_expr.span, "question mark operator is useless here", "try", - format!("{}", utils::snippet(cx, inner_expr.span, r#""...""#)), + format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index c377d373ad6..7a7bc7a44cd 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint, span_lint_and_sugg}; +use crate::utils::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index c9b59b89306..757ead2c24c 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,6 +1,7 @@ use std::cmp; -use crate::utils::{is_self_ty, snippet, span_lint_and_sugg}; +use crate::utils::{is_self_ty, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_ast::attr; diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index c9d18c3cb72..fbe54e92ab9 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index c2649a135eb..bfe8bf33f51 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,7 +1,8 @@ //! Checks for usage of `&Vec[_]` and `&String`. use crate::utils::ptr::get_spans; -use crate::utils::{is_allowed, match_qpath, paths, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{is_allowed, match_qpath, paths, span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 3be792ce5e4..4f83e370c5f 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -1,4 +1,5 @@ use crate::utils; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -54,8 +55,8 @@ impl LateLintPass<'_> for PtrEq { if_chain! { if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); - if let Some(left_snip) = utils::snippet_opt(cx, left_var.span); - if let Some(right_snip) = utils::snippet_opt(cx, right_var.span); + if let Some(left_snip) = snippet_opt(cx, left_var.span); + if let Some(right_snip) = snippet_opt(cx, right_var.span); then { utils::span_lint_and_sugg( cx, diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index e0996804a59..b801defeb24 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_opt, span_lint, span_lint_and_sugg}; +use crate::utils::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index dc00aaffa58..43431425a43 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -8,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use crate::utils::sugg::Sugg; -use crate::utils::{eq_expr_value, match_def_path, match_qpath, paths, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{eq_expr_value, match_def_path, match_qpath, paths, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for expressions that could be replaced by the question mark operator. diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 59503817c0f..3ce8949bf8b 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,4 +1,5 @@ use crate::consts::{constant, Constant}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; @@ -14,8 +15,8 @@ use std::cmp::Ordering; use crate::utils::sugg::Sugg; use crate::utils::{ - get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path, snippet, snippet_opt, - snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, + get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path, span_lint, span_lint_and_sugg, + span_lint_and_then, }; use crate::utils::{higher, SpanlessEq}; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index d2e5a5db372..84723acd034 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - fn_has_unsatisfiable_preds, match_def_path, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then, -}; +use crate::utils::{fn_has_unsatisfiable_preds, match_def_path, paths, span_lint_hir, span_lint_hir_and_then}; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth}; use if_chain::if_chain; use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation}; diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f398b3fff25..283e25553cf 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,4 +1,5 @@ -use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_then}; +use crate::utils::{span_lint, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 992d1901584..85ea91a387b 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -6,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::{lint::in_external_macro, ty::TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for redundant slicing expressions which use the full range, and diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index fcfa3c12755..1352a651723 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,4 +1,5 @@ -use crate::utils::{meets_msrv, snippet, span_lint_and_then}; +use crate::utils::{meets_msrv, span_lint_and_then}; +use clippy_utils::source::snippet; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 8cd6692ce03..cec6b06262b 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -1,12 +1,12 @@ -use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; +use crate::utils::{last_path_segment, span_lint_and_sugg}; +use clippy_utils::source::snippet; +use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; -use if_chain::if_chain; -use rustc_errors::Applicability; - declare_clippy_lint! { /// **What it does:** Checks for usage of `&Option<&T>`. /// diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index e1450466a7c..31e834ac174 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,5 +1,6 @@ use crate::utils::sugg::Sugg; -use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 7d668739c5a..a88078c12a3 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{in_macro, snippet, span_lint_and_sugg}; +use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 40c0f1f4589..eb7fe403fd7 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; @@ -11,7 +12,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::sym; -use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{fn_def_id, in_macro, match_qpath, span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for `let`-bindings, which are subsequently diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs index e096c9aebc1..e62b75de4ca 100644 --- a/clippy_lints/src/self_assignment.rs +++ b/clippy_lints/src/self_assignment.rs @@ -1,4 +1,5 @@ -use crate::utils::{eq_expr_value, snippet, span_lint}; +use crate::utils::{eq_expr_value, span_lint}; +use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 839c995e525..695d7233af2 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, snippet_with_macro_callsite, span_lint_and_sugg, sugg}; +use crate::utils::{in_macro, span_lint_and_sugg, sugg}; +use clippy_utils::source::snippet_with_macro_callsite; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 32f6bc74642..4a8cacb31fd 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,4 +1,5 @@ -use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then}; +use crate::utils::{contains_name, higher, iter_input_pats, span_lint_and_then}; +use clippy_utils::source::snippet; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 62b4b40df45..ce93ab23b2f 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -3,6 +3,7 @@ use crate::utils::{ get_parent_expr, is_allowed, match_function_call, method_calls, paths, span_lint, span_lint_and_help, span_lint_and_sugg, }; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -204,7 +205,6 @@ declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - use crate::utils::{snippet, snippet_with_applicability}; use rustc_ast::LitKind; if_chain! { diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 44521885d20..3bdd9b7e4cb 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,5 +1,6 @@ use crate::utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index ba2d73a8228..d4a495f3ea9 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,5 +1,6 @@ use crate::utils::sugg::Sugg; -use crate::utils::{differing_macro_contexts, eq_expr_value, snippet_with_applicability, span_lint_and_then}; +use crate::utils::{differing_macro_contexts, eq_expr_value, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index eeda39bfa20..940273afc57 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{match_def_path, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index daff5f81e8c..d3314271c21 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_help, SpanlessHash}; +use crate::utils::{in_macro, span_lint_and_help, SpanlessHash}; +use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 01b00bb0a22..4780eb9b14e 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,5 +1,6 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; -use crate::utils::{snippet, span_lint_and_sugg, span_lint_and_then, sugg}; +use crate::utils::{span_lint_and_sugg, span_lint_and_then, sugg}; +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index f4b0f205993..0633697687a 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -1,4 +1,5 @@ -use crate::utils::{last_path_segment, snippet}; +use crate::utils::last_path_segment; +use clippy_utils::source::snippet; use clippy_utils::ty::is_normalizable; use if_chain::if_chain; use rustc_hir::{Expr, GenericArg, QPath, TyKind}; diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index bdb81ea32d7..e356add8e9d 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - differing_macro_contexts, in_macro, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, - span_lint_and_sugg, -}; +use crate::utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index a7a511b21cf..01aeea7a67f 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,3 +1,6 @@ +use crate::utils::{match_path, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath, @@ -5,10 +8,6 @@ use rustc_hir::{ }; use rustc_lint::LateContext; -use if_chain::if_chain; - -use crate::utils::{match_path, paths, snippet, span_lint_and_sugg}; - use super::BORROWED_BOX; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, mut_ty: &MutTy<'_>) -> bool { diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index fcd38718b9b..279a971318c 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -13,6 +13,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; +use clippy_utils::source::{indent_of, reindent_multiline, snippet, snippet_opt, snippet_with_macro_callsite}; use clippy_utils::ty::{is_isize_or_usize, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -38,9 +39,8 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, indent_of, int_bits, match_path, multispan_sugg, - reindent_multiline, sext, snippet, snippet_opt, snippet_with_macro_callsite, span_lint, span_lint_and_help, - span_lint_and_then, unsext, + clip, comparisons, differing_macro_contexts, higher, int_bits, match_path, multispan_sugg, sext, span_lint, + span_lint_and_help, span_lint_and_then, unsext, }; declare_clippy_lint! { diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index e34b95147e1..0ace1807535 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -1,11 +1,10 @@ +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{ - get_qpath_generic_tys, is_ty_param_diagnostic_item, snippet_with_applicability, span_lint_and_sugg, -}; +use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, span_lint_and_sugg}; use super::RC_BUFFER; diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 5da6db179c4..c6f6a2f6564 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -1,12 +1,10 @@ +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{ - get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item, snippet_with_applicability, - span_lint_and_sugg, -}; +use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item, span_lint_and_sugg}; use super::{utils, REDUNDANT_ALLOCATION}; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 2530cc133c6..6f45442b9ba 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -1,3 +1,5 @@ +use clippy_utils::source::snippet; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; @@ -6,9 +8,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; use rustc_typeck::hir_ty_to_ty; -use if_chain::if_chain; - -use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; +use crate::utils::{last_path_segment, span_lint_and_sugg}; use super::VEC_BOX; diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 93d59cc7fcd..e44fec7ad8e 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_allowed, snippet, span_lint_and_sugg}; +use crate::utils::{is_allowed, span_lint_and_sugg}; +use clippy_utils::source::snippet; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 8e076397c11..01497de3211 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,7 +1,7 @@ use crate::utils::{ - contains_return, in_macro, match_qpath, paths, return_ty, snippet, span_lint_and_then, - visitors::find_all_ret_expressions, + contains_return, in_macro, match_qpath, paths, return_ty, span_lint_and_then, visitors::find_all_ret_expressions, }; +use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index a31cd5fda84..a90d26fc95c 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,3 +1,4 @@ +use clippy_utils::source::position_before_rarrow; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit::FnKind; @@ -7,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::{position_before_rarrow, span_lint_and_sugg}; +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f0523cec621..de7eb42d56d 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,7 @@ -use crate::utils::{in_macro, meets_msrv, snippet_opt, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; +use crate::utils::{in_macro, meets_msrv, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 23032c74f9a..e6b4fde560f 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,8 +1,8 @@ use crate::utils::sugg::Sugg; use crate::utils::{ - get_parent_expr, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite, - span_lint_and_help, span_lint_and_sugg, + get_parent_expr, match_def_path, match_trait_method, paths, span_lint_and_help, span_lint_and_sugg, }; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 2f4bc74ef64..04b8d9ee2c7 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,8 +1,9 @@ use crate::consts::{constant_simple, Constant}; use crate::utils::{ - is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, snippet, span_lint, + is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq, }; +use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 682cc35a7d7..cd09a5b53e0 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,6 +1,7 @@ use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; -use crate::utils::{higher, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{higher, span_lint_and_sugg}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index b3262a253e7..4ad787ecf66 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, path_to_local, path_to_local_id, paths, snippet, span_lint_and_sugg}; +use crate::utils::{match_def_path, path_to_local, path_to_local_id, paths, span_lint_and_sugg}; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 094b1a42346..e12ca49fd4c 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index f21f5180554..f2fef73a641 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,7 +1,8 @@ use std::borrow::Cow; use std::ops::Range; -use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle}; use rustc_ast::token; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index e28ad27d9a6..4c13a185d5d 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_context, constant_simple}; -use crate::{differing_macro_contexts, snippet_opt}; +use crate::differing_macro_contexts; +use crate::source::snippet_opt; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 366962d8b77..d895d798b5e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -41,6 +41,7 @@ pub mod numeric_literal; pub mod paths; pub mod ptr; pub mod qualify_min_const_fn; +pub mod source; pub mod sugg; pub mod ty; pub mod usage; @@ -50,14 +51,12 @@ pub use self::attrs::*; pub use self::diagnostics::*; pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; -use std::borrow::Cow; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use if_chain::if_chain; use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -75,11 +74,11 @@ use rustc_middle::ty as rustc_ty; use rustc_middle::ty::{layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_semver::RustcVersion; use rustc_session::Session; -use rustc_span::hygiene::{self, ExpnKind, MacroKind}; +use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::sym; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{BytePos, Pos, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::Integer; use smallvec::SmallVec; @@ -236,20 +235,6 @@ pub fn in_macro(span: Span) -> bool { } } -// If the snippet is empty, it's an attribute that was inserted during macro -// expansion and we want to ignore those, because they could come from external -// sources that the user has no control over. -// For some reason these attributes don't have any expansion info on them, so -// we have to check it this way until there is a better way. -pub fn is_present_in_source(cx: &T, span: Span) -> bool { - if let Some(snippet) = snippet_opt(cx, span) { - if snippet.is_empty() { - return false; - } - } - true -} - /// Checks if given pattern is a wildcard (`_`) pub fn is_wild<'tcx>(pat: &impl std::ops::Deref>) -> bool { matches!(pat.kind, PatKind::Wild) @@ -713,211 +698,6 @@ pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec { fmc.result } -/// Converts a span to a code snippet if available, otherwise use default. -/// -/// This is useful if you want to provide suggestions for your lint or more generally, if you want -/// to convert a given `Span` to a `str`. -/// -/// # Example -/// ```rust,ignore -/// snippet(cx, expr.span, "..") -/// ``` -pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) -} - -/// Same as `snippet`, but it adapts the applicability level by following rules: -/// -/// - Applicability level `Unspecified` will never be changed. -/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. -/// - If the default value is used and the applicability level is `MachineApplicable`, change it to -/// `HasPlaceholders` -pub fn snippet_with_applicability<'a, T: LintContext>( - cx: &T, - span: Span, - default: &'a str, - applicability: &mut Applicability, -) -> Cow<'a, str> { - if *applicability != Applicability::Unspecified && span.from_expansion() { - *applicability = Applicability::MaybeIncorrect; - } - snippet_opt(cx, span).map_or_else( - || { - if *applicability == Applicability::MachineApplicable { - *applicability = Applicability::HasPlaceholders; - } - Cow::Borrowed(default) - }, - From::from, - ) -} - -/// Same as `snippet`, but should only be used when it's clear that the input span is -/// not a macro argument. -pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet(cx, span.source_callsite(), default) -} - -/// Converts a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt(cx: &T, span: Span) -> Option { - cx.sess().source_map().span_to_snippet(span).ok() -} - -/// Converts a span (from a block) to a code snippet if available, otherwise use default. -/// -/// This trims the code of indentation, except for the first line. Use it for blocks or block-like -/// things which need to be printed as such. -/// -/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the -/// resulting snippet of the given span. -/// -/// # Example -/// -/// ```rust,ignore -/// snippet_block(cx, block.span, "..", None) -/// // where, `block` is the block of the if expr -/// if x { -/// y; -/// } -/// // will return the snippet -/// { -/// y; -/// } -/// ``` -/// -/// ```rust,ignore -/// snippet_block(cx, block.span, "..", Some(if_expr.span)) -/// // where, `block` is the block of the if expr -/// if x { -/// y; -/// } -/// // will return the snippet -/// { -/// y; -/// } // aligned with `if` -/// ``` -/// Note that the first line of the snippet always has 0 indentation. -pub fn snippet_block<'a, T: LintContext>( - cx: &T, - span: Span, - default: &'a str, - indent_relative_to: Option, -) -> Cow<'a, str> { - let snip = snippet(cx, span, default); - let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - reindent_multiline(snip, true, indent) -} - -/// Same as `snippet_block`, but adapts the applicability level by the rules of -/// `snippet_with_applicability`. -pub fn snippet_block_with_applicability<'a, T: LintContext>( - cx: &T, - span: Span, - default: &'a str, - indent_relative_to: Option, - applicability: &mut Applicability, -) -> Cow<'a, str> { - let snip = snippet_with_applicability(cx, span, default, applicability); - let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - reindent_multiline(snip, true, indent) -} - -/// Same as `snippet_with_applicability`, but first walks the span up to the given context. This -/// will result in the macro call, rather then the expansion, if the span is from a child context. -/// If the span is not from a child context, it will be used directly instead. -/// -/// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node -/// would result in `box []`. If given the context of the address of expression, this function will -/// correctly get a snippet of `vec![]`. -/// -/// This will also return whether or not the snippet is a macro call. -pub fn snippet_with_context( - cx: &LateContext<'_>, - span: Span, - outer: SyntaxContext, - default: &'a str, - applicability: &mut Applicability, -) -> (Cow<'a, str>, bool) { - let outer_span = hygiene::walk_chain(span, outer); - let (span, is_macro_call) = if outer_span.ctxt() == outer { - (outer_span, span.ctxt() != outer) - } else { - // The span is from a macro argument, and the outer context is the macro using the argument - if *applicability != Applicability::Unspecified { - *applicability = Applicability::MaybeIncorrect; - } - // TODO: get the argument span. - (span, false) - }; - - ( - snippet_with_applicability(cx, span, default, applicability), - is_macro_call, - ) -} - -/// Returns a new Span that extends the original Span to the first non-whitespace char of the first -/// line. -/// -/// ```rust,ignore -/// let x = (); -/// // ^^ -/// // will be converted to -/// let x = (); -/// // ^^^^^^^^^^ -/// ``` -pub fn first_line_of_span(cx: &T, span: Span) -> Span { - first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) -} - -fn first_char_in_first_line(cx: &T, span: Span) -> Option { - let line_span = line_span(cx, span); - snippet_opt(cx, line_span).and_then(|snip| { - snip.find(|c: char| !c.is_whitespace()) - .map(|pos| line_span.lo() + BytePos::from_usize(pos)) - }) -} - -/// Returns the indentation of the line of a span -/// -/// ```rust,ignore -/// let x = (); -/// // ^^ -- will return 0 -/// let x = (); -/// // ^^ -- will return 4 -/// ``` -pub fn indent_of(cx: &T, span: Span) -> Option { - snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) -} - -/// Returns the positon just before rarrow -/// -/// ```rust,ignore -/// fn into(self) -> () {} -/// ^ -/// // in case of unformatted code -/// fn into2(self)-> () {} -/// ^ -/// fn into3(self) -> () {} -/// ^ -/// ``` -pub fn position_before_rarrow(s: &str) -> Option { - s.rfind("->").map(|rpos| { - let mut rpos = rpos; - let chars: Vec = s.chars().collect(); - while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } - } - break; - } - rpos - }) -} - /// Extends the span to the beginning of the spans line, incl. whitespaces. /// /// ```rust,ignore @@ -935,66 +715,6 @@ fn line_span(cx: &T, span: Span) -> Span { Span::new(line_start, span.hi(), span.ctxt()) } -/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. -/// Also takes an `Option` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>( - cx: &T, - expr: &Expr<'_>, - option: Option, - default: &'a str, - indent_relative_to: Option, -) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default, indent_relative_to); - let string = option.unwrap_or_default(); - if expr.span.from_expansion() { - Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) - } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{}{}", code, string)) - } else if string.is_empty() { - Cow::Owned(format!("{{ {} }}", code)) - } else { - Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) - } -} - -/// Reindent a multiline string with possibility of ignoring the first line. -#[allow(clippy::needless_pass_by_value)] -pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { - let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); - let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); - reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() -} - -fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, ch: char) -> String { - let x = s - .lines() - .skip(ignore_first as usize) - .filter_map(|l| { - if l.is_empty() { - None - } else { - // ignore empty lines - Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0) - } - }) - .min() - .unwrap_or(0); - let indent = indent.unwrap_or(0); - s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.is_empty() { - l.to_owned() - } else if x > indent { - l.split_at(x - indent).1.to_owned() - } else { - " ".repeat(indent - x) + l - } - }) - .collect::>() - .join("\n") -} - /// Gets the span of the node, if there is one. pub fn get_node_span(node: Node<'_>) -> Option { match node { @@ -1366,39 +1086,6 @@ pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 { (u << amt) >> amt } -/// Removes block comments from the given `Vec` of lines. -/// -/// # Examples -/// -/// ```rust,ignore -/// without_block_comments(vec!["/*", "foo", "*/"]); -/// // => vec![] -/// -/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); -/// // => vec!["bar"] -/// ``` -pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { - let mut without = vec![]; - - let mut nest_level = 0; - - for line in lines { - if line.contains("/*") { - nest_level += 1; - continue; - } else if line.contains("*/") { - nest_level -= 1; - continue; - } - - if nest_level == 0 { - without.push(line); - } - } - - without -} - pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool { let map = &tcx.hir(); let mut prev_enclosing_node = None; @@ -1777,100 +1464,3 @@ pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { } false } - -#[cfg(test)] -mod test { - use super::{reindent_multiline, without_block_comments}; - - #[test] - fn test_reindent_multiline_single_line() { - assert_eq!("", reindent_multiline("".into(), false, None)); - assert_eq!("...", reindent_multiline("...".into(), false, None)); - assert_eq!("...", reindent_multiline(" ...".into(), false, None)); - assert_eq!("...", reindent_multiline("\t...".into(), false, None)); - assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); - } - - #[test] - #[rustfmt::skip] - fn test_reindent_multiline_block() { - assert_eq!("\ - if x { - y - } else { - z - }", reindent_multiline(" if x { - y - } else { - z - }".into(), false, None)); - assert_eq!("\ - if x { - \ty - } else { - \tz - }", reindent_multiline(" if x { - \ty - } else { - \tz - }".into(), false, None)); - } - - #[test] - #[rustfmt::skip] - fn test_reindent_multiline_empty_line() { - assert_eq!("\ - if x { - y - - } else { - z - }", reindent_multiline(" if x { - y - - } else { - z - }".into(), false, None)); - } - - #[test] - #[rustfmt::skip] - fn test_reindent_multiline_lines_deeper() { - assert_eq!("\ - if x { - y - } else { - z - }", reindent_multiline("\ - if x { - y - } else { - z - }".into(), true, Some(8))); - } - - #[test] - fn test_without_block_comments_lines_without_block_comments() { - let result = without_block_comments(vec!["/*", "", "*/"]); - println!("result: {:?}", result); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); - assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); - - let result = without_block_comments(vec!["/* rust", "", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* one-line comment */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["foo", "bar", "baz"]); - assert_eq!(result, vec!["foo", "bar", "baz"]); - } -} diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index df6143edbca..5885cc83560 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,4 +1,5 @@ -use crate::{get_pat_name, match_var, snippet}; +use crate::source::snippet; +use crate::{get_pat_name, match_var}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Body, BodyId, Expr, ExprKind, Param}; use rustc_lint::LateContext; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs new file mode 100644 index 00000000000..2d794d48dc5 --- /dev/null +++ b/clippy_utils/src/source.rs @@ -0,0 +1,420 @@ +//! Utils for extracting, inspecting or transforming source code + +#![allow(clippy::module_name_repetitions)] + +use crate::line_span; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_span::hygiene; +use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use std::borrow::Cow; + +/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. +/// Also takes an `Option` which can be put inside the braces. +pub fn expr_block<'a, T: LintContext>( + cx: &T, + expr: &Expr<'_>, + option: Option, + default: &'a str, + indent_relative_to: Option, +) -> Cow<'a, str> { + let code = snippet_block(cx, expr.span, default, indent_relative_to); + let string = option.unwrap_or_default(); + if expr.span.from_expansion() { + Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + } else if let ExprKind::Block(_, _) = expr.kind { + Cow::Owned(format!("{}{}", code, string)) + } else if string.is_empty() { + Cow::Owned(format!("{{ {} }}", code)) + } else { + Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) + } +} + +/// Returns a new Span that extends the original Span to the first non-whitespace char of the first +/// line. +/// +/// ```rust,ignore +/// let x = (); +/// // ^^ +/// // will be converted to +/// let x = (); +/// // ^^^^^^^^^^ +/// ``` +pub fn first_line_of_span(cx: &T, span: Span) -> Span { + first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) +} + +fn first_char_in_first_line(cx: &T, span: Span) -> Option { + let line_span = line_span(cx, span); + snippet_opt(cx, line_span).and_then(|snip| { + snip.find(|c: char| !c.is_whitespace()) + .map(|pos| line_span.lo() + BytePos::from_usize(pos)) + }) +} + +/// Returns the indentation of the line of a span +/// +/// ```rust,ignore +/// let x = (); +/// // ^^ -- will return 0 +/// let x = (); +/// // ^^ -- will return 4 +/// ``` +pub fn indent_of(cx: &T, span: Span) -> Option { + snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) +} + +// If the snippet is empty, it's an attribute that was inserted during macro +// expansion and we want to ignore those, because they could come from external +// sources that the user has no control over. +// For some reason these attributes don't have any expansion info on them, so +// we have to check it this way until there is a better way. +pub fn is_present_in_source(cx: &T, span: Span) -> bool { + if let Some(snippet) = snippet_opt(cx, span) { + if snippet.is_empty() { + return false; + } + } + true +} + +/// Returns the positon just before rarrow +/// +/// ```rust,ignore +/// fn into(self) -> () {} +/// ^ +/// // in case of unformatted code +/// fn into2(self)-> () {} +/// ^ +/// fn into3(self) -> () {} +/// ^ +/// ``` +pub fn position_before_rarrow(s: &str) -> Option { + s.rfind("->").map(|rpos| { + let mut rpos = rpos; + let chars: Vec = s.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } + rpos + }) +} + +/// Reindent a multiline string with possibility of ignoring the first line. +#[allow(clippy::needless_pass_by_value)] +pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { + let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); + let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); + reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() +} + +fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, ch: char) -> String { + let x = s + .lines() + .skip(ignore_first as usize) + .filter_map(|l| { + if l.is_empty() { + None + } else { + // ignore empty lines + Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0) + } + }) + .min() + .unwrap_or(0); + let indent = indent.unwrap_or(0); + s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l.to_owned() + } else if x > indent { + l.split_at(x - indent).1.to_owned() + } else { + " ".repeat(indent - x) + l + } + }) + .collect::>() + .join("\n") +} + +/// Converts a span to a code snippet if available, otherwise use default. +/// +/// This is useful if you want to provide suggestions for your lint or more generally, if you want +/// to convert a given `Span` to a `str`. +/// +/// # Example +/// ```rust,ignore +/// snippet(cx, expr.span, "..") +/// ``` +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) +} + +/// Same as `snippet`, but it adapts the applicability level by following rules: +/// +/// - Applicability level `Unspecified` will never be changed. +/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. +/// - If the default value is used and the applicability level is `MachineApplicable`, change it to +/// `HasPlaceholders` +pub fn snippet_with_applicability<'a, T: LintContext>( + cx: &T, + span: Span, + default: &'a str, + applicability: &mut Applicability, +) -> Cow<'a, str> { + if *applicability != Applicability::Unspecified && span.from_expansion() { + *applicability = Applicability::MaybeIncorrect; + } + snippet_opt(cx, span).map_or_else( + || { + if *applicability == Applicability::MachineApplicable { + *applicability = Applicability::HasPlaceholders; + } + Cow::Borrowed(default) + }, + From::from, + ) +} + +/// Same as `snippet`, but should only be used when it's clear that the input span is +/// not a macro argument. +pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + snippet(cx, span.source_callsite(), default) +} + +/// Converts a span to a code snippet. Returns `None` if not available. +pub fn snippet_opt(cx: &T, span: Span) -> Option { + cx.sess().source_map().span_to_snippet(span).ok() +} + +/// Converts a span (from a block) to a code snippet if available, otherwise use default. +/// +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like +/// things which need to be printed as such. +/// +/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the +/// resulting snippet of the given span. +/// +/// # Example +/// +/// ```rust,ignore +/// snippet_block(cx, block.span, "..", None) +/// // where, `block` is the block of the if expr +/// if x { +/// y; +/// } +/// // will return the snippet +/// { +/// y; +/// } +/// ``` +/// +/// ```rust,ignore +/// snippet_block(cx, block.span, "..", Some(if_expr.span)) +/// // where, `block` is the block of the if expr +/// if x { +/// y; +/// } +/// // will return the snippet +/// { +/// y; +/// } // aligned with `if` +/// ``` +/// Note that the first line of the snippet always has 0 indentation. +pub fn snippet_block<'a, T: LintContext>( + cx: &T, + span: Span, + default: &'a str, + indent_relative_to: Option, +) -> Cow<'a, str> { + let snip = snippet(cx, span, default); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + reindent_multiline(snip, true, indent) +} + +/// Same as `snippet_block`, but adapts the applicability level by the rules of +/// `snippet_with_applicability`. +pub fn snippet_block_with_applicability<'a, T: LintContext>( + cx: &T, + span: Span, + default: &'a str, + indent_relative_to: Option, + applicability: &mut Applicability, +) -> Cow<'a, str> { + let snip = snippet_with_applicability(cx, span, default, applicability); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + reindent_multiline(snip, true, indent) +} + +/// Same as `snippet_with_applicability`, but first walks the span up to the given context. This +/// will result in the macro call, rather then the expansion, if the span is from a child context. +/// If the span is not from a child context, it will be used directly instead. +/// +/// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node +/// would result in `box []`. If given the context of the address of expression, this function will +/// correctly get a snippet of `vec![]`. +/// +/// This will also return whether or not the snippet is a macro call. +pub fn snippet_with_context( + cx: &LateContext<'_>, + span: Span, + outer: SyntaxContext, + default: &'a str, + applicability: &mut Applicability, +) -> (Cow<'a, str>, bool) { + let outer_span = hygiene::walk_chain(span, outer); + let (span, is_macro_call) = if outer_span.ctxt() == outer { + (outer_span, span.ctxt() != outer) + } else { + // The span is from a macro argument, and the outer context is the macro using the argument + if *applicability != Applicability::Unspecified { + *applicability = Applicability::MaybeIncorrect; + } + // TODO: get the argument span. + (span, false) + }; + + ( + snippet_with_applicability(cx, span, default, applicability), + is_macro_call, + ) +} + +/// Removes block comments from the given `Vec` of lines. +/// +/// # Examples +/// +/// ```rust,ignore +/// without_block_comments(vec!["/*", "foo", "*/"]); +/// // => vec![] +/// +/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); +/// // => vec!["bar"] +/// ``` +pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { + let mut without = vec![]; + + let mut nest_level = 0; + + for line in lines { + if line.contains("/*") { + nest_level += 1; + continue; + } else if line.contains("*/") { + nest_level -= 1; + continue; + } + + if nest_level == 0 { + without.push(line); + } + } + + without +} + +#[cfg(test)] +mod test { + use super::{reindent_multiline, without_block_comments}; + + #[test] + fn test_reindent_multiline_single_line() { + assert_eq!("", reindent_multiline("".into(), false, None)); + assert_eq!("...", reindent_multiline("...".into(), false, None)); + assert_eq!("...", reindent_multiline(" ...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); + } + + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_block() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline(" if x { + y + } else { + z + }".into(), false, None)); + assert_eq!("\ + if x { + \ty + } else { + \tz + }", reindent_multiline(" if x { + \ty + } else { + \tz + }".into(), false, None)); + } + + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_empty_line() { + assert_eq!("\ + if x { + y + + } else { + z + }", reindent_multiline(" if x { + y + + } else { + z + }".into(), false, None)); + } + + #[test] + #[rustfmt::skip] + fn test_reindent_multiline_lines_deeper() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline("\ + if x { + y + } else { + z + }".into(), true, Some(8))); + } + + #[test] + fn test_without_block_comments_lines_without_block_comments() { + let result = without_block_comments(vec!["/*", "", "*/"]); + println!("result: {:?}", result); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); + assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); + + let result = without_block_comments(vec!["/* rust", "", "*/"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["/* one-line comment */"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); + assert!(result.is_empty()); + + let result = without_block_comments(vec!["foo", "bar", "baz"]); + assert_eq!(result, vec!["foo", "bar", "baz"]); + } +} diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index d4f6f4281d3..b2fe4317154 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -1,7 +1,8 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::{higher, snippet, snippet_opt, snippet_with_macro_callsite}; +use crate::higher; +use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ast, token}; use rustc_ast_pretty::pprust::token_kind_to_string; -- cgit 1.4.1-3-g733a5 From 1c3a3e7dc62ae3b4b84cc00c067789dae1d722c9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 15 Mar 2021 19:55:45 -0500 Subject: Don't re-export clippy_utils::diagnostics::* --- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/arithmetic.rs | 2 +- clippy_lints/src/as_conversions.rs | 3 +-- clippy_lints/src/asm_syntax.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 3 ++- clippy_lints/src/assign_ops.rs | 3 ++- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/atomic_ordering.rs | 3 ++- clippy_lints/src/attrs.rs | 3 ++- clippy_lints/src/await_holding_invalid.rs | 3 ++- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/blacklisted_name.rs | 2 +- clippy_lints/src/blocks_in_if_conditions.rs | 3 ++- clippy_lints/src/booleans.rs | 3 ++- clippy_lints/src/bytecount.rs | 3 ++- clippy_lints/src/cargo_common_metadata.rs | 3 ++- clippy_lints/src/case_sensitive_file_extension_comparisons.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 3 ++- clippy_lints/src/casts/cast_possible_truncation.rs | 2 +- clippy_lints/src/casts/cast_possible_wrap.rs | 3 +-- clippy_lints/src/casts/cast_precision_loss.rs | 3 +-- clippy_lints/src/casts/cast_ptr_alignment.rs | 3 ++- clippy_lints/src/casts/cast_ref_to_mut.rs | 6 ++---- clippy_lints/src/casts/cast_sign_loss.rs | 3 ++- clippy_lints/src/casts/char_lit_as_u8.rs | 3 +-- clippy_lints/src/casts/fn_to_numeric_cast.rs | 2 +- clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs | 2 +- clippy_lints/src/casts/ptr_as_ptr.rs | 3 ++- clippy_lints/src/casts/unnecessary_cast.rs | 3 ++- clippy_lints/src/checked_conversions.rs | 3 ++- clippy_lints/src/cognitive_complexity.rs | 3 ++- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/collapsible_match.rs | 3 ++- clippy_lints/src/comparison_chain.rs | 3 ++- clippy_lints/src/copies.rs | 3 ++- clippy_lints/src/copy_iterator.rs | 2 +- clippy_lints/src/create_dir.rs | 3 ++- clippy_lints/src/dbg_macro.rs | 2 +- clippy_lints/src/default.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 3 +-- clippy_lints/src/dereference.rs | 3 ++- clippy_lints/src/derive.rs | 6 ++---- clippy_lints/src/disallowed_method.rs | 3 ++- clippy_lints/src/doc.rs | 5 ++--- clippy_lints/src/double_comparison.rs | 3 ++- clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 3 ++- clippy_lints/src/duration_subsec.rs | 2 +- clippy_lints/src/else_if_without_else.rs | 3 +-- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/eq_op.rs | 6 ++---- clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/escape.rs | 3 +-- clippy_lints/src/eta_reduction.rs | 3 ++- clippy_lints/src/eval_order_dependence.rs | 3 ++- clippy_lints/src/excessive_bools.rs | 3 ++- clippy_lints/src/exhaustive_items.rs | 4 +--- clippy_lints/src/exit.rs | 3 ++- clippy_lints/src/explicit_write.rs | 3 ++- clippy_lints/src/fallible_impl_from.rs | 3 ++- clippy_lints/src/float_equality_without_abs.rs | 3 ++- clippy_lints/src/float_literal.rs | 3 ++- clippy_lints/src/floating_point_arithmetic.rs | 3 ++- clippy_lints/src/format.rs | 3 ++- clippy_lints/src/formatting.rs | 3 ++- clippy_lints/src/from_over_into.rs | 3 ++- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions.rs | 3 ++- clippy_lints/src/future_not_send.rs | 3 ++- clippy_lints/src/get_last_with_len.rs | 3 ++- clippy_lints/src/identity_op.rs | 3 ++- clippy_lints/src/if_let_mutex.rs | 3 ++- clippy_lints/src/if_let_some_result.rs | 3 ++- clippy_lints/src/if_not_else.rs | 3 +-- clippy_lints/src/if_then_some_else_none.rs | 3 ++- clippy_lints/src/implicit_return.rs | 3 ++- clippy_lints/src/implicit_saturating_sub.rs | 3 ++- clippy_lints/src/inconsistent_struct_constructor.rs | 3 +-- clippy_lints/src/indexing_slicing.rs | 3 ++- clippy_lints/src/infinite_iter.rs | 3 ++- clippy_lints/src/inherent_impl.rs | 3 ++- clippy_lints/src/inherent_to_string.rs | 3 ++- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/int_plus_one.rs | 3 +-- clippy_lints/src/integer_division.rs | 2 +- clippy_lints/src/items_after_statements.rs | 2 +- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/len_zero.rs | 3 ++- clippy_lints/src/let_if_seq.rs | 3 ++- clippy_lints/src/let_underscore.rs | 3 ++- clippy_lints/src/lifetimes.rs | 3 ++- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops/empty_loop.rs | 3 ++- clippy_lints/src/loops/explicit_counter_loop.rs | 3 ++- clippy_lints/src/loops/explicit_into_iter_loop.rs | 2 +- clippy_lints/src/loops/explicit_iter_loop.rs | 3 ++- clippy_lints/src/loops/for_kv_map.rs | 3 ++- clippy_lints/src/loops/for_loops_over_fallibles.rs | 5 ++--- clippy_lints/src/loops/iter_next_loop.rs | 3 ++- clippy_lints/src/loops/manual_flatten.rs | 3 ++- clippy_lints/src/loops/manual_memcpy.rs | 3 ++- clippy_lints/src/loops/mut_range_bound.rs | 3 ++- clippy_lints/src/loops/needless_collect.rs | 3 ++- clippy_lints/src/loops/needless_range_loop.rs | 4 ++-- clippy_lints/src/loops/never_loop.rs | 2 +- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/loops/single_element_loop.rs | 3 ++- clippy_lints/src/loops/while_immutable_condition.rs | 2 +- clippy_lints/src/loops/while_let_loop.rs | 2 +- clippy_lints/src/loops/while_let_on_iterator.rs | 2 +- clippy_lints/src/macro_use.rs | 3 ++- clippy_lints/src/main_recursion.rs | 3 ++- clippy_lints/src/manual_async_fn.rs | 3 ++- clippy_lints/src/manual_map.rs | 3 ++- clippy_lints/src/manual_non_exhaustive.rs | 3 ++- clippy_lints/src/manual_ok_or.rs | 3 ++- clippy_lints/src/manual_strip.rs | 3 ++- clippy_lints/src/manual_unwrap_or.rs | 3 ++- clippy_lints/src/map_clone.rs | 3 ++- clippy_lints/src/map_err_ignore.rs | 3 +-- clippy_lints/src/map_identity.rs | 3 ++- clippy_lints/src/map_unit_fn.rs | 3 ++- clippy_lints/src/match_on_vec_items.rs | 2 +- clippy_lints/src/matches.rs | 11 +++++++---- clippy_lints/src/mem_discriminant.rs | 3 ++- clippy_lints/src/mem_forget.rs | 3 ++- clippy_lints/src/mem_replace.rs | 6 ++---- clippy_lints/src/methods/bind_instead_of_map.rs | 6 ++---- clippy_lints/src/methods/bytes_nth.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 3 ++- clippy_lints/src/methods/clone_on_ref_ptr.rs | 3 ++- clippy_lints/src/methods/expect_fun_call.rs | 3 ++- clippy_lints/src/methods/expect_used.rs | 2 +- clippy_lints/src/methods/filetype_is_file.rs | 3 ++- clippy_lints/src/methods/filter_flat_map.rs | 3 ++- clippy_lints/src/methods/filter_map.rs | 3 ++- clippy_lints/src/methods/filter_map_flat_map.rs | 3 ++- clippy_lints/src/methods/filter_map_identity.rs | 3 ++- clippy_lints/src/methods/filter_map_map.rs | 3 ++- clippy_lints/src/methods/filter_map_next.rs | 3 ++- clippy_lints/src/methods/filter_next.rs | 3 ++- clippy_lints/src/methods/flat_map_identity.rs | 3 ++- clippy_lints/src/methods/from_iter_instead_of_collect.rs | 3 ++- clippy_lints/src/methods/get_unwrap.rs | 3 ++- clippy_lints/src/methods/implicit_clone.rs | 2 +- clippy_lints/src/methods/inefficient_to_string.rs | 3 ++- clippy_lints/src/methods/inspect_for_each.rs | 3 ++- clippy_lints/src/methods/into_iter_on_ref.rs | 3 ++- clippy_lints/src/methods/iter_cloned_collect.rs | 2 +- clippy_lints/src/methods/iter_count.rs | 3 ++- clippy_lints/src/methods/iter_next_slice.rs | 3 ++- clippy_lints/src/methods/iter_nth.rs | 2 +- clippy_lints/src/methods/iter_nth_zero.rs | 3 ++- clippy_lints/src/methods/iter_skip_next.rs | 3 ++- clippy_lints/src/methods/iterator_step_by_zero.rs | 3 ++- clippy_lints/src/methods/manual_saturating_arithmetic.rs | 3 ++- clippy_lints/src/methods/map_collect_result_unit.rs | 3 ++- clippy_lints/src/methods/map_flatten.rs | 3 ++- clippy_lints/src/methods/map_unwrap_or.rs | 3 ++- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/methods/ok_expect.rs | 2 +- clippy_lints/src/methods/option_as_ref_deref.rs | 3 ++- clippy_lints/src/methods/option_map_or_none.rs | 3 ++- clippy_lints/src/methods/option_map_unwrap_or.rs | 3 ++- clippy_lints/src/methods/or_fun_call.rs | 3 ++- clippy_lints/src/methods/search_is_some.rs | 3 ++- clippy_lints/src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_pattern.rs | 2 +- clippy_lints/src/methods/single_char_push_string.rs | 2 +- clippy_lints/src/methods/skip_while_next.rs | 3 ++- clippy_lints/src/methods/string_extend_chars.rs | 3 ++- clippy_lints/src/methods/suspicious_map.rs | 3 ++- clippy_lints/src/methods/uninit_assumed_init.rs | 3 ++- clippy_lints/src/methods/unnecessary_filter_map.rs | 3 ++- clippy_lints/src/methods/unnecessary_fold.rs | 3 ++- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/methods/unwrap_used.rs | 2 +- clippy_lints/src/methods/useless_asref.rs | 3 ++- clippy_lints/src/methods/wrong_self_convention.rs | 2 +- clippy_lints/src/methods/zst_offset.rs | 2 +- clippy_lints/src/minmax.rs | 3 ++- clippy_lints/src/misc.rs | 4 ++-- clippy_lints/src/misc_early.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 3 ++- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/modulo_arithmetic.rs | 3 ++- clippy_lints/src/multiple_crate_versions.rs | 3 ++- clippy_lints/src/mut_key.rs | 3 ++- clippy_lints/src/mut_mut.rs | 3 ++- clippy_lints/src/mut_mutex_lock.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 3 ++- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_arbitrary_self_type.rs | 3 ++- clippy_lints/src/needless_bool.rs | 3 ++- clippy_lints/src/needless_borrow.rs | 3 ++- clippy_lints/src/needless_borrowed_ref.rs | 2 +- clippy_lints/src/needless_continue.rs | 3 +-- clippy_lints/src/needless_pass_by_value.rs | 3 ++- clippy_lints/src/needless_question_mark.rs | 3 ++- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 3 ++- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 3 ++- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/non_copy_const.rs | 3 ++- clippy_lints/src/non_expressive_names.rs | 2 +- clippy_lints/src/open_options.rs | 3 ++- clippy_lints/src/option_env_unwrap.rs | 3 ++- clippy_lints/src/option_if_let_else.rs | 3 ++- clippy_lints/src/overflow_check_conditional.rs | 3 ++- clippy_lints/src/panic_in_result_fn.rs | 3 ++- clippy_lints/src/panic_unimplemented.rs | 3 ++- clippy_lints/src/partialeq_ne_impl.rs | 3 ++- clippy_lints/src/pass_by_ref_or_value.rs | 3 ++- clippy_lints/src/path_buf_push_overwrite.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 3 ++- clippy_lints/src/precedence.rs | 2 +- clippy_lints/src/ptr.rs | 3 ++- clippy_lints/src/ptr_eq.rs | 3 ++- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/question_mark.rs | 3 ++- clippy_lints/src/ranges.rs | 6 ++---- clippy_lints/src/redundant_clone.rs | 3 ++- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_else.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 3 ++- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 3 +-- clippy_lints/src/redundant_static_lifetimes.rs | 3 ++- clippy_lints/src/ref_option_ref.rs | 3 ++- clippy_lints/src/reference.rs | 3 ++- clippy_lints/src/regex.rs | 3 ++- clippy_lints/src/repeat_once.rs | 3 ++- clippy_lints/src/returns.rs | 3 ++- clippy_lints/src/self_assignment.rs | 3 ++- clippy_lints/src/semicolon_if_nothing_returned.rs | 3 ++- clippy_lints/src/serde_api.rs | 3 ++- clippy_lints/src/shadow.rs | 3 ++- clippy_lints/src/single_component_path_imports.rs | 3 ++- clippy_lints/src/size_of_in_element_count.rs | 3 ++- clippy_lints/src/slow_vector_initialization.rs | 3 ++- clippy_lints/src/stable_sort_primitive.rs | 3 ++- clippy_lints/src/strings.rs | 6 ++---- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 3 ++- clippy_lints/src/swap.rs | 3 ++- clippy_lints/src/tabs_in_doc_comments.rs | 2 +- clippy_lints/src/temporary_assignment.rs | 3 ++- clippy_lints/src/to_digit_is_some.rs | 3 ++- clippy_lints/src/to_string_in_display.rs | 3 ++- clippy_lints/src/trait_bounds.rs | 3 ++- clippy_lints/src/transmute/crosspointer_transmute.rs | 2 +- clippy_lints/src/transmute/transmute_float_to_int.rs | 3 ++- clippy_lints/src/transmute/transmute_int_to_bool.rs | 3 ++- clippy_lints/src/transmute/transmute_int_to_char.rs | 3 ++- clippy_lints/src/transmute/transmute_int_to_float.rs | 3 ++- clippy_lints/src/transmute/transmute_ptr_to_ptr.rs | 3 ++- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 3 ++- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 3 ++- .../src/transmute/transmutes_expressible_as_ptr_casts.rs | 3 ++- clippy_lints/src/transmute/unsound_collection_transmute.rs | 3 ++- clippy_lints/src/transmute/useless_transmute.rs | 3 ++- clippy_lints/src/transmute/wrong_transmute.rs | 2 +- clippy_lints/src/transmuting_null.rs | 3 ++- clippy_lints/src/try_err.rs | 3 ++- clippy_lints/src/types/borrowed_box.rs | 3 ++- clippy_lints/src/types/box_vec.rs | 3 ++- clippy_lints/src/types/linked_list.rs | 3 ++- clippy_lints/src/types/mod.rs | 6 ++---- clippy_lints/src/types/option_option.rs | 3 ++- clippy_lints/src/types/rc_buffer.rs | 3 ++- clippy_lints/src/types/redundant_allocation.rs | 3 ++- clippy_lints/src/types/vec_box.rs | 3 ++- clippy_lints/src/undropped_manually_drops.rs | 3 ++- clippy_lints/src/unicode.rs | 3 ++- clippy_lints/src/unit_return_expecting_ord.rs | 3 ++- clippy_lints/src/unnamed_address.rs | 3 ++- clippy_lints/src/unnecessary_sort_by.rs | 6 +++--- clippy_lints/src/unnecessary_wraps.rs | 5 ++--- clippy_lints/src/unnested_or_patterns.rs | 3 ++- clippy_lints/src/unsafe_removed_from_name.rs | 2 +- clippy_lints/src/unused_io_amount.rs | 3 ++- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/unused_unit.rs | 2 +- clippy_lints/src/unwrap.rs | 3 ++- clippy_lints/src/unwrap_in_result.rs | 3 ++- clippy_lints/src/upper_case_acronyms.rs | 4 ++-- clippy_lints/src/use_self.rs | 4 ++-- clippy_lints/src/useless_conversion.rs | 5 ++--- clippy_lints/src/utils/internal_lints.rs | 7 +++---- clippy_lints/src/vec.rs | 3 ++- clippy_lints/src/vec_init_then_push.rs | 3 ++- clippy_lints/src/vec_resize_to_zero.rs | 2 +- clippy_lints/src/verbose_file_reads.rs | 3 ++- clippy_lints/src/wildcard_dependencies.rs | 3 ++- clippy_lints/src/wildcard_imports.rs | 3 ++- clippy_lints/src/write.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 3 ++- clippy_utils/src/lib.rs | 3 +-- 307 files changed, 530 insertions(+), 368 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 1d511a86c90..3d04abe094d 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 61fdf9495b9..c560f545d6a 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -1,5 +1,5 @@ use crate::consts::constant_simple; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index c30d65bbc57..4b31e16094e 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -1,10 +1,9 @@ +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** Checks for usage of `as` conversions. /// diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index ef1f1a14afc..b970c71b753 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 3b6f64e7769..bae4d4957a9 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, span_lint_and_help}; +use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call}; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, UnOp}; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 031827e7e89..8581e176e0c 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,5 +1,6 @@ -use crate::utils::{eq_expr_value, get_trait_def_id, span_lint_and_then, trait_ref_of_method}; +use crate::utils::{eq_expr_value, get_trait_def_id, trait_ref_of_method}; use crate::utils::{higher, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use if_chain::if_chain; diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index a5ed6016874..e6c7c68f91a 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 703d8a6f62b..231e74e16c0 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, span_lint_and_help}; +use crate::utils::match_def_path; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 04b0e71e4a3..6be6722375d 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,6 +1,7 @@ //! checks for attributes -use crate::utils::{match_panic_def_id, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::match_panic_def_id; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 14b6a156c62..3a3296c2c3d 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_note}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint_and_note; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index a4ee54076ee..2b8400344f5 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; use crate::utils::sugg::Sugg; -use crate::utils::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 153870fb416..b26ef33e056 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index f43f98d1dc0..343c4821c56 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, get_parent_expr, span_lint, span_lint_and_sugg}; +use crate::utils::{differing_macro_contexts, get_parent_expr}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; use if_chain::if_chain; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 12a07c60438..1303613b8c4 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,4 +1,5 @@ -use crate::utils::{eq_expr_value, get_trait_def_id, in_macro, paths, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{eq_expr_value, get_trait_def_id, in_macro, paths}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index d02861b1b1e..c1ca787c1e5 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,4 +1,5 @@ -use crate::utils::{contains_name, get_pat_name, paths, single_segment_path, span_lint_and_sugg}; +use crate::utils::{contains_name, get_pat_name, paths, single_segment_path}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; use if_chain::if_chain; diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index cc2869ab495..f0ef482164a 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -2,7 +2,8 @@ use std::path::PathBuf; -use crate::utils::{run_lints, span_lint}; +use crate::utils::run_lints; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index b15fe65352a..c9ef379be56 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind, PathSegment}; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 62ba19c0e16..4b660188d82 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; @@ -5,7 +6,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::{in_constant, span_lint_and_sugg}; +use crate::utils::in_constant; use super::{utils, CAST_LOSSLESS}; diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 522ef5348be..75d7c55b637 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -3,7 +3,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use super::{utils, CAST_POSSIBLE_TRUNCATION}; diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 931252415ad..2c5c1d7cb46 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -1,10 +1,9 @@ +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use crate::utils::span_lint; - use super::{utils, CAST_POSSIBLE_WRAP}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index b6905c21c78..63ac8fd2dd2 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -1,10 +1,9 @@ +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::span_lint; - use super::{utils, CAST_PRECISION_LOSS}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 87fb5557be0..6a45ec61c54 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -6,7 +7,7 @@ use rustc_target::abi::LayoutOf; use if_chain::if_chain; -use crate::utils::{is_hir_ty_cfg_dependant, span_lint}; +use crate::utils::is_hir_ty_cfg_dependant; use super::CAST_PTR_ALIGNMENT; diff --git a/clippy_lints/src/casts/cast_ref_to_mut.rs b/clippy_lints/src/casts/cast_ref_to_mut.rs index 3fdc1c6168b..d9bf1ea58b9 100644 --- a/clippy_lints/src/casts/cast_ref_to_mut.rs +++ b/clippy_lints/src/casts/cast_ref_to_mut.rs @@ -1,11 +1,9 @@ +use clippy_utils::diagnostics::span_lint; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, MutTy, Mutability, TyKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; -use if_chain::if_chain; - -use crate::utils::span_lint; - use super::CAST_REF_TO_MUT; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 9656fbebd77..2965a840a82 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -5,7 +5,8 @@ use rustc_middle::ty::{self, Ty}; use if_chain::if_chain; use crate::consts::{constant, Constant}; -use crate::utils::{method_chain_args, sext, span_lint}; +use crate::utils::{method_chain_args, sext}; +use clippy_utils::diagnostics::span_lint; use super::CAST_SIGN_LOSS; diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index 75aa559359c..099a0de881f 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::LitKind; @@ -6,8 +7,6 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, UintTy}; -use crate::utils::span_lint_and_then; - use super::CHAR_LIT_AS_U8; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index 723bfa5befe..35350d8a25b 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index a3108f8a983..6287f479b5b 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index abfbadf3642..2c25f865cb8 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -8,8 +8,9 @@ use rustc_semver::RustcVersion; use if_chain::if_chain; +use crate::utils::meets_msrv; use crate::utils::sugg::Sugg; -use crate::utils::{meets_msrv, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use super::PTR_AS_PTR; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index eb0ee012e6c..a84e658024a 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::{LitFloatType, LitIntType, LitKind}; @@ -7,7 +8,7 @@ use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; -use crate::utils::{numeric_literal::NumericLiteral, span_lint_and_sugg}; +use crate::utils::numeric_literal::NumericLiteral; use super::UNNECESSARY_CAST; diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 4f3daa427e3..8b62e315e04 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,5 +1,6 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -10,7 +11,7 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{meets_msrv, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{meets_msrv, SpanlessEq}; const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 5b8ef01505b..8134f3af3ef 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::Attribute; @@ -11,7 +12,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; -use crate::utils::{span_lint_and_help, LimitStack}; +use crate::utils::LimitStack; declare_clippy_lint! { /// **What it does:** Checks for methods with high cognitive complexity. diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index c866f18ef3e..dbe70f90732 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -12,6 +12,7 @@ //! //! This lint is **warn** by default +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet_block, snippet_block_with_applicability}; use if_chain::if_chain; use rustc_ast::ast; @@ -20,7 +21,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::sugg::Sugg; -use crate::utils::{span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for nested `if` statements which can be collapsed diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 3c45525684b..5ff2518bd94 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -1,5 +1,6 @@ use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{path_to_local, span_lint_and_then, SpanlessEq}; +use crate::utils::{path_to_local, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp}; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 9843033a2e0..5411905791c 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, if_sequence, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq}; +use crate::utils::{get_trait_def_id, if_sequence, parent_node_is_if_expr, paths, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::implements_trait; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 944aaafb46d..f86f0da6d6f 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,5 +1,6 @@ use crate::utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash}; -use crate::utils::{get_parent_expr, if_sequence, span_lint_and_note}; +use crate::utils::{get_parent_expr, if_sequence}; +use clippy_utils::diagnostics::span_lint_and_note; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 434d8958da5..35079c6bedc 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 0785e25b0a2..01ca2837a99 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_sugg}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 3171a945eb0..286cc7e223e 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::snippet_opt; use rustc_ast::ast; use rustc_ast::tokenstream::TokenStream; diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 7d975b5a3d9..0b074c088d4 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,5 +1,5 @@ use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; -use crate::utils::{span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index e58dcb942c6..d136db9373c 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; @@ -13,8 +14,6 @@ use rustc_middle::{ }; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_sugg; - declare_clippy_lint! { /// **What it does:** Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type /// inference. diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index e112338dfea..62ec2f8ce48 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_node, in_macro, is_allowed, span_lint_and_sugg}; +use crate::utils::{get_parent_node, in_macro, is_allowed}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::peel_mid_ty_refs; use rustc_ast::util::parser::PREC_PREFIX; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 460fe385272..a7f2106e357 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,8 +1,6 @@ use crate::utils::paths; -use crate::utils::{ - get_trait_def_id, is_allowed, is_automatically_derived, match_def_path, span_lint_and_help, span_lint_and_note, - span_lint_and_then, -}; +use crate::utils::{get_trait_def_id, is_allowed, is_automatically_derived, match_def_path}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs index 56dc6d18a58..16023bc53b0 100644 --- a/clippy_lints/src/disallowed_method.rs +++ b/clippy_lints/src/disallowed_method.rs @@ -1,4 +1,5 @@ -use crate::utils::{fn_def_id, span_lint}; +use crate::utils::fn_def_id; +use clippy_utils::diagnostics::span_lint; use rustc_data_structures::fx::FxHashSet; use rustc_hir::Expr; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 4f3c573691e..d9952325c4b 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty, span_lint, span_lint_and_note, -}; +use crate::utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use itertools::Itertools; diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 3de027b2cc6..549720feb2d 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,5 +1,6 @@ //! Lint on unnecessary double comparisons. Some examples: +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -7,7 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::utils::{eq_expr_value, span_lint_and_sugg}; +use crate::utils::eq_expr_value; declare_clippy_lint! { /// **What it does:** Checks for double comparisons that could be simplified to a single expression. diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index abbcaf43f41..5afdcb3c09f 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index dd145ba6867..fe86adcec45 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_note}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 195143d720d..40c75f568ae 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -9,7 +9,7 @@ use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 95123e6ff6f..26984df9539 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,12 +1,11 @@ //! Lint on if expressions with an else if, but without a final else branch. +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 077c3b75fb8..c92984a9834 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,6 +1,6 @@ //! lint when there is an enum with no variants -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 93723219594..cc774831491 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,6 +1,6 @@ -use crate::utils::span_lint_and_then; use crate::utils::SpanlessEq; use crate::utils::{get_item_name, paths}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index aa235642ac3..7a98ae39d3a 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -2,7 +2,7 @@ //! don't fit into an `i32` use crate::consts::{miri_to_const, Constant}; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::util::IntTypeExt; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 660131cf176..d2d8acb443b 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,7 +1,7 @@ //! lint on enum variants that are prefixed or suffixed by the same characters use crate::utils::camel_case; -use crate::utils::{span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 0a5917c10ea..1b2f66fb628 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, multispan_sugg, span_lint, - span_lint_and_then, -}; +use crate::utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; use if_chain::if_chain; diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index dbd1ff514f0..59602616781 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,10 +1,10 @@ +use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::span_lint; declare_clippy_lint! { /// **What it does:** Checks for erasing operations, e.g., `x * 0`. diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index a7258eea0ad..06da14a9844 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::contains_ty; use rustc_hir::intravisit; use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node}; @@ -11,8 +12,6 @@ use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; -use crate::utils::span_lint; - #[derive(Copy, Clone)] pub struct BoxedLocal { pub too_large_for_stack: u64, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index e8d5b992b63..2557e9f2796 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::higher; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; @@ -10,7 +11,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_adjusted, iter_input_pats, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{is_adjusted, iter_input_pats}; declare_clippy_lint! { /// **What it does:** Checks for closures which just call another function where diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 83cee11c3a8..3711ba4a7ee 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_expr, path_to_local, path_to_local_id, span_lint, span_lint_and_note}; +use crate::utils::{get_parent_expr, path_to_local, path_to_local_id}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 6a85b57af07..683e0435351 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -1,4 +1,5 @@ -use crate::utils::{attr_by_name, in_macro, match_path_ast, span_lint_and_help}; +use crate::utils::{attr_by_name, in_macro, match_path_ast}; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 5e31072523d..60ad2e8ee14 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -1,14 +1,12 @@ +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use if_chain::if_chain; - use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::span_lint_and_then; - declare_clippy_lint! { /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` /// diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 91585927000..adfb644b199 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_entrypoint_fn, match_def_path, paths, span_lint}; +use crate::utils::{is_entrypoint_fn, match_def_path, paths}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index f8038d06e50..0861cba4675 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, match_function_call, paths, span_lint, span_lint_and_sugg}; +use crate::utils::{is_expn_of, match_function_call, paths}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index cc4e570956b..5efe465a667 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, match_panic_def_id, method_chain_args, span_lint_and_then}; +use crate::utils::{is_expn_of, match_panic_def_id, method_chain_args}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index c1c08597ee6..b3593d328cc 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_then, sugg}; +use crate::utils::{match_def_path, paths, sugg}; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 8e256f34684..6446fe62a64 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -1,4 +1,5 @@ -use crate::utils::{numeric_literal, span_lint_and_sugg}; +use crate::utils::numeric_literal; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 086a791520f..8b53384ecbd 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,7 +2,8 @@ use crate::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use crate::utils::{eq_expr_value, get_parent_expr, numeric_literal, span_lint_and_sugg, sugg}; +use crate::utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index c0048bb2175..db27225707d 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,5 +1,6 @@ use crate::utils::paths; -use crate::utils::{is_expn_of, last_path_segment, match_def_path, match_function_call, span_lint_and_then}; +use crate::utils::{is_expn_of, last_path_segment, match_def_path, match_function_call}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 590de04717a..4dadd2ba936 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, span_lint_and_help, span_lint_and_note}; +use crate::utils::differing_macro_contexts; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index b644bb07990..5eea4d14759 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,5 +1,6 @@ use crate::utils::paths::INTO; -use crate::utils::{match_def_path, meets_msrv, span_lint_and_help}; +use crate::utils::{match_def_path, meets_msrv}; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index b92c8ccfb1b..b9a44f26381 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -7,7 +8,6 @@ use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; -use crate::utils::span_lint_and_sugg; use crate::utils::sugg::Sugg; declare_clippy_lint! { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 104c692dcec..37288d7a0b2 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,7 +1,8 @@ use crate::utils::{ attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr, - path_to_local, return_ty, span_lint, span_lint_and_help, span_lint_and_then, trait_ref_of_method, + path_to_local, return_ty, trait_ref_of_method, }; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, type_is_unsafe_function}; use if_chain::if_chain; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 9e1a8864a3e..36960e7f51b 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -1,4 +1,5 @@ use crate::utils; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; @@ -84,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { fulfillment_cx.select_all_or_error(&infcx) }); if let Err(send_errors) = send_result { - utils::span_lint_and_then( + span_lint_and_then( cx, FUTURE_NOT_SEND, span, diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 875cd33bc8f..6f14ede0ecb 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -1,6 +1,7 @@ //! lint on using `x.get(x.len() - 1)` instead of `x.last()` -use crate::utils::{span_lint_and_sugg, SpanlessEq}; +use crate::utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index fc93864c74a..385ea020328 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -7,7 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::{clip, span_lint, unsext}; +use crate::utils::{clip, unsext}; +use clippy_utils::diagnostics::span_lint; declare_clippy_lint! { /// **What it does:** Checks for identity operations, e.g., `x + 0`. diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index f53d1b1cf3b..c2ec8b3ffd1 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,4 +1,5 @@ -use crate::utils::{span_lint_and_help, SpanlessEq}; +use crate::utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir::intravisit::{self as visit, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 9f7ca95a8f3..59094d1147a 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,4 +1,5 @@ -use crate::utils::{method_chain_args, span_lint_and_sugg}; +use crate::utils::method_chain_args; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index b86d2e76656..c56f67df061 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,13 +1,12 @@ //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an /// else branch. diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 7e1807786ee..c4e87300b7b 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,4 +1,5 @@ use crate::utils; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; @@ -100,7 +101,7 @@ impl LateLintPass<'_> for IfThenSomeElseNone { cond_snip, closure_body, ); - utils::span_lint_and_help( + span_lint_and_help( cx, IF_THEN_SOME_ELSE_NONE, expr.span, diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index e86bd49251d..70ea9a92279 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_panic_def_id, span_lint_and_then}; +use crate::utils::match_panic_def_id; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 16e162badb5..3d2798f3fb4 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, match_qpath, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{in_macro, match_qpath, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 4762d5d40f3..b7986da7820 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; @@ -7,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; -use crate::utils::span_lint_and_sugg; - declare_clippy_lint! { /// **What it does:** Checks for struct constructors where all fields are shorthand and /// the order of the field init shorthand in the constructor is inconsistent diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index c919ec097a2..4c0f976f79a 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -1,7 +1,8 @@ //! lint on indexing and slicing operations use crate::consts::{constant, Constant}; -use crate::utils::{higher, span_lint, span_lint_and_help}; +use crate::utils::higher; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 6bce205ec3a..addd95c6eae 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,9 +1,10 @@ +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, match_type}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{get_trait_def_id, higher, match_qpath, paths, span_lint}; +use crate::utils::{get_trait_def_id, higher, match_qpath, paths}; declare_clippy_lint! { /// **What it does:** Checks for iteration that is guaranteed to be infinite. diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 005c461f105..f838ce190dc 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,6 +1,7 @@ //! lint on inherent implementations -use crate::utils::{in_macro, span_lint_and_then}; +use crate::utils::in_macro; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id, Crate, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 9207413cd69..6b29feeb4ed 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir::{ImplItem, ImplItemKind}; @@ -5,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::{get_trait_def_id, paths, return_ty, span_lint_and_help, trait_ref_of_method}; +use crate::utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; declare_clippy_lint! { /// **What it does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 00acbd6cc3f..87fe5123cf6 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,7 +1,7 @@ //! checks for `#[inline]` on trait methods without bodies -use crate::utils::span_lint_and_then; use crate::utils::sugg::DiagnosticBuilderExt; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 9eae653dd67..c4a1222b51f 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,13 +1,12 @@ //! lint on blocks unnecessarily using >= with a + 1 or - 1 +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_sugg; - declare_clippy_lint! { /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index 39b4605e72f..e5482f675e7 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 0927d218446..c69571f32a2 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,6 +1,6 @@ //! lint when items are used after statements -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Block, ItemKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index a76595ed089..48dc5fefe99 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -1,5 +1,5 @@ use crate::rustc_target::abi::LayoutOf; -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index cbb5192bfd9..76584dc1822 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,6 +1,6 @@ //! lint when there is a large size difference between variants on an enum -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VariantData}; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index ceae4243e63..c46b98022c6 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; @@ -7,7 +8,6 @@ use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use crate::rustc_target::abi::LayoutOf; -use crate::utils::span_lint_and_help; declare_clippy_lint! { /// **What it does:** Checks for local arrays that may be too large. diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e758a269fbe..a644a4113ae 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_item_name, get_parent_as_impl, is_allowed, span_lint, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{get_item_name, get_parent_as_impl, is_allowed}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 7059ba21207..4b7e02398fb 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,4 +1,5 @@ -use crate::utils::{path_to_local_id, span_lint_and_then, visitors::LocalUsedVisitor}; +use crate::utils::{path_to_local_id, visitors::LocalUsedVisitor}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 2da7137b48b..eee2503b481 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_must_use_ty, match_type}; use if_chain::if_chain; use rustc_hir::{Local, PatKind}; @@ -6,7 +7,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, paths, span_lint_and_help}; +use crate::utils::{is_must_use_func_call, paths}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 33ff01a30e8..0848aaed815 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint, trait_ref_of_method}; +use crate::utils::{in_macro, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::intravisit::{ walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 8bc7bf37ef1..dd303bc0a01 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -4,8 +4,8 @@ use crate::utils::{ in_macro, numeric_literal::{NumericLiteral, Radix}, - span_lint_and_sugg, }; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; diff --git a/clippy_lints/src/loops/empty_loop.rs b/clippy_lints/src/loops/empty_loop.rs index 43e85538f28..d52a061fc8f 100644 --- a/clippy_lints/src/loops/empty_loop.rs +++ b/clippy_lints/src/loops/empty_loop.rs @@ -1,5 +1,6 @@ use super::EMPTY_LOOP; -use crate::utils::{is_in_panic_handler, is_no_std_crate, span_lint_and_help}; +use crate::utils::{is_in_panic_handler, is_no_std_crate}; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Block, Expr}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 1f6d48fe915..87ce4e4c20c 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,7 +1,8 @@ use super::{ get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP, }; -use crate::utils::{get_enclosing_block, is_integer_const, span_lint_and_sugg}; +use crate::utils::{get_enclosing_block, is_integer_const}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index e5b3dc7aad7..4871a031187 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,5 +1,5 @@ use super::EXPLICIT_INTO_ITER_LOOP; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index d2000d80ac1..259e95e5ef4 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,5 +1,6 @@ use super::EXPLICIT_ITER_LOOP; -use crate::utils::{match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 19a68dd78d1..bf037f392e0 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,6 +1,7 @@ use super::FOR_KV_MAP; use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{multispan_sugg, paths, span_lint_and_then, sugg}; +use crate::utils::{paths, sugg}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; diff --git a/clippy_lints/src/loops/for_loops_over_fallibles.rs b/clippy_lints/src/loops/for_loops_over_fallibles.rs index 5140448592d..d49b0517dcf 100644 --- a/clippy_lints/src/loops/for_loops_over_fallibles.rs +++ b/clippy_lints/src/loops/for_loops_over_fallibles.rs @@ -1,8 +1,7 @@ +use super::FOR_LOOPS_OVER_FALLIBLES; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; - -use super::FOR_LOOPS_OVER_FALLIBLES; -use crate::utils::span_lint_and_help; use rustc_hir::{Expr, Pat}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/loops/iter_next_loop.rs b/clippy_lints/src/loops/iter_next_loop.rs index d6b40fa9fa8..27a03562800 100644 --- a/clippy_lints/src/loops/iter_next_loop.rs +++ b/clippy_lints/src/loops/iter_next_loop.rs @@ -1,9 +1,10 @@ use super::ITER_NEXT_LOOP; +use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_span::sym; -use crate::utils::{is_trait_method, span_lint}; +use crate::utils::is_trait_method; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, expr: &Expr<'_>) -> bool { if is_trait_method(cx, arg, sym::Iterator) { diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 3d3ae6f3152..43580d6071a 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -1,6 +1,7 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; -use crate::utils::{is_ok_ctor, is_some_ctor, path_to_local_id, span_lint_and_then}; +use crate::utils::{is_ok_ctor, is_some_ctor, path_to_local_id}; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, StmtKind}; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index c9c25641160..ff68d136999 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -1,6 +1,7 @@ use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; use crate::utils::sugg::Sugg; -use crate::utils::{get_enclosing_block, higher, path_to_local, span_lint_and_sugg, sugg}; +use crate::utils::{get_enclosing_block, higher, path_to_local, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 3ae592950f1..175aee53a9a 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -1,5 +1,6 @@ use super::MUT_RANGE_BOUND; -use crate::utils::{higher, path_to_local, span_lint}; +use crate::utils::{higher, path_to_local}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BindingAnnotation, Expr, HirId, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 59f7b23af75..a3b731eefa0 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -1,6 +1,7 @@ use super::NEEDLESS_COLLECT; use crate::utils::sugg::Sugg; -use crate::utils::{is_trait_method, path_to_local_id, paths, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{is_trait_method, path_to_local_id, paths}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 674cb34c37b..ca679d7ebe1 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -1,9 +1,9 @@ use super::NEEDLESS_RANGE_LOOP; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - contains_name, higher, is_integer_const, match_trait_method, multispan_sugg, path_to_local_id, paths, - span_lint_and_then, sugg, SpanlessEq, + contains_name, higher, is_integer_const, match_trait_method, path_to_local_id, paths, sugg, SpanlessEq, }; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use if_chain::if_chain; diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 45e1001d755..82ec2635aeb 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -1,5 +1,5 @@ use super::NEVER_LOOP; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Stmt, StmtKind}; use rustc_lint::LateContext; use std::iter::{once, Iterator}; diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 255d6de4a36..849d7ec718c 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -1,5 +1,5 @@ use super::SAME_ITEM_PUSH; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 4f83191d919..172eb963ae3 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,5 +1,6 @@ use super::{get_span_of_entire_for_loop, SINGLE_ELEMENT_LOOP}; -use crate::utils::{single_segment_path, span_lint_and_sugg}; +use crate::utils::single_segment_path; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index 05e0a722563..a037a06de81 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -1,7 +1,7 @@ use super::WHILE_IMMUTABLE_CONDITION; use crate::consts::constant; -use crate::utils::span_lint_and_then; use crate::utils::usage::mutated_variables; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index dbd9126861f..ffe8c0c5494 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -1,5 +1,5 @@ use super::WHILE_LET_LOOP; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, StmtKind}; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index ccabe586c2b..29ad9e735cc 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -3,8 +3,8 @@ use super::WHILE_LET_ON_ITERATOR; use crate::utils::usage::mutated_variables; use crate::utils::{ get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, - span_lint_and_sugg, }; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use if_chain::if_chain; diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 637f10f6609..92f95645734 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg}; +use crate::utils::in_macro; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 5db2968e42c..6c0308cbd92 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -1,10 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_hir::{Crate, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{is_entrypoint_fn, is_no_std_crate, span_lint_and_help}; +use crate::utils::{is_entrypoint_fn, is_no_std_crate}; declare_clippy_lint! { /// **What it does:** Checks for recursion using the entrypoint. diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index ebc493c0f7e..1db5cf56962 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,6 @@ +use crate::utils::match_function_call; use crate::utils::paths::FUTURE_FROM_GENERATOR; -use crate::utils::{match_function_call, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 3896645ca7d..fd563bec769 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -1,8 +1,9 @@ use crate::{ map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF, - utils::{is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs, span_lint_and_sugg}, + utils::{is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs}, }; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use rustc_ast::util::parser::PREC_POSTFIX; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 0b8c049b466..705c1ec1859 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,4 +1,5 @@ -use crate::utils::{meets_msrv, span_lint_and_then}; +use crate::utils::meets_msrv; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index f436eccc0dc..a1e5c752f83 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_qpath, path_to_local_id, paths, span_lint_and_sugg}; +use crate::utils::{match_qpath, path_to_local_id, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 3bfca8bea40..bc4e255b03d 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,6 +1,7 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; -use crate::utils::{eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, span_lint_and_then}; +use crate::utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 7a4040539e3..0e030e0e261 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,6 +1,7 @@ use crate::consts::constant_simple; use crate::utils; use crate::utils::{path_to_local_id, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; @@ -112,7 +113,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { then { let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); - utils::span_lint_and_sugg( + span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, &format!("this pattern reimplements `{}`", case.unwrap_fn_path()), diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index e10d7647bcf..fd39052871b 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,5 +1,6 @@ use crate::utils::is_trait_method; -use crate::utils::{remove_blocks, span_lint_and_sugg}; +use crate::utils::remove_blocks; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 76fe8e776ea..a6a63961be5 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -1,5 +1,4 @@ -use crate::utils::span_lint_and_help; - +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 79570367ed9..84ec23c4e2f 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks, span_lint_and_sugg}; +use crate::utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 24bcc808585..3bd4a965765 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,4 +1,5 @@ -use crate::utils::{iter_input_pats, method_chain_args, span_lint_and_then}; +use crate::utils::{iter_input_pats, method_chain_args}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 57dcd8709b8..ccaa5e98c83 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 4ae1ce977f4..1aa09b82822 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,11 +2,13 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, multispan_sugg, - path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, remove_blocks, span_lint_and_help, - span_lint_and_note, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, + get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local, + path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, remove_blocks, strip_pat_refs, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::diagnostics::{ + multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, +}; use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use if_chain::if_chain; @@ -1614,7 +1616,8 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{is_trait_method, match_qpath, paths, span_lint_and_then}; + use crate::utils::{is_trait_method, match_qpath, paths}; + use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index fbdc0cdb2d8..85353d4cdde 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint_and_then}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::walk_ptrs_ty_depth; use if_chain::if_chain; diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index d34f9761e26..1a8cb82514b 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index bf3f6f7f830..87cb66a6770 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,5 @@ -use crate::utils::{ - in_macro, match_def_path, match_qpath, meets_msrv, paths, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, -}; +use crate::utils::{in_macro, match_def_path, match_qpath, meets_msrv, paths}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diagnostic_assoc_item; use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 99b3be67f18..7d6104ebb7f 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,8 +1,6 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; -use crate::utils::{ - in_macro, match_qpath, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, span_lint_and_sugg, - span_lint_and_then, visitors::find_all_ret_expressions, -}; +use crate::utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions}; +use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::match_type; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index f81e9a8c524..4f88f80a304 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 954d589a47e..d1c7789a241 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -1,4 +1,5 @@ -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 90ecb2382e7..b49ae42b12f 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,4 +1,5 @@ -use crate::utils::{paths, span_lint_and_sugg}; +use crate::utils::paths; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 9e96d571337..1c673c11d65 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, span_lint_and_sugg}; +use crate::utils::is_expn_of; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 37c41194b4a..64531b29ade 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 791fe3647cb..005c94a6018 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_expr, paths, span_lint_and_help}; +use crate::utils::{get_parent_expr, paths}; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/filter_flat_map.rs b/clippy_lints/src/methods/filter_flat_map.rs index 42f05aa0b3a..4820bb137c1 100644 --- a/clippy_lints/src/methods/filter_flat_map.rs +++ b/clippy_lints/src/methods/filter_flat_map.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_help}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 964c4903ed2..af91370df20 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, path_to_local_id, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{is_trait_method, path_to_local_id, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/filter_map_flat_map.rs b/clippy_lints/src/methods/filter_map_flat_map.rs index e113f3f71b1..5294ef97528 100644 --- a/clippy_lints/src/methods/filter_map_flat_map.rs +++ b/clippy_lints/src/methods/filter_map_flat_map.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_help}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 5f627b42abc..4461baf4f7c 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths, span_lint_and_sugg}; +use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/filter_map_map.rs b/clippy_lints/src/methods/filter_map_map.rs index 2e704c4c555..8f17350054b 100644 --- a/clippy_lints/src/methods/filter_map_map.rs +++ b/clippy_lints/src/methods/filter_map_map.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_help}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index ed75315b52c..8fbadd1d457 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, meets_msrv, span_lint, span_lint_and_sugg}; +use crate::utils::{is_trait_method, meets_msrv}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 097f9fdf2c4..af16ea19007 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint, span_lint_and_sugg}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 19ddceeccce..669ac1f743f 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, match_qpath, paths, span_lint_and_sugg}; +use crate::utils::{is_trait_method, match_qpath, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 9b46adaac58..5d0a07992c8 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, paths, span_lint_and_sugg, sugg}; +use crate::utils::{get_trait_def_id, paths, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index b9d34b402bb..ac855419d00 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, paths, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index a769493d11d..04461ad5c3a 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 19d05b5c693..56de7a8bc5e 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,5 +1,6 @@ use super::INEFFICIENT_TO_STRING; -use crate::utils::{match_def_path, paths, span_lint_and_then}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index e7c3a433fe1..c9bbfbc37eb 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -1,8 +1,9 @@ +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::{source_map::Span, sym}; -use crate::utils::{is_trait_method, span_lint_and_help}; +use crate::utils::is_trait_method; use super::INSPECT_FOR_EACH; diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index f28f082e6fc..a862b55e139 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::has_iter_method; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 1e1d3fdcf70..cd575c9cb02 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -1,5 +1,5 @@ use crate::methods::derefs_to_slice; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 0f393423b7d..bfd62ff1f0d 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{paths, span_lint_and_sugg}; +use crate::utils::paths; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index f79942576da..ce599682bbe 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -1,5 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, higher, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, higher}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 17600bb8153..2619793e1e2 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,6 +1,6 @@ use crate::methods::derefs_to_slice; use crate::methods::iter_nth_zero; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index 98ddfdfdf9c..f2b2dd8c097 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_trait_method, span_lint_and_sugg}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index d191ea0a831..6100613bcac 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_sugg}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 019a08f746e..51c1ab0484e 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_trait_method, span_lint}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index d090a35a3cf..0c8a002e359 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_qpath, span_lint_and_sugg}; +use crate::utils::match_qpath; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index 349b26b9d58..b59998fc8b4 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_sugg}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 56719b3cff2..6f5e723fbfb 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_sugg}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 96dbc7ddc63..8ef02b4a641 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,6 @@ +use crate::utils::meets_msrv; use crate::utils::usage::mutated_variables; -use crate::utils::{meets_msrv, span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 47617e4722e..af8fe7abd96 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -52,6 +52,7 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use if_chain::if_chain; @@ -69,8 +70,7 @@ use rustc_typeck::hir_ty_to_ty; use crate::utils::{ contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls, - method_chain_args, paths, return_ty, single_segment_path, span_lint, span_lint_and_help, span_lint_and_sugg, - SpanlessEq, + method_chain_args, paths, return_ty, single_segment_path, SpanlessEq, }; declare_clippy_lint! { diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index 2618d04b242..e6ce9cac397 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 6597e9f96a8..f921d7b16c0 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, span_lint_and_sugg}; +use crate::utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index eed71d02467..e8b057c2d74 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_qpath, paths, span_lint_and_sugg}; +use crate::utils::{match_qpath, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 398d8f13bd4..c6459648cd5 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, span_lint_and_then}; +use crate::utils::differing_macro_contexts; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 634feebe54a..1b43802a08e 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,5 +1,6 @@ use crate::utils::eager_or_lazy::is_lazyness_candidate; -use crate::utils::{contains_return, get_trait_def_id, last_path_segment, paths, span_lint_and_sugg}; +use crate::utils::{contains_return, get_trait_def_id, last_path_segment, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 6054579d988..18e1064b018 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_help, span_lint_and_sugg, strip_pat_refs}; +use crate::utils::{is_trait_method, strip_pat_refs}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index ff67564b39d..cd87d2c56b7 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,5 +1,5 @@ use crate::methods::get_hint_if_single_char_arg; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index 61cbc9d2f0a..12d6418d700 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -1,5 +1,5 @@ use crate::methods::get_hint_if_single_char_arg; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 18df90c1ab3..882703a987d 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,5 +1,5 @@ use crate::methods::get_hint_if_single_char_arg; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/skip_while_next.rs b/clippy_lints/src/methods/skip_while_next.rs index a9ff78c3260..8995226191b 100644 --- a/clippy_lints/src/methods/skip_while_next.rs +++ b/clippy_lints/src/methods/skip_while_next.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, span_lint_and_help}; +use crate::utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 1b26e8314af..d9b97168490 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -1,4 +1,5 @@ -use crate::utils::{method_chain_args, span_lint_and_sugg}; +use crate::utils::method_chain_args; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 0ffa71de30c..fd4651dd182 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -1,5 +1,6 @@ use crate::utils::usage::mutated_variables; -use crate::utils::{expr_or_init, is_trait_method, span_lint_and_help}; +use crate::utils::{expr_or_init, is_trait_method}; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 798b66192c8..071856c3ba6 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, match_qpath, paths, span_lint}; +use crate::utils::{match_def_path, match_qpath, paths}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 686874c0a24..670134c68f2 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,5 +1,6 @@ use crate::utils::usage::mutated_variables; -use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths, span_lint}; +use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 4d5cbdd619d..3ccde57de3f 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_trait_method, path_to_local_id, remove_blocks, span_lint_and_sugg, strip_pat_refs}; +use crate::utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 444abde3d0f..3874673bf9f 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,5 +1,5 @@ -use crate::utils::span_lint_and_sugg; use crate::utils::{eager_or_lazy, usage}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index efe43a6a952..2f5806115bd 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index c6d84aedc0a..13c95e33fef 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_parent_expr, match_trait_method, paths, span_lint_and_sugg}; +use crate::utils::{get_parent_expr, match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index c8bcad7be3e..b728d7d8d08 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -1,5 +1,5 @@ use crate::methods::SelfKind; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_lint::LateContext; use rustc_middle::ty::TyS; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index f1335726736..9f6a7c4db17 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 8d0c3b8e0fe..6a4e70e50af 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{match_def_path, match_trait_method, paths, span_lint}; +use crate::utils::{match_def_path, match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index f161054cc8c..03d07287005 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::implements_trait; use if_chain::if_chain; @@ -20,8 +21,7 @@ use crate::consts::{constant, Constant}; use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, - last_path_segment, match_qpath, span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then, unsext, - SpanlessEq, + last_path_segment, match_qpath, unsext, SpanlessEq, }; declare_clippy_lint! { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 6ec523498e1..3c6a7071c24 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{ BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 4cc20b8d38c..aba4accccb1 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,6 @@ use crate::utils::qualify_min_const_fn::is_min_const_fn; -use crate::utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, span_lint, trait_ref_of_method}; +use crate::utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::has_drop; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 6ec4c38d0f9..fd6f31faa94 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -5,7 +5,7 @@ // [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415 // -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_ast::attr; diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index da59c820999..dd4488f3f02 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index da3ae1d652f..1b00cf2c75d 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{sext, span_lint_and_then}; +use crate::utils::sext; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index c1773cef7a8..6eaeaebe781 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,6 +1,7 @@ //! lint on multiple versions of a crate being used -use crate::utils::{run_lints, span_lint}; +use crate::utils::run_lints; +use clippy_utils::diagnostics::span_lint; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Crate, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 908b7bb7ce0..39aec79734c 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method}; +use crate::utils::{match_def_path, paths, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TypeFoldable; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index d7239b328bb..c11ccc94890 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,4 +1,5 @@ -use crate::utils::{higher, span_lint}; +use crate::utils::higher; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs index e4a57661f97..b9ba74c7d02 100644 --- a/clippy_lints/src/mut_mutex_lock.rs +++ b/clippy_lints/src/mut_mutex_lock.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 3f0b765df15..0c09ddb8073 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::Subst; diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 9ac127abe0a..fb8895e08d0 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,4 +1,5 @@ -use crate::utils::{higher, is_direct_expn_of, span_lint}; +use crate::utils::{higher, is_direct_expn_of}; +use clippy_utils::diagnostics::span_lint; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 9f746ce2e1a..354e2c3fb74 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -2,7 +2,7 @@ //! //! This lint is **warn** by default -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 7687962bdd9..c62ff7323f3 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg}; +use crate::utils::in_macro; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 22adbdf09a6..4c67304d23e 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -3,7 +3,8 @@ //! This lint is **warn** by default use crate::utils::sugg::Sugg; -use crate::utils::{is_expn_of, parent_node_is_if_expr, span_lint, span_lint_and_sugg}; +use crate::utils::{is_expn_of, parent_node_is_if_expr}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index d8b574af1fe..72436b51dcb 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -2,7 +2,8 @@ //! //! This lint is **warn** by default -use crate::utils::{is_automatically_derived, span_lint_and_then}; +use crate::utils::is_automatically_derived; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 5ee71f25694..7fbffe04a3f 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 4ff90704207..91c97ef7c2a 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -33,6 +33,7 @@ //! ``` //! //! This lint is **warn** by default. +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -40,8 +41,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; -use crate::utils::span_lint_and_help; - declare_clippy_lint! { /// **What it does:** The lint checks for `if`-statements appearing in loops /// that contain a `continue` statement in either their main blocks or their diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 6f7a5d85480..fc8ee6cb8ef 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,5 +1,6 @@ use crate::utils::ptr::get_spans; -use crate::utils::{get_trait_def_id, is_self, multispan_sugg, paths, span_lint_and_then}; +use crate::utils::{get_trait_def_id, is_self, paths}; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index bcc39ff855c..ecf48d082af 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -140,7 +141,7 @@ fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner), }; - utils::span_lint_and_sugg( + span_lint_and_sugg( cx, NEEDLESS_QUESTION_MARK, entire_expr.span, diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 41cf541ecf5..e93de8a252a 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 67d49f06ad9..e291885d34d 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -5,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{self, paths, span_lint}; +use crate::utils::{self, paths}; declare_clippy_lint! { /// **What it does:** diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index ef7cc65cfcf..7b00879251f 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -5,7 +6,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{self, Constant}; -use crate::utils::span_lint; declare_clippy_lint! { /// **What it does:** Checks for multiplication by -1 as a form of negation. diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index de2899c3462..9fbb6b02742 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,6 +1,7 @@ use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then}; +use crate::utils::{get_trait_def_id, return_ty}; +use clippy_utils::diagnostics::span_lint_hir_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 7a7bc7a44cd..83953a16bc8 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; use rustc_errors::Applicability; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 8aebce67917..5db614497e3 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -4,6 +4,7 @@ use std::ptr; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -18,7 +19,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{in_constant, span_lint_and_then}; +use crate::utils::in_constant; use if_chain::if_chain; // FIXME: this is a correctness problem but there's no suitable diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 7c74b316018..52661416de6 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use rustc_ast::ast::{ Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind, }; diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 71e77932f7a..8e8aaa67afa 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,4 +1,5 @@ -use crate::utils::{paths, span_lint}; +use crate::utils::paths; +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::match_type; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index fd653044a1b..343159f9ae2 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_direct_expn_of, span_lint_and_help}; +use crate::utils::is_direct_expn_of; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 8a6d257848f..eab08a58320 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,7 +1,8 @@ use crate::utils; use crate::utils::eager_or_lazy; +use crate::utils::paths; use crate::utils::sugg::Sugg; -use crate::utils::{paths, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 3c041bac234..524b96921fe 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,4 +1,5 @@ -use crate::utils::{span_lint, SpanlessEq}; +use crate::utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 1821e2611ff..880951f3e3e 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,4 +1,5 @@ -use crate::utils::{find_macro_calls, return_ty, span_lint_and_then}; +use crate::utils::{find_macro_calls, return_ty}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 359620cc079..ad4ed831941 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_expn_of, match_panic_call, span_lint}; +use crate::utils::{is_expn_of, match_panic_call}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index aca1ed5ca65..06985cef4ff 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_automatically_derived, span_lint_hir}; +use crate::utils::is_automatically_derived; +use clippy_utils::diagnostics::span_lint_hir; use if_chain::if_chain; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 757ead2c24c..c14273840c4 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,6 +1,7 @@ use std::cmp; -use crate::utils::{is_self_ty, span_lint_and_sugg}; +use crate::utils::is_self_ty; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use if_chain::if_chain; diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 46533682d42..95ffae28d8c 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index 5539331d046..dd63cf99e42 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -1,4 +1,5 @@ -use crate::utils::{last_path_segment, span_lint_and_help}; +use crate::utils::last_path_segment; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{ intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind, QPath, Stmt, StmtKind, diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index fbe54e92ab9..9cf00c953b9 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index bfe8bf33f51..779eddcc170 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,7 +1,8 @@ //! Checks for usage of `&Vec[_]` and `&String`. use crate::utils::ptr::get_spans; -use crate::utils::{is_allowed, match_qpath, paths, span_lint, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{is_allowed, match_qpath, paths}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; use if_chain::if_chain; diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 4f83e370c5f..82408c639b1 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -1,4 +1,5 @@ use crate::utils; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; @@ -58,7 +59,7 @@ impl LateLintPass<'_> for PtrEq { if let Some(left_snip) = snippet_opt(cx, left_var.span); if let Some(right_snip) = snippet_opt(cx, right_var.span); then { - utils::span_lint_and_sugg( + span_lint_and_sugg( cx, PTR_EQ, expr.span, diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index b801defeb24..c04b4255256 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 43431425a43..c4686623487 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -9,7 +9,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use crate::utils::sugg::Sugg; -use crate::utils::{eq_expr_value, match_def_path, match_qpath, paths, span_lint_and_sugg}; +use crate::utils::{eq_expr_value, match_def_path, match_qpath, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for expressions that could be replaced by the question mark operator. diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 3ce8949bf8b..d476d95256f 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,4 +1,5 @@ use crate::consts::{constant, Constant}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; @@ -14,10 +15,7 @@ use rustc_span::symbol::Ident; use std::cmp::Ordering; use crate::utils::sugg::Sugg; -use crate::utils::{ - get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path, span_lint, span_lint_and_sugg, - span_lint_and_then, -}; +use crate::utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path}; use crate::utils::{higher, SpanlessEq}; declare_clippy_lint! { diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 84723acd034..3d799328bb5 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,4 +1,5 @@ -use crate::utils::{fn_has_unsatisfiable_preds, match_def_path, paths, span_lint_hir, span_lint_hir_and_then}; +use crate::utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; +use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth}; use if_chain::if_chain; diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 283e25553cf..2977a108d14 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,4 +1,4 @@ -use crate::utils::{span_lint, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 3d585cd27a3..061526c6f09 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{walk_expr, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 38dcf7a192c..fd11150bce2 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,4 +1,5 @@ -use crate::utils::{meets_msrv, span_lint_and_sugg}; +use crate::utils::meets_msrv; +use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index c876bae2303..e091095de13 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VisibilityKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 85ea91a387b..6da7b5fbcc8 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; @@ -7,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::{lint::in_external_macro, ty::TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_sugg; - declare_clippy_lint! { /// **What it does:** Checks for redundant slicing expressions which use the full range, and /// do not change the type. diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 1352a651723..da8339a795a 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,4 +1,5 @@ -use crate::utils::{meets_msrv, span_lint_and_then}; +use crate::utils::meets_msrv; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index cec6b06262b..452fef0694f 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -1,4 +1,5 @@ -use crate::utils::{last_path_segment, span_lint_and_sugg}; +use crate::utils::last_path_segment; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 31e834ac174..ec2acb6a0ab 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,5 +1,6 @@ +use crate::utils::in_macro; use crate::utils::sugg::Sugg; -use crate::utils::{in_macro, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 1edea613148..bfa21ba9c97 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,5 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index a88078c12a3..b39e9d5a78c 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{in_macro, span_lint_and_sugg}; +use crate::utils::in_macro; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index eb7fe403fd7..59d3c0ca5f0 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::Attribute; @@ -12,7 +13,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::sym; -use crate::utils::{fn_def_id, in_macro, match_qpath, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{fn_def_id, in_macro, match_qpath}; declare_clippy_lint! { /// **What it does:** Checks for `let`-bindings, which are subsequently diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs index e62b75de4ca..320d1a8dbe3 100644 --- a/clippy_lints/src/self_assignment.rs +++ b/clippy_lints/src/self_assignment.rs @@ -1,4 +1,5 @@ -use crate::utils::{eq_expr_value, span_lint}; +use crate::utils::eq_expr_value; +use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 695d7233af2..e43947025b9 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg, sugg}; +use crate::utils::{in_macro, sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_macro_callsite; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 90cf1b6c861..632715852c5 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, paths, span_lint}; +use crate::utils::{get_trait_def_id, paths}; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 4a8cacb31fd..8ef58b6d563 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,4 +1,5 @@ -use crate::utils::{contains_name, higher, iter_input_pats, span_lint_and_then}; +use crate::utils::{contains_name, higher, iter_input_pats}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_hir::intravisit::FnKind; use rustc_hir::{ diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 1fc4ff5c2e6..6d15a6c444e 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg}; +use crate::utils::in_macro; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 87e386baadc..8920d446b9c 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,7 +1,8 @@ //! Lint on use of `size_of` or `size_of_val` of T in an expression //! expecting a count of T -use crate::utils::{match_def_path, paths, span_lint_and_help}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::BinOpKind; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 96f6881556c..7f0f21084af 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,5 +1,6 @@ use crate::utils::sugg::Sugg; -use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq}; +use crate::utils::{get_enclosing_block, match_qpath, SpanlessEq}; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index 276a9338819..85e4bb806e7 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_slice_of_primitives, span_lint_and_then, sugg::Sugg}; +use crate::utils::{is_slice_of_primitives, sugg::Sugg}; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index ce93ab23b2f..626166f9008 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,8 +1,6 @@ use crate::utils::SpanlessEq; -use crate::utils::{ - get_parent_expr, is_allowed, match_function_call, method_calls, paths, span_lint, span_lint_and_help, - span_lint_and_sugg, -}; +use crate::utils::{get_parent_expr, is_allowed, match_function_call, method_calls, paths}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 3bdd9b7e4cb..364c99adc69 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,5 +1,5 @@ use crate::utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; use if_chain::if_chain; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 0b7d08cb164..ef14b6c5136 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method}; +use crate::utils::{get_trait_def_id, trait_ref_of_method}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index d4a495f3ea9..83fe3c49959 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,5 +1,6 @@ use crate::utils::sugg::Sugg; -use crate::utils::{differing_macro_contexts, eq_expr_value, span_lint_and_then}; +use crate::utils::{differing_macro_contexts, eq_expr_value}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index 74ccd9235de..88bd2feaadd 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index fb891866364..75a13cb9187 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_adjusted, span_lint}; +use crate::utils::is_adjusted; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 940273afc57..abc9b2fe88e 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, span_lint_and_sugg}; +use crate::utils::match_def_path; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index 84ec2aa18ab..42605c01089 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths, span_lint}; +use crate::utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index d3314271c21..cfcc8da9910 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_help, SpanlessHash}; +use crate::utils::{in_macro, SpanlessHash}; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/transmute/crosspointer_transmute.rs b/clippy_lints/src/transmute/crosspointer_transmute.rs index ce87defaa94..25d0543c861 100644 --- a/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -1,5 +1,5 @@ use super::CROSSPOINTER_TRANSMUTE; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 562d880e39a..f61b5362b5a 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_FLOAT_TO_INT; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_ast as ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/transmute/transmute_int_to_bool.rs b/clippy_lints/src/transmute/transmute_int_to_bool.rs index 5b609f906a3..ebdd1eba744 100644 --- a/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_INT_TO_BOOL; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 29d2450618a..afecfc3d701 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_INT_TO_CHAR; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index f83fba8966a..c762a7ab885 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_INT_TO_FLOAT; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index f4e60a3020c..820c56a215e 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_PTR_TO_PTR; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index f5dbbbe33bc..049210e555c 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,6 +1,7 @@ use super::utils::get_type_snippet; use super::TRANSMUTE_PTR_TO_REF; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, QPath}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 4780eb9b14e..993ef8698f8 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,5 +1,6 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; -use crate::utils::{span_lint_and_sugg, span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index dea896622f1..da7d1016d97 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,6 +1,7 @@ use super::utils::can_be_expressed_as_pointer_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; -use crate::utils::{span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 503c5e0ff38..9bea88be7da 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,6 +1,7 @@ use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; -use crate::utils::{match_def_path, paths, span_lint}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 83441514af0..29ffe03b673 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -1,5 +1,6 @@ use super::USELESS_TRANSMUTE; -use crate::utils::{span_lint, span_lint_and_then, sugg}; +use crate::utils::sugg; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/wrong_transmute.rs b/clippy_lints/src/transmute/wrong_transmute.rs index d6d77f2c834..2118f3d6950 100644 --- a/clippy_lints/src/transmute/wrong_transmute.rs +++ b/clippy_lints/src/transmute/wrong_transmute.rs @@ -1,5 +1,5 @@ use super::WRONG_TRANSMUTE; -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 2ba2b646f00..3a2b1359a54 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,5 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{match_qpath, paths, span_lint}; +use crate::utils::{match_qpath, paths}; +use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index e356add8e9d..1fce03b4f47 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths, span_lint_and_sugg}; +use crate::utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 01aeea7a67f..eab81b1e246 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_path, paths, span_lint_and_sugg}; +use crate::utils::{match_path, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/types/box_vec.rs b/clippy_lints/src/types/box_vec.rs index 6aa98e435e1..6d04a47a5c8 100644 --- a/clippy_lints/src/types/box_vec.rs +++ b/clippy_lints/src/types/box_vec.rs @@ -1,8 +1,9 @@ +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{is_ty_param_diagnostic_item, span_lint_and_help}; +use crate::utils::is_ty_param_diagnostic_item; use super::BOX_VEC; diff --git a/clippy_lints/src/types/linked_list.rs b/clippy_lints/src/types/linked_list.rs index 47eb4ede4e4..e9e1995f6a5 100644 --- a/clippy_lints/src/types/linked_list.rs +++ b/clippy_lints/src/types/linked_list.rs @@ -1,7 +1,8 @@ +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{self as hir, def_id::DefId}; use rustc_lint::LateContext; -use crate::utils::{match_def_path, paths, span_lint_and_help}; +use crate::utils::{match_def_path, paths}; use super::LINKEDLIST; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 279a971318c..ac4fe502a7a 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -13,6 +13,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; +use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_help, span_lint_and_then}; use clippy_utils::source::{indent_of, reindent_multiline, snippet, snippet_opt, snippet_with_macro_callsite}; use clippy_utils::ty::{is_isize_or_usize, is_type_diagnostic_item}; use if_chain::if_chain; @@ -38,10 +39,7 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, int_bits, match_path, multispan_sugg, sext, span_lint, - span_lint_and_help, span_lint_and_then, unsext, -}; +use crate::utils::{clip, comparisons, differing_macro_contexts, higher, int_bits, match_path, sext, unsext}; declare_clippy_lint! { /// **What it does:** Checks for use of `Box>` anywhere in the code. diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index dc5db963b4e..79c5a32de2c 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -1,8 +1,9 @@ +use clippy_utils::diagnostics::span_lint; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{is_ty_param_diagnostic_item, span_lint}; +use crate::utils::is_ty_param_diagnostic_item; use super::OPTION_OPTION; diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 0ace1807535..d5fc23f2e39 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -1,10 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, span_lint_and_sugg}; +use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item}; use super::RC_BUFFER; diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index c6f6a2f6564..71c014f96f7 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -1,10 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item, span_lint_and_sugg}; +use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item}; use super::{utils, REDUNDANT_ALLOCATION}; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 6f45442b9ba..8cedb0ede2b 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; @@ -8,7 +9,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{last_path_segment, span_lint_and_sugg}; +use crate::utils::last_path_segment; use super::VEC_BOX; diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index 8c34ca16e6f..943573a2b53 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_function_call, paths, span_lint_and_help}; +use crate::utils::{match_function_call, paths}; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_lang_item; use rustc_hir::{lang_items, Expr}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index e44fec7ad8e..c37bbf297f8 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_allowed, span_lint_and_sugg}; +use crate::utils::is_allowed; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index c6ae8b9b598..d0456347f8a 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -1,4 +1,5 @@ -use crate::utils::{get_trait_def_id, paths, span_lint, span_lint_and_help}; +use crate::utils::{get_trait_def_id, paths}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, StmtKind}; diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 9582c162e77..2c51a8556d9 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; +use crate::utils::{match_def_path, paths}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 7e385b00646..aa83f6a74be 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,5 @@ -use crate::utils; use crate::utils::sugg::Sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -233,7 +233,7 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { impl LateLintPass<'_> for UnnecessarySortBy { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { match detect_lint(cx, expr) { - Some(LintTrigger::SortByKey(trigger)) => utils::span_lint_and_sugg( + Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( cx, UNNECESSARY_SORT_BY, expr.span, @@ -256,7 +256,7 @@ impl LateLintPass<'_> for UnnecessarySortBy { Applicability::MachineApplicable }, ), - Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg( + Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( cx, UNNECESSARY_SORT_BY, expr.span, diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 01497de3211..cb20192b683 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,5 @@ -use crate::utils::{ - contains_return, in_macro, match_qpath, paths, return_ty, span_lint_and_then, visitors::find_all_ret_expressions, -}; +use crate::utils::{contains_return, in_macro, match_qpath, paths, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 7f4f16f8faf..42ff1809ff4 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,7 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; -use crate::utils::{over, span_lint_and_then}; +use crate::utils::over; +use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 154082a0fdb..16ad9d2dfd3 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 43166d26787..31fd61f99f2 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,4 +1,5 @@ -use crate::utils::{is_try, match_trait_method, paths, span_lint}; +use crate::utils::{is_try, match_trait_method, paths}; +use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 812482cf5cf..4642bf07c45 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,9 +1,9 @@ +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::span_lint_and_help; use crate::utils::visitors::LocalUsedVisitor; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index a90d26fc95c..c45b851211c 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 43b5f138a42..75b2f2da602 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,4 +1,5 @@ -use crate::utils::{differing_macro_contexts, span_lint_and_then, usage::is_potentially_mutated}; +use crate::utils::{differing_macro_contexts, usage::is_potentially_mutated}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 6a8f8211566..a85f3ce5c9c 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,4 +1,5 @@ -use crate::utils::{method_chain_args, return_ty, span_lint_and_then}; +use crate::utils::{method_chain_args, return_ty}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 0470e1dbbb8..7ce9aa13184 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{Item, ItemKind, Variant}; @@ -81,7 +81,7 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) { // assume that two-letter words are some kind of valid abbreviation like FP for false positive // (and don't warn) if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2) - // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive + // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive // upper-case-acronyms-aggressive config option enabled || (be_aggressive && ident != &corrected) { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index de7eb42d56d..9a42c833470 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,7 +1,7 @@ +use crate::utils::{in_macro, meets_msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; - -use crate::utils::{in_macro, meets_msrv, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index e6b4fde560f..1eb152daac8 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,7 +1,6 @@ use crate::utils::sugg::Sugg; -use crate::utils::{ - get_parent_expr, match_def_path, match_trait_method, paths, span_lint_and_help, span_lint_and_sugg, -}; +use crate::utils::{get_parent_expr, match_def_path, match_trait_method, paths}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 04b8d9ee2c7..a566362ae78 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,8 +1,7 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{ - is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, span_lint, - span_lint_and_help, span_lint_and_sugg, SpanlessEq, -}; +use crate::utils::{is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq}; + +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use if_chain::if_chain; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index cd09a5b53e0..9e142413365 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,6 +1,7 @@ use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; -use crate::utils::{higher, span_lint_and_sugg}; +use crate::utils::higher; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use if_chain::if_chain; diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 4ad787ecf66..3ef55a82a17 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,4 +1,5 @@ -use crate::utils::{match_def_path, path_to_local, path_to_local_id, paths, span_lint_and_sugg}; +use crate::utils::{match_def_path, path_to_local, path_to_local_id, paths}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index d2494b321ef..9a2fb1414a1 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 079a4279c60..01dc54dc5fd 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -1,4 +1,5 @@ -use crate::utils::{paths, span_lint_and_help}; +use crate::utils::paths; +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index cd1864f461d..8f96b962279 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -1,4 +1,5 @@ -use crate::utils::{run_lints, span_lint}; +use crate::utils::run_lints; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index e12ca49fd4c..424ca2a4c2f 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,4 +1,5 @@ -use crate::utils::{in_macro, span_lint_and_sugg}; +use crate::utils::in_macro; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index f2fef73a641..fd3e5a7ce91 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::ops::Range; -use crate::utils::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle}; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 11d96e15ff1..3b4890ad560 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,5 +1,5 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index ab27b60cfa4..82466da6862 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; @@ -8,7 +9,7 @@ use rustc_span::sym; use rustc_target::abi::LayoutOf as _; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{paths, span_lint_and_help}; +use crate::utils::paths; declare_clippy_lint! { /// **What it does:** Checks for maps with zero-sized value types anywhere in the code. diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index d895d798b5e..d3cf2a34709 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -33,7 +33,7 @@ pub mod attrs; pub mod camel_case; pub mod comparisons; pub mod consts; -mod diagnostics; +pub mod diagnostics; pub mod eager_or_lazy; pub mod higher; mod hir_utils; @@ -48,7 +48,6 @@ pub mod usage; pub mod visitors; pub use self::attrs::*; -pub use self::diagnostics::*; pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; use std::collections::hash_map::Entry; -- cgit 1.4.1-3-g733a5 From 0743e841f07b7c41f65187fbf71f90bb5dc71982 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 16 Mar 2021 11:06:34 -0500 Subject: Don't re-export clippy_utils::* --- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/assign_ops.rs | 6 +++--- clippy_lints/src/atomic_ordering.rs | 2 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/blocks_in_if_conditions.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/cargo_common_metadata.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 3 +-- clippy_lints/src/casts/cast_possible_truncation.rs | 3 +-- clippy_lints/src/casts/cast_ptr_alignment.rs | 6 ++---- clippy_lints/src/casts/cast_sign_loss.rs | 10 ++++------ clippy_lints/src/casts/mod.rs | 3 +-- clippy_lints/src/casts/ptr_as_ptr.rs | 10 ++++------ clippy_lints/src/casts/unnecessary_cast.rs | 3 +-- clippy_lints/src/checked_conversions.rs | 3 +-- clippy_lints/src/cognitive_complexity.rs | 3 +-- clippy_lints/src/collapsible_if.rs | 3 +-- clippy_lints/src/collapsible_match.rs | 4 ++-- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 4 ++-- clippy_lints/src/create_dir.rs | 2 +- clippy_lints/src/default.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/derive.rs | 4 ++-- clippy_lints/src/disallowed_method.rs | 2 +- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/double_comparison.rs | 3 +-- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/duration_subsec.rs | 2 +- clippy_lints/src/entry.rs | 4 ++-- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/eta_reduction.rs | 3 +-- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/excessive_bools.rs | 2 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/float_equality_without_abs.rs | 2 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format.rs | 4 ++-- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/from_over_into.rs | 4 ++-- clippy_lints/src/from_str_radix_10.rs | 3 +-- clippy_lints/src/functions.rs | 8 ++++---- clippy_lints/src/future_not_send.rs | 4 ++-- clippy_lints/src/get_last_with_len.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/if_let_some_result.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 10 +++++----- clippy_lints/src/implicit_return.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/infinite_iter.rs | 3 +-- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/inherent_to_string.rs | 3 +-- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/let_underscore.rs | 3 +-- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/literal_representation.rs | 6 +++--- clippy_lints/src/loops/empty_loop.rs | 2 +- clippy_lints/src/loops/explicit_counter_loop.rs | 2 +- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/for_kv_map.rs | 4 ++-- clippy_lints/src/loops/iter_next_loop.rs | 3 +-- clippy_lints/src/loops/manual_flatten.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 4 ++-- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/loops/needless_collect.rs | 4 ++-- clippy_lints/src/loops/needless_range_loop.rs | 8 ++++---- clippy_lints/src/loops/single_element_loop.rs | 2 +- clippy_lints/src/loops/utils.rs | 2 +- clippy_lints/src/loops/while_immutable_condition.rs | 2 +- clippy_lints/src/loops/while_let_on_iterator.rs | 8 ++++---- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/main_recursion.rs | 3 +-- clippy_lints/src/manual_async_fn.rs | 4 ++-- clippy_lints/src/manual_map.rs | 7 ++----- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_ok_or.rs | 2 +- clippy_lints/src/manual_strip.rs | 4 ++-- clippy_lints/src/manual_unwrap_or.rs | 14 +++++++------- clippy_lints/src/map_clone.rs | 4 ++-- clippy_lints/src/map_identity.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches.rs | 16 ++++++++-------- clippy_lints/src/mem_discriminant.rs | 2 +- clippy_lints/src/mem_forget.rs | 2 +- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 2 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 2 +- clippy_lints/src/methods/filetype_is_file.rs | 2 +- clippy_lints/src/methods/filter_flat_map.rs | 2 +- clippy_lints/src/methods/filter_map.rs | 2 +- clippy_lints/src/methods/filter_map_flat_map.rs | 2 +- clippy_lints/src/methods/filter_map_identity.rs | 2 +- clippy_lints/src/methods/filter_map_map.rs | 2 +- clippy_lints/src/methods/filter_map_next.rs | 2 +- clippy_lints/src/methods/filter_next.rs | 2 +- clippy_lints/src/methods/flat_map_identity.rs | 2 +- .../src/methods/from_iter_instead_of_collect.rs | 2 +- clippy_lints/src/methods/get_unwrap.rs | 2 +- clippy_lints/src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/inspect_for_each.rs | 3 +-- clippy_lints/src/methods/into_iter_on_ref.rs | 2 +- clippy_lints/src/methods/iter_count.rs | 2 +- clippy_lints/src/methods/iter_next_slice.rs | 2 +- clippy_lints/src/methods/iter_nth_zero.rs | 2 +- clippy_lints/src/methods/iter_skip_next.rs | 2 +- clippy_lints/src/methods/iterator_step_by_zero.rs | 2 +- .../src/methods/manual_saturating_arithmetic.rs | 2 +- clippy_lints/src/methods/map_collect_result_unit.rs | 2 +- clippy_lints/src/methods/map_flatten.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 4 ++-- clippy_lints/src/methods/mod.rs | 9 ++++----- clippy_lints/src/methods/option_as_ref_deref.rs | 2 +- clippy_lints/src/methods/option_map_or_none.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 4 ++-- clippy_lints/src/methods/search_is_some.rs | 2 +- clippy_lints/src/methods/skip_while_next.rs | 2 +- clippy_lints/src/methods/string_extend_chars.rs | 2 +- clippy_lints/src/methods/suspicious_map.rs | 4 ++-- clippy_lints/src/methods/uninit_assumed_init.rs | 2 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 7 +++---- clippy_lints/src/methods/unnecessary_fold.rs | 2 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/methods/useless_asref.rs | 2 +- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 4 ++-- clippy_lints/src/missing_const_for_fn.rs | 4 ++-- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/multiple_crate_versions.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 4 ++-- clippy_lints/src/needless_borrow.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_lints/src/needless_question_mark.rs | 11 +++++------ clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 5 ++--- clippy_lints/src/new_without_default.rs | 6 +++--- clippy_lints/src/non_copy_const.rs | 5 ++--- clippy_lints/src/open_options.rs | 2 +- clippy_lints/src/option_env_unwrap.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 19 +++++++++---------- clippy_lints/src/overflow_check_conditional.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/partialeq_ne_impl.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 2 +- clippy_lints/src/ptr.rs | 4 ++-- clippy_lints/src/ptr_eq.rs | 4 ++-- clippy_lints/src/question_mark.rs | 7 +++---- clippy_lints/src/ranges.rs | 7 +++---- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/ref_option_ref.rs | 2 +- clippy_lints/src/reference.rs | 4 ++-- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/repeat_once.rs | 2 +- clippy_lints/src/returns.rs | 3 +-- clippy_lints/src/self_assignment.rs | 2 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 2 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/single_component_path_imports.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- clippy_lints/src/slow_vector_initialization.rs | 4 ++-- clippy_lints/src/stable_sort_primitive.rs | 4 +--- clippy_lints/src/strings.rs | 4 ++-- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 4 ++-- clippy_lints/src/swap.rs | 4 ++-- clippy_lints/src/temporary_assignment.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/to_string_in_display.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/transmute/transmute_float_to_int.rs | 2 +- clippy_lints/src/transmute/transmute_int_to_bool.rs | 2 +- clippy_lints/src/transmute/transmute_int_to_char.rs | 2 +- clippy_lints/src/transmute/transmute_int_to_float.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ptr.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 2 +- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 2 +- .../transmute/transmutes_expressible_as_ptr_casts.rs | 2 +- .../src/transmute/unsound_collection_transmute.rs | 2 +- clippy_lints/src/transmute/useless_transmute.rs | 2 +- clippy_lints/src/transmute/utils.rs | 2 +- clippy_lints/src/transmuting_null.rs | 2 +- clippy_lints/src/try_err.rs | 2 +- clippy_lints/src/types/borrowed_box.rs | 2 +- clippy_lints/src/types/box_vec.rs | 3 +-- clippy_lints/src/types/linked_list.rs | 3 +-- clippy_lints/src/types/mod.rs | 8 ++++---- clippy_lints/src/types/option_option.rs | 3 +-- clippy_lints/src/types/rc_buffer.rs | 3 +-- clippy_lints/src/types/redundant_allocation.rs | 3 +-- clippy_lints/src/types/utils.rs | 6 ++---- clippy_lints/src/types/vec_box.rs | 3 +-- clippy_lints/src/undropped_manually_drops.rs | 2 +- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/let_unit_value.rs | 7 +++---- clippy_lints/src/unit_types/unit_arg.rs | 8 +++----- clippy_lints/src/unit_types/unit_cmp.rs | 3 +-- clippy_lints/src/unnamed_address.rs | 2 +- clippy_lints/src/unnecessary_sort_by.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 4 ++-- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_lints/src/unused_self.rs | 3 +-- clippy_lints/src/unused_unit.rs | 3 +-- clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/useless_conversion.rs | 4 ++-- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/inspector.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 3 +-- clippy_lints/src/utils/mod.rs | 2 -- clippy_lints/src/vec.rs | 2 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/vec_resize_to_zero.rs | 7 +++---- clippy_lints/src/verbose_file_reads.rs | 2 +- clippy_lints/src/wildcard_dependencies.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 3 +-- 243 files changed, 344 insertions(+), 399 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index bae4d4957a9..16905781c56 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,7 +1,7 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; +use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 8581e176e0c..5b8fb9b436a 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,8 +1,8 @@ -use crate::utils::{eq_expr_value, get_trait_def_id, trait_ref_of_method}; -use crate::utils::{higher, sugg}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::{eq_expr_value, get_trait_def_id, trait_ref_of_method}; +use clippy_utils::{higher, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps { $($trait_name:ident),+) => { match $op { $(hir::BinOpKind::$trait_name => { - let [krate, module] = crate::utils::paths::OPS_MODULE; + let [krate, module] = clippy_utils::paths::OPS_MODULE; let path: [&str; 3] = [krate, module, concat!(stringify!($trait_name), "Assign")]; let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) { trait_id diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 231e74e16c0..dfb18199325 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -1,5 +1,5 @@ -use crate::utils::match_def_path; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::match_def_path; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 6be6722375d..f805f716e6b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,7 +1,7 @@ //! checks for attributes -use crate::utils::match_panic_def_id; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::match_panic_def_id; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 3a3296c2c3d..68eee0520b3 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,5 +1,5 @@ -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{match_def_path, paths}; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 2b8400344f5..f7daf3dab49 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::sugg::Sugg; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 343c4821c56..badcf8d2a43 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,7 +1,7 @@ -use crate::utils::{differing_macro_contexts, get_parent_expr}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::{differing_macro_contexts, get_parent_expr}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 1303613b8c4..58d9aa9c005 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,7 +1,7 @@ -use crate::utils::{eq_expr_value, get_trait_def_id, in_macro, paths}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{eq_expr_value, get_trait_def_id, in_macro, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index c1ca787c1e5..846ac08e93a 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,7 +1,7 @@ -use crate::utils::{contains_name, get_pat_name, paths, single_segment_path}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; +use clippy_utils::{contains_name, get_pat_name, paths, single_segment_path}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index f0ef482164a..fce5c559672 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -2,8 +2,8 @@ use std::path::PathBuf; -use crate::utils::run_lints; use clippy_utils::diagnostics::span_lint; +use clippy_utils::run_lints; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 4b660188d82..869deecfbd5 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_constant; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; @@ -6,8 +7,6 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use crate::utils::in_constant; - use super::{utils, CAST_LOSSLESS}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 75d7c55b637..833ad122e0d 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,10 +1,9 @@ +use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use clippy_utils::diagnostics::span_lint; - use super::{utils, CAST_POSSIBLE_TRUNCATION}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 6a45ec61c54..5208156ffd2 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,14 +1,12 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_hir_ty_cfg_dependant; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; -use if_chain::if_chain; - -use crate::utils::is_hir_ty_cfg_dependant; - use super::CAST_PTR_ALIGNMENT; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 2965a840a82..bf722d0a3f4 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,13 +1,11 @@ +use crate::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{method_chain_args, sext}; +use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use if_chain::if_chain; - -use crate::consts::{constant, Constant}; -use crate::utils::{method_chain_args, sext}; -use clippy_utils::diagnostics::span_lint; - use super::CAST_SIGN_LOSS; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index b726bd75f1d..d9e172c01a7 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -12,14 +12,13 @@ mod ptr_as_ptr; mod unnecessary_cast; mod utils; +use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::is_hir_ty_cfg_dependant; - declare_clippy_lint! { /// **What it does:** Checks for casts from any numerical to a float type where /// the receiving type cannot store all values from the original type without diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 2c25f865cb8..9113e5a0920 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,17 +1,15 @@ use std::borrow::Cow; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::meets_msrv; +use clippy_utils::sugg::Sugg; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, TypeAndMut}; use rustc_semver::RustcVersion; -use if_chain::if_chain; - -use crate::utils::meets_msrv; -use crate::utils::sugg::Sugg; -use clippy_utils::diagnostics::span_lint_and_sugg; - use super::PTR_AS_PTR; const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0); diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index a84e658024a..9ed359922fd 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::{LitFloatType, LitIntType, LitKind}; @@ -8,8 +9,6 @@ use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; -use crate::utils::numeric_literal::NumericLiteral; - use super::UNNECESSARY_CAST; pub(super) fn check( diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 8b62e315e04..ed46cac493a 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{meets_msrv, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -11,8 +12,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{meets_msrv, SpanlessEq}; - const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); declare_clippy_lint! { diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 8134f3af3ef..4cc542f723c 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,6 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::LimitStack; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; @@ -12,8 +13,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; -use crate::utils::LimitStack; - declare_clippy_lint! { /// **What it does:** Checks for methods with high cognitive complexity. /// diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index dbe70f90732..dae5c86bd44 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -14,14 +14,13 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet_block, snippet_block_with_applicability}; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::sugg::Sugg; - declare_clippy_lint! { /// **What it does:** Checks for nested `if` statements which can be collapsed /// by `&&`-combining their conditions. diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 5ff2518bd94..e2b3686ddf0 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -1,6 +1,6 @@ -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{path_to_local, SpanlessEq}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{path_to_local, SpanlessEq}; use if_chain::if_chain; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp}; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 5411905791c..d601cb7c224 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,6 @@ -use crate::utils::{get_trait_def_id, if_sequence, parent_node_is_if_expr, paths, SpanlessEq}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, if_sequence, parent_node_is_if_expr, paths, SpanlessEq}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f86f0da6d6f..46093a16571 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,6 +1,6 @@ -use crate::utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash}; -use crate::utils::{get_parent_expr, if_sequence}; use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::{get_parent_expr, if_sequence}; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 01ca2837a99..ac890c90c97 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,6 +1,6 @@ -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 0b074c088d4..d046e894792 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,6 +1,6 @@ -use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 62ec2f8ce48..1415f8e235a 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ -use crate::utils::{get_parent_node, in_macro, is_allowed}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::peel_mid_ty_refs; +use clippy_utils::{get_parent_node, in_macro, is_allowed}; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a7f2106e357..834136f910d 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,7 +1,7 @@ -use crate::utils::paths; -use crate::utils::{get_trait_def_id, is_allowed, is_automatically_derived, match_def_path}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; +use clippy_utils::paths; use clippy_utils::ty::is_copy; +use clippy_utils::{get_trait_def_id, is_allowed, is_automatically_derived, match_def_path}; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs index 16023bc53b0..ded0a0fff54 100644 --- a/clippy_lints/src/disallowed_method.rs +++ b/clippy_lints/src/disallowed_method.rs @@ -1,5 +1,5 @@ -use crate::utils::fn_def_id; use clippy_utils::diagnostics::span_lint; +use clippy_utils::fn_def_id; use rustc_data_structures::fx::FxHashSet; use rustc_hir::Expr; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index d9952325c4b..5fa278b2897 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,6 +1,6 @@ -use crate::utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind}; diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 549720feb2d..1d291565ec1 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,6 +1,7 @@ //! Lint on unnecessary double comparisons. Some examples: use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eq_expr_value; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -8,8 +9,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::utils::eq_expr_value; - declare_clippy_lint! { /// **What it does:** Checks for double comparisons that could be simplified to a single expression. /// diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index fe86adcec45..7e7ec017bbb 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,6 +1,6 @@ -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 40c75f568ae..746c1f6df91 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -8,8 +8,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use crate::consts::{constant, Constant}; -use crate::utils::paths; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; declare_clippy_lint! { /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index cc774831491..25eb048448c 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,8 +1,8 @@ -use crate::utils::SpanlessEq; -use crate::utils::{get_item_name, paths}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::SpanlessEq; +use clippy_utils::{get_item_name, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index d2d8acb443b..0ecc0bc3eb6 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,6 +1,6 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use crate::utils::camel_case; +use clippy_utils::camel_case; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 1b2f66fb628..6d7046ac8b7 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,7 +1,7 @@ -use crate::utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of}; use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; +use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 2557e9f2796..99253555a95 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -3,6 +3,7 @@ use clippy_utils::higher; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, type_is_unsafe_function}; +use clippy_utils::{is_adjusted, iter_input_pats}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; @@ -11,8 +12,6 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_adjusted, iter_input_pats}; - declare_clippy_lint! { /// **What it does:** Checks for closures which just call another function where /// the function can be called directly. `unsafe` functions or calls where types diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 3711ba4a7ee..5d5b67de843 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,5 +1,5 @@ -use crate::utils::{get_parent_expr, path_to_local, path_to_local_id}; use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 683e0435351..6c9652fd87d 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -1,5 +1,5 @@ -use crate::utils::{attr_by_name, in_macro, match_path_ast}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{attr_by_name, in_macro, match_path_ast}; use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index adfb644b199..635b6d83eab 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_entrypoint_fn, match_def_path, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_entrypoint_fn, match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 0861cba4675..4146b7baa10 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_expn_of, match_function_call, paths}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 5efe465a667..52a5a7acf0d 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,6 +1,6 @@ -use crate::utils::{is_expn_of, match_panic_def_id, method_chain_args}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index b3593d328cc..0c59db360f9 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -1,5 +1,5 @@ -use crate::utils::{match_def_path, paths, sugg}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{match_def_path, paths, sugg}; use if_chain::if_chain; use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 6446fe62a64..1ca5c685a75 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -1,5 +1,5 @@ -use crate::utils::numeric_literal; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::numeric_literal; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 8b53384ecbd..0b5f0379ce6 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,8 +2,8 @@ use crate::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use crate::utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index db27225707d..a33f987b423 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,8 +1,8 @@ -use crate::utils::paths; -use crate::utils::{is_expn_of, last_path_segment, match_def_path, match_function_call}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_expn_of, last_path_segment, match_def_path, match_function_call}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 4dadd2ba936..b10e83c0ea8 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,5 +1,5 @@ -use crate::utils::differing_macro_contexts; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; +use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 5eea4d14759..e5ec245e502 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,6 +1,6 @@ -use crate::utils::paths::INTO; -use crate::utils::{match_def_path, meets_msrv}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::paths::INTO; +use clippy_utils::{match_def_path, meets_msrv}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index b9a44f26381..3da5bc95b6d 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -8,8 +9,6 @@ use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; -use crate::utils::sugg::Sugg; - declare_clippy_lint! { /// **What it does:** /// Checks for function invocations of the form `primitive::from_str_radix(s, 10)` diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 37288d7a0b2..730492fc7e3 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,10 +1,10 @@ -use crate::utils::{ - attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr, - path_to_local, return_ty, trait_ref_of_method, -}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, type_is_unsafe_function}; +use clippy_utils::{ + attr_by_name, attrs::is_proc_macro, is_trait_impl_item, iter_input_pats, match_def_path, must_use_attr, + path_to_local, return_ty, trait_ref_of_method, +}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 36960e7f51b..04730ace887 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -1,5 +1,5 @@ -use crate::utils; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::return_ty; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let FnKind::Closure = kind { return; } - let ret_ty = utils::return_ty(cx, hir_id); + let ret_ty = return_ty(cx, hir_id); if let Opaque(id, subst) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(id); let mut is_future = false; diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 6f14ede0ecb..cbcef567c53 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -1,9 +1,9 @@ //! lint on using `x.get(x.len() - 1)` instead of `x.last()` -use crate::utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 385ea020328..8bed5e1bf64 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -7,8 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::{clip, unsext}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{clip, unsext}; declare_clippy_lint! { /// **What it does:** Checks for identity operations, e.g., `x + 0`. diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index c2ec8b3ffd1..4aab43256bf 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,6 +1,6 @@ -use crate::utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_hir::intravisit::{self as visit, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, MatchSource}; diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 59094d1147a..6e9280c8c7e 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,5 +1,5 @@ -use crate::utils::method_chain_args; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index c4e87300b7b..0b5bf060d4c 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ -use crate::utils; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::{match_qpath, meets_msrv, parent_node_is_if_expr}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -58,7 +58,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl LateLintPass<'_> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { - if !utils::meets_msrv(self.msrv.as_ref(), &IF_THEN_SOME_ELSE_NONE_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &IF_THEN_SOME_ELSE_NONE_MSRV) { return; } @@ -67,7 +67,7 @@ impl LateLintPass<'_> for IfThenSomeElseNone { } // We only care about the top-most `if` in the chain - if utils::parent_node_is_if_expr(expr, cx) { + if parent_node_is_if_expr(expr, cx) { return; } @@ -77,12 +77,12 @@ impl LateLintPass<'_> for IfThenSomeElseNone { if let Some(ref then_expr) = then_block.expr; if let ExprKind::Call(ref then_call, [then_arg]) = then_expr.kind; if let ExprKind::Path(ref then_call_qpath) = then_call.kind; - if utils::match_qpath(then_call_qpath, &utils::paths::OPTION_SOME); + if match_qpath(then_call_qpath, &clippy_utils::paths::OPTION_SOME); if let ExprKind::Block(ref els_block, _) = els.kind; if els_block.stmts.is_empty(); if let Some(ref els_expr) = els_block.expr; if let ExprKind::Path(ref els_call_qpath) = els_expr.kind; - if utils::match_qpath(els_call_qpath, &utils::paths::OPTION_NONE); + if match_qpath(els_call_qpath, &clippy_utils::paths::OPTION_NONE); then { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 70ea9a92279..6863645a92d 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,5 +1,5 @@ -use crate::utils::match_panic_def_id; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::match_panic_def_id; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 3d2798f3fb4..5207c628987 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,5 +1,5 @@ -use crate::utils::{in_macro, match_qpath, SpanlessEq}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{in_macro, match_qpath, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 4c0f976f79a..94d39019608 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -1,8 +1,8 @@ //! lint on indexing and slicing operations use crate::consts::{constant, Constant}; -use crate::utils::higher; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::higher; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index addd95c6eae..fb35bc1e780 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, match_type}; +use clippy_utils::{get_trait_def_id, higher, match_qpath, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{get_trait_def_id, higher, match_qpath, paths}; - declare_clippy_lint! { /// **What it does:** Checks for iteration that is guaranteed to be infinite. /// diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index f838ce190dc..5b2e70e3ce9 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,7 +1,7 @@ //! lint on inherent implementations -use crate::utils::in_macro; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_macro; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id, Crate, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 6b29feeb4ed..b023e13e846 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; use if_chain::if_chain; use rustc_hir::{ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; - declare_clippy_lint! { /// **What it does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. /// diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 87fe5123cf6..20f00bd51ba 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,7 +1,7 @@ //! checks for `#[inline]` on trait methods without bodies -use crate::utils::sugg::DiagnosticBuilderExt; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::DiagnosticBuilderExt; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index a644a4113ae..717f2ea84f4 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,6 +1,6 @@ -use crate::utils::{get_item_name, get_parent_as_impl, is_allowed}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_item_name, get_parent_as_impl, is_allowed}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 4b7e02398fb..2d7d9c9befb 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,6 +1,6 @@ -use crate::utils::{path_to_local_id, visitors::LocalUsedVisitor}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; +use clippy_utils::{path_to_local_id, visitors::LocalUsedVisitor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index eee2503b481..7e3a76ded2c 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_must_use_ty, match_type}; +use clippy_utils::{is_must_use_func_call, paths}; use if_chain::if_chain; use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -7,8 +8,6 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, paths}; - declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` /// where expr is #[must_use] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f479d756a33..9b2876ddc11 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -42,7 +42,7 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; -use crate::utils::parse_msrv; +use clippy_utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; use rustc_session::Session; diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 0848aaed815..a2f093e6ef7 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,5 +1,5 @@ -use crate::utils::{in_macro, trait_ref_of_method}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{in_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::intravisit::{ walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index dd303bc0a01..7fd55151226 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,12 +1,12 @@ //! Lints concerned with the grouping of digits with underscores in integral or //! floating-point literal expressions. -use crate::utils::{ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::{ in_macro, numeric_literal::{NumericLiteral, Radix}, }; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/empty_loop.rs b/clippy_lints/src/loops/empty_loop.rs index d52a061fc8f..dda09fecdf9 100644 --- a/clippy_lints/src/loops/empty_loop.rs +++ b/clippy_lints/src/loops/empty_loop.rs @@ -1,6 +1,6 @@ use super::EMPTY_LOOP; -use crate::utils::{is_in_panic_handler, is_no_std_crate}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{is_in_panic_handler, is_no_std_crate}; use rustc_hir::{Block, Expr}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 87ce4e4c20c..f14dbb1d642 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,9 +1,9 @@ use super::{ get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP, }; -use crate::utils::{get_enclosing_block, is_integer_const}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_enclosing_block, is_integer_const}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 259e95e5ef4..92aa2beb66d 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,8 +1,8 @@ use super::EXPLICIT_ITER_LOOP; -use crate::utils::{match_trait_method, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{match_trait_method, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index bf037f392e0..8f18f54119b 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,9 +1,9 @@ use super::FOR_KV_MAP; -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{paths, sugg}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{paths, sugg}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; diff --git a/clippy_lints/src/loops/iter_next_loop.rs b/clippy_lints/src/loops/iter_next_loop.rs index 27a03562800..9148fbfd497 100644 --- a/clippy_lints/src/loops/iter_next_loop.rs +++ b/clippy_lints/src/loops/iter_next_loop.rs @@ -1,11 +1,10 @@ use super::ITER_NEXT_LOOP; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_trait_method; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_span::sym; -use crate::utils::is_trait_method; - pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, expr: &Expr<'_>) -> bool { if is_trait_method(cx, arg, sym::Iterator) { span_lint( diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 43580d6071a..be87f67d300 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -1,7 +1,7 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; -use crate::utils::{is_ok_ctor, is_some_ctor, path_to_local_id}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_ok_ctor, is_some_ctor, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, StmtKind}; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index ff68d136999..af6d56a89af 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -1,9 +1,9 @@ use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; -use crate::utils::sugg::Sugg; -use crate::utils::{get_enclosing_block, higher, path_to_local, sugg}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 2a372c6307e..20291491998 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -18,7 +18,7 @@ mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; -use crate::utils::higher; +use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 175aee53a9a..f4e4064ba1d 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -1,6 +1,6 @@ use super::MUT_RANGE_BOUND; -use crate::utils::{higher, path_to_local}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{higher, path_to_local}; use if_chain::if_chain; use rustc_hir::{BindingAnnotation, Expr, HirId, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index a3b731eefa0..5594fc7b046 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -1,9 +1,9 @@ use super::NEEDLESS_COLLECT; -use crate::utils::sugg::Sugg; -use crate::utils::{is_trait_method, path_to_local_id, paths}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{is_trait_method, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index ca679d7ebe1..3c40d54cb42 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -1,11 +1,11 @@ use super::NEEDLESS_RANGE_LOOP; -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{ - contains_name, higher, is_integer_const, match_trait_method, path_to_local_id, paths, sugg, SpanlessEq, -}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{ + contains_name, higher, is_integer_const, match_trait_method, path_to_local_id, paths, sugg, SpanlessEq, +}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 172eb963ae3..8451c1c6130 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,6 +1,6 @@ use super::{get_span_of_entire_for_loop, SINGLE_ELEMENT_LOOP}; -use crate::utils::single_segment_path; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::single_segment_path; use clippy_utils::source::{indent_of, snippet}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index b85676570b4..bb409c48532 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -1,5 +1,5 @@ -use crate::utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; use clippy_utils::ty::{has_iter_method, implements_trait}; +use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index a037a06de81..cad9ff8489a 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -1,7 +1,7 @@ use super::WHILE_IMMUTABLE_CONDITION; use crate::consts::constant; -use crate::utils::usage::mutated_variables; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::usage::mutated_variables; use if_chain::if_chain; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 29ad9e735cc..57fc6250a9a 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -1,12 +1,12 @@ use super::utils::{LoopNestVisitor, Nesting}; use super::WHILE_LET_ON_ITERATOR; -use crate::utils::usage::mutated_variables; -use crate::utils::{ - get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, -}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{ + get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 92f95645734..d573c297838 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -1,5 +1,5 @@ -use crate::utils::in_macro; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 6c0308cbd92..07d8a440aea 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; +use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; use if_chain::if_chain; use rustc_hir::{Crate, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::{is_entrypoint_fn, is_no_std_crate}; - declare_clippy_lint! { /// **What it does:** Checks for recursion using the entrypoint. /// diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 1db5cf56962..5d88ff3b99f 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,6 +1,6 @@ -use crate::utils::match_function_call; -use crate::utils::paths::FUTURE_FROM_GENERATOR; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::match_function_call; +use clippy_utils::paths::FUTURE_FROM_GENERATOR; use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index fd563bec769..cd9594737bf 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -1,11 +1,8 @@ -use crate::{ - map_unit_fn::OPTION_MAP_UNIT_FN, - matches::MATCH_AS_REF, - utils::{is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs}, -}; +use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; +use clippy_utils::{is_allowed, match_def_path, match_var, paths, peel_hir_expr_refs}; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 705c1ec1859..a9a89ae5659 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,5 +1,5 @@ -use crate::utils::meets_msrv; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::meets_msrv; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index a1e5c752f83..9bfae602c40 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,7 +1,7 @@ -use crate::utils::{match_qpath, path_to_local_id, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_qpath, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind}; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index bc4e255b03d..9da37efddac 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,8 +1,8 @@ use crate::consts::{constant, Constant}; -use crate::utils::usage::mutated_variables; -use crate::utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 615e2d5c2af..4f139f8d39a 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,9 +1,9 @@ use crate::consts::constant_simple; -use crate::utils; -use crate::utils::{in_constant, path_to_local_id, sugg}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::contains_return_break_continue_macro; +use clippy_utils::{in_constant, match_qpath, path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; @@ -75,19 +75,19 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind { PatKind::Path(ref some_qpath) => - utils::match_qpath(some_qpath, &utils::paths::OPTION_NONE), + match_qpath(some_qpath, &clippy_utils::paths::OPTION_NONE), PatKind::TupleStruct(ref err_qpath, &[Pat { kind: PatKind::Wild, .. }], _) => - utils::match_qpath(err_qpath, &utils::paths::RESULT_ERR), + match_qpath(err_qpath, &clippy_utils::paths::RESULT_ERR), _ => false, } ); let unwrap_arm = &arms[1 - idx]; if let PatKind::TupleStruct(ref unwrap_qpath, &[unwrap_pat], _) = unwrap_arm.pat.kind; - if utils::match_qpath(unwrap_qpath, &utils::paths::OPTION_SOME) - || utils::match_qpath(unwrap_qpath, &utils::paths::RESULT_OK); + if match_qpath(unwrap_qpath, &clippy_utils::paths::OPTION_SOME) + || match_qpath(unwrap_qpath, &clippy_utils::paths::RESULT_OK); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); - if !utils::usage::contains_return_break_continue_macro(or_arm.body); + if !contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) } else { diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index fd39052871b..cfcc705eabc 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,6 +1,6 @@ -use crate::utils::is_trait_method; -use crate::utils::remove_blocks; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::remove_blocks; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 84ec23c4e2f..75191e1f9ee 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -1,6 +1,6 @@ -use crate::utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 3bd4a965765..d4764b5ccff 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,7 +1,7 @@ -use crate::utils::{iter_input_pats, method_chain_args}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{iter_input_pats, method_chain_args}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 1aa09b82822..e94c7094cac 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,16 +1,16 @@ use crate::consts::{constant, miri_to_const, Constant}; -use crate::utils::sugg::Sugg; -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{ - get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local, - path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, remove_blocks, strip_pat_refs, -}; -use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use clippy_utils::diagnostics::{ multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; +use clippy_utils::visitors::LocalUsedVisitor; +use clippy_utils::{ + get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local, + path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, remove_blocks, strip_pat_refs, +}; +use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -1616,9 +1616,9 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; - use crate::utils::{is_trait_method, match_qpath, paths}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; + use clippy_utils::{is_trait_method, match_qpath, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index 85353d4cdde..7895ba9f1e0 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -1,7 +1,7 @@ -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::walk_ptrs_ty_depth; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 1a8cb82514b..c13802e3953 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,5 +1,5 @@ -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, paths}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 87cb66a6770..426c108d89f 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,7 @@ -use crate::utils::{in_macro, match_def_path, match_qpath, meets_msrv, paths}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diagnostic_assoc_item; use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::{in_macro, match_def_path, match_qpath, meets_msrv, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 7d6104ebb7f..0ba8a98a018 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,8 +1,8 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; -use crate::utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::match_type; +use clippy_utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index d1c7789a241..949152cf789 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -1,5 +1,5 @@ -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index b49ae42b12f..03c949d5c31 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,5 +1,5 @@ -use crate::utils::paths; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 1c673c11d65..e7bffa66b3f 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ -use crate::utils::is_expn_of; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_expn_of; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 005c94a6018..39d2f15dbc8 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -1,6 +1,6 @@ -use crate::utils::{get_parent_expr, paths}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::match_type; +use clippy_utils::{get_parent_expr, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filter_flat_map.rs b/clippy_lints/src/methods/filter_flat_map.rs index 4820bb137c1..2f3a3c55ab5 100644 --- a/clippy_lints/src/methods/filter_flat_map.rs +++ b/clippy_lints/src/methods/filter_flat_map.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index af91370df20..2cb476acb2b 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,6 +1,6 @@ -use crate::utils::{is_trait_method, path_to_local_id, SpanlessEq}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::{is_trait_method, path_to_local_id, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/filter_map_flat_map.rs b/clippy_lints/src/methods/filter_map_flat_map.rs index 5294ef97528..b1a4dc98eb8 100644 --- a/clippy_lints/src/methods/filter_map_flat_map.rs +++ b/clippy_lints/src/methods/filter_map_flat_map.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 4461baf4f7c..80598d88508 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/filter_map_map.rs b/clippy_lints/src/methods/filter_map_map.rs index 8f17350054b..0b0a8b1dd3b 100644 --- a/clippy_lints/src/methods/filter_map_map.rs +++ b/clippy_lints/src/methods/filter_map_map.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 8fbadd1d457..ba57abd16c9 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,6 +1,6 @@ -use crate::utils::{is_trait_method, meets_msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet; +use clippy_utils::{is_trait_method, meets_msrv}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index af16ea19007..6cd24334414 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 669ac1f743f..034ea6c6562 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_trait_method, match_qpath, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_trait_method, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 5d0a07992c8..2095a60e44b 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,6 +1,6 @@ -use crate::utils::{get_trait_def_id, paths, sugg}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index ac855419d00..b122a0a0b89 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -1,8 +1,8 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::{get_parent_expr, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 56de7a8bc5e..d10a540c24e 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,8 +1,8 @@ use super::INEFFICIENT_TO_STRING; -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index c9bbfbc37eb..7fd3ef1a622 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::{source_map::Span, sym}; -use crate::utils::is_trait_method; - use super::INSPECT_FOR_EACH; /// lint use of `inspect().for_each()` for `Iterators` diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index a862b55e139..cfe749cf361 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,6 +1,6 @@ -use crate::utils::{match_trait_method, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::has_iter_method; +use clippy_utils::{match_trait_method, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index bfd62ff1f0d..fd3d53816a1 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,6 +1,6 @@ use crate::methods::derefs_to_slice; -use crate::utils::paths; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index ce599682bbe..feebf8b8209 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -1,8 +1,8 @@ use crate::methods::derefs_to_slice; -use crate::utils::{get_parent_expr, higher}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_parent_expr, higher}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index f2b2dd8c097..a12f672739c 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index 6100613bcac..ea01860b456 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 51c1ab0484e..3baa580314f 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 0c8a002e359..f16699322d1 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,5 +1,5 @@ -use crate::utils::match_qpath; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::match_qpath; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index b59998fc8b4..e4402b2da21 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 6f5e723fbfb..4bc52b036a8 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 8ef02b4a641..deb4b4492b5 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,8 +1,8 @@ -use crate::utils::meets_msrv; -use crate::utils::usage::mutated_variables; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::meets_msrv; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::mutated_variables; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index af8fe7abd96..cbfb350ebb1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -55,6 +55,10 @@ use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::{ + contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls, + method_chain_args, paths, return_ty, single_segment_path, SpanlessEq, +}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -68,11 +72,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{sym, SymbolStr}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{ - contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls, - method_chain_args, paths, return_ty, single_segment_path, SpanlessEq, -}; - declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. /// diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index f921d7b16c0..d11ede080dc 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,7 +1,7 @@ -use crate::utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index e8b057c2d74..d93db2c22e4 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,7 +1,7 @@ -use crate::utils::{match_qpath, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_qpath, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index c6459648cd5..e252abc177a 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,5 @@ -use crate::utils::differing_macro_contexts; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 1b43802a08e..4880d13f39a 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,8 +1,8 @@ -use crate::utils::eager_or_lazy::is_lazyness_candidate; -use crate::utils::{contains_return, get_trait_def_id, last_path_segment, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::is_lazyness_candidate; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; +use clippy_utils::{contains_return, get_trait_def_id, last_path_segment, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 18e1064b018..13546dc1779 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,7 +1,7 @@ -use crate::utils::{is_trait_method, strip_pat_refs}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/skip_while_next.rs b/clippy_lints/src/methods/skip_while_next.rs index 8995226191b..3db83785b59 100644 --- a/clippy_lints/src/methods/skip_while_next.rs +++ b/clippy_lints/src/methods/skip_while_next.rs @@ -1,5 +1,5 @@ -use crate::utils::is_trait_method; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index d9b97168490..52b26a36fe3 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -1,5 +1,5 @@ -use crate::utils::method_chain_args; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index fd4651dd182..7015bd54c35 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -1,6 +1,6 @@ -use crate::utils::usage::mutated_variables; -use crate::utils::{expr_or_init, is_trait_method}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{expr_or_init, is_trait_method}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 071856c3ba6..f2f6ef4be6c 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ -use crate::utils::{match_def_path, match_qpath, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, match_qpath, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 670134c68f2..48d905ab833 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,14 +1,13 @@ -use crate::utils::usage::mutated_variables; -use crate::utils::{is_trait_method, match_qpath, path_to_local_id, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::usage::mutated_variables; +use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_span::sym; -use if_chain::if_chain; - use super::UNNECESSARY_FILTER_MAP; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 3ccde57de3f..1268fd4bda9 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,6 +1,6 @@ -use crate::utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 3874673bf9f..a86185bf0a6 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,7 +1,7 @@ -use crate::utils::{eager_or_lazy, usage}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{eager_or_lazy, usage}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 13c95e33fef..b5505af0f7e 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,7 +1,7 @@ -use crate::utils::{get_parent_expr, match_trait_method, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; +use clippy_utils::{get_parent_expr, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 6a4e70e50af..776f4c7b741 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,6 +1,6 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{match_def_path, match_trait_method, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 03d07287005..026ea50936a 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -18,8 +18,8 @@ use rustc_span::source_map::{ExpnKind, Span}; use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; -use crate::utils::sugg::Sugg; -use crate::utils::{ +use clippy_utils::sugg::Sugg; +use clippy_utils::{ get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, last_path_segment, match_qpath, unsext, SpanlessEq, }; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index aba4accccb1..23554669d97 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,7 @@ -use crate::utils::qualify_min_const_fn::is_min_const_fn; -use crate::utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 1b00cf2c75d..6a52de4f713 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::sext; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sext; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index 6eaeaebe781..584daa5e119 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,7 +1,7 @@ //! lint on multiple versions of a crate being used -use crate::utils::run_lints; use clippy_utils::diagnostics::span_lint; +use clippy_utils::run_lints; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Crate, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 39aec79734c..41bd07bcf1e 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,5 +1,5 @@ -use crate::utils::{match_def_path, paths, trait_ref_of_method}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, paths, trait_ref_of_method}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TypeFoldable; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index c11ccc94890..ef33e41a5fa 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,5 +1,5 @@ -use crate::utils::higher; use clippy_utils::diagnostics::span_lint; +use clippy_utils::higher; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index fb8895e08d0..533c5a22db0 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,5 +1,5 @@ -use crate::utils::{higher, is_direct_expn_of}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{higher, is_direct_expn_of}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index c62ff7323f3..3e2b2782ed5 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,5 +1,5 @@ -use crate::utils::in_macro; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use if_chain::if_chain; use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 4c67304d23e..db7b3423ad9 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -2,10 +2,10 @@ //! //! This lint is **warn** by default -use crate::utils::sugg::Sugg; -use crate::utils::{is_expn_of, parent_node_is_if_expr}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use clippy_utils::{is_expn_of, parent_node_is_if_expr}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 72436b51dcb..79d84da2dfc 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -2,8 +2,8 @@ //! //! This lint is **warn** by default -use crate::utils::is_automatically_derived; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_automatically_derived; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index fc8ee6cb8ef..075bbf9a426 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,8 +1,8 @@ -use crate::utils::ptr::get_spans; -use crate::utils::{get_trait_def_id, is_self, paths}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::ptr::get_spans; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index ecf48d082af..99e85e6683c 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,6 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_ok_ctor, is_some_ctor, meets_msrv}; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -8,9 +10,6 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; -use crate::utils; -use if_chain::if_chain; - declare_clippy_lint! { /// **What it does:** /// Suggests alternatives for useless applications of `?` in terminating expressions @@ -161,7 +160,7 @@ fn is_some_or_ok_call<'a>( // Check outer expression matches CALL_IDENT(ARGUMENT) format if let ExprKind::Call(path, args) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind; - if utils::is_some_ctor(cx, path.res) || utils::is_ok_ctor(cx, path.res); + if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); // Extract inner expression from ARGUMENT if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; @@ -182,7 +181,7 @@ fn is_some_or_ok_call<'a>( let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type); // Check for Option MSRV - let meets_option_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV); + let meets_option_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV); if outer_is_some && inner_is_some && meets_option_msrv { return Some(SomeOkCall::SomeCall(expr, inner_expr)); } @@ -196,7 +195,7 @@ fn is_some_or_ok_call<'a>( let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr); // Must meet Result MSRV - let meets_result_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV); + let meets_result_msrv = meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV); if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv { return Some(SomeOkCall::OkCall(expr, inner_expr)); } diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index e291885d34d..4b935c7b906 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::implements_trait; +use clippy_utils::{self, get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{self, paths}; - declare_clippy_lint! { /// **What it does:** /// Checks for the usage of negated comparison operators on types which only implement @@ -61,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { let ty = cx.typeck_results().expr_ty(left); let implements_ord = { - if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) { + if let Some(id) = get_trait_def_id(cx, &paths::ORD) { implements_trait(cx, ty, id, &[]) } else { return; diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 9fbb6b02742..502e5e4bf37 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,7 +1,7 @@ -use crate::utils::paths; -use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, return_ty}; use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::paths; +use clippy_utils::sugg::DiagnosticBuilderExt; +use clippy_utils::{get_trait_def_id, return_ty}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5db614497e3..b86ae1426ef 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -5,6 +5,8 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_constant; +use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -19,9 +21,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::in_constant; -use if_chain::if_chain; - // FIXME: this is a correctness problem but there's no suitable // warn-by-default category. declare_clippy_lint! { diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 8e8aaa67afa..c61dff4b8e0 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,5 +1,5 @@ -use crate::utils::paths; use clippy_utils::diagnostics::span_lint; +use clippy_utils::paths; use clippy_utils::ty::match_type; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 343159f9ae2..a0bc324e026 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -1,5 +1,5 @@ -use crate::utils::is_direct_expn_of; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_direct_expn_of; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index eab08a58320..a76a4a33f1f 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,11 +1,10 @@ -use crate::utils; -use crate::utils::eager_or_lazy; -use crate::utils::paths; -use crate::utils::sugg::Sugg; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::contains_return_break_continue_macro; +use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, match_qpath}; use if_chain::if_chain; - use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -110,7 +109,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { /// If this is the else body of an if/else expression, then we need to wrap /// it in curly braces. Otherwise, we don't. fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { + get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { let mut should_wrap = false; if let Some(Expr { @@ -160,15 +159,15 @@ fn detect_option_if_let_else<'tcx>( expr: &'_ Expr<'tcx>, ) -> Option { if_chain! { - if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly + if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; - if utils::match_qpath(struct_qpath, &paths::OPTION_SOME); + if match_qpath(struct_qpath, &paths::OPTION_SOME); if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; - if !utils::usage::contains_return_break_continue_macro(arms[0].body); - if !utils::usage::contains_return_break_continue_macro(arms[1].body); + if !contains_return_break_continue_macro(arms[0].body); + if !contains_return_break_continue_macro(arms[1].body); then { let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_arm(&arms[0])?; diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 524b96921fe..cf667c6e805 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,5 +1,5 @@ -use crate::utils::SpanlessEq; use clippy_utils::diagnostics::span_lint; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 880951f3e3e..d32b937b209 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,6 +1,6 @@ -use crate::utils::{find_macro_calls, return_ty}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{find_macro_calls, return_ty}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index ad4ed831941..d06e7f8fe1e 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_expn_of, match_panic_call}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_expn_of, match_panic_call}; use if_chain::if_chain; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 06985cef4ff..1251ddd9a02 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,5 +1,5 @@ -use crate::utils::is_automatically_derived; use clippy_utils::diagnostics::span_lint_hir; +use clippy_utils::is_automatically_derived; use if_chain::if_chain; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index c14273840c4..9a5b1c3b944 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,7 +1,7 @@ use std::cmp; -use crate::utils::is_self_ty; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_self_ty; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use if_chain::if_chain; diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index dd63cf99e42..288e0e4586e 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -1,5 +1,5 @@ -use crate::utils::last_path_segment; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::last_path_segment; use rustc_hir::{ intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind, QPath, Stmt, StmtKind, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 779eddcc170..be686b1b0cd 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,10 +1,10 @@ //! Checks for usage of `&Vec[_]` and `&String`. -use crate::utils::ptr::get_spans; -use crate::utils::{is_allowed, match_qpath, paths}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; +use clippy_utils::{is_allowed, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 82408c639b1..5796c59c8b3 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -1,5 +1,5 @@ -use crate::utils; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; @@ -42,7 +42,7 @@ static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; impl LateLintPass<'_> for PtrEq { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if utils::in_macro(expr.span) { + if in_macro(expr.span) { return; } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index c4686623487..2054255a7c9 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,5 +1,8 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{eq_expr_value, match_def_path, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -8,10 +11,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use crate::utils::sugg::Sugg; -use crate::utils::{eq_expr_value, match_def_path, match_qpath, paths}; -use clippy_utils::diagnostics::span_lint_and_sugg; - declare_clippy_lint! { /// **What it does:** Checks for expressions that could be replaced by the question mark operator. /// diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index d476d95256f..95b21489eb5 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,6 +1,9 @@ use crate::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path}; +use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; @@ -14,10 +17,6 @@ use rustc_span::sym; use rustc_span::symbol::Ident; use std::cmp::Ordering; -use crate::utils::sugg::Sugg; -use crate::utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path}; -use crate::utils::{higher, SpanlessEq}; - declare_clippy_lint! { /// **What it does:** Checks for zipping a collection with the range of /// `0.._.len()`. diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 3d799328bb5..60da2bcb04a 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,7 +1,7 @@ -use crate::utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth}; +use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index fd11150bce2..f77be6fdf04 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ -use crate::utils::meets_msrv; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::meets_msrv; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index da8339a795a..32b57698ec5 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ -use crate::utils::meets_msrv; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::meets_msrv; use clippy_utils::source::snippet; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 452fef0694f..0922cfa494e 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -1,5 +1,5 @@ -use crate::utils::last_path_segment; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::last_path_segment; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index ec2acb6a0ab..d6336389b0a 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,7 +1,7 @@ -use crate::utils::in_macro; -use crate::utils::sugg::Sugg; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index bfa21ba9c97..1cc332de894 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,6 +1,6 @@ use crate::consts::{constant, Constant}; -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index b39e9d5a78c..63e5ec69e66 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,6 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::in_macro; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 59d3c0ca5f0..8995ae431ad 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; +use clippy_utils::{fn_def_id, in_macro, match_qpath}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; @@ -13,8 +14,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::sym; -use crate::utils::{fn_def_id, in_macro, match_qpath}; - declare_clippy_lint! { /// **What it does:** Checks for `let`-bindings, which are subsequently /// returned. diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs index 320d1a8dbe3..e7925c4fbde 100644 --- a/clippy_lints/src/self_assignment.rs +++ b/clippy_lints/src/self_assignment.rs @@ -1,5 +1,5 @@ -use crate::utils::eq_expr_value; use clippy_utils::diagnostics::span_lint; +use clippy_utils::eq_expr_value; use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index e43947025b9..f61af15fbed 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,6 +1,6 @@ -use crate::utils::{in_macro, sugg}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::{in_macro, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 632715852c5..169f7d26285 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,5 +1,5 @@ -use crate::utils::{get_trait_def_id, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{get_trait_def_id, paths}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 8ef58b6d563..612d2fd84cb 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,6 +1,6 @@ -use crate::utils::{contains_name, higher, iter_input_pats}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; +use clippy_utils::{contains_name, higher, iter_input_pats}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 6d15a6c444e..c9d72aabb6a 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,5 +1,5 @@ -use crate::utils::in_macro; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use if_chain::if_chain; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 8920d446b9c..09e00866815 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,8 +1,8 @@ //! Lint on use of `size_of` or `size_of_val` of T in an expression //! expecting a count of T -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::BinOpKind; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 7f0f21084af..d55a83f1613 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,6 +1,6 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{get_enclosing_block, match_qpath, SpanlessEq}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_enclosing_block, match_qpath, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index 85e4bb806e7..65790375c73 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -1,8 +1,6 @@ -use crate::utils::{is_slice_of_primitives, sugg::Sugg}; use clippy_utils::diagnostics::span_lint_and_then; - +use clippy_utils::{is_slice_of_primitives, sugg::Sugg}; use if_chain::if_chain; - use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 626166f9008..760f5e3b432 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,8 +1,8 @@ -use crate::utils::SpanlessEq; -use crate::utils::{get_parent_expr, is_allowed, match_function_call, method_calls, paths}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; +use clippy_utils::{get_parent_expr, is_allowed, match_function_call, method_calls, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 364c99adc69..1e5d3c17e3b 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -use crate::utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index ef14b6c5136..0f024c9a11e 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,5 +1,5 @@ -use crate::utils::{get_trait_def_id, trait_ref_of_method}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{get_trait_def_id, trait_ref_of_method}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; @@ -159,7 +159,7 @@ fn check_binop( expected_ops: &[hir::BinOpKind], ) -> Option<&'static str> { let mut trait_ids = vec![]; - let [krate, module] = crate::utils::paths::OPS_MODULE; + let [krate, module] = clippy_utils::paths::OPS_MODULE; for &t in traits { let path = [krate, module, t]; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 83fe3c49959..14519eaa962 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,8 +1,8 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{differing_macro_contexts, eq_expr_value}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, eq_expr_value}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 75a13cb9187..8ef25dc816c 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -1,5 +1,5 @@ -use crate::utils::is_adjusted; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_adjusted; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index abc9b2fe88e..c66a596c784 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,5 +1,5 @@ -use crate::utils::match_def_path; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::match_def_path; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index 42605c01089..42ec14c31b5 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index cfcc8da9910..3ff27c3bcf4 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,6 +1,6 @@ -use crate::utils::{in_macro, SpanlessHash}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::{in_macro, SpanlessHash}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index c1870f5208b..47d58bd30db 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -12,7 +12,7 @@ mod useless_transmute; mod utils; mod wrong_transmute; -use crate::utils::{in_constant, match_def_path, paths}; +use clippy_utils::{in_constant, match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index f61b5362b5a..72489f27cd3 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_FLOAT_TO_INT; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use if_chain::if_chain; use rustc_ast as ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/transmute/transmute_int_to_bool.rs b/clippy_lints/src/transmute/transmute_int_to_bool.rs index ebdd1eba744..cc0a5643e2a 100644 --- a/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_BOOL; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index afecfc3d701..8f884e6a4a1 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_CHAR; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index c762a7ab885..2b6a4cff81e 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_FLOAT; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 820c56a215e..7b646bfc0c6 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_PTR_TO_PTR; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 049210e555c..f14eef93645 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,7 +1,7 @@ use super::utils::get_type_snippet; use super::TRANSMUTE_PTR_TO_REF; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, QPath}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 993ef8698f8..d105e37abf9 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,7 +1,7 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; -use crate::utils::sugg; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; +use clippy_utils::sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index da7d1016d97..e2c6d130f3c 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,7 +1,7 @@ use super::utils::can_be_expressed_as_pointer_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; -use crate::utils::sugg; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 9bea88be7da..de9277e016e 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,7 +1,7 @@ use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_def_path, paths}; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 29ffe03b673..445bcf60fa7 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -1,6 +1,6 @@ use super::USELESS_TRANSMUTE; -use crate::utils::sugg; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 0633697687a..c6d0d63b0b5 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -1,4 +1,4 @@ -use crate::utils::last_path_segment; +use clippy_utils::last_path_segment; use clippy_utils::source::snippet; use clippy_utils::ty::is_normalizable; use if_chain::if_chain; diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 3a2b1359a54..d42cdde110e 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,6 +1,6 @@ use crate::consts::{constant_context, Constant}; -use crate::utils::{match_qpath, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{match_qpath, paths}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 1fce03b4f47..e61058c2749 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,7 +1,7 @@ -use crate::utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index eab81b1e246..1721fcfdcf4 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,6 +1,6 @@ -use crate::utils::{match_path, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::{match_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ diff --git a/clippy_lints/src/types/box_vec.rs b/clippy_lints/src/types/box_vec.rs index 6d04a47a5c8..d8b1953457c 100644 --- a/clippy_lints/src/types/box_vec.rs +++ b/clippy_lints/src/types/box_vec.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_ty_param_diagnostic_item; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::is_ty_param_diagnostic_item; - use super::BOX_VEC; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/clippy_lints/src/types/linked_list.rs b/clippy_lints/src/types/linked_list.rs index e9e1995f6a5..a9fbe7aa315 100644 --- a/clippy_lints/src/types/linked_list.rs +++ b/clippy_lints/src/types/linked_list.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{match_def_path, paths}; use rustc_hir::{self as hir, def_id::DefId}; use rustc_lint::LateContext; -use crate::utils::{match_def_path, paths}; - use super::LINKEDLIST; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, def_id: DefId) -> bool { diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 5103a259559..c0cd48e94b2 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -36,8 +36,8 @@ use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; -use crate::utils::paths; -use crate::utils::{clip, comparisons, differing_macro_contexts, int_bits, match_path, sext, unsext}; +use clippy_utils::paths; +use clippy_utils::{clip, comparisons, differing_macro_contexts, int_bits, match_path, sext, unsext}; declare_clippy_lint! { /// **What it does:** Checks for use of `Box>` anywhere in the code. @@ -618,7 +618,7 @@ fn detect_absurd_comparison<'tcx>( ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> { use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible}; use crate::types::ExtremeType::{Maximum, Minimum}; - use crate::utils::comparisons::{normalize_comparison, Rel}; + use clippy_utils::comparisons::{normalize_comparison, Rel}; // absurd comparison only makes sense on primitive types // primitive types don't implement comparison operators with each other @@ -860,7 +860,7 @@ fn upcast_comparison_bounds_err<'tcx>( rhs: &'tcx Expr<'_>, invert: bool, ) { - use crate::utils::comparisons::Rel; + use clippy_utils::comparisons::Rel; if let Some((lb, ub)) = lhs_bounds { if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index 79c5a32de2c..b2692c48076 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_ty_param_diagnostic_item; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::is_ty_param_diagnostic_item; - use super::OPTION_OPTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index d5fc23f2e39..ef629a35d10 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item}; - use super::RC_BUFFER; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 71c014f96f7..c0c1f340583 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use crate::utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item}; - use super::{utils, REDUNDANT_ALLOCATION}; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index 4d64748f998..45f891ed718 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -1,11 +1,9 @@ +use clippy_utils::last_path_segment; +use if_chain::if_chain; use rustc_hir::{GenericArg, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; -use crate::utils::last_path_segment; - -use if_chain::if_chain; - pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option { let last = last_path_segment(qpath); if_chain! { diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 8cedb0ede2b..d2c373db261 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::last_path_segment; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; @@ -9,8 +10,6 @@ use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; use rustc_typeck::hir_ty_to_ty; -use crate::utils::last_path_segment; - use super::VEC_BOX; pub(super) fn check( diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index 943573a2b53..b6749069176 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -1,6 +1,6 @@ -use crate::utils::{match_function_call, paths}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{match_function_call, paths}; use rustc_hir::{lang_items, Expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index c37bbf297f8..d81e31f5a21 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,5 +1,5 @@ -use crate::utils::is_allowed; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_allowed; use clippy_utils::source::snippet; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index d0456347f8a..bad3e488bb6 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -1,5 +1,5 @@ -use crate::utils::{get_trait_def_id, paths}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::{get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, StmtKind}; diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 55715cc6bf3..8698a718bbd 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,12 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher; +use clippy_utils::source::snippet_with_macro_callsite; use rustc_errors::Applicability; use rustc_hir::{Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use crate::utils::diagnostics::span_lint_and_then; -use crate::utils::higher; -use crate::utils::source::snippet_with_macro_callsite; - use super::LET_UNIT_VALUE; pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) { diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index d4ef645fc8d..925ab577099 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,12 +1,10 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; -use if_chain::if_chain; - -use crate::utils::diagnostics::span_lint_and_then; -use crate::utils::source::{indent_of, reindent_multiline, snippet_opt}; - use super::{utils, UNIT_ARG}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index f9c0374c86d..b3077dec5d8 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -1,9 +1,8 @@ +use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use crate::utils::diagnostics::span_lint; - use super::UNIT_CMP; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 2c51a8556d9..d5bc3de6698 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -1,5 +1,5 @@ -use crate::utils::{match_def_path, paths}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index aa83f6a74be..e23bab5eba0 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,5 @@ -use crate::utils::sugg::Sugg; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index cb20192b683..9e227164695 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,6 @@ -use crate::utils::{contains_return, in_macro, match_qpath, paths, return_ty, visitors::find_all_ret_expressions}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; +use clippy_utils::{contains_return, in_macro, match_qpath, paths, return_ty, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 42ff1809ff4..512d505dfb5 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,8 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] -use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; -use crate::utils::over; +use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::over; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 31fd61f99f2..9990052e114 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,5 +1,5 @@ -use crate::utils::{is_try, match_trait_method, paths}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 4642bf07c45..aef4ce75915 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::visitors::LocalUsedVisitor; use if_chain::if_chain; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::visitors::LocalUsedVisitor; - declare_clippy_lint! { /// **What it does:** Checks methods that contain a `self` argument but don't use it /// diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index c45b851211c..329ea49024b 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,3 +1,4 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::position_before_rarrow; use if_chain::if_chain; use rustc_ast::ast; @@ -8,8 +9,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use clippy_utils::diagnostics::span_lint_and_sugg; - declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. /// diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 75b2f2da602..fb29acca18a 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,6 +1,6 @@ -use crate::utils::{differing_macro_contexts, usage::is_potentially_mutated}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{differing_macro_contexts, usage::is_potentially_mutated}; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp}; diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index a85f3ce5c9c..0d745813beb 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,6 +1,6 @@ -use crate::utils::{method_chain_args, return_ty}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{method_chain_args, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 9a42c833470..116cb8b1e1c 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ -use crate::utils::{in_macro, meets_msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; +use clippy_utils::{in_macro, meets_msrv}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 1eb152daac8..3e1b69e676b 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,8 +1,8 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{get_parent_expr, match_def_path, match_trait_method, paths}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 3dd190ba440..2de5b1a628e 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,7 +1,7 @@ //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. -use crate::utils::get_attr; +use clippy_utils::get_attr; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 9e3973e1d51..191ff6e4f16 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -1,6 +1,6 @@ //! checks for attributes -use crate::utils::get_attr; +use clippy_utils::get_attr; use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index a566362ae78..c496ff1fb24 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,9 +1,8 @@ use crate::consts::{constant_simple, Constant}; -use crate::utils::{is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq}; - use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; +use clippy_utils::{is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; use rustc_ast::visit::FnKind; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index be9a07f8d7c..d8b31344e6d 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -3,5 +3,3 @@ pub mod conf; pub mod inspector; #[cfg(feature = "internal-lints")] pub mod internal_lints; - -pub use clippy_utils::*; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 9e142413365..1af9583887f 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,7 +1,7 @@ use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; -use crate::utils::higher; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use if_chain::if_chain; diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 3ef55a82a17..8b696ed1c84 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,7 +1,7 @@ -use crate::utils::{match_def_path, path_to_local, path_to_local_id, paths}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index 9a2fb1414a1..e035d3c5cad 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -1,15 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; +use rustc_ast::LitKind; use rustc_errors::Applicability; +use rustc_hir as hir; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use crate::utils::{match_def_path, paths}; -use rustc_ast::LitKind; -use rustc_hir as hir; - declare_clippy_lint! { /// **What it does:** Finds occurrences of `Vec::resize(0, an_int)` /// diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 01dc54dc5fd..ec209b30951 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -1,5 +1,5 @@ -use crate::utils::paths; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::paths; use clippy_utils::ty::match_type; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index 8f96b962279..60c3489a449 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -1,5 +1,5 @@ -use crate::utils::run_lints; use clippy_utils::diagnostics::span_lint; +use clippy_utils::run_lints; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 424ca2a4c2f..51c1117d206 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,5 +1,5 @@ -use crate::utils::in_macro; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 82466da6862..2abd033e2a0 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::paths; use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; @@ -9,8 +10,6 @@ use rustc_span::sym; use rustc_target::abi::LayoutOf as _; use rustc_typeck::hir_ty_to_ty; -use crate::utils::paths; - declare_clippy_lint! { /// **What it does:** Checks for maps with zero-sized value types anywhere in the code. /// -- cgit 1.4.1-3-g733a5 From 94fb2b58a30f46cd462bea088ea523ed8f4d9580 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 13 Mar 2021 17:17:10 +0900 Subject: move chars_cmp and chars_next_cmp to its own modules --- clippy_lints/src/methods/chars_cmp.rs | 54 +++++++++++++++++++++++++++ clippy_lints/src/methods/chars_next_cmp.rs | 8 ++++ clippy_lints/src/methods/mod.rs | 59 +++--------------------------- 3 files changed, 68 insertions(+), 53 deletions(-) create mode 100644 clippy_lints/src/methods/chars_cmp.rs create mode 100644 clippy_lints/src/methods/chars_next_cmp.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs new file mode 100644 index 00000000000..f9af06d200c --- /dev/null +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -0,0 +1,54 @@ +use crate::utils::{method_chain_args, single_segment_path}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_lint::Lint; +use rustc_middle::ty; +use rustc_span::sym; + +/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. +pub(super) fn check( + cx: &LateContext<'_>, + info: &crate::methods::BinaryExprInfo<'_>, + chain_methods: &[&str], + lint: &'static Lint, + suggest: &str, +) -> bool { + if_chain! { + if let Some(args) = method_chain_args(info.chain, chain_methods); + if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind; + if arg_char.len() == 1; + if let hir::ExprKind::Path(ref qpath) = fun.kind; + if let Some(segment) = single_segment_path(qpath); + if segment.ident.name == sym::Some; + then { + let mut applicability = Applicability::MachineApplicable; + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); + + if *self_ty.kind() != ty::Str { + return false; + } + + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{}` method", suggest), + "like this", + format!("{}{}.{}({})", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + suggest, + snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), + applicability, + ); + + return true; + } + } + + false +} diff --git a/clippy_lints/src/methods/chars_next_cmp.rs b/clippy_lints/src/methods/chars_next_cmp.rs new file mode 100644 index 00000000000..a6701d8830e --- /dev/null +++ b/clippy_lints/src/methods/chars_next_cmp.rs @@ -0,0 +1,8 @@ +use rustc_lint::LateContext; + +use super::CHARS_NEXT_CMP; + +/// Checks for the `CHARS_NEXT_CMP` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cbfb350ebb1..d288c51907e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,7 @@ mod bind_instead_of_map; mod bytes_nth; +mod chars_cmp; +mod chars_next_cmp; mod clone_on_copy; mod clone_on_ref_ptr; mod expect_fun_call; @@ -2024,7 +2026,7 @@ struct BinaryExprInfo<'a> { /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) { macro_rules! lint_with_both_lhs_and_rhs { - ($func:ident, $cx:expr, $info:ident) => { + ($func:expr, $cx:expr, $info:ident) => { if !$func($cx, $info) { ::std::mem::swap(&mut $info.chain, &mut $info.other); if $func($cx, $info) { @@ -2034,67 +2036,18 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr }; } - lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info); + lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info); lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info); lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info); lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info); } -/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. -fn lint_chars_cmp( - cx: &LateContext<'_>, - info: &BinaryExprInfo<'_>, - chain_methods: &[&str], - lint: &'static Lint, - suggest: &str, -) -> bool { - if_chain! { - if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind; - if arg_char.len() == 1; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym::Some; - then { - let mut applicability = Applicability::MachineApplicable; - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); - - if *self_ty.kind() != ty::Str { - return false; - } - - span_lint_and_sugg( - cx, - lint, - info.expr.span, - &format!("you should use the `{}` method", suggest), - "like this", - format!("{}{}.{}({})", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), - suggest, - snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), - applicability, - ); - - return true; - } - } - - false -} - -/// Checks for the `CHARS_NEXT_CMP` lint. -fn lint_chars_next_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") -} - /// Checks for the `CHARS_LAST_CMP` lint. fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { + if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { true } else { - lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") + chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") } } -- cgit 1.4.1-3-g733a5 From 058d8c878ab51ccd65e636456207b3d63ee532b5 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 13 Mar 2021 17:28:22 +0900 Subject: move chars_cmp_with_unwrap, chars_last_cmp and chars_next_cmp_with_unwrap to their own modules --- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 44 +++++++++++++++ clippy_lints/src/methods/chars_last_cmp.rs | 13 +++++ .../src/methods/chars_next_cmp_with_unwrap.rs | 8 +++ clippy_lints/src/methods/mod.rs | 64 +++------------------- 4 files changed, 74 insertions(+), 55 deletions(-) create mode 100644 clippy_lints/src/methods/chars_cmp_with_unwrap.rs create mode 100644 clippy_lints/src/methods/chars_last_cmp.rs create mode 100644 clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs new file mode 100644 index 00000000000..3ba59171f77 --- /dev/null +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -0,0 +1,44 @@ +use crate::utils::method_chain_args; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_lint::Lint; + +/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + info: &crate::methods::BinaryExprInfo<'_>, + chain_methods: &[&str], + lint: &'static Lint, + suggest: &str, +) -> bool { + if_chain! { + if let Some(args) = method_chain_args(info.chain, chain_methods); + if let hir::ExprKind::Lit(ref lit) = info.other.kind; + if let ast::LitKind::Char(c) = lit.node; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{}` method", suggest), + "like this", + format!("{}{}.{}('{}')", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + suggest, + c), + applicability, + ); + + true + } else { + false + } + } +} diff --git a/clippy_lints/src/methods/chars_last_cmp.rs b/clippy_lints/src/methods/chars_last_cmp.rs new file mode 100644 index 00000000000..07bbc5ca1bf --- /dev/null +++ b/clippy_lints/src/methods/chars_last_cmp.rs @@ -0,0 +1,13 @@ +use crate::methods::chars_cmp; +use rustc_lint::LateContext; + +use super::CHARS_LAST_CMP; + +/// Checks for the `CHARS_LAST_CMP` lint. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { + true + } else { + chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") + } +} diff --git a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs new file mode 100644 index 00000000000..28ede28e935 --- /dev/null +++ b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs @@ -0,0 +1,8 @@ +use rustc_lint::LateContext; + +use super::CHARS_NEXT_CMP; + +/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d288c51907e..b4c32e45da9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,7 +1,10 @@ mod bind_instead_of_map; mod bytes_nth; mod chars_cmp; +mod chars_cmp_with_unwrap; +mod chars_last_cmp; mod chars_next_cmp; +mod chars_next_cmp_with_unwrap; mod clone_on_copy; mod clone_on_ref_ptr; mod expect_fun_call; @@ -54,7 +57,7 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{ @@ -66,7 +69,7 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{TraitItem, TraitItemKind}; -use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_semver::RustcVersion; @@ -2037,66 +2040,17 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr } lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info); - lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info); - lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info); + lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info); + lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info); lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info); } -/// Checks for the `CHARS_LAST_CMP` lint. -fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { - true - } else { - chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") - } -} - -/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. -fn lint_chars_cmp_with_unwrap<'tcx>( - cx: &LateContext<'tcx>, - info: &BinaryExprInfo<'_>, - chain_methods: &[&str], - lint: &'static Lint, - suggest: &str, -) -> bool { - if_chain! { - if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Lit(ref lit) = info.other.kind; - if let ast::LitKind::Char(c) = lit.node; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - lint, - info.expr.span, - &format!("you should use the `{}` method", suggest), - "like this", - format!("{}{}.{}('{}')", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), - suggest, - c), - applicability, - ); - - true - } else { - false - } - } -} - -/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. -fn lint_chars_next_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") -} - /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { + if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { true } else { - lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") + chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") } } -- cgit 1.4.1-3-g733a5 From c07c046b317bf9a75b04e97c37396436351d80ab Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 13 Mar 2021 17:36:04 +0900 Subject: refactor string_extend_chars: return when obj type is not string --- clippy_lints/src/methods/string_extend_chars.rs | 57 +++++++++++++------------ 1 file changed, 29 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 52b26a36fe3..5c688ac5621 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -12,34 +12,35 @@ use super::STRING_EXTEND_CHARS; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); - if is_type_diagnostic_item(cx, obj_ty, sym::string_type) { - let arg = &args[1]; - if let Some(arglists) = method_chain_args(arg, &["chars"]) { - let target = &arglists[0][0]; - let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); - let ref_str = if *self_ty.kind() == ty::Str { - "" - } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { - "&" - } else { - return; - }; + if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) { + return; + } + let arg = &args[1]; + if let Some(arglists) = method_chain_args(arg, &["chars"]) { + let target = &arglists[0][0]; + let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); + let ref_str = if *self_ty.kind() == ty::Str { + "" + } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { + "&" + } else { + return; + }; - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - STRING_EXTEND_CHARS, - expr.span, - "calling `.extend(_.chars())`", - "try this", - format!( - "{}.push_str({}{})", - snippet_with_applicability(cx, args[0].span, "..", &mut applicability), - ref_str, - snippet_with_applicability(cx, target.span, "..", &mut applicability) - ), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + STRING_EXTEND_CHARS, + expr.span, + "calling `.extend(_.chars())`", + "try this", + format!( + "{}.push_str({}{})", + snippet_with_applicability(cx, args[0].span, "..", &mut applicability), + ref_str, + snippet_with_applicability(cx, target.span, "..", &mut applicability) + ), + applicability, + ); } } -- cgit 1.4.1-3-g733a5 From e578a536c703cd799b74f261e345121bd889be45 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 13 Mar 2021 18:13:31 +0900 Subject: move derefs_to_slice to methods/utils.rs --- clippy_lints/src/methods/utils.rs | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 clippy_lints/src/methods/utils.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs new file mode 100644 index 00000000000..3596aaa089b --- /dev/null +++ b/clippy_lints/src/methods/utils.rs @@ -0,0 +1,46 @@ +use crate::utils::is_type_diagnostic_item; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_middle::ty::Ty; +use rustc_span::symbol::sym; + +pub fn derefs_to_slice<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ty: Ty<'tcx>, +) -> Option<&'tcx hir::Expr<'tcx>> { + fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { + match ty.kind() { + ty::Slice(_) => true, + ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), + ty::Array(_, size) => size + .try_eval_usize(cx.tcx, cx.param_env) + .map_or(false, |size| size < 32), + ty::Ref(_, inner, _) => may_slice(cx, inner), + _ => false, + } + } + + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { + Some(&args[0]) + } else { + None + } + } else { + match ty.kind() { + ty::Slice(_) => Some(expr), + ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), + ty::Ref(_, inner, _) => { + if may_slice(cx, inner) { + Some(expr) + } else { + None + } + }, + _ => None, + } + } +} -- cgit 1.4.1-3-g733a5 From 1bec8b606540813cc068c5b564aa2dbd3d212823 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 13 Mar 2021 18:16:38 +0900 Subject: use derefs_to_slice in methods/utils.rs --- clippy_lints/src/methods/get_unwrap.rs | 2 +- clippy_lints/src/methods/iter_cloned_collect.rs | 2 +- clippy_lints/src/methods/iter_count.rs | 2 +- clippy_lints/src/methods/iter_next_slice.rs | 2 +- clippy_lints/src/methods/iter_nth.rs | 2 +- clippy_lints/src/methods/mod.rs | 42 +------------------------ 6 files changed, 6 insertions(+), 46 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index b122a0a0b89..b3a9743c614 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -1,4 +1,4 @@ -use crate::methods::derefs_to_slice; +use super::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index cd575c9cb02..848f47e39f6 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -1,4 +1,4 @@ -use crate::methods::derefs_to_slice; +use crate::methods::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index fd3d53816a1..e394a8fe819 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,4 +1,4 @@ -use crate::methods::derefs_to_slice; +use super::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; use clippy_utils::source::snippet_with_applicability; diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index feebf8b8209..869b2cdd1a6 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -1,4 +1,4 @@ -use crate::methods::derefs_to_slice; +use crate::methods::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 2619793e1e2..2e7220025f8 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,7 +1,7 @@ -use crate::methods::derefs_to_slice; use crate::methods::iter_nth_zero; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; +use crate::methods::utils::derefs_to_slice; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b4c32e45da9..e16ab4bc20b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -53,6 +53,7 @@ mod unnecessary_fold; mod unnecessary_lazy_eval; mod unwrap_used; mod useless_asref; +mod utils; mod wrong_self_convention; mod zst_offset; @@ -1976,47 +1977,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } - -fn derefs_to_slice<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ty: Ty<'tcx>, -) -> Option<&'tcx hir::Expr<'tcx>> { - fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { - match ty.kind() { - ty::Slice(_) => true, - ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), - ty::Array(_, size) => size - .try_eval_usize(cx.tcx, cx.param_env) - .map_or(false, |size| size < 32), - ty::Ref(_, inner, _) => may_slice(cx, inner), - _ => false, - } - } - - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { - if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { - Some(&args[0]) - } else { - None - } - } else { - match ty.kind() { - ty::Slice(_) => Some(expr), - ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), - ty::Ref(_, inner, _) => { - if may_slice(cx, inner) { - Some(expr) - } else { - None - } - }, - _ => None, - } - } -} - /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { -- cgit 1.4.1-3-g733a5 From f0a101d81dc25fae998d0670348d928f1789439b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 14 Mar 2021 01:05:37 +0900 Subject: remove a needless variable --- clippy_lints/src/methods/iter_skip_next.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index ea01860b456..b1d398876d3 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -12,14 +12,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir // lint if caller of skip is an Iterator if is_trait_method(cx, expr, sym::Iterator) { if let [caller, n] = skip_args { - let hint = format!(".nth({})", snippet(cx, n.span, "..")); span_lint_and_sugg( cx, ITER_SKIP_NEXT, expr.span.trim_start(caller.span).unwrap(), "called `skip(..).next()` on an iterator", "use `nth` instead", - hint, + format!(".nth({})", snippet(cx, n.span, "..")), Applicability::MachineApplicable, ); } -- cgit 1.4.1-3-g733a5 From 0c81311bf0093e991c0b5ca8b69096a5c5cd161c Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 14 Mar 2021 01:18:04 +0900 Subject: extract a condition into a function. --- clippy_lints/src/methods/iter_next_slice.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index 869b2cdd1a6..2155159bf7c 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -47,12 +47,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite ); } } - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type) - || matches!( - &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), - ty::Array(_, _) - ) - { + } else if is_vec_or_array(cx, caller_expr) { // caller is a Vec or an Array let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( @@ -69,3 +64,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, ite ); } } + +fn is_vec_or_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type) + || matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) +} -- cgit 1.4.1-3-g733a5 From b6597eec0b3fcd9598fd4f90daa2d4d781e0aabc Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 14 Mar 2021 01:37:33 +0900 Subject: remove unused arguments --- clippy_lints/src/methods/filter_flat_map.rs | 7 +------ clippy_lints/src/methods/filter_map_flat_map.rs | 7 +------ clippy_lints/src/methods/filter_map_map.rs | 7 +------ clippy_lints/src/methods/mod.rs | 6 +++--- 4 files changed, 6 insertions(+), 21 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_flat_map.rs b/clippy_lints/src/methods/filter_flat_map.rs index 2f3a3c55ab5..1588eec8882 100644 --- a/clippy_lints/src/methods/filter_flat_map.rs +++ b/clippy_lints/src/methods/filter_flat_map.rs @@ -7,12 +7,7 @@ use rustc_span::sym; use super::FILTER_MAP; /// lint use of `filter().flat_map()` for `Iterators` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.filter().flat_map()` is an Iterator if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; diff --git a/clippy_lints/src/methods/filter_map_flat_map.rs b/clippy_lints/src/methods/filter_map_flat_map.rs index b1a4dc98eb8..741b1e7e361 100644 --- a/clippy_lints/src/methods/filter_map_flat_map.rs +++ b/clippy_lints/src/methods/filter_map_flat_map.rs @@ -7,12 +7,7 @@ use rustc_span::sym; use super::FILTER_MAP; /// lint use of `filter_map().flat_map()` for `Iterators` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.filter_map().flat_map()` is an Iterator if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; diff --git a/clippy_lints/src/methods/filter_map_map.rs b/clippy_lints/src/methods/filter_map_map.rs index 0b0a8b1dd3b..713bbf25837 100644 --- a/clippy_lints/src/methods/filter_map_map.rs +++ b/clippy_lints/src/methods/filter_map_map.rs @@ -7,12 +7,7 @@ use rustc_span::sym; use super::FILTER_MAP; /// lint use of `filter_map().map()` for `Iterators` -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - _filter_args: &'tcx [hir::Expr<'_>], - _map_args: &'tcx [hir::Expr<'_>], -) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.filter_map().map()` is an Iterator if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter_map(..).map(..)` on an `Iterator`"; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e16ab4bc20b..044348a2c34 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1715,11 +1715,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), ["map", "filter"] => filter_map::check(cx, expr, false), - ["map", "filter_map"] => filter_map_map::check(cx, expr, arg_lists[1], arg_lists[0]), + ["map", "filter_map"] => filter_map_map::check(cx, expr), ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), ["map", "find"] => filter_map::check(cx, expr, true), - ["flat_map", "filter"] => filter_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), - ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), + ["flat_map", "filter"] => filter_flat_map::check(cx, expr), + ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr), ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]), ["is_some", "find"] => search_is_some::check(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), -- cgit 1.4.1-3-g733a5 From f0f787192006a7b0a508b90a03dcfdd37b3c31d2 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 11:15:25 +0900 Subject: fmt --- clippy_lints/src/methods/iter_nth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 2e7220025f8..bf1575660d1 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,7 +1,7 @@ use crate::methods::iter_nth_zero; +use crate::methods::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; -use crate::methods::utils::derefs_to_slice; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::symbol::sym; -- cgit 1.4.1-3-g733a5 From 48430849465ae94255e78f895197b09c2ce3b03e Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 11:18:02 +0900 Subject: use clippy_utils::ty::is_type_diagnostic_item --- clippy_lints/src/methods/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 3596aaa089b..4d801148cbc 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,4 +1,4 @@ -use crate::utils::is_type_diagnostic_item; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -- cgit 1.4.1-3-g733a5 From 3d9b45df0fa6bc04d864aa4a67fdb631b9bf0a99 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 12:33:09 +0900 Subject: move single_char_add_str to its own module --- clippy_lints/src/methods/single_char_add_str.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 clippy_lints/src/methods/single_char_add_str.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/single_char_add_str.rs b/clippy_lints/src/methods/single_char_add_str.rs new file mode 100644 index 00000000000..3df88e5b69c --- /dev/null +++ b/clippy_lints/src/methods/single_char_add_str.rs @@ -0,0 +1,15 @@ +use crate::methods::{single_char_insert_string, single_char_push_string}; +use crate::utils::match_def_path; +use crate::utils::paths; +use rustc_hir as hir; +use rustc_lint::LateContext; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + single_char_push_string::check(cx, expr, args); + } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { + single_char_insert_string::check(cx, expr, args); + } + } +} -- cgit 1.4.1-3-g733a5 From 62490c41af1a5dab806e45dd2bc0b8d56a3c3c23 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 12:34:37 +0900 Subject: extract conditions into modules --- clippy_lints/src/methods/clone_on_copy.rs | 10 ++++++++-- clippy_lints/src/methods/clone_on_ref_ptr.rs | 8 ++++++-- clippy_lints/src/methods/inefficient_to_string.rs | 11 +++++++---- clippy_lints/src/methods/mod.rs | 20 +++++--------------- 4 files changed, 26 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 949152cf789..edb6649b87b 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -4,14 +4,20 @@ use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; +use rustc_span::symbol::{sym, Symbol}; use std::iter; use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { + if !(args.len() == 1 && method_name == sym::clone) { + return; + } + let arg = &args[0]; + let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); let ty = cx.typeck_results().expr_ty(expr); if let ty::Ref(_, inner, _) = arg_ty.kind() { if let ty::Ref(_, innermost, _) = inner.kind() { diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 03c949d5c31..6417bc81304 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -6,11 +6,15 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Symbol}; use super::CLONE_ON_REF_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { + if !(args.len() == 1 && method_name == sym::clone) { + return; + } + let arg = &args[0]; let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index d10a540c24e..950ec62c9fe 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,4 +1,3 @@ -use super::INEFFICIENT_TO_STRING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth}; @@ -8,14 +7,18 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; +use rustc_span::symbol::{sym, Symbol}; + +use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { if_chain! { + if args.len() == 1 && method_name == sym!(to_string); if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); + let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); let self_ty = substs.type_at(0); let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); if deref_count >= 1; @@ -32,7 +35,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr self_ty, deref_self_ty )); let mut applicability = Applicability::MachineApplicable; - let arg_snippet = snippet_with_applicability(cx, arg.span, "..", &mut applicability); + let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diag.span_suggestion( expr.span, "try dereferencing the receiver", diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 044348a2c34..bbf7f1d312b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -41,6 +41,7 @@ mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; mod search_is_some; +mod single_char_add_str; mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; @@ -1785,23 +1786,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); + clone_on_copy::check(cx, expr, method_call.ident.name, args); + clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args); let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); - if args.len() == 1 && method_call.ident.name == sym::clone { - clone_on_copy::check(cx, expr, &args[0], self_ty); - clone_on_ref_ptr::check(cx, expr, &args[0]); - } - if args.len() == 1 && method_call.ident.name == sym!(to_string) { - inefficient_to_string::check(cx, expr, &args[0], self_ty); - } - - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { - single_char_push_string::check(cx, expr, args); - } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { - single_char_insert_string::check(cx, expr, args); - } - } + inefficient_to_string::check(cx, expr, method_call.ident.name, args); + single_char_add_str::check(cx, expr, args); match self_ty.kind() { ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { -- cgit 1.4.1-3-g733a5 From d38076995258ed7f1ebd270f2f32b1744c688e71 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 13:22:25 +0900 Subject: extract conditions for `from_iter_instead_of_collect` into its own module --- clippy_lints/src/methods/chars_cmp.rs | 2 +- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 2 +- clippy_lints/src/methods/from_iter_instead_of_collect.rs | 12 +++++++----- clippy_lints/src/methods/mod.rs | 13 ++++--------- clippy_lints/src/methods/single_char_add_str.rs | 3 +-- 5 files changed, 14 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index f9af06d200c..c668fe52781 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -1,6 +1,6 @@ -use crate::utils::{method_chain_args, single_segment_path}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{method_chain_args, single_segment_path}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 3ba59171f77..4275857757f 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -1,5 +1,5 @@ -use crate::utils::method_chain_args; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 2095a60e44b..15cf5674313 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,20 +1,22 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, paths, sugg}; +use clippy_utils::{get_trait_def_id, match_qpath, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Ty; use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let ty = cx.typeck_results().expr_ty(expr); - let arg_ty = cx.typeck_results().expr_ty(&args[0]); - +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func_kind: &ExprKind<'_>) { if_chain! { + if let hir::ExprKind::Path(path) = func_kind; + if match_qpath(path, &["from_iter"]); + let ty = cx.typeck_results().expr_ty(expr); + let arg_ty = cx.typeck_results().expr_ty(&args[0]); if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bbf7f1d312b..808b64d9493 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -63,8 +63,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{ - contains_return, get_trait_def_id, in_macro, iter_input_pats, match_def_path, match_qpath, method_calls, - method_chain_args, paths, return_ty, single_segment_path, SpanlessEq, + contains_return, get_trait_def_id, in_macro, iter_input_pats, match_qpath, method_calls, paths, return_ty, + SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -1777,22 +1777,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(ref func, ref args) => { - if let hir::ExprKind::Path(path) = &func.kind { - if match_qpath(path, &["from_iter"]) { - from_iter_instead_of_collect::check(cx, expr, args); - } - } + from_iter_instead_of_collect::check(cx, expr, args, &func.kind); }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); clone_on_copy::check(cx, expr, method_call.ident.name, args); clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args); - - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); inefficient_to_string::check(cx, expr, method_call.ident.name, args); single_char_add_str::check(cx, expr, args); + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); match self_ty.kind() { ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { for &(method, pos) in &PATTERN_METHODS { diff --git a/clippy_lints/src/methods/single_char_add_str.rs b/clippy_lints/src/methods/single_char_add_str.rs index 3df88e5b69c..9a5fabcf7cd 100644 --- a/clippy_lints/src/methods/single_char_add_str.rs +++ b/clippy_lints/src/methods/single_char_add_str.rs @@ -1,6 +1,5 @@ use crate::methods::{single_char_insert_string, single_char_push_string}; -use crate::utils::match_def_path; -use crate::utils::paths; +use clippy_utils::{match_def_path, paths}; use rustc_hir as hir; use rustc_lint::LateContext; -- cgit 1.4.1-3-g733a5 From 7a7fcc0eda1d62f44ec374bad3d14226888238ad Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 14:14:06 +0900 Subject: extract condition for into_iter_on_ref to its own module --- clippy_lints/src/methods/into_iter_on_ref.rs | 47 +++++++++++++++++----------- clippy_lints/src/methods/mod.rs | 7 ++--- 2 files changed, 31 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index cfe749cf361..5d59fa86c9e 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,32 +1,43 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::has_iter_method; use clippy_utils::{match_trait_method, paths}; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use super::INTO_ITER_ON_REF; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) { - if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) { - return; - } - if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) { - span_lint_and_sugg( - cx, - INTO_ITER_ON_REF, - method_span, - &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", - method_name, kind, - ), - "call directly", - method_name.to_string(), - Applicability::MachineApplicable, - ); +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + method_span: Span, + method_name: Symbol, + args: &[hir::Expr<'_>], +) { + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + if_chain! { + if let ty::Ref(..) = self_ty.kind(); + if method_name == sym::into_iter; + if match_trait_method(cx, expr, &paths::INTO_ITERATOR); + if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty); + then { + span_lint_and_sugg( + cx, + INTO_ITER_ON_REF, + method_span, + &format!( + "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", + method_name, kind, + ), + "call directly", + method_name.to_string(), + Applicability::MachineApplicable, + ); + } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 808b64d9493..e8cefbd7422 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1786,9 +1786,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args); inefficient_to_string::check(cx, expr, method_call.ident.name, args); single_char_add_str::check(cx, expr, args); + into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args); - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); - match self_ty.kind() { + match cx.typeck_results().expr_ty_adjusted(&args[0]).kind() { ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { for &(method, pos) in &PATTERN_METHODS { if method_call.ident.name.as_str() == method && args.len() > pos { @@ -1796,9 +1796,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } }, - ty::Ref(..) if method_call.ident.name == sym::into_iter => { - into_iter_on_ref::check(cx, expr, self_ty, *method_span); - }, _ => (), } }, -- cgit 1.4.1-3-g733a5 From 4d1f2bc56519a9b37daaec84273f97e3aba4318b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 14:26:27 +0900 Subject: extract conditions for single_char_pattern into its own module --- clippy_lints/src/methods/mod.rs | 12 +-------- clippy_lints/src/methods/single_char_pattern.rs | 36 ++++++++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e8cefbd7422..b97dee27c52 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1787,17 +1787,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::check(cx, expr, method_call.ident.name, args); single_char_add_str::check(cx, expr, args); into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args); - - match cx.typeck_results().expr_ty_adjusted(&args[0]).kind() { - ty::Ref(_, ty, _) if *ty.kind() == ty::Str => { - for &(method, pos) in &PATTERN_METHODS { - if method_call.ident.name.as_str() == method && args.len() > pos { - single_char_pattern::check(cx, expr, &args[pos]); - } - } - }, - _ => (), - } + single_char_pattern::check(cx, expr, method_call.ident.name, args); }, hir::ExprKind::Binary(op, ref lhs, ref rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index 12d6418d700..ae998468c2d 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -1,23 +1,35 @@ use crate::methods::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; /// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - let mut applicability = Applicability::MachineApplicable; - if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "try using a `char` instead", - hint, - applicability, - ); +pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { + for &(method, pos) in &crate::methods::PATTERN_METHODS { + if_chain! { + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind(); + if *ty.kind() == ty::Str; + if method_name.as_str() == method && args.len() > pos; + let arg = &args[pos]; + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability); + then { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "try using a `char` instead", + hint, + applicability, + ); + } + } } } -- cgit 1.4.1-3-g733a5 From 27963c8dce5b2db8c6c308681682bbb33938e125 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 14:34:20 +0900 Subject: move chars_last_cmp_with_unwrap to its own module --- clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs | 13 +++++++++++++ clippy_lints/src/methods/mod.rs | 12 ++---------- 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs new file mode 100644 index 00000000000..c29ee0ec8c8 --- /dev/null +++ b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs @@ -0,0 +1,13 @@ +use crate::methods::chars_cmp_with_unwrap; +use rustc_lint::LateContext; + +use super::CHARS_LAST_CMP; + +/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { + if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { + true + } else { + chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b97dee27c52..f124d0b12f5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3,6 +3,7 @@ mod bytes_nth; mod chars_cmp; mod chars_cmp_with_unwrap; mod chars_last_cmp; +mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; mod clone_on_copy; @@ -1974,16 +1975,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info); lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info); lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info); - lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info); -} - -/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. -fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { - true - } else { - chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with") - } + lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info); } fn get_hint_if_single_char_arg( -- cgit 1.4.1-3-g733a5 From 602bcf3e4f5f540e2f81d9e807e28b35c7bee0ed Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Mar 2021 14:45:20 +0900 Subject: move get_hint_if_single_char_arg to methods/utils.rs --- clippy_lints/src/methods/mod.rs | 31 -------------------- .../src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_pattern.rs | 2 +- .../src/methods/single_char_push_string.rs | 2 +- clippy_lints/src/methods/utils.rs | 34 +++++++++++++++++++++- 5 files changed, 36 insertions(+), 35 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f124d0b12f5..a80162015dc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -61,15 +61,12 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{ contains_return, get_trait_def_id, in_macro, iter_input_pats, match_qpath, method_calls, paths, return_ty, SpanlessEq, }; use if_chain::if_chain; -use rustc_ast::ast; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -1978,34 +1975,6 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info); } -fn get_hint_if_single_char_arg( - cx: &LateContext<'_>, - arg: &hir::Expr<'_>, - applicability: &mut Applicability, -) -> Option { - if_chain! { - if let hir::ExprKind::Lit(lit) = &arg.kind; - if let ast::LitKind::Str(r, style) = lit.node; - let string = r.as_str(); - if string.chars().count() == 1; - then { - let snip = snippet_with_applicability(cx, arg.span, &string, applicability); - let ch = if let ast::StrStyle::Raw(nhash) = style { - let nhash = nhash as usize; - // for raw string: r##"a"## - &snip[(nhash + 2)..(snip.len() - 1 - nhash)] - } else { - // for regular string: "a" - &snip[1..(snip.len() - 1)] - }; - let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); - Some(hint) - } else { - None - } - } -} - const FN_HEADER: hir::FnHeader = hir::FnHeader { unsafety: hir::Unsafety::Normal, constness: hir::Constness::NotConst, diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index cd87d2c56b7..3f3e3bd7dfd 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,4 +1,4 @@ -use crate::methods::get_hint_if_single_char_arg; +use crate::methods::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index ae998468c2d..abead199098 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -1,4 +1,4 @@ -use crate::methods::get_hint_if_single_char_arg; +use crate::methods::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 882703a987d..189157f819e 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,4 +1,4 @@ -use crate::methods::get_hint_if_single_char_arg; +use crate::methods::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 4d801148cbc..8de23e1bc6e 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,11 +1,15 @@ +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; use rustc_span::symbol::sym; -pub fn derefs_to_slice<'tcx>( +pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, @@ -44,3 +48,31 @@ pub fn derefs_to_slice<'tcx>( } } } + +pub(super) fn get_hint_if_single_char_arg( + cx: &LateContext<'_>, + arg: &hir::Expr<'_>, + applicability: &mut Applicability, +) -> Option { + if_chain! { + if let hir::ExprKind::Lit(lit) = &arg.kind; + if let ast::LitKind::Str(r, style) = lit.node; + let string = r.as_str(); + if string.chars().count() == 1; + then { + let snip = snippet_with_applicability(cx, arg.span, &string, applicability); + let ch = if let ast::StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; + let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); + Some(hint) + } else { + None + } + } +} -- cgit 1.4.1-3-g733a5 From 0edd5f881d287dcff1b7401c44c8482cbd627c6b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 18 Mar 2021 01:06:24 +0900 Subject: remove the use of paths --- clippy_lints/src/methods/into_iter_on_ref.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 5d59fa86c9e..da13b4ba37a 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::ty::has_iter_method; -use clippy_utils::{match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -22,7 +22,7 @@ pub(super) fn check( if_chain! { if let ty::Ref(..) = self_ty.kind(); if method_name == sym::into_iter; - if match_trait_method(cx, expr, &paths::INTO_ITERATOR); + if is_trait_method(cx, expr, sym::IntoIterator); if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty); then { span_lint_and_sugg( -- cgit 1.4.1-3-g733a5 From b6a2757561167f831939f874735e259e655031a1 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 18 Mar 2021 01:23:37 +0900 Subject: replace crate::methods::utils with super::utils --- clippy_lints/src/methods/iter_next_slice.rs | 2 +- clippy_lints/src/methods/iter_nth.rs | 2 +- clippy_lints/src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_pattern.rs | 2 +- clippy_lints/src/methods/single_char_push_string.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index 2155159bf7c..e9b37b6f2bd 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -1,4 +1,4 @@ -use crate::methods::utils::derefs_to_slice; +use super::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index bf1575660d1..c46af427b3c 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -1,5 +1,5 @@ +use super::utils::derefs_to_slice; use crate::methods::iter_nth_zero; -use crate::methods::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 3f3e3bd7dfd..6cdc954c03b 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,4 +1,4 @@ -use crate::methods::utils::get_hint_if_single_char_arg; +use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index abead199098..f4090c7c617 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -1,4 +1,4 @@ -use crate::methods::utils::get_hint_if_single_char_arg; +use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 189157f819e..0237d39cbdb 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,4 +1,4 @@ -use crate::methods::utils::get_hint_if_single_char_arg; +use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -- cgit 1.4.1-3-g733a5 From ea15fb2177b0c33352363c130bc296a0dd1a794a Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Wed, 17 Mar 2021 15:52:14 +0100 Subject: wrong_self_convention: `to_` respects `Copy` types More details here: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv --- clippy_lints/src/methods/mod.rs | 39 +++++++----- clippy_lints/src/methods/wrong_self_convention.rs | 74 +++++++++++++---------- tests/ui/use_self.fixed | 1 + tests/ui/use_self.rs | 1 + tests/ui/use_self.stderr | 46 +++++++------- tests/ui/wrong_self_convention.rs | 32 ++++++++++ tests/ui/wrong_self_convention.stderr | 36 +++++------ tests/ui/wrong_self_conventions_mut.stderr | 4 +- 8 files changed, 143 insertions(+), 90 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index af8fe7abd96..722effc29b2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -193,14 +193,18 @@ declare_clippy_lint! { /// **What it does:** Checks for methods with certain name prefixes and which /// doesn't match how self is taken. The actual rules are: /// - /// |Prefix |Postfix |`self` taken | - /// |-------|------------|----------------------| - /// |`as_` | none |`&self` or `&mut self`| - /// |`from_`| none | none | - /// |`into_`| none |`self` | - /// |`is_` | none |`&self` or none | - /// |`to_` | `_mut` |`&mut &self` | - /// |`to_` | not `_mut` |`&self` | + /// |Prefix |Postfix |`self` taken | `self` type | + /// |-------|------------|-----------------------|--------------| + /// |`as_` | none |`&self` or `&mut self` | any | + /// |`from_`| none | none | any | + /// |`into_`| none |`self` | any | + /// |`is_` | none |`&self` or none | any | + /// |`to_` | `_mut` |`&mut self` | any | + /// |`to_` | not `_mut` |`self` | `Copy` | + /// |`to_` | not `_mut` |`&self` | not `Copy` | + /// + /// Please find more info here: + /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv /// /// **Why is this bad?** Consistency breeds readability. If you follow the /// conventions, your users won't be surprised that they, e.g., need to supply a @@ -1837,10 +1841,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let item = cx.tcx.hir().expect_item(parent); let self_ty = cx.tcx.type_of(item.def_id); - // if this impl block implements a trait, lint in trait definition instead - if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind { - return; - } + let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); if_chain! { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; @@ -1855,7 +1856,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let Some(first_arg_ty) = first_arg_ty; then { - if cx.access_levels.is_exported(impl_item.hir_id()) { + // if this impl block implements a trait, lint in trait definition instead + if !implements_trait && cx.access_levels.is_exported(impl_item.hir_id()) { // check missing trait implementations for method_config in &TRAIT_METHODS { if name == method_config.method_name && @@ -1891,11 +1893,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { item.vis.node.is_pub(), self_ty, first_arg_ty, - first_arg.pat.span + first_arg.pat.span, + false ); } } + // if this impl block implements a trait, lint in trait definition instead + if implements_trait { + return; + } + if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { let ret_ty = return_ty(cx, impl_item.hir_id()); @@ -1947,7 +1955,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { false, self_ty, first_arg_ty, - first_arg_span + first_arg_span, + true ); } } diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index b728d7d8d08..bece8f251da 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -1,5 +1,6 @@ use crate::methods::SelfKind; use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_copy; use rustc_lint::LateContext; use rustc_middle::ty::TyS; use rustc_span::source_map::Span; @@ -9,7 +10,7 @@ use super::WRONG_PUB_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION; #[rustfmt::skip] -const CONVENTIONS: [(&[Convention], &[SelfKind]); 8] = [ +const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ (&[Convention::Eq("new")], &[SelfKind::No]), (&[Convention::StartsWith("as_")], &[SelfKind::Ref, SelfKind::RefMut]), (&[Convention::StartsWith("from_")], &[SelfKind::No]), @@ -17,7 +18,11 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 8] = [ (&[Convention::StartsWith("is_")], &[SelfKind::Ref, SelfKind::No]), (&[Convention::Eq("to_mut")], &[SelfKind::RefMut]), (&[Convention::StartsWith("to_"), Convention::EndsWith("_mut")], &[SelfKind::RefMut]), - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut")], &[SelfKind::Ref]), + + // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types). + // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; enum Convention { @@ -25,16 +30,20 @@ enum Convention { StartsWith(&'static str), EndsWith(&'static str), NotEndsWith(&'static str), + IsSelfTypeCopy(bool), + ImplementsTrait(bool), } impl Convention { #[must_use] - fn check(&self, other: &str) -> bool { + fn check<'tcx>(&self, cx: &LateContext<'tcx>, self_ty: &'tcx TyS<'tcx>, other: &str, is_trait_def: bool) -> bool { match *self { Self::Eq(this) => this == other, Self::StartsWith(this) => other.starts_with(this) && this != other, Self::EndsWith(this) => other.ends_with(this) && this != other, - Self::NotEndsWith(this) => !Self::EndsWith(this).check(other), + Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, is_trait_def), + Self::IsSelfTypeCopy(is_true) => is_true == is_copy(cx, self_ty), + Self::ImplementsTrait(is_true) => is_true == is_trait_def, } } } @@ -46,6 +55,10 @@ impl fmt::Display for Convention { Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), Self::EndsWith(this) => '*'.fmt(f).and_then(|_| this.fmt(f)), Self::NotEndsWith(this) => '~'.fmt(f).and_then(|_| this.fmt(f)), + Self::IsSelfTypeCopy(is_true) => format!("self type is {} Copy", if is_true { "" } else { "not" }).fmt(f), + Self::ImplementsTrait(is_true) => { + format!("Method {} implement a trait", if is_true { "" } else { "do not" }).fmt(f) + }, } } } @@ -57,45 +70,42 @@ pub(super) fn check<'tcx>( self_ty: &'tcx TyS<'tcx>, first_arg_ty: &'tcx TyS<'tcx>, first_arg_span: Span, + is_trait_item: bool, ) { let lint = if is_pub { WRONG_PUB_SELF_CONVENTION } else { WRONG_SELF_CONVENTION }; - if let Some((conventions, self_kinds)) = &CONVENTIONS - .iter() - .find(|(convs, _)| convs.iter().all(|conv| conv.check(item_name))) - { + if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { + convs + .iter() + .all(|conv| conv.check(cx, self_ty, item_name, is_trait_item)) + }) { if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { let suggestion = { if conventions.len() > 1 { - let special_case = { - // Don't mention `NotEndsWith` when there is also `StartsWith` convention present - if conventions.len() == 2 { - match conventions { - [Convention::StartsWith(starts_with), Convention::NotEndsWith(_)] - | [Convention::NotEndsWith(_), Convention::StartsWith(starts_with)] => { - Some(format!("methods called `{}`", Convention::StartsWith(starts_with))) - }, - _ => None, - } - } else { - None - } - }; - - if let Some(suggestion) = special_case { - suggestion - } else { - let s = conventions + // Don't mention `NotEndsWith` when there is also `StartsWith` convention present + let cut_ends_with_conv = conventions.iter().any(|conv| matches!(conv, Convention::StartsWith(_))) + && conventions .iter() - .map(|c| format!("`{}`", &c.to_string())) - .collect::>() - .join(" and "); + .any(|conv| matches!(conv, Convention::NotEndsWith(_))); + + let s = conventions + .iter() + .filter_map(|conv| { + if (cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_))) + || matches!(conv, Convention::ImplementsTrait(_)) + { + None + } else { + Some(format!("`{}`", &conv.to_string())) + } + }) + .collect::>() + .join(" and "); - format!("methods called like this: ({})", &s) - } + format!("methods with the following characteristics: ({})", &s) } else { format!("methods called `{}`", &conventions[0]) } diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index a630936e3b1..1986b54e66c 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -79,6 +79,7 @@ mod issue2894 { } // This should not be linted + #[allow(clippy::wrong_self_convention)] impl IntoBytes for u8 { fn to_bytes(&self) -> Vec { vec![*self] diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index f3e081dd203..acc18280f1a 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -79,6 +79,7 @@ mod issue2894 { } // This should not be linted + #[allow(clippy::wrong_self_convention)] impl IntoBytes for u8 { fn to_bytes(&self) -> Vec { vec![*self] diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index e1410d2e652..a2c95963487 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -37,139 +37,139 @@ LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:93:24 + --> $DIR/use_self.rs:94:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:93:55 + --> $DIR/use_self.rs:94:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:108:13 + --> $DIR/use_self.rs:109:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:143:29 + --> $DIR/use_self.rs:144:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:144:21 + --> $DIR/use_self.rs:145:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:155:21 + --> $DIR/use_self.rs:156:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:156:13 + --> $DIR/use_self.rs:157:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:173:21 + --> $DIR/use_self.rs:174:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:174:21 + --> $DIR/use_self.rs:175:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:175:21 + --> $DIR/use_self.rs:176:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:217:13 + --> $DIR/use_self.rs:218:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:218:13 + --> $DIR/use_self.rs:219:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:220:13 + --> $DIR/use_self.rs:221:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:239:13 + --> $DIR/use_self.rs:240:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:253:25 + --> $DIR/use_self.rs:254:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:254:13 + --> $DIR/use_self.rs:255:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:258:16 + --> $DIR/use_self.rs:259:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:258:22 + --> $DIR/use_self.rs:259:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:281:29 + --> $DIR/use_self.rs:282:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:282:13 + --> $DIR/use_self.rs:283:13 | LL | Foo { value } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:319:21 + --> $DIR/use_self.rs:320:21 | LL | type From = T::From; | ^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:320:19 + --> $DIR/use_self.rs:321:19 | LL | type To = T::To; | ^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:453:13 + --> $DIR/use_self.rs:454:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 6cfc0fcb4ca..ba9e19a1722 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -163,3 +163,35 @@ mod issue6307 { fn to_mut(&mut self); } } + +mod issue6727 { + trait ToU64 { + fn to_u64(self) -> u64; + fn to_u64_v2(&self) -> u64; + } + + #[derive(Clone, Copy)] + struct FooCopy; + + impl ToU64 for FooCopy { + fn to_u64(self) -> u64 { + 1 + } + // trigger lint + fn to_u64_v2(&self) -> u64 { + 1 + } + } + + struct FooNoCopy; + + impl ToU64 for FooNoCopy { + // trigger lint + fn to_u64(self) -> u64 { + 2 + } + fn to_u64_v2(&self) -> u64 { + 2 + } + } +} diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index f43fea0d513..6daa334ed48 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -39,7 +39,7 @@ LL | fn is_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference +error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference --> $DIR/wrong_self_convention.rs:42:15 | LL | fn to_i32(self) {} @@ -79,7 +79,7 @@ LL | pub fn is_i64(self) {} | = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference +error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference --> $DIR/wrong_self_convention.rs:49:19 | LL | pub fn to_i64(self) {} @@ -119,14 +119,6 @@ LL | fn is_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference - --> $DIR/wrong_self_convention.rs:102:19 - | -LL | fn to_i32(self) {} - | ^^^^ - | - = help: consider choosing a less ambiguous name - error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:104:21 | @@ -159,14 +151,6 @@ LL | fn is_i32(self); | = help: consider choosing a less ambiguous name -error: methods called `to_*` usually take self by reference - --> $DIR/wrong_self_convention.rs:126:19 - | -LL | fn to_i32(self); - | ^^^^ - | - = help: consider choosing a less ambiguous name - error: methods called `from_*` usually take no self --> $DIR/wrong_self_convention.rs:128:21 | @@ -191,5 +175,21 @@ LL | fn from_i32(self); | = help: consider choosing a less ambiguous name +error: methods with the following characteristics: (`to_*` and `self type is Copy`) usually take self by value + --> $DIR/wrong_self_convention.rs:181:22 + | +LL | fn to_u64_v2(&self) -> u64 { + | ^^^^^ + | + = help: consider choosing a less ambiguous name + +error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference + --> $DIR/wrong_self_convention.rs:190:19 + | +LL | fn to_u64(self) -> u64 { + | ^^^^ + | + = help: consider choosing a less ambiguous name + error: aborting due to 24 previous errors diff --git a/tests/ui/wrong_self_conventions_mut.stderr b/tests/ui/wrong_self_conventions_mut.stderr index 7662b38e67d..8095188758c 100644 --- a/tests/ui/wrong_self_conventions_mut.stderr +++ b/tests/ui/wrong_self_conventions_mut.stderr @@ -1,4 +1,4 @@ -error: methods called `to_*` usually take self by reference +error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference --> $DIR/wrong_self_conventions_mut.rs:15:24 | LL | pub fn to_many(&mut self) -> Option<&mut [T]> { @@ -7,7 +7,7 @@ LL | pub fn to_many(&mut self) -> Option<&mut [T]> { = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name -error: methods called like this: (`to_*` and `*_mut`) usually take self by mutable reference +error: methods with the following characteristics: (`to_*` and `*_mut`) usually take self by mutable reference --> $DIR/wrong_self_conventions_mut.rs:23:28 | LL | pub fn to_many_mut(&self) -> Option<&[T]> { -- cgit 1.4.1-3-g733a5 From b1f89ee02ff05d559a27949601bef628e498b128 Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Wed, 17 Mar 2021 20:29:31 +0100 Subject: or_fun_call: trigger on unsafe blocks --- clippy_lints/src/methods/or_fun_call.rs | 13 +++++++++++-- tests/ui/or_fun_call.fixed | 14 ++++++++++++++ tests/ui/or_fun_call.rs | 14 ++++++++++++++ tests/ui/or_fun_call.stderr | 20 +++++++++++++++++++- 4 files changed, 58 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 1b43802a08e..22df3e028f9 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -6,6 +6,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::{BlockCheckMode, UnsafeSource}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Span; @@ -154,7 +155,6 @@ pub(super) fn check<'tcx>( } } } - if args.len() == 2 { match args[1].kind { hir::ExprKind::Call(ref fun, ref or_args) => { @@ -167,7 +167,16 @@ pub(super) fn check<'tcx>( hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); }, - _ => {}, + hir::ExprKind::Block(block, _) => { + if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { + if let Some(block_expr) = block.expr { + if let hir::ExprKind::MethodCall(..) = block_expr.kind { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + } + } + } + }, + _ => (), } } } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 64347cae5da..660245f10c3 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -132,4 +132,18 @@ fn f() -> Option<()> { Some(()) } +mod issue6675 { + unsafe fn foo() { + let mut s = "test".to_owned(); + None.unwrap_or_else(|| s.as_mut_vec()); + } + + fn bar() { + let mut s = "test".to_owned(); + None.unwrap_or_else(|| unsafe { s.as_mut_vec() }); + #[rustfmt::skip] + None.unwrap_or_else(|| unsafe { s.as_mut_vec() }); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 7faab0017b2..c589b170bdd 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -132,4 +132,18 @@ fn f() -> Option<()> { Some(()) } +mod issue6675 { + unsafe fn foo() { + let mut s = "test".to_owned(); + None.unwrap_or(s.as_mut_vec()); + } + + fn bar() { + let mut s = "test".to_owned(); + None.unwrap_or(unsafe { s.as_mut_vec() }); + #[rustfmt::skip] + None.unwrap_or( unsafe { s.as_mut_vec() } ); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 1e2bfd490e0..d63b3443592 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -114,5 +114,23 @@ error: use of `or` followed by a function call LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 19 previous errors +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:138:14 + | +LL | None.unwrap_or(s.as_mut_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:143:14 + | +LL | None.unwrap_or(unsafe { s.as_mut_vec() }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:145:14 + | +LL | None.unwrap_or( unsafe { s.as_mut_vec() } ); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` + +error: aborting due to 22 previous errors -- cgit 1.4.1-3-g733a5 From 1f2d01641d6ef2f283265eb603c7d231692b6a89 Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Thu, 18 Mar 2021 19:45:13 +0100 Subject: wrong_self_convention: Enhance lint message --- clippy_lints/src/methods/mod.rs | 8 ++-- clippy_lints/src/methods/wrong_self_convention.rs | 19 +++++---- tests/ui/def_id_nocore.stderr | 2 +- tests/ui/wrong_self_convention.stderr | 48 +++++++++++------------ tests/ui/wrong_self_conventions_mut.stderr | 4 +- 5 files changed, 42 insertions(+), 39 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 722effc29b2..a3652c18a78 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2348,10 +2348,10 @@ impl SelfKind { #[must_use] fn description(self) -> &'static str { match self { - Self::Value => "self by value", - Self::Ref => "self by reference", - Self::RefMut => "self by mutable reference", - Self::No => "no self", + Self::Value => "`self` by value", + Self::Ref => "`self` by reference", + Self::RefMut => "`self` by mutable reference", + Self::No => "no `self`", } } } diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index bece8f251da..59e683aa9a7 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -51,13 +51,16 @@ impl Convention { impl fmt::Display for Convention { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { - Self::Eq(this) => this.fmt(f), - Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), - Self::EndsWith(this) => '*'.fmt(f).and_then(|_| this.fmt(f)), - Self::NotEndsWith(this) => '~'.fmt(f).and_then(|_| this.fmt(f)), - Self::IsSelfTypeCopy(is_true) => format!("self type is {} Copy", if is_true { "" } else { "not" }).fmt(f), + Self::Eq(this) => format!("`{}`", this).fmt(f), + Self::StartsWith(this) => format!("`{}*`", this).fmt(f), + Self::EndsWith(this) => format!("`*{}`", this).fmt(f), + Self::NotEndsWith(this) => format!("`~{}`", this).fmt(f), + Self::IsSelfTypeCopy(is_true) => { + format!("`self` type is{} `Copy`", if is_true { "" } else { " not" }).fmt(f) + }, Self::ImplementsTrait(is_true) => { - format!("Method {} implement a trait", if is_true { "" } else { "do not" }).fmt(f) + let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") }; + format!("Method{} implement{} a trait", negation, s_suffix).fmt(f) }, } } @@ -99,7 +102,7 @@ pub(super) fn check<'tcx>( { None } else { - Some(format!("`{}`", &conv.to_string())) + Some(conv.to_string()) } }) .collect::>() @@ -107,7 +110,7 @@ pub(super) fn check<'tcx>( format!("methods with the following characteristics: ({})", &s) } else { - format!("methods called `{}`", &conventions[0]) + format!("methods called {}", &conventions[0]) } }; diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index a3e9cc75b08..702684f6b43 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,4 +1,4 @@ -error: methods called `as_*` usually take self by reference or self by mutable reference +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/def_id_nocore.rs:26:19 | LL | pub fn as_ref(self) -> &'static str { diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 6daa334ed48..1d58a12ac79 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,4 +1,4 @@ -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:18:17 | LL | fn from_i32(self) {} @@ -7,7 +7,7 @@ LL | fn from_i32(self) {} = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:24:21 | LL | pub fn from_i64(self) {} @@ -15,7 +15,7 @@ LL | pub fn from_i64(self) {} | = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:36:15 | LL | fn as_i32(self) {} @@ -23,7 +23,7 @@ LL | fn as_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:38:17 | LL | fn into_i32(&self) {} @@ -31,7 +31,7 @@ LL | fn into_i32(&self) {} | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:40:15 | LL | fn is_i32(self) {} @@ -39,7 +39,7 @@ LL | fn is_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference --> $DIR/wrong_self_convention.rs:42:15 | LL | fn to_i32(self) {} @@ -47,7 +47,7 @@ LL | fn to_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:44:17 | LL | fn from_i32(self) {} @@ -55,7 +55,7 @@ LL | fn from_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn as_i64(self) {} @@ -63,7 +63,7 @@ LL | pub fn as_i64(self) {} | = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:47:21 | LL | pub fn into_i64(&self) {} @@ -71,7 +71,7 @@ LL | pub fn into_i64(&self) {} | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn is_i64(self) {} @@ -79,7 +79,7 @@ LL | pub fn is_i64(self) {} | = help: consider choosing a less ambiguous name -error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference --> $DIR/wrong_self_convention.rs:49:19 | LL | pub fn to_i64(self) {} @@ -87,7 +87,7 @@ LL | pub fn to_i64(self) {} | = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:50:21 | LL | pub fn from_i64(self) {} @@ -95,7 +95,7 @@ LL | pub fn from_i64(self) {} | = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:95:19 | LL | fn as_i32(self) {} @@ -103,7 +103,7 @@ LL | fn as_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:98:25 | LL | fn into_i32_ref(&self) {} @@ -111,7 +111,7 @@ LL | fn into_i32_ref(&self) {} | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:100:19 | LL | fn is_i32(self) {} @@ -119,7 +119,7 @@ LL | fn is_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:104:21 | LL | fn from_i32(self) {} @@ -127,7 +127,7 @@ LL | fn from_i32(self) {} | = help: consider choosing a less ambiguous name -error: methods called `as_*` usually take self by reference or self by mutable reference +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference --> $DIR/wrong_self_convention.rs:119:19 | LL | fn as_i32(self); @@ -135,7 +135,7 @@ LL | fn as_i32(self); | = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:122:25 | LL | fn into_i32_ref(&self); @@ -143,7 +143,7 @@ LL | fn into_i32_ref(&self); | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take self by reference or no self +error: methods called `is_*` usually take `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:124:19 | LL | fn is_i32(self); @@ -151,7 +151,7 @@ LL | fn is_i32(self); | = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:128:21 | LL | fn from_i32(self); @@ -159,7 +159,7 @@ LL | fn from_i32(self); | = help: consider choosing a less ambiguous name -error: methods called `into_*` usually take self by value +error: methods called `into_*` usually take `self` by value --> $DIR/wrong_self_convention.rs:146:25 | LL | fn into_i32_ref(&self); @@ -167,7 +167,7 @@ LL | fn into_i32_ref(&self); | = help: consider choosing a less ambiguous name -error: methods called `from_*` usually take no self +error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:152:21 | LL | fn from_i32(self); @@ -175,7 +175,7 @@ LL | fn from_i32(self); | = help: consider choosing a less ambiguous name -error: methods with the following characteristics: (`to_*` and `self type is Copy`) usually take self by value +error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value --> $DIR/wrong_self_convention.rs:181:22 | LL | fn to_u64_v2(&self) -> u64 { @@ -183,7 +183,7 @@ LL | fn to_u64_v2(&self) -> u64 { | = help: consider choosing a less ambiguous name -error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference --> $DIR/wrong_self_convention.rs:190:19 | LL | fn to_u64(self) -> u64 { diff --git a/tests/ui/wrong_self_conventions_mut.stderr b/tests/ui/wrong_self_conventions_mut.stderr index 8095188758c..6ce37c59491 100644 --- a/tests/ui/wrong_self_conventions_mut.stderr +++ b/tests/ui/wrong_self_conventions_mut.stderr @@ -1,4 +1,4 @@ -error: methods with the following characteristics: (`to_*` and `self type is not Copy`) usually take self by reference +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference --> $DIR/wrong_self_conventions_mut.rs:15:24 | LL | pub fn to_many(&mut self) -> Option<&mut [T]> { @@ -7,7 +7,7 @@ LL | pub fn to_many(&mut self) -> Option<&mut [T]> { = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name -error: methods with the following characteristics: (`to_*` and `*_mut`) usually take self by mutable reference +error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference --> $DIR/wrong_self_conventions_mut.rs:23:28 | LL | pub fn to_many_mut(&self) -> Option<&[T]> { -- cgit 1.4.1-3-g733a5 From 2ffee89b752212d4e7d72ece16636d7c43b11c63 Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Sat, 20 Mar 2021 14:30:45 +0100 Subject: search_is_some: check also when search is none --- clippy_lints/src/methods/mod.rs | 57 ++++++++++++--- clippy_lints/src/methods/search_is_some.rs | 107 +++++++++++++++++++++-------- tests/ui/search_is_some.rs | 37 +++++++++- tests/ui/search_is_some.stderr | 44 ++++++++++-- tests/ui/search_is_some_fixable.fixed | 35 +++++++++- tests/ui/search_is_some_fixable.rs | 35 +++++++++- tests/ui/search_is_some_fixable.stderr | 92 ++++++++++++++++++++++++- 7 files changed, 359 insertions(+), 48 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 46deb20f97d..5be28354769 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -588,26 +588,31 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for an iterator or string search (such as `find()`, - /// `position()`, or `rposition()`) followed by a call to `is_some()`. + /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.any(_)` or `_.contains(_)`. + /// **Why is this bad?** Readability, this can be written more concisely as: + /// * `_.any(_)`, or `_.contains(_)` for `is_some()`, + /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`. /// /// **Known problems:** None. /// /// **Example:** /// ```rust - /// # let vec = vec![1]; + /// let vec = vec![1]; /// vec.iter().find(|x| **x == 0).is_some(); + /// + /// let _ = "hello world".find("world").is_none(); /// ``` /// Could be written as /// ```rust - /// # let vec = vec![1]; + /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); + /// + /// let _ = !"hello world".contains("world"); /// ``` pub SEARCH_IS_SOME, complexity, - "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`" + "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)" } declare_clippy_lint! { @@ -1720,12 +1725,42 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]), - ["is_some", "find"] => search_is_some::check(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]), - ["is_some", "position"] => { - search_is_some::check(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1]) + [option_check_method, "find"] if "is_some" == *option_check_method || "is_none" == *option_check_method => { + search_is_some::check( + cx, + expr, + "find", + option_check_method, + arg_lists[1], + arg_lists[0], + method_spans[1], + ) }, - ["is_some", "rposition"] => { - search_is_some::check(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) + [option_check_method, "position"] + if "is_some" == *option_check_method || "is_none" == *option_check_method => + { + search_is_some::check( + cx, + expr, + "position", + option_check_method, + arg_lists[1], + arg_lists[0], + method_spans[1], + ) + }, + [option_check_method, "rposition"] + if "is_some" == *option_check_method || "is_none" == *option_check_method => + { + search_is_some::check( + cx, + expr, + "rposition", + option_check_method, + arg_lists[1], + arg_lists[0], + method_spans[1], + ) }, ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]), ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 13546dc1779..de7d168295f 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -14,11 +14,13 @@ use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; /// lint searching an Iterator followed by `is_some()` -/// or calling `find()` on a string followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` or `is_none()` +#[allow(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, search_method: &str, + option_check_method: &str, search_args: &'tcx [hir::Expr<'_>], is_some_args: &'tcx [hir::Expr<'_>], method_span: Span, @@ -26,10 +28,9 @@ pub(super) fn check<'tcx>( // lint if caller of search is an Iterator if is_trait_method(cx, &is_some_args[0], sym::Iterator) { let msg = format!( - "called `is_some()` after searching an `Iterator` with `{}`", - search_method + "called `{}()` after searching an `Iterator` with `{}`", + option_check_method, search_method ); - let hint = "this is more succinctly expressed by calling `any()`"; let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -53,20 +54,49 @@ pub(super) fn check<'tcx>( } }; // add note if not multi-line - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - &msg, - "use `any()` instead", - format!( - "any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); + match option_check_method { + "is_some" => { + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `any()` instead", + format!( + "any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + }, + "is_none" => { + let iter = snippet(cx, search_args[0].span, ".."); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + "use `!_.any()` instead", + format!( + "!{}.any({})", + iter, + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + }, + _ => (), + } } else { - span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); + let hint = format!( + "this is more succinctly expressed by calling `any()`{}", + if option_check_method == "is_none" { + " with negation" + } else { + "" + } + ); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, &hint); } } // lint if `find()` is called by `String` or `&str` @@ -83,18 +113,37 @@ pub(super) fn check<'tcx>( if is_string_or_str_slice(&search_args[0]); if is_string_or_str_slice(&search_args[1]); then { - let msg = "called `is_some()` after calling `find()` on a string"; - let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - msg, - "use `contains()` instead", - format!("contains({})", find_arg), - applicability, - ); + let msg = format!("called `{}()` after calling `find()` on a string", option_check_method); + match option_check_method { + "is_some" => { + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `contains()` instead", + format!("contains({})", find_arg), + applicability, + ); + }, + "is_none" => { + let string = snippet(cx, search_args[0].span, ".."); + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + "use `!_.contains()` instead", + format!("!{}.contains({})", string, find_arg), + applicability, + ); + }, + _ => (), + } } } } diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index f0dc3b3d06b..72bc6ef35d3 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,8 +1,9 @@ // aux-build:option_helpers.rs +#![warn(clippy::search_is_some)] +#![allow(dead_code)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; -#[warn(clippy::search_is_some)] #[rustfmt::skip] fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; @@ -36,3 +37,37 @@ fn main() { // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); } + +#[rustfmt::skip] +fn is_none() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + + // Check `find().is_none()`, multi-line case. + let _ = v.iter().find(|&x| { + *x < 0 + } + ).is_none(); + + // Check `position().is_none()`, multi-line case. + let _ = v.iter().position(|&x| { + x < 0 + } + ).is_none(); + + // Check `rposition().is_none()`, multi-line case. + let _ = v.iter().rposition(|&x| { + x < 0 + } + ).is_none(); + + // Check that we don't lint if the caller is not an `Iterator` or string + let falsepos = IteratorFalsePositives { foo: 0 }; + let _ = falsepos.find().is_none(); + let _ = falsepos.position().is_none(); + let _ = falsepos.rposition().is_none(); + // check that we don't lint if `find()` is called with + // `Pattern` that is not a string + let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none(); +} diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index c601f568c60..f3c758e451e 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:13:13 + --> $DIR/search_is_some.rs:14:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -12,7 +12,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `position` - --> $DIR/search_is_some.rs:19:13 + --> $DIR/search_is_some.rs:20:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -24,7 +24,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some.rs:25:13 + --> $DIR/search_is_some.rs:26:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -35,5 +35,41 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` -error: aborting due to 3 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:48:13 + | +LL | let _ = v.iter().find(|&x| { + | _____________^ +LL | | *x < 0 +LL | | } +LL | | ).is_none(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` with negation + +error: called `is_none()` after searching an `Iterator` with `position` + --> $DIR/search_is_some.rs:54:13 + | +LL | let _ = v.iter().position(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_none(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` with negation + +error: called `is_none()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some.rs:60:13 + | +LL | let _ = v.iter().rposition(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_none(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` with negation + +error: aborting due to 6 previous errors diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed index dc3f290e562..62ff16f67f4 100644 --- a/tests/ui/search_is_some_fixable.fixed +++ b/tests/ui/search_is_some_fixable.fixed @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![warn(clippy::search_is_some)] fn main() { @@ -33,3 +33,36 @@ fn main() { let _ = s1[2..].contains(&s2); let _ = s1[2..].contains(&s2[2..]); } + +fn is_none() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_none()`, single-line case. + let _ = !v.iter().any(|x| *x < 0); + let _ = !(0..1).any(|x| **y == x); // one dereference less + let _ = !(0..1).any(|x| x == 0); + let _ = !v.iter().any(|x| *x == 0); + + // Check `position().is_none()`, single-line case. + let _ = !v.iter().any(|&x| x < 0); + + // Check `rposition().is_none()`, single-line case. + let _ = !v.iter().any(|&x| x < 0); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + + // caller of `find()` is a `&`static str` + let _ = !"hello world".contains("world"); + let _ = !"hello world".contains(&s2); + let _ = !"hello world".contains(&s2[2..]); + // caller of `find()` is a `String` + let _ = !s1.contains("world"); + let _ = !s1.contains(&s2); + let _ = !s1.contains(&s2[2..]); + // caller of `find()` is slice of `String` + let _ = !s1[2..].contains("world"); + let _ = !s1[2..].contains(&s2); + let _ = !s1[2..].contains(&s2[2..]); +} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs index 146cf5adf1b..8407f716647 100644 --- a/tests/ui/search_is_some_fixable.rs +++ b/tests/ui/search_is_some_fixable.rs @@ -1,5 +1,5 @@ // run-rustfix - +#![allow(dead_code)] #![warn(clippy::search_is_some)] fn main() { @@ -33,3 +33,36 @@ fn main() { let _ = s1[2..].find(&s2).is_some(); let _ = s1[2..].find(&s2[2..]).is_some(); } + +fn is_none() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_none()`, single-line case. + let _ = v.iter().find(|&x| *x < 0).is_none(); + let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_none(); + let _ = v.iter().find(|x| **x == 0).is_none(); + + // Check `position().is_none()`, single-line case. + let _ = v.iter().position(|&x| x < 0).is_none(); + + // Check `rposition().is_none()`, single-line case. + let _ = v.iter().rposition(|&x| x < 0).is_none(); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + + // caller of `find()` is a `&`static str` + let _ = "hello world".find("world").is_none(); + let _ = "hello world".find(&s2).is_none(); + let _ = "hello world".find(&s2[2..]).is_none(); + // caller of `find()` is a `String` + let _ = s1.find("world").is_none(); + let _ = s1.find(&s2).is_none(); + let _ = s1.find(&s2[2..]).is_none(); + // caller of `find()` is slice of `String` + let _ = s1[2..].find("world").is_none(); + let _ = s1[2..].find(&s2).is_none(); + let _ = s1[2..].find(&s2[2..]).is_none(); +} diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index 23c1d9a901b..bd1b6955a97 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -90,5 +90,95 @@ error: called `is_some()` after calling `find()` on a string LL | let _ = s1[2..].find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` -error: aborting due to 15 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:42:13 + | +LL | let _ = v.iter().find(|&x| *x < 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:43:13 + | +LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:44:13 + | +LL | let _ = (0..1).find(|x| *x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:45:13 + | +LL | let _ = v.iter().find(|x| **x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)` + +error: called `is_none()` after searching an `Iterator` with `position` + --> $DIR/search_is_some_fixable.rs:48:13 + | +LL | let _ = v.iter().position(|&x| x < 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + +error: called `is_none()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some_fixable.rs:51:13 + | +LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:57:13 + | +LL | let _ = "hello world".find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:58:13 + | +LL | let _ = "hello world".find(&s2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:59:13 + | +LL | let _ = "hello world".find(&s2[2..]).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:61:13 + | +LL | let _ = s1.find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:62:13 + | +LL | let _ = s1.find(&s2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:63:13 + | +LL | let _ = s1.find(&s2[2..]).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:65:13 + | +LL | let _ = s1[2..].find("world").is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:66:13 + | +LL | let _ = s1[2..].find(&s2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)` + +error: called `is_none()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:67:13 + | +LL | let _ = s1[2..].find(&s2[2..]).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` + +error: aborting due to 30 previous errors -- cgit 1.4.1-3-g733a5 From 45e775697ea4376224275e0c568fbefed6645fee Mon Sep 17 00:00:00 2001 From: Jamie Quigley Date: Mon, 22 Mar 2021 19:34:20 +0000 Subject: Ignore str::len() in or_fun_call lint. --- clippy_lints/src/methods/or_fun_call.rs | 2 +- tests/ui/or_fun_call.fixed | 3 +++ tests/ui/or_fun_call.rs | 3 +++ tests/ui/or_fun_call.stderr | 6 +++--- 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index e6b473dbafa..20861ff8686 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -91,7 +91,7 @@ pub(super) fn check<'tcx>( let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); match ty.kind() { - ty::Slice(_) | ty::Array(_, _) => return, + ty::Slice(_) | ty::Array(_, _) | ty::Str => return, _ => (), } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 660245f10c3..4390ff7dc30 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -120,6 +120,9 @@ fn test_or_with_ctors() { let slice = &["foo"][..]; let _ = opt.ok_or(slice.len()); + + let string = "foo"; + let _ = opt.ok_or(string.len()); } // Issue 4514 - early return diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index c589b170bdd..75908c974cc 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -120,6 +120,9 @@ fn test_or_with_ctors() { let slice = &["foo"][..]; let _ = opt.ok_or(slice.len()); + + let string = "foo"; + let _ = opt.ok_or(string.len()); } // Issue 4514 - early return diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index d63b3443592..9905029ce91 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -115,19 +115,19 @@ LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:138:14 + --> $DIR/or_fun_call.rs:141:14 | LL | None.unwrap_or(s.as_mut_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:143:14 + --> $DIR/or_fun_call.rs:146:14 | LL | None.unwrap_or(unsafe { s.as_mut_vec() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:145:14 + --> $DIR/or_fun_call.rs:148:14 | LL | None.unwrap_or( unsafe { s.as_mut_vec() } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` -- cgit 1.4.1-3-g733a5 From 9132dbdf310bbffbf5a8efd3b52f68189e3ee15e Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 23 Mar 2021 10:40:27 -0500 Subject: Factor out eq_ty_kind --- clippy_lints/src/methods/mod.rs | 18 ++++++++---------- clippy_utils/src/hir_utils.rs | 12 ++---------- 2 files changed, 10 insertions(+), 20 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b37d744269e..d77f9c03cae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -62,13 +62,11 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{ - contains_return, get_trait_def_id, in_macro, iter_input_pats, match_qpath, method_calls, paths, return_ty, - SpanlessEq, -}; +use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::{TraitItem, TraitItemKind}; +use rustc_hir::def::Res; +use rustc_hir::{PrimTy, QPath, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; @@ -1872,7 +1870,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { for method_config in &TRAIT_METHODS { if name == method_config.method_name && sig.decl.inputs.len() == method_config.param_count && - method_config.output_type.matches(cx, &sig.decl.output) && + method_config.output_type.matches(&sig.decl.output) && method_config.self_kind.matches(cx, self_ty, first_arg_ty) && fn_header_equals(method_config.fn_header, sig.header) && method_config.lifetime_param_cond(&impl_item) @@ -2199,8 +2197,8 @@ enum OutType { } impl OutType { - fn matches(self, cx: &LateContext<'_>, ty: &hir::FnRetTy<'_>) -> bool { - let is_unit = |ty: &hir::Ty<'_>| SpanlessEq::new(cx).eq_ty_kind(&ty.kind, &hir::TyKind::Tup(&[])); + fn matches(self, ty: &hir::FnRetTy<'_>) -> bool { + let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[])); match (self, ty) { (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true, (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true, @@ -2213,8 +2211,8 @@ impl OutType { } fn is_bool(ty: &hir::Ty<'_>) -> bool { - if let hir::TyKind::Path(ref p) = ty.kind { - match_qpath(p, &["bool"]) + if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + matches!(path.res, Res::PrimTy(PrimTy::Bool)) } else { false } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 4c13a185d5d..5cfeaee28cf 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -80,10 +80,6 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool { self.inter_expr().eq_path_segments(left, right) } - - pub fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool { - self.inter_expr().eq_ty_kind(left, right) - } } struct HirEqInterExpr<'a, 'b, 'tcx> { @@ -378,13 +374,9 @@ impl HirEqInterExpr<'_, '_, '_> { left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r)) } - fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { - self.eq_ty_kind(&left.kind, &right.kind) - } - #[allow(clippy::similar_names)] - fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool { - match (left, right) { + fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { + match (&left.kind, &right.kind) { (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => { let cx = self.inner.cx; -- cgit 1.4.1-3-g733a5 From 2f8d71b9dc5cbb2a26ecd88f943c8a225e28108f Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 25 Mar 2021 00:17:43 +0900 Subject: merge imports --- clippy_lints/src/methods/utils.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 8de23e1bc6e..ac6b55396da 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -5,8 +5,7 @@ use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; pub(super) fn derefs_to_slice<'tcx>( -- cgit 1.4.1-3-g733a5 From 99b8a671981eb9bf2c624027940bf9ae4cd23087 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 22 Mar 2021 21:38:14 -0400 Subject: Fix false positive with `new_ret_no_self` when returning `Self` with different generic arguments --- clippy_lints/src/methods/mod.rs | 14 +++++++++++--- clippy_utils/src/ty.rs | 11 ++++++++++- tests/ui/new_ret_no_self.rs | 10 ++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d77f9c03cae..b6be77b03e5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -61,7 +61,7 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::ty::{contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{contains_adt, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; @@ -1916,7 +1916,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods { 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 contains_ty(ret_ty, self_ty) { + if let Some(self_adt) = self_ty.ty_adt_def() { + if contains_adt(ret_ty, self_adt) { + return; + } + } else if contains_ty(ret_ty, self_ty) { return; } @@ -1926,7 +1930,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods { for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { // walk the associated type and check for Self - if contains_ty(projection_predicate.ty, self_ty) { + if let Some(self_adt) = self_ty.ty_adt_def() { + if contains_adt(projection_predicate.ty, self_adt) { + return; + } + } else if contains_ty(projection_predicate.ty, self_ty) { return; } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index f4a1ae67da3..b9724efb04f 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -11,7 +11,7 @@ use rustc_hir::{TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, IntTy, Ty, TypeFoldable, UintTy}; +use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; use rustc_span::sym; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; @@ -43,6 +43,15 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { }) } +/// Walks into `ty` and returns `true` if any inner type is any instance of the given abstract data +/// type.` +pub fn contains_adt(ty: Ty<'_>, adt: &AdtDef) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + /// Returns true if ty has `iter` or `iter_mut` methods pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option { // FIXME: instead of this hard-coded list, we should check if `::iter` diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index e82873629a5..2f315ffe298 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -340,3 +340,13 @@ mod issue5435 { } } } + +// issue #1724 +struct RetOtherSelf(T); +struct RetOtherSelfWrapper(T); + +impl RetOtherSelf { + fn new(t: T) -> RetOtherSelf> { + RetOtherSelf(RetOtherSelfWrapper(t)) + } +} -- cgit 1.4.1-3-g733a5 From 6e88900f9ecc3b1e9ffce777d5e74e0eb3554ef4 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 24 Mar 2021 16:19:27 -0400 Subject: Rename `contains_adt` to `contains_adt_constructor` --- clippy_lints/src/methods/mod.rs | 6 +++--- clippy_utils/src/ty.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b6be77b03e5..fccdee07877 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -61,7 +61,7 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::ty::{contains_adt, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; @@ -1917,7 +1917,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { // 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(ret_ty, self_adt) { + if contains_adt_constructor(ret_ty, self_adt) { return; } } else if contains_ty(ret_ty, self_ty) { @@ -1931,7 +1931,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { // walk the associated type and check for Self if let Some(self_adt) = self_ty.ty_adt_def() { - if contains_adt(projection_predicate.ty, self_adt) { + if contains_adt_constructor(projection_predicate.ty, self_adt) { return; } } else if contains_ty(projection_predicate.ty, self_ty) { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index b9724efb04f..807cfbc4c7f 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -43,9 +43,9 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { }) } -/// Walks into `ty` and returns `true` if any inner type is any instance of the given abstract data -/// type.` -pub fn contains_adt(ty: Ty<'_>, adt: &AdtDef) -> bool { +/// Walks into `ty` and returns `true` if any inner type is an instance of the given adt +/// constructor. +pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool { ty.walk().any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, -- cgit 1.4.1-3-g733a5 From d2657769a22f15098343f9272f52a01145698786 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 29 Mar 2021 13:29:58 -0400 Subject: Improve `clone_on_copy` Lint on `_.clone().method()` when method takes self by value Set applicability correctly Correct suggestion when the cloned value is a macro call. e.g. `m!(x).clone()` Don't lint when not using the `Clone` trait --- clippy_lints/src/methods/clone_on_copy.rs | 118 +++++++++++++++++------------- tests/ui/clone_on_copy.fixed | 34 ++++++++- tests/ui/clone_on_copy.rs | 34 ++++++++- tests/ui/clone_on_copy.stderr | 30 ++++++-- tests/ui/clone_on_copy_mut.rs | 18 ----- 5 files changed, 157 insertions(+), 77 deletions(-) delete mode 100644 tests/ui/clone_on_copy_mut.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index edb6649b87b..ce2e8fa8b10 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -1,10 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::get_parent_node; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; use std::iter; @@ -12,12 +14,26 @@ use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { - if !(args.len() == 1 && method_name == sym::clone) { +#[allow(clippy::too_many_lines)] +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) { + let arg = match args { + [arg] if method_name == sym::clone => arg, + _ => return, + }; + if cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .and_then(|id| cx.tcx.trait_of_item(id)) + .zip(cx.tcx.lang_items().clone_trait()) + .map_or(true, |(x, y)| x != y) + { return; } - let arg = &args[0]; - let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + let arg_adjustments = cx.typeck_results().expr_adjustments(arg); + let arg_ty = arg_adjustments + .last() + .map_or_else(|| cx.typeck_results().expr_ty(arg), |a| a.target); + let ty = cx.typeck_results().expr_ty(expr); if let ty::Ref(_, inner, _) = arg_ty.kind() { if let ty::Ref(_, innermost, _) = inner.kind() { @@ -61,57 +77,57 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym } if is_copy(cx, ty) { - let snip; - if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) { - let parent = cx.tcx.hir().get_parent_node(expr.hir_id); - match &cx.tcx.hir().get(parent) { - hir::Node::Expr(parent) => match parent.kind { - // &*x is a nop, &x.clone() is not - hir::ExprKind::AddrOf(..) => return, - // (*x).func() is useless, x.clone().func() can work in case func borrows mutably - hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => { - return; - }, - - _ => {}, - }, - hir::Node::Stmt(stmt) => { - if let hir::StmtKind::Local(ref loc) = stmt.kind { - if let hir::PatKind::Ref(..) = loc.pat.kind { - // let ref y = *x borrows x, let ref y = x.clone() does not - return; - } - } - }, - _ => {}, + let parent_is_suffix_expr = match get_parent_node(cx.tcx, expr.hir_id) { + Some(Node::Expr(parent)) => match parent.kind { + // &*x is a nop, &x.clone() is not + ExprKind::AddrOf(..) => return, + // (*x).func() is useless, x.clone().func() can work in case func borrows self + ExprKind::MethodCall(_, _, [self_arg, ..], _) + if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => + { + return; + } + ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, + ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) + | ExprKind::Field(..) + | ExprKind::Index(..) => true, + _ => false, + }, + // local binding capturing a reference + Some(Node::Local(l)) + if matches!( + l.pat.kind, + PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) + ) => + { + return; } + _ => false, + }; - // x.clone() might have dereferenced x, possibly through Deref impls - if cx.typeck_results().expr_ty(arg) == ty { - snip = Some(("try removing the `clone` call", format!("{}", snippet))); - } else { - let deref_count = cx - .typeck_results() - .expr_adjustments(arg) - .iter() - .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) - .count(); - let derefs: String = iter::repeat('*').take(deref_count).collect(); - snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet))); - } + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut app).0; + + let deref_count = arg_adjustments + .iter() + .take_while(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); + let (help, sugg) = if deref_count == 0 { + ("try removing the `clone` call", snip.into()) + } else if parent_is_suffix_expr { + ("try dereferencing it", format!("({}{})", "*".repeat(deref_count), snip)) } else { - snip = None; - } - span_lint_and_then( + ("try dereferencing it", format!("{}{}", "*".repeat(deref_count), snip)) + }; + + span_lint_and_sugg( cx, CLONE_ON_COPY, expr.span, &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), - |diag| { - if let Some((text, snip)) = snip { - diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable); - } - }, + help, + sugg, + app, ); } } diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index d924625132e..8d43f64768d 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -6,7 +6,8 @@ clippy::deref_addrof, clippy::no_effect, clippy::unnecessary_operation, - clippy::vec_init_then_push + clippy::vec_init_then_push, + clippy::toplevel_ref_arg )] use std::cell::RefCell; @@ -29,6 +30,37 @@ fn clone_on_copy() { let rc = RefCell::new(0); *rc.borrow(); + let x = 0u32; + x.rotate_left(1); + + #[derive(Clone, Copy)] + struct Foo; + impl Foo { + fn clone(&self) -> u32 { + 0 + } + } + Foo.clone(); // ok, this is not the clone trait + + macro_rules! m { + ($e:expr) => {{ $e }}; + } + m!(42); + + struct Wrap([u32; 2]); + impl core::ops::Deref for Wrap { + type Target = [u32; 2]; + fn deref(&self) -> &[u32; 2] { + &self.0 + } + } + let x = Wrap([0, 0]); + (*x)[0]; + + let x = 42; + let ref y = x.clone(); // ok, binds by reference + let ref mut y = x.clone(); // ok, binds by reference + // Issue #4348 let mut x = 43; let _ = &x.clone(); // ok, getting a ref diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 97f49467244..f15501f7184 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -6,7 +6,8 @@ clippy::deref_addrof, clippy::no_effect, clippy::unnecessary_operation, - clippy::vec_init_then_push + clippy::vec_init_then_push, + clippy::toplevel_ref_arg )] use std::cell::RefCell; @@ -29,6 +30,37 @@ fn clone_on_copy() { let rc = RefCell::new(0); rc.borrow().clone(); + let x = 0u32; + x.clone().rotate_left(1); + + #[derive(Clone, Copy)] + struct Foo; + impl Foo { + fn clone(&self) -> u32 { + 0 + } + } + Foo.clone(); // ok, this is not the clone trait + + macro_rules! m { + ($e:expr) => {{ $e }}; + } + m!(42).clone(); + + struct Wrap([u32; 2]); + impl core::ops::Deref for Wrap { + type Target = [u32; 2]; + fn deref(&self) -> &[u32; 2] { + &self.0 + } + } + let x = Wrap([0, 0]); + x.clone()[0]; + + let x = 42; + let ref y = x.clone(); // ok, binds by reference + let ref mut y = x.clone(); // ok, binds by reference + // Issue #4348 let mut x = 43; let _ = &x.clone(); // ok, getting a ref diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 7a706884fb0..e7d28b4320b 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -1,5 +1,5 @@ error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:23:5 + --> $DIR/clone_on_copy.rs:24:5 | LL | 42.clone(); | ^^^^^^^^^^ help: try removing the `clone` call: `42` @@ -7,28 +7,46 @@ LL | 42.clone(); = note: `-D clippy::clone-on-copy` implied by `-D warnings` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:27:5 + --> $DIR/clone_on_copy.rs:28:5 | LL | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:30:5 + --> $DIR/clone_on_copy.rs:31:5 | LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` +error: using `clone` on type `u32` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:34:5 + | +LL | x.clone().rotate_left(1); + | ^^^^^^^^^ help: try removing the `clone` call: `x` + +error: using `clone` on type `i32` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:48:5 + | +LL | m!(42).clone(); + | ^^^^^^^^^^^^^^ help: try removing the `clone` call: `m!(42)` + +error: using `clone` on type `[u32; 2]` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:58:5 + | +LL | x.clone()[0]; + | ^^^^^^^^^ help: try dereferencing it: `(*x)` + error: using `clone` on type `char` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:36:14 + --> $DIR/clone_on_copy.rs:68:14 | LL | is_ascii('z'.clone()); | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` error: using `clone` on type `i32` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:40:14 + --> $DIR/clone_on_copy.rs:72:14 | LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/clone_on_copy_mut.rs b/tests/ui/clone_on_copy_mut.rs deleted file mode 100644 index 5bfa256623b..00000000000 --- a/tests/ui/clone_on_copy_mut.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub fn dec_read_dec(i: &mut i32) -> i32 { - *i -= 1; - let ret = *i; - *i -= 1; - ret -} - -pub fn minus_1(i: &i32) -> i32 { - dec_read_dec(&mut i.clone()) -} - -fn main() { - let mut i = 10; - assert_eq!(minus_1(&i), 9); - assert_eq!(i, 10); - assert_eq!(dec_read_dec(&mut i), 9); - assert_eq!(i, 8); -} -- cgit 1.4.1-3-g733a5 From 6966c78be74ec7dea5cbbb18f1ec10771bf4b728 Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Mon, 29 Mar 2021 12:51:23 -0700 Subject: wrong_self_convention: fix FP inside trait impl for `to_*` method When the `to_*` method takes `&self` and it is a trait implementation, we don't trigger the lint. --- clippy_lints/src/methods/mod.rs | 10 ++++++- clippy_lints/src/methods/wrong_self_convention.rs | 32 ++++++++++++++++++----- tests/ui/wrong_self_convention.rs | 9 ++----- tests/ui/wrong_self_convention.stderr | 4 +-- tests/ui/wrong_self_convention2.rs | 32 +++++++++++++++++++++++ tests/ui/wrong_self_convention2.stderr | 11 ++++++++ 6 files changed, 81 insertions(+), 17 deletions(-) create mode 100644 tests/ui/wrong_self_convention2.rs create mode 100644 tests/ui/wrong_self_convention2.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fccdee07877..95592523928 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -205,6 +205,13 @@ declare_clippy_lint! { /// |`to_` | not `_mut` |`self` | `Copy` | /// |`to_` | not `_mut` |`&self` | not `Copy` | /// + /// Note: Clippy doesn't trigger methods with `to_` prefix in: + /// - Traits definition. + /// Clippy can not tell if a type that implements a trait is `Copy` or not. + /// - Traits implementation, when `&self` is taken. + /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait + /// (see e.g. the `std::string::ToString` trait). + /// /// Please find more info here: /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv /// @@ -1850,7 +1857,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = cx.tcx.type_of(item.def_id); let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); - if_chain! { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next(); @@ -1902,6 +1908,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { self_ty, first_arg_ty, first_arg.pat.span, + implements_trait, false ); } @@ -1972,6 +1979,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { self_ty, first_arg_ty, first_arg_span, + false, true ); } diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 59e683aa9a7..1e0de249a91 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -21,8 +21,10 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types). // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]), - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::ImplementsTrait(false)], &[SelfKind::Value]), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), + Convention::IsTraitItem(false)], &[SelfKind::Ref]), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), + Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; enum Convention { @@ -32,18 +34,27 @@ enum Convention { NotEndsWith(&'static str), IsSelfTypeCopy(bool), ImplementsTrait(bool), + IsTraitItem(bool), } impl Convention { #[must_use] - fn check<'tcx>(&self, cx: &LateContext<'tcx>, self_ty: &'tcx TyS<'tcx>, other: &str, is_trait_def: bool) -> bool { + fn check<'tcx>( + &self, + cx: &LateContext<'tcx>, + self_ty: &'tcx TyS<'tcx>, + other: &str, + implements_trait: bool, + is_trait_item: bool, + ) -> bool { match *self { Self::Eq(this) => this == other, Self::StartsWith(this) => other.starts_with(this) && this != other, Self::EndsWith(this) => other.ends_with(this) && this != other, - Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, is_trait_def), + Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, implements_trait, is_trait_item), Self::IsSelfTypeCopy(is_true) => is_true == is_copy(cx, self_ty), - Self::ImplementsTrait(is_true) => is_true == is_trait_def, + Self::ImplementsTrait(is_true) => is_true == implements_trait, + Self::IsTraitItem(is_true) => is_true == is_trait_item, } } } @@ -60,12 +71,17 @@ impl fmt::Display for Convention { }, Self::ImplementsTrait(is_true) => { let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") }; - format!("Method{} implement{} a trait", negation, s_suffix).fmt(f) + format!("method{} implement{} a trait", negation, s_suffix).fmt(f) + }, + Self::IsTraitItem(is_true) => { + let suffix = if is_true { " is" } else { " is not" }; + format!("method{} a trait item", suffix).fmt(f) }, } } } +#[allow(clippy::too_many_arguments)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, item_name: &str, @@ -73,6 +89,7 @@ pub(super) fn check<'tcx>( self_ty: &'tcx TyS<'tcx>, first_arg_ty: &'tcx TyS<'tcx>, first_arg_span: Span, + implements_trait: bool, is_trait_item: bool, ) { let lint = if is_pub { @@ -83,7 +100,7 @@ pub(super) fn check<'tcx>( if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { convs .iter() - .all(|conv| conv.check(cx, self_ty, item_name, is_trait_item)) + .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item)) }) { if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { let suggestion = { @@ -99,6 +116,7 @@ pub(super) fn check<'tcx>( .filter_map(|conv| { if (cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_))) || matches!(conv, Convention::ImplementsTrait(_)) + || matches!(conv, Convention::IsTraitItem(_)) { None } else { diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index ba9e19a1722..cdfbdb8b0db 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -165,15 +165,10 @@ mod issue6307 { } mod issue6727 { - trait ToU64 { - fn to_u64(self) -> u64; - fn to_u64_v2(&self) -> u64; - } - #[derive(Clone, Copy)] struct FooCopy; - impl ToU64 for FooCopy { + impl FooCopy { fn to_u64(self) -> u64 { 1 } @@ -185,7 +180,7 @@ mod issue6727 { struct FooNoCopy; - impl ToU64 for FooNoCopy { + impl FooNoCopy { // trigger lint fn to_u64(self) -> u64 { 2 diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 1d58a12ac79..29f5ba82695 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -176,7 +176,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value - --> $DIR/wrong_self_convention.rs:181:22 + --> $DIR/wrong_self_convention.rs:176:22 | LL | fn to_u64_v2(&self) -> u64 { | ^^^^^ @@ -184,7 +184,7 @@ LL | fn to_u64_v2(&self) -> u64 { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:190:19 + --> $DIR/wrong_self_convention.rs:185:19 | LL | fn to_u64(self) -> u64 { | ^^^^ diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs new file mode 100644 index 00000000000..8b42aa59e13 --- /dev/null +++ b/tests/ui/wrong_self_convention2.rs @@ -0,0 +1,32 @@ +// edition:2018 +#![warn(clippy::wrong_self_convention)] +#![warn(clippy::wrong_pub_self_convention)] +#![allow(dead_code)] + +fn main() {} + +mod issue6983 { + pub struct Thing; + pub trait Trait { + fn to_thing(&self) -> Thing; + } + + impl Trait for u8 { + // don't trigger, e.g. `ToString` from `std` requires `&self` + fn to_thing(&self) -> Thing { + Thing + } + } + + trait ToU64 { + fn to_u64(self) -> u64; + } + + struct FooNoCopy; + // trigger lint + impl ToU64 for FooNoCopy { + fn to_u64(self) -> u64 { + 2 + } + } +} diff --git a/tests/ui/wrong_self_convention2.stderr b/tests/ui/wrong_self_convention2.stderr new file mode 100644 index 00000000000..0ca1a390974 --- /dev/null +++ b/tests/ui/wrong_self_convention2.stderr @@ -0,0 +1,11 @@ +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference + --> $DIR/wrong_self_convention2.rs:28:19 + | +LL | fn to_u64(self) -> u64 { + | ^^^^ + | + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 56fbbf7b8fc7c99a6c54dfff6847770a4ed27eb1 Mon Sep 17 00:00:00 2001 From: Eric Loren Date: Sat, 14 Nov 2020 19:47:17 -0500 Subject: Suggest `flatten` instead of `is_some` -> `unwrap` --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 3 + clippy_lints/src/methods/filter_map.rs | 213 ++++++++++++++++++++++----------- clippy_lints/src/methods/mod.rs | 27 ++++- tests/ui/option_filter_map.fixed | 23 ++++ tests/ui/option_filter_map.rs | 25 ++++ tests/ui/option_filter_map.stderr | 56 +++++++++ 8 files changed, 280 insertions(+), 70 deletions(-) create mode 100644 tests/ui/option_filter_map.fixed create mode 100644 tests/ui/option_filter_map.rs create mode 100644 tests/ui/option_filter_map.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 57996802182..47af42e14ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2389,6 +2389,7 @@ Released 2018-09-13 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap +[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map [`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn diff --git a/README.md b/README.md index 63057609bb6..8c0c16c443d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 450 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f013613119c..82abd4803db 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -804,6 +804,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::NEW_RET_NO_SELF, &methods::OK_EXPECT, &methods::OPTION_AS_REF_DEREF, + &methods::OPTION_FILTER_MAP, &methods::OPTION_MAP_OR_NONE, &methods::OR_FUN_CALL, &methods::RESULT_MAP_OR_INTO_OPTION, @@ -1596,6 +1597,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_AS_REF_DEREF), + LintId::of(&methods::OPTION_FILTER_MAP), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::OR_FUN_CALL), LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), @@ -1891,6 +1893,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::MANUAL_FILTER_MAP), LintId::of(&methods::MANUAL_FIND_MAP), LintId::of(&methods::OPTION_AS_REF_DEREF), + LintId::of(&methods::OPTION_FILTER_MAP), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::SUSPICIOUS_MAP), diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 2cb476acb2b..68f8480dc51 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,87 +1,166 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::{is_trait_method, path_to_local_id, SpanlessEq}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, PatKind, UnOp}; +use rustc_hir::def::Res; +use rustc_hir::{Expr, ExprKind, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::TyS; -use rustc_span::symbol::sym; +use rustc_span::source_map::Span; +use rustc_span::symbol::{sym, Symbol}; +use std::borrow::Cow; use super::MANUAL_FILTER_MAP; use super::MANUAL_FIND_MAP; +use super::OPTION_FILTER_MAP; + +fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { + match &expr.kind { + hir::ExprKind::Path(QPath::TypeRelative(_, ref mname)) => mname.ident.name == method_name, + hir::ExprKind::Path(QPath::Resolved(_, segments)) => { + segments.segments.last().unwrap().ident.name == method_name + }, + hir::ExprKind::Closure(_, _, c, _, _) => { + let body = cx.tcx.hir().body(*c); + let closure_expr = remove_blocks(&body.value); + let arg_id = body.params[0].pat.hir_id; + match closure_expr.kind { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, ref args, _) => { + if_chain! { + if ident.name == method_name; + if let hir::ExprKind::Path(path) = &args[0].kind; + if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id); + then { + return arg_id == *local + } + } + false + }, + _ => false, + } + }, + _ => false, + } +} + +fn is_option_filter_map<'tcx>( + cx: &LateContext<'tcx>, + filter_arg: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, +) -> bool { + is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) +} + +/// lint use of `filter().map()` for `Iterators` +fn lint_filter_some_map_unwrap<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + filter_recv: &'tcx hir::Expr<'_>, + filter_arg: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, + target_span: Span, + methods_span: Span, +) { + let iterator = is_trait_method(cx, expr, sym::Iterator); + let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&filter_recv), sym::option_type); + if (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) { + let msg = "`filter` for `Some` followed by `unwrap`"; + let help = "consider using `flatten` instead"; + let sugg = format!( + "{}", + reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, target_span),) + ); + span_lint_and_sugg( + cx, + OPTION_FILTER_MAP, + methods_span, + msg, + help, + sugg, + Applicability::MachineApplicable, + ); + } +} /// lint use of `filter().map()` or `find().map()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool, target_span: Span) { if_chain! { - if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; - if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind; - if is_trait_method(cx, map_recv, sym::Iterator); + if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; + if let ExprKind::MethodCall(_, _, [filter_recv, filter_arg], filter_span) = map_recv.kind; + then { + lint_filter_some_map_unwrap(cx, expr, filter_recv, filter_arg, + map_arg, target_span, filter_span.to(map_span)); + if_chain! { + if is_trait_method(cx, map_recv, sym::Iterator); - // filter(|x| ...is_some())... - if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; - let filter_body = cx.tcx.hir().body(filter_body_id); - if let [filter_param] = filter_body.params; - // optional ref pattern: `filter(|&x| ..)` - let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { - (ref_pat, true) - } else { - (filter_param.pat, false) - }; - // closure ends with is_some() or is_ok() - if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) { - Some(false) - } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) { - Some(true) - } else { - None - }; - if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + // filter(|x| ...is_some())... + if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind; + let filter_body = cx.tcx.hir().body(filter_body_id); + if let [filter_param] = filter_body.params; + // optional ref pattern: `filter(|&x| ..)` + let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + }; + // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; + if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind; + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) { + Some(false) + } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) { + Some(true) + } else { + None + }; + if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; - // ...map(|x| ...unwrap()) - if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind; - let map_body = cx.tcx.hir().body(map_body_id); - if let [map_param] = map_body.params; - if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; - // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + // ...map(|x| ...unwrap()) + if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind; + let map_body = cx.tcx.hir().body(map_body_id); + if let [map_param] = map_body.params; + if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + // closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind; + if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; - // let the filter closure arg and the map closure arg be equal - if_chain! { - if path_to_local_id(a_path, filter_param_id); - if path_to_local_id(b, map_param_id); - if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); - then { - return true; + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; + then { expr_path } else { a } + }; + // let the filter closure arg and the map closure arg be equal + if_chain! { + if path_to_local_id(a_path, filter_param_id); + if path_to_local_id(b, map_param_id); + if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); + then { + return true; + } } - } - false - }; - if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); - then { - let span = filter_span.to(map_span); - let (filter_name, lint) = if is_find { - ("find", MANUAL_FIND_MAP) - } else { - ("filter", MANUAL_FILTER_MAP) + false }; - let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name); - let to_opt = if is_result { ".ok()" } else { "" }; - let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident, - snippet(cx, map_arg.span, ".."), to_opt); - span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); + then { + let span = filter_span.to(map_span); + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) + } else { + ("filter", MANUAL_FILTER_MAP) + }; + let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name); + let to_opt = if is_result { ".ok()" } else { "" }; + let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident, + snippet(cx, map_arg.span, ".."), to_opt); + span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + } + } } } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fccdee07877..8a04fd0060d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -896,6 +896,28 @@ declare_clippy_lint! { "using `Iterator::step_by(0)`, which will panic at runtime" } +declare_clippy_lint! { + /// **What it does:** Checks for indirect collection of populated `Option` + /// + /// **Why is this bad?** `Option` is like a collection of 0-1 things, so `flatten` + /// automatically does this without suspicious-looking `unwrap` calls. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let _ = std::iter::empty::>().filter(Option::is_some).map(Option::unwrap); + /// ``` + /// Use instead: + /// ```rust + /// let _ = std::iter::empty::>().flatten(); + /// ``` + pub OPTION_FILTER_MAP, + complexity, + "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation" +} + declare_clippy_lint! { /// **What it does:** Checks for the use of `iter.nth(0)`. /// @@ -1651,6 +1673,7 @@ impl_lint_pass!(Methods => [ FILTER_MAP_IDENTITY, MANUAL_FILTER_MAP, MANUAL_FIND_MAP, + OPTION_FILTER_MAP, FILTER_MAP_NEXT, FLAT_MAP_IDENTITY, MAP_FLATTEN, @@ -1720,10 +1743,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]), ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), - ["map", "filter"] => filter_map::check(cx, expr, false), + ["map", "filter"] => filter_map::check(cx, expr, false, method_spans[0]), ["map", "filter_map"] => filter_map_map::check(cx, expr), ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), - ["map", "find"] => filter_map::check(cx, expr, true), + ["map", "find"] => filter_map::check(cx, expr, true, method_spans[0]), ["flat_map", "filter"] => filter_flat_map::check(cx, expr), ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr), ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), diff --git a/tests/ui/option_filter_map.fixed b/tests/ui/option_filter_map.fixed new file mode 100644 index 00000000000..f9d1825ade0 --- /dev/null +++ b/tests/ui/option_filter_map.fixed @@ -0,0 +1,23 @@ +#![warn(clippy::option_filter_map)] +// run-rustfix +fn odds_out(x: i32) -> Option { + if x % 2 == 0 { Some(x) } else { None } +} + +fn main() { + let _ = Some(Some(1)).flatten(); + let _ = Some(Some(1)).flatten(); + let _ = Some(1).map(odds_out).flatten(); + let _ = Some(1).map(odds_out).flatten(); + + let _ = vec![Some(1)].into_iter().flatten(); + let _ = vec![Some(1)].into_iter().flatten(); + let _ = vec![1] + .into_iter() + .map(odds_out) + .flatten(); + let _ = vec![1] + .into_iter() + .map(odds_out) + .flatten(); +} diff --git a/tests/ui/option_filter_map.rs b/tests/ui/option_filter_map.rs new file mode 100644 index 00000000000..588e1ccccce --- /dev/null +++ b/tests/ui/option_filter_map.rs @@ -0,0 +1,25 @@ +#![warn(clippy::option_filter_map)] +// run-rustfix +fn odds_out(x: i32) -> Option { + if x % 2 == 0 { Some(x) } else { None } +} + +fn main() { + let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); + let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); + let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); + let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); + + let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); + let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); + let _ = vec![1] + .into_iter() + .map(odds_out) + .filter(Option::is_some) + .map(Option::unwrap); + let _ = vec![1] + .into_iter() + .map(odds_out) + .filter(|o| o.is_some()) + .map(|o| o.unwrap()); +} diff --git a/tests/ui/option_filter_map.stderr b/tests/ui/option_filter_map.stderr new file mode 100644 index 00000000000..31a82969d5a --- /dev/null +++ b/tests/ui/option_filter_map.stderr @@ -0,0 +1,56 @@ +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:8:27 + | +LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + | + = note: `-D clippy::option-filter-map` implied by `-D warnings` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:9:27 + | +LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:10:35 + | +LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:11:35 + | +LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:13:39 + | +LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:14:39 + | +LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:18:10 + | +LL | .filter(Option::is_some) + | __________^ +LL | | .map(Option::unwrap); + | |____________________________^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Some` followed by `unwrap` + --> $DIR/option_filter_map.rs:23:10 + | +LL | .filter(|o| o.is_some()) + | __________^ +LL | | .map(|o| o.unwrap()); + | |____________________________^ help: consider using `flatten` instead: `flatten()` + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From 21083875d211c29fcfa4a21fcd66d4601d2b618b Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 10 Mar 2021 23:40:20 -0600 Subject: Destructure args in methods module --- clippy_lints/src/methods/bind_instead_of_map.rs | 14 +- clippy_lints/src/methods/bytes_nth.rs | 11 +- clippy_lints/src/methods/expect_used.rs | 4 +- clippy_lints/src/methods/filetype_is_file.rs | 4 +- clippy_lints/src/methods/filter_map.rs | 50 ++-- clippy_lints/src/methods/filter_map_identity.rs | 15 +- clippy_lints/src/methods/filter_map_next.rs | 7 +- clippy_lints/src/methods/filter_next.rs | 11 +- clippy_lints/src/methods/flat_map_identity.rs | 4 +- clippy_lints/src/methods/get_unwrap.rs | 20 +- clippy_lints/src/methods/iter_cloned_collect.rs | 4 +- clippy_lints/src/methods/iter_count.rs | 8 +- clippy_lints/src/methods/iter_next_slice.rs | 4 +- clippy_lints/src/methods/iter_nth.rs | 14 +- clippy_lints/src/methods/iter_nth_zero.rs | 6 +- clippy_lints/src/methods/iter_skip_next.rs | 22 +- clippy_lints/src/methods/iterator_step_by_zero.rs | 4 +- .../src/methods/manual_saturating_arithmetic.rs | 13 +- .../src/methods/map_collect_result_unit.rs | 9 +- clippy_lints/src/methods/map_flatten.rs | 19 +- clippy_lints/src/methods/map_unwrap_or.rs | 21 +- clippy_lints/src/methods/mod.rs | 283 ++++++++++++--------- clippy_lints/src/methods/ok_expect.rs | 6 +- clippy_lints/src/methods/option_as_ref_deref.rs | 16 +- clippy_lints/src/methods/option_map_or_none.rs | 22 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 22 +- clippy_lints/src/methods/search_is_some.rs | 88 ++++--- clippy_lints/src/methods/skip_while_next.rs | 2 +- clippy_lints/src/methods/string_extend_chars.rs | 7 +- clippy_lints/src/methods/suspicious_map.rs | 9 +- clippy_lints/src/methods/uninit_assumed_init.rs | 8 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 4 +- clippy_lints/src/methods/unnecessary_fold.rs | 33 +-- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 11 +- clippy_lints/src/methods/unwrap_used.rs | 4 +- clippy_lints/src/methods/useless_asref.rs | 3 +- clippy_lints/src/methods/zst_offset.rs | 5 +- 37 files changed, 412 insertions(+), 375 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 0ba8a98a018..8ccb8f4268c 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -80,7 +80,7 @@ pub(crate) trait BindInsteadOfMap { fn lint_closure_autofixable( cx: &LateContext<'_>, expr: &hir::Expr<'_>, - args: &[hir::Expr<'_>], + recv: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>, closure_args_span: Span, ) -> bool { @@ -103,7 +103,7 @@ pub(crate) trait BindInsteadOfMap { }; let closure_args_snip = snippet(cx, closure_args_span, ".."); - let option_snip = snippet(cx, args[0].span, ".."); + let option_snip = snippet(cx, recv.span, ".."); let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip); span_lint_and_sugg( cx, @@ -158,17 +158,17 @@ pub(crate) trait BindInsteadOfMap { } /// Lint use of `_.and_then(|x| Some(y))` for `Option`s - fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool { - if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) { + fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool { + if !match_type(cx, cx.typeck_results().expr_ty(recv), Self::TYPE_QPATH) { return false; } - match args[1].kind { + match arg.kind { hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => { let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); - if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { + if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) { true } else { Self::lint_closure(cx, expr, closure_expr) @@ -182,7 +182,7 @@ pub(crate) trait BindInsteadOfMap { expr.span, Self::no_op_msg().as_ref(), "use the expression directly", - snippet(cx, args[0].span, "..").into(), + snippet(cx, recv.span, "..").into(), Applicability::MachineApplicable, ); true diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 4f88f80a304..77f140510b6 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -3,16 +3,15 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_span::sym; use super::BYTES_NTH; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) { if_chain! { - if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind; - let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs(); + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) { Some("String") } else if ty.is_str() { @@ -31,8 +30,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' "try", format!( "{}.as_bytes().get({})", - snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), - snippet_with_applicability(cx, args[1].span, "..", &mut applicability) + snippet_with_applicability(cx, recv.span, "..", &mut applicability), + snippet_with_applicability(cx, n_arg.span, "..", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 64531b29ade..63a834fdce0 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -7,8 +7,8 @@ use rustc_span::sym; use super::EXPECT_USED; /// lint use of `expect()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) { - let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs(); +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { + let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { Some((EXPECT_USED, "an Option", "None")) diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 39d2f15dbc8..7b2967feb0f 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -8,8 +8,8 @@ use rustc_span::source_map::Span; use super::FILETYPE_IS_FILE; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let ty = cx.typeck_results().expr_ty(&args[0]); +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); if !match_type(cx, ty, &paths::FILE_TYPE) { return; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 68f8480dc51..45d1ed953b4 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -46,21 +46,17 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy } } -fn is_option_filter_map<'tcx>( - cx: &LateContext<'tcx>, - filter_arg: &'tcx hir::Expr<'_>, - map_arg: &'tcx hir::Expr<'_>, -) -> bool { +fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } /// lint use of `filter().map()` for `Iterators` -fn lint_filter_some_map_unwrap<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - filter_recv: &'tcx hir::Expr<'_>, - filter_arg: &'tcx hir::Expr<'_>, - map_arg: &'tcx hir::Expr<'_>, +fn lint_filter_some_map_unwrap( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + filter_recv: &hir::Expr<'_>, + filter_arg: &hir::Expr<'_>, + map_arg: &hir::Expr<'_>, target_span: Span, methods_span: Span, ) { @@ -86,14 +82,28 @@ fn lint_filter_some_map_unwrap<'tcx>( } /// lint use of `filter().map()` or `find().map()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool, target_span: Span) { +#[allow(clippy::too_many_arguments)] +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + filter_recv: &hir::Expr<'_>, + filter_arg: &hir::Expr<'_>, + filter_span: Span, + map_recv: &hir::Expr<'_>, + map_arg: &hir::Expr<'_>, + map_span: Span, + is_find: bool, +) { + lint_filter_some_map_unwrap( + cx, + expr, + filter_recv, + filter_arg, + map_arg, + map_span, + filter_span.with_hi(expr.span.hi()), + ); if_chain! { - if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind; - if let ExprKind::MethodCall(_, _, [filter_recv, filter_arg], filter_span) = map_recv.kind; - then { - lint_filter_some_map_unwrap(cx, expr, filter_recv, filter_arg, - map_arg, target_span, filter_span.to(map_span)); - if_chain! { if is_trait_method(cx, map_recv, sym::Iterator); // filter(|x| ...is_some())... @@ -148,7 +158,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_ }; if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); then { - let span = filter_span.to(map_span); + let span = filter_span.with_hi(expr.span.hi()); let (filter_name, lint) = if is_find { ("find", MANUAL_FIND_MAP) } else { @@ -160,7 +170,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_ snippet(cx, map_arg.span, ".."), to_opt); span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); } - } - } } } diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 80598d88508..3a61f4ccad7 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -8,15 +8,8 @@ use rustc_span::{source_map::Span, sym}; use super::FILTER_MAP_IDENTITY; -pub(super) fn check( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_map_args: &[hir::Expr<'_>], - filter_map_span: Span, -) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { if is_trait_method(cx, expr, sym::Iterator) { - let arg_node = &filter_map_args[1].kind; - let apply_lint = |message: &str| { span_lint_and_sugg( cx, @@ -30,8 +23,8 @@ pub(super) fn check( }; if_chain! { - if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; - let body = cx.tcx.hir().body(*body_id); + if let hir::ExprKind::Closure(_, _, body_id, _, _) = filter_map_arg.kind; + let body = cx.tcx.hir().body(body_id); if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind; if path_to_local_id(&body.value, binding_id); @@ -41,7 +34,7 @@ pub(super) fn check( } if_chain! { - if let hir::ExprKind::Path(ref qpath) = arg_node; + if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind; if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index ba57abd16c9..2b19e4ee8c0 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -14,7 +14,8 @@ const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, - filter_args: &'tcx [hir::Expr<'_>], + recv: &'tcx hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, msrv: Option<&RustcVersion>, ) { if is_trait_method(cx, expr, sym::Iterator) { @@ -24,9 +25,9 @@ pub(super) fn check<'tcx>( let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find_map(..)` instead"; - let filter_snippet = snippet(cx, filter_args[1].span, ".."); + let filter_snippet = snippet(cx, arg.span, ".."); if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet(cx, filter_args[0].span, ".."); + let iter_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, FILTER_MAP_NEXT, diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 6cd24334414..172714f6b01 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -9,14 +9,19 @@ use rustc_span::sym; use super::FILTER_NEXT; /// lint use of `filter().next()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + filter_arg: &'tcx hir::Expr<'_>, +) { // lint if caller of `.filter().next()` is an Iterator if is_trait_method(cx, expr, sym::Iterator) { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; - let filter_snippet = snippet(cx, filter_args[1].span, ".."); + let filter_snippet = snippet(cx, filter_arg.span, ".."); if filter_snippet.lines().count() <= 1 { - let iter_snippet = snippet(cx, filter_args[0].span, ".."); + let iter_snippet = snippet(cx, recv.span, ".."); // add note if not multi-line span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 034ea6c6562..664885a2f0e 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -12,11 +12,11 @@ use super::FLAT_MAP_IDENTITY; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, - flat_map_args: &'tcx [hir::Expr<'_>], + flat_map_arg: &'tcx hir::Expr<'_>, flat_map_span: Span, ) { if is_trait_method(cx, expr, sym::Iterator) { - let arg_node = &flat_map_args[1].kind; + let arg_node = &flat_map_arg.kind; let apply_lint = |message: &str| { span_lint_and_sugg( diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index b3a9743c614..54f28064384 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -11,18 +11,20 @@ use rustc_span::sym; use super::GET_UNWRAP; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + recv: &'tcx hir::Expr<'tcx>, + get_arg: &'tcx hir::Expr<'_>, + is_mut: bool, +) { // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`, // because they do not implement `IndexMut` let mut applicability = Applicability::MachineApplicable; - let expr_ty = cx.typeck_results().expr_ty(&get_args[0]); - let get_args_str = if get_args.len() > 1 { - snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability) - } else { - return; // not linting on a .get().unwrap() chain or variant - }; + let expr_ty = cx.typeck_results().expr_ty(recv); + let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability); let mut needs_ref; - let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() { + let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() { needs_ref = get_args_str.parse::().is_ok(); "slice" } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { @@ -77,7 +79,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args format!( "{}{}[{}]", borrow_str, - snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability), + snippet_with_applicability(cx, recv.span, "..", &mut applicability), get_args_str ), applicability, diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 848f47e39f6..739f313716e 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -9,10 +9,10 @@ use rustc_span::sym; use super::ITER_CLONED_COLLECT; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { if_chain! { if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type); - if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])); + if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)); if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); then { diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index e394a8fe819..c6b7c7cd179 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -10,9 +10,9 @@ use rustc_span::sym; use super::ITER_COUNT; -pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], iter_method: &str) { - let ty = cx.typeck_results().expr_ty(&iter_args[0]); - let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() { +pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) { + let ty = cx.typeck_results().expr_ty(recv); + let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { "slice" } else if is_type_diagnostic_item(cx, ty, sym::vec_type) { "Vec" @@ -42,7 +42,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &' "try", format!( "{}.len()", - snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + snippet_with_applicability(cx, recv.span, "..", &mut applicability), ), applicability, ); diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index e9b37b6f2bd..dab0a43a096 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -13,9 +13,7 @@ use rustc_span::symbol::sym; use super::ITER_NEXT_SLICE; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { - let caller_expr = &iter_args[0]; - +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, caller_expr: &'tcx hir::Expr<'_>) { // Skip lint if the `iter().next()` expression is a for loop argument, // since it is already covered by `&loops::ITER_NEXT_LOOP` let mut parent_expr_opt = get_parent_expr(cx, expr); diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index c46af427b3c..c2232239fe4 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -11,20 +11,20 @@ use super::ITER_NTH; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, - nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]], + iter_recv: &'tcx hir::Expr<'tcx>, + nth_recv: &hir::Expr<'_>, + nth_arg: &hir::Expr<'_>, is_mut: bool, ) { - let iter_args = nth_and_iter_args[1]; let mut_str = if is_mut { "_mut" } else { "" }; - let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { + let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() { "slice" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vec_type) { "Vec" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vecdeque_type) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vecdeque_type) { "VecDeque" } else { - let nth_args = nth_and_iter_args[0]; - iter_nth_zero::check(cx, expr, &nth_args); + iter_nth_zero::check(cx, expr, nth_recv, nth_arg); return; // caller is not a type that we want to lint }; diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index a12f672739c..52d7c15332e 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -10,10 +10,10 @@ use rustc_span::sym; use super::ITER_NTH_ZERO; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, expr, sym::Iterator); - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]); + if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args expr.span, "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", "try calling `.next()` instead of `.nth(0)`", - format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)), + format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)), applicability, ); } diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index b1d398876d3..e32594757d0 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -8,19 +8,17 @@ use rustc_span::sym; use super::ITER_SKIP_NEXT; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { // lint if caller of skip is an Iterator if is_trait_method(cx, expr, sym::Iterator) { - if let [caller, n] = skip_args { - span_lint_and_sugg( - cx, - ITER_SKIP_NEXT, - expr.span.trim_start(caller.span).unwrap(), - "called `skip(..).next()` on an iterator", - "use `nth` instead", - format!(".nth({})", snippet(cx, n.span, "..")), - Applicability::MachineApplicable, - ); - } + span_lint_and_sugg( + cx, + ITER_SKIP_NEXT, + expr.span.trim_start(recv.span).unwrap(), + "called `skip(..).next()` on an iterator", + "use `nth` instead", + format!(".nth({})", snippet(cx, arg.span, "..")), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 3baa580314f..06b12998b1a 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -7,9 +7,9 @@ use rustc_span::sym; use super::ITERATOR_STEP_BY_ZERO; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { if is_trait_method(cx, expr, sym::Iterator) { - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) { + if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) { span_lint( cx, ITERATOR_STEP_BY_ZERO, diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index f16699322d1..6c5a842a912 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -8,11 +8,14 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_target::abi::LayoutOf; -pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>]], arith: &str) { - let unwrap_arg = &args[0][1]; - let arith_lhs = &args[1][0]; - let arith_rhs = &args[1][1]; - +pub fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + arith_lhs: &hir::Expr<'_>, + arith_rhs: &hir::Expr<'_>, + unwrap_arg: &hir::Expr<'_>, + arith: &str, +) { let ty = cx.typeck_results().expr_ty(arith_lhs); if !ty.is_integral() { return; diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index e4402b2da21..82063ad70b5 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -14,13 +14,13 @@ use super::MAP_COLLECT_RESULT_UNIT; pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, - map_args: &[hir::Expr<'_>], - collect_args: &[hir::Expr<'_>], + iter: &hir::Expr<'_>, + map_fn: &hir::Expr<'_>, + collect_recv: &hir::Expr<'_>, ) { if_chain! { // called on Iterator - if let [map_expr] = collect_args; - if is_trait_method(cx, map_expr, sym::Iterator); + if is_trait_method(cx, collect_recv, sym::Iterator); // return of collect `Result<(),_>` let collect_ret_ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); @@ -28,7 +28,6 @@ pub(super) fn check( if let Some(result_t) = substs.types().next(); if result_t.is_unit(); // get parts for snippet - if let [iter, map_fn] = map_args; then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 4bc52b036a8..e8ad16bc0de 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -11,10 +11,15 @@ use rustc_span::symbol::sym; use super::MAP_FLATTEN; /// lint use of `map().flatten()` for `Iterators` and 'Options' -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, +) { // lint if caller of `.map().flatten()` is an Iterator if is_trait_method(cx, expr, sym::Iterator) { - let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]); + let map_closure_ty = cx.typeck_results().expr_ty(map_arg); let is_map_to_option = match map_closure_ty.kind() { ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { let map_closure_sig = match map_closure_ty.kind() { @@ -34,12 +39,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map // `(...).map(...)` has type `impl Iterator> "flat_map" }; - let func_snippet = snippet(cx, map_args[1].span, ".."); + let func_snippet = snippet(cx, map_arg.span, ".."); let hint = format!(".{0}({1})", method_to_use, func_snippet); span_lint_and_sugg( cx, MAP_FLATTEN, - expr.span.with_lo(map_args[0].span.hi()), + expr.span.with_lo(recv.span.hi()), "called `map(..).flatten()` on an `Iterator`", &format!("try using `{}` instead", method_to_use), hint, @@ -48,13 +53,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } // lint if caller of `.map().flatten()` is an Option - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { - let func_snippet = snippet(cx, map_args[1].span, ".."); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) { + let func_snippet = snippet(cx, map_arg.span, ".."); let hint = format!(".and_then({})", func_snippet); span_lint_and_sugg( cx, MAP_FLATTEN, - expr.span.with_lo(map_args[0].span.hi()), + expr.span.with_lo(recv.span.hi()), "called `map(..).flatten()` on an `Option`", "try using `and_then` instead", hint, diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index deb4b4492b5..4330fea727b 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -18,22 +18,23 @@ const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, - map_args: &'tcx [hir::Expr<'_>], - unwrap_args: &'tcx [hir::Expr<'_>], + recv: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, + unwrap_arg: &'tcx hir::Expr<'_>, msrv: Option<&RustcVersion>, ) -> bool { if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { return false; } // lint if the caller of `map()` is an `Option` - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); if is_option || is_result { // Don't make a suggestion that may fail to compile due to mutably borrowing // the same variable twice. - let map_mutated_vars = mutated_variables(&map_args[0], cx); - let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx); + let map_mutated_vars = mutated_variables(recv, cx); + let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx); if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) { if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() { return false; @@ -51,14 +52,14 @@ pub(super) fn check<'tcx>( `.map_or_else(, )` instead" }; // get snippets for args to map() and unwrap_or_else() - let map_snippet = snippet(cx, map_args[1].span, ".."); - let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); + let map_snippet = snippet(cx, map_arg.span, ".."); + let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); // lint, with note if neither arg is > 1 line and both map() and // unwrap_or_else() have the same span let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt(); + let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt(); if same_span && !multiline { - let var_snippet = snippet(cx, map_args[0].span, ".."); + let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, MAP_UNWRAP_OR, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8a04fd0060d..9a95354db7a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -62,17 +62,18 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty}; +use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::{PrimTy, QPath, TraitItem, TraitItemKind}; +use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::{sym, SymbolStr}; +use rustc_span::symbol::SymbolStr; +use rustc_span::{sym, Span}; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { @@ -1704,134 +1705,32 @@ impl_lint_pass!(Methods => [ IMPLICIT_CLONE ]); +/// Extracts a method call name, args, and `Span` of the method name. +fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(SymbolStr, &'tcx [hir::Expr<'tcx>], Span)> { + if let ExprKind::MethodCall(path, span, args, _) = recv.kind { + if !args.iter().any(|e| e.span.from_expansion()) { + return Some((path.ident.name.as_str(), args, span)); + } + } + None +} + +/// Same as `method_call` but the `SymbolStr` is dereferenced into a temporary `&str` +macro_rules! method_call { + ($expr:expr) => { + method_call($expr) + .as_ref() + .map(|&(ref name, args, span)| (&**name, args, span)) + }; +} + impl<'tcx> LateLintPass<'tcx> for Methods { - #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if in_macro(expr.span) { return; } - let (method_names, arg_lists, method_spans) = method_calls(expr, 2); - let method_names: Vec = method_names.iter().map(|s| s.as_str()).collect(); - let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect(); - - match method_names.as_slice() { - ["unwrap", "get"] => get_unwrap::check(cx, expr, arg_lists[1], false), - ["unwrap", "get_mut"] => get_unwrap::check(cx, expr, arg_lists[1], true), - ["unwrap", ..] => unwrap_used::check(cx, expr, arg_lists[0]), - ["expect", "ok"] => ok_expect::check(cx, expr, arg_lists[1]), - ["expect", ..] => expect_used::check(cx, expr, arg_lists[0]), - ["unwrap_or", "map"] => option_map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), - ["unwrap_or_else", "map"] => { - if !map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) { - unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"); - } - }, - ["map_or", ..] => option_map_or_none::check(cx, expr, arg_lists[0]), - ["and_then", ..] => { - let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, arg_lists[0]); - let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, arg_lists[0]); - if !biom_option_linted && !biom_result_linted { - unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "and"); - } - }, - ["or_else", ..] => { - if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, arg_lists[0]) { - unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "or"); - } - }, - ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]), - ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]), - ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]), - ["map", "filter"] => filter_map::check(cx, expr, false, method_spans[0]), - ["map", "filter_map"] => filter_map_map::check(cx, expr), - ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()), - ["map", "find"] => filter_map::check(cx, expr, true, method_spans[0]), - ["flat_map", "filter"] => filter_flat_map::check(cx, expr), - ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr), - ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]), - ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]), - [option_check_method, "find"] if "is_some" == *option_check_method || "is_none" == *option_check_method => { - search_is_some::check( - cx, - expr, - "find", - option_check_method, - arg_lists[1], - arg_lists[0], - method_spans[1], - ) - }, - [option_check_method, "position"] - if "is_some" == *option_check_method || "is_none" == *option_check_method => - { - search_is_some::check( - cx, - expr, - "position", - option_check_method, - arg_lists[1], - arg_lists[0], - method_spans[1], - ) - }, - [option_check_method, "rposition"] - if "is_some" == *option_check_method || "is_none" == *option_check_method => - { - search_is_some::check( - cx, - expr, - "rposition", - option_check_method, - arg_lists[1], - arg_lists[0], - method_spans[1], - ) - }, - ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]), - ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"), - ["count", "iter"] => iter_count::check(cx, expr, &arg_lists[1], "iter"), - ["count", "iter_mut"] => iter_count::check(cx, expr, &arg_lists[1], "iter_mut"), - ["nth", "iter"] => iter_nth::check(cx, expr, &arg_lists, false), - ["nth", "iter_mut"] => iter_nth::check(cx, expr, &arg_lists, true), - ["nth", "bytes"] => bytes_nth::check(cx, expr, &arg_lists[1]), - ["nth", ..] => iter_nth_zero::check(cx, expr, arg_lists[0]), - ["step_by", ..] => iterator_step_by_zero::check(cx, expr, arg_lists[0]), - ["next", "skip"] => iter_skip_next::check(cx, expr, arg_lists[1]), - ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]), - ["as_ref"] => useless_asref::check(cx, expr, "as_ref", arg_lists[0]), - ["as_mut"] => useless_asref::check(cx, expr, "as_mut", arg_lists[0]), - ["fold", ..] => unnecessary_fold::check(cx, expr, arg_lists[0], method_spans[0]), - ["filter_map", ..] => { - unnecessary_filter_map::check(cx, expr, arg_lists[0]); - filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); - }, - ["count", "map"] => suspicious_map::check(cx, expr, arg_lists[1], arg_lists[0]), - ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr), - ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { - manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..]) - }, - ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { - zst_offset::check(cx, expr, arg_lists[0]) - }, - ["is_file", ..] => filetype_is_file::check(cx, expr, arg_lists[0]), - ["map", "as_ref"] => { - option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) - }, - ["map", "as_mut"] => { - option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) - }, - ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"), - ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"), - ["ok_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "ok_or"), - ["collect", "map"] => map_collect_result_unit::check(cx, expr, arg_lists[1], arg_lists[0]), - ["for_each", "inspect"] => inspect_for_each::check(cx, expr, method_spans[1]), - ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned), - ["to_os_string", ..] => implicit_clone::check(cx, expr, sym::OsStr), - ["to_path_buf", ..] => implicit_clone::check(cx, expr, sym::Path), - ["to_vec", ..] => implicit_clone::check(cx, expr, sym::slice), - _ => {}, - } + check_methods(cx, expr, self.msrv.as_ref()); match expr.kind { hir::ExprKind::Call(ref func, ref args) => { @@ -2020,6 +1919,140 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } + +#[allow(clippy::too_many_lines)] +fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) { + if let Some((name, [recv, args @ ..], span)) = method_call!(expr) { + match (name, args) { + ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => { + zst_offset::check(cx, expr, recv) + }, + ("and_then", [arg]) => { + let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); + let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); + if !biom_option_linted && !biom_result_linted { + unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); + } + }, + ("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), + ("collect", []) => match method_call!(recv) { + Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2), + Some(("map", [m_recv, m_arg], _)) => { + map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); + }, + _ => {}, + }, + ("count", []) => match method_call!(recv) { + Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { + iter_count::check(cx, expr, recv2, name); + }, + Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), + _ => {}, + }, + ("expect", [_]) => match method_call!(recv) { + Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), + _ => expect_used::check(cx, expr, recv), + }, + ("extend", [arg]) => string_extend_chars::check(cx, expr, recv, arg), + ("filter_map", [arg]) => { + unnecessary_filter_map::check(cx, expr, arg); + filter_map_identity::check(cx, expr, arg, span); + }, + ("flat_map", [flm_arg]) => match method_call!(recv) { + Some(("filter", [_, _], _)) => filter_flat_map::check(cx, expr), + Some(("filter_map", [_, _], _)) => filter_map_flat_map::check(cx, expr), + _ => flat_map_identity::check(cx, expr, flm_arg, span), + }, + ("flatten", []) => { + if let Some(("map", [recv, map_arg], _)) = method_call!(recv) { + map_flatten::check(cx, expr, recv, map_arg); + } + }, + ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), + ("for_each", [_]) => { + if let Some(("inspect", [_, _], span2)) = method_call!(recv) { + inspect_for_each::check(cx, expr, span2); + } + }, + ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), + ("is_file", []) => filetype_is_file::check(cx, expr, recv), + ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), + ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), + ("map", [m_arg]) => { + 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, msrv), + ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv), + ("filter", [f_arg]) => { + filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false) + }, + ("filter_map", [_]) => filter_map_map::check(cx, expr), + ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true), + _ => {}, + } + } + }, + ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), + ("next", []) => { + if let Some((name, [recv, args @ ..], _)) = method_call!(recv) { + match (name, args) { + ("filter", [arg]) => filter_next::check(cx, expr, recv, arg), + ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv), + ("iter", []) => iter_next_slice::check(cx, expr, recv), + ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg), + ("skip_while", [_]) => skip_while_next::check(cx, expr), + _ => {}, + } + } + }, + ("nth", [n_arg]) => match method_call!(recv) { + Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg), + 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"), + ("or_else", [arg]) => { + if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) { + unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); + } + }, + ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), + ("to_os_string", []) => implicit_clone::check(cx, expr, sym::OsStr), + ("to_owned", []) => implicit_clone::check(cx, expr, sym::ToOwned), + ("to_path_buf", []) => implicit_clone::check(cx, expr, sym::Path), + ("to_vec", []) => implicit_clone::check(cx, expr, sym::slice), + ("unwrap", []) => match method_call!(recv) { + Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), + Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), + _ => unwrap_used::check(cx, expr, recv), + }, + ("unwrap_or", [u_arg]) => match method_call!(recv) { + 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)) => { + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span) + }, + _ => {}, + }, + ("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, msrv) => {}, + _ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"), + }, + _ => {}, + } + } +} + +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) { + search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span) + } +} + /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index e6ce9cac397..d0b1b4b84be 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -9,11 +9,11 @@ use rustc_span::sym; use super::OK_EXPECT; /// lint use of `ok().expect()` for `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { // lint if the caller of `ok()` is a `Result` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type); - let result_type = cx.typeck_results().expr_ty(&ok_args[0]); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + let result_type = cx.typeck_results().expr_ty(recv); if let Some(error_type) = get_error_type(cx, result_type); if has_debug_impl(error_type, cx); diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index d11ede080dc..1367a0c21d8 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -18,8 +18,8 @@ const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, - as_ref_args: &[hir::Expr<'_>], - map_args: &[hir::Expr<'_>], + as_ref_recv: &hir::Expr<'_>, + map_arg: &hir::Expr<'_>, is_mut: bool, msrv: Option<&RustcVersion>, ) { @@ -29,7 +29,7 @@ pub(super) fn check<'tcx>( let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); - let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); + let option_ty = cx.typeck_results().expr_ty(as_ref_recv); if !is_type_diagnostic_item(cx, option_ty, sym::option_type) { return; } @@ -46,9 +46,9 @@ pub(super) fn check<'tcx>( &paths::VEC_AS_MUT_SLICE, ]; - let is_deref = match map_args[1].kind { + let is_deref = match map_arg.kind { hir::ExprKind::Path(ref expr_qpath) => cx - .qpath_res(expr_qpath, map_args[1].hir_id) + .qpath_res(expr_qpath, map_arg.hir_id) .opt_def_id() .map_or(false, |fun_def_id| { deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) @@ -96,12 +96,12 @@ pub(super) fn check<'tcx>( if is_deref { let current_method = if is_mut { - format!(".as_mut().map({})", snippet(cx, map_args[1].span, "..")) + format!(".as_mut().map({})", snippet(cx, map_arg.span, "..")) } else { - format!(".as_ref().map({})", snippet(cx, map_args[1].span, "..")) + format!(".as_ref().map({})", snippet(cx, map_arg.span, "..")) }; let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; - let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint); + let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint); let suggestion = format!("try using {} instead", method_hint); let msg = format!( diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index d93db2c22e4..013a6f90ac9 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -11,9 +11,15 @@ use super::OPTION_MAP_OR_NONE; use super::RESULT_MAP_OR_INTO_OPTION; /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type); +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + def_arg: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, +) { + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); // There are two variants of this `map_or` lint: // (1) using `map_or` as an adapter from `Result` to `Option` @@ -25,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } let (lint_name, msg, instead, hint) = { - let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind { + let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { match_qpath(qpath, &paths::OPTION_NONE) } else { return; @@ -36,15 +42,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map return; } - let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind { + let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { match_qpath(qpath, &paths::OPTION_SOME) } else { false }; if is_option { - let self_snippet = snippet(cx, map_or_args[0].span, ".."); - let func_snippet = snippet(cx, map_or_args[2].span, ".."); + let self_snippet = snippet(cx, recv.span, ".."); + let func_snippet = snippet(cx, map_arg.span, ".."); let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ `and_then(..)` instead"; ( @@ -56,7 +62,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } else if f_arg_is_some { let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ `ok()` instead"; - let self_snippet = snippet(cx, map_or_args[0].span, ".."); + let self_snippet = snippet(cx, recv.span, ".."); ( RESULT_MAP_OR_INTO_OPTION, msg, diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index e252abc177a..5bca49dec24 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -18,13 +18,15 @@ use super::MAP_UNWRAP_OR; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &rustc_hir::Expr<'_>, - map_args: &'tcx [rustc_hir::Expr<'_>], - unwrap_args: &'tcx [rustc_hir::Expr<'_>], + recv: &rustc_hir::Expr<'_>, + map_arg: &'tcx rustc_hir::Expr<'_>, + unwrap_recv: &rustc_hir::Expr<'_>, + unwrap_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, ) { // lint if the caller of `map()` is an `Option` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { - if !is_copy(cx, cx.typeck_results().expr_ty(&unwrap_args[1])) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) { + if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { // Do not lint if the `map` argument uses identifiers in the `map` // argument that are also used in the `unwrap_or` argument @@ -32,27 +34,27 @@ pub(super) fn check<'tcx>( cx, identifiers: FxHashSet::default(), }; - unwrap_visitor.visit_expr(&unwrap_args[1]); + unwrap_visitor.visit_expr(unwrap_arg); let mut map_expr_visitor = MapExprVisitor { cx, identifiers: unwrap_visitor.identifiers, found_identifier: false, }; - map_expr_visitor.visit_expr(&map_args[1]); + map_expr_visitor.visit_expr(map_arg); if map_expr_visitor.found_identifier { return; } } - if differing_macro_contexts(unwrap_args[1].span, map_span) { + if differing_macro_contexts(unwrap_arg.span, map_span) { return; } let mut applicability = Applicability::MachineApplicable; // get snippet for unwrap_or() - let unwrap_snippet = snippet_with_applicability(cx, unwrap_args[1].span, "..", &mut applicability); + let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); // lint message // comparing the snippet from source to raw text ("None") below is safe // because we already have checked the type. @@ -70,14 +72,14 @@ pub(super) fn check<'tcx>( ); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { - let map_arg_span = map_args[1].span; + let map_arg_span = map_arg.span; let mut suggestion = vec![ ( map_span, String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }), ), - (expr.span.with_lo(unwrap_args[0].span.hi()), String::from("")), + (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")), ]; if !unwrap_snippet_none { diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index de7d168295f..8a94d7f4155 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -15,29 +15,31 @@ use super::SEARCH_IS_SOME; /// lint searching an Iterator followed by `is_some()` /// or calling `find()` on a string followed by `is_some()` or `is_none()` -#[allow(clippy::too_many_lines)] +#[allow(clippy::too_many_arguments, clippy::too_many_lines)] pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, + cx: &LateContext<'_>, expr: &'tcx hir::Expr<'_>, search_method: &str, - option_check_method: &str, - search_args: &'tcx [hir::Expr<'_>], - is_some_args: &'tcx [hir::Expr<'_>], + is_some: bool, + search_recv: &hir::Expr<'_>, + search_arg: &'tcx hir::Expr<'_>, + is_some_recv: &hir::Expr<'_>, method_span: Span, ) { + let option_check_method = if is_some { "is_some" } else { "is_none" }; // lint if caller of search is an Iterator - if is_trait_method(cx, &is_some_args[0], sym::Iterator) { + if is_trait_method(cx, is_some_recv, sym::Iterator) { let msg = format!( "called `{}()` after searching an `Iterator` with `{}`", option_check_method, search_method ); - let search_snippet = snippet(cx, search_args[1].span, ".."); + let search_snippet = snippet(cx, search_arg.span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let any_search_snippet = if_chain! { if search_method == "find"; - if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind; + if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind; let closure_body = cx.tcx.hir().body(body_id); if let Some(closure_arg) = closure_body.params.get(0); then { @@ -54,38 +56,34 @@ pub(super) fn check<'tcx>( } }; // add note if not multi-line - match option_check_method { - "is_some" => { - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - &msg, - "use `any()` instead", - format!( - "any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); - }, - "is_none" => { - let iter = snippet(cx, search_args[0].span, ".."); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - expr.span, - &msg, - "use `!_.any()` instead", - format!( - "!{}.any({})", - iter, - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); - }, - _ => (), + if is_some { + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `any()` instead", + format!( + "any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + } else { + let iter = snippet(cx, search_recv.span, ".."); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + "use `!_.any()` instead", + format!( + "!{}.any({})", + iter, + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); } } else { let hint = format!( @@ -110,14 +108,14 @@ pub(super) fn check<'tcx>( } }; if_chain! { - if is_string_or_str_slice(&search_args[0]); - if is_string_or_str_slice(&search_args[1]); + if is_string_or_str_slice(&search_recv); + if is_string_or_str_slice(&search_arg); then { let msg = format!("called `{}()` after calling `find()` on a string", option_check_method); match option_check_method { "is_some" => { let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); span_lint_and_sugg( cx, SEARCH_IS_SOME, @@ -129,9 +127,9 @@ pub(super) fn check<'tcx>( ); }, "is_none" => { - let string = snippet(cx, search_args[0].span, ".."); + let string = snippet(cx, search_recv.span, ".."); let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); span_lint_and_sugg( cx, SEARCH_IS_SOME, diff --git a/clippy_lints/src/methods/skip_while_next.rs b/clippy_lints/src/methods/skip_while_next.rs index 3db83785b59..9f0b6c34ea2 100644 --- a/clippy_lints/src/methods/skip_while_next.rs +++ b/clippy_lints/src/methods/skip_while_next.rs @@ -7,7 +7,7 @@ use rustc_span::sym; use super::SKIP_WHILE_NEXT; /// lint use of `skip_while().next()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, _skip_while_args: &'tcx [hir::Expr<'_>]) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // lint if caller of `.skip_while().next()` is an Iterator if is_trait_method(cx, expr, sym::Iterator) { span_lint_and_help( diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 5c688ac5621..6e7890a3080 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -10,12 +10,11 @@ use rustc_span::symbol::sym; use super::STRING_EXTEND_CHARS; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { + let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) { return; } - let arg = &args[1]; if let Some(arglists) = method_chain_args(arg, &["chars"]) { let target = &arglists[0][0]; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); @@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp "try this", format!( "{}.push_str({}{})", - snippet_with_applicability(cx, args[0].span, "..", &mut applicability), + snippet_with_applicability(cx, recv.span, "..", &mut applicability), ref_str, snippet_with_applicability(cx, target.span, "..", &mut applicability) ), diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 7015bd54c35..0fd0668c734 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -8,15 +8,8 @@ use rustc_span::sym; use super::SUSPICIOUS_MAP; -pub fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &hir::Expr<'_>, - map_args: &[hir::Expr<'_>], - count_args: &[hir::Expr<'_>], -) { +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) { if_chain! { - if let [count_recv] = count_args; - if let [_, map_arg] = map_args; if is_trait_method(cx, count_recv, sym::Iterator); let closure = expr_or_init(cx, map_arg); if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id); diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index f2f6ef4be6c..3cc1912b15a 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -8,18 +8,18 @@ use rustc_middle::ty::{self, Ty}; use super::UNINIT_ASSUMED_INIT; /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter) -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::Call(ref callee, ref args) = expr.kind; + if let hir::ExprKind::Call(ref callee, ref args) = recv.kind; if args.is_empty(); if let hir::ExprKind::Path(ref path) = callee.kind; if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); - if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer)); + if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( cx, UNINIT_ASSUMED_INIT, - outer.span, + expr.span, "this call for this type may be undefined behavior" ); } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 48d905ab833..dac7e039e37 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -10,12 +10,12 @@ use rustc_span::sym; use super::UNNECESSARY_FILTER_MAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if !is_trait_method(cx, expr, sym::Iterator) { return; } - if let hir::ExprKind::Closure(_, _, body_id, ..) = args[1].kind { + if let hir::ExprKind::Closure(_, _, body_id, ..) = arg.kind { let body = cx.tcx.hir().body(body_id); let arg_id = body.params[0].pat.hir_id; let mutates_arg = diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 1268fd4bda9..7c16470348f 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -11,11 +11,17 @@ use rustc_span::{source_map::Span, sym}; use super::UNNECESSARY_FOLD; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + init: &hir::Expr<'_>, + acc: &hir::Expr<'_>, + fold_span: Span, +) { fn check_fold_with_op( cx: &LateContext<'_>, expr: &hir::Expr<'_>, - fold_args: &[hir::Expr<'_>], + acc: &hir::Expr<'_>, fold_span: Span, op: hir::BinOpKind, replacement_method_name: &str, @@ -23,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir ) { if_chain! { // Extract the body of the closure passed to fold - if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind; + if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind; let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); @@ -74,25 +80,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir return; } - assert!( - fold_args.len() == 3, - "Expected fold_args to have three entries - the receiver, the initial value and the closure" - ); - // Check if the first argument to .fold is a suitable literal - if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind { + if let hir::ExprKind::Lit(ref lit) = init.kind { match lit.node { - ast::LitKind::Bool(false) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true) - }, - ast::LitKind::Bool(true) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true) - }, - ast::LitKind::Int(0, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false) - }, + ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true), + ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true), + ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false), ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false) + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false) }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a86185bf0a6..b7380883a5e 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -14,14 +14,15 @@ use super::UNNECESSARY_LAZY_EVALUATIONS; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, - args: &'tcx [hir::Expr<'_>], + recv: &'tcx hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::option_type); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::result_type); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); if is_option || is_result { - if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { + if let hir::ExprKind::Closure(_, _, eid, _, _) = arg.kind { let body = cx.tcx.hir().body(eid); let body_expr = &body.value; @@ -55,7 +56,7 @@ pub(super) fn check<'tcx>( &format!("use `{}` instead", simplify_using), format!( "{0}.{1}({2})", - snippet(cx, args[0].span, ".."), + snippet(cx, recv.span, ".."), simplify_using, snippet(cx, body_expr.span, ".."), ), diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 2f5806115bd..7fd1948594d 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -7,8 +7,8 @@ use rustc_span::sym; use super::UNWRAP_USED; /// lint use of `unwrap()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { - let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { + let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { Some((UNWRAP_USED, "an Option", "None")) diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index b5505af0f7e..e0b1de68b37 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -10,12 +10,11 @@ use rustc_lint::LateContext; use super::USELESS_ASREF; /// Checks for the `USELESS_ASREF` lint. -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" // check if the call is to the actual `AsRef` or `AsMut` trait if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) { // check if the type after `as_ref` or `as_mut` is the same as before - let recvr = &as_ref_args[0]; let rcv_ty = cx.typeck_results().expr_ty(recvr); let res_ty = cx.typeck_results().expr_ty(expr); let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty); diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index 9f6a7c4db17..0489d0f6fcf 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -6,10 +6,9 @@ use rustc_middle::ty; use super::ZST_OFFSET; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { - if args.len() == 2; - if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind(); + if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(recv).kind(); if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); if layout.is_zst(); then { -- cgit 1.4.1-3-g733a5 From 827d6aaad4a7ec24dd3191160cefe0c1e0b654b9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 30 Mar 2021 14:59:59 -0500 Subject: Eat dogfood --- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/bytecount.rs | 82 ++++++++-------- clippy_lints/src/checked_conversions.rs | 6 +- clippy_lints/src/collapsible_match.rs | 2 +- clippy_lints/src/default.rs | 43 +++++---- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/exit.rs | 16 ++-- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/formatting.rs | 3 +- clippy_lints/src/if_let_mutex.rs | 22 ++--- clippy_lints/src/loops/manual_flatten.rs | 3 +- clippy_lints/src/loops/manual_memcpy.rs | 4 +- clippy_lints/src/loops/needless_collect.rs | 105 ++++++++++----------- clippy_lints/src/loops/needless_range_loop.rs | 74 +++++++-------- clippy_lints/src/loops/same_item_push.rs | 2 +- .../src/loops/while_immutable_condition.rs | 3 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/map_clone.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 16 ++-- clippy_lints/src/matches.rs | 4 +- clippy_lints/src/mem_replace.rs | 49 +++++----- clippy_lints/src/methods/bytes_nth.rs | 50 +++++----- .../src/methods/from_iter_instead_of_collect.rs | 2 +- clippy_lints/src/methods/mod.rs | 7 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 18 ++-- clippy_lints/src/misc.rs | 102 ++++++++++---------- clippy_lints/src/new_without_default.rs | 96 +++++++++---------- clippy_lints/src/non_copy_const.rs | 22 ++--- clippy_lints/src/panic_unimplemented.rs | 7 +- clippy_lints/src/ptr.rs | 23 +++-- clippy_lints/src/ranges.rs | 49 +++++----- clippy_lints/src/redundant_closure_call.rs | 4 +- clippy_lints/src/suspicious_trait_impl.rs | 7 +- .../src/transmute/transmute_float_to_int.rs | 2 +- clippy_lints/src/try_err.rs | 11 +-- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 4 +- clippy_lints/src/unnamed_address.rs | 4 +- clippy_lints/src/unused_self.rs | 25 +++-- clippy_lints/src/unwrap_in_result.rs | 44 ++++----- clippy_lints/src/useless_conversion.rs | 41 ++++---- clippy_lints/src/utils/internal_lints.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 31 +++--- 43 files changed, 469 insertions(+), 532 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 3cef8d2a78b..0ce46e1c214 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -371,8 +371,8 @@ fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { if meta_item.path.segments.len() > 1; if let tool_name = meta_item.path.segments[0].ident; if tool_name.name == sym::clippy; - let lint_name = meta_item.path.segments.last().unwrap().ident.name; then { + let lint_name = meta_item.path.segments.last().unwrap().ident.name; return Some(lint_name.as_str()); } } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 846ac08e93a..1546d823167 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -45,52 +45,48 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { if filter.ident.name == sym!(filter); if filter_args.len() == 2; if let ExprKind::Closure(_, _, body_id, _, _) = filter_args[1].kind; + let body = cx.tcx.hir().body(body_id); + if body.params.len() == 1; + if let Some(argname) = get_pat_name(&body.params[0].pat); + if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind; + if op.node == BinOpKind::Eq; + if match_type(cx, + cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(), + &paths::SLICE_ITER); then { - let body = cx.tcx.hir().body(body_id); - if_chain! { - if body.params.len() == 1; - if let Some(argname) = get_pat_name(&body.params[0].pat); - if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind; - if op.node == BinOpKind::Eq; - if match_type(cx, - cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(), - &paths::SLICE_ITER); - then { - let needle = match get_path_name(l) { - Some(name) if check_arg(name, argname, r) => r, - _ => match get_path_name(r) { - Some(name) if check_arg(name, argname, l) => l, - _ => { return; } - } - }; - if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() { - return; - } - let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = - filter_args[0].kind { - let p = path.ident.name; - if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { - &args[0] - } else { - &filter_args[0] - } - } else { - &filter_args[0] - }; - let mut applicability = Applicability::MaybeIncorrect; - span_lint_and_sugg( - cx, - NAIVE_BYTECOUNT, - expr.span, - "you appear to be counting bytes the naive way", - "consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet_with_applicability(cx, haystack.span, "..", &mut applicability), - snippet_with_applicability(cx, needle.span, "..", &mut applicability)), - applicability, - ); + let needle = match get_path_name(l) { + Some(name) if check_arg(name, argname, r) => r, + _ => match get_path_name(r) { + Some(name) if check_arg(name, argname, l) => l, + _ => { return; } } }; + if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() { + return; + } + let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = + filter_args[0].kind { + let p = path.ident.name; + if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { + &args[0] + } else { + &filter_args[0] + } + } else { + &filter_args[0] + }; + let mut applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + NAIVE_BYTECOUNT, + expr.span, + "you appear to be counting bytes the naive way", + "consider using the bytecount crate", + format!("bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + applicability, + ); } }; } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index ed46cac493a..b38c70bcc41 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -321,9 +321,8 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: if path.ident.name.as_str() == function; if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind; if let [int] = &*tp.segments; - let name = &int.ident.name.as_str(); - then { + let name = &int.ident.name.as_str(); candidates.iter().find(|c| name == *c).cloned() } else { None @@ -336,9 +335,8 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { if_chain! { if let QPath::Resolved(_, ref path) = *path; if let [ty] = &*path.segments; - let name = &ty.ident.name.as_str(); - then { + let name = &ty.ident.name.as_str(); INTS.iter().find(|c| name == *c).cloned() } else { None diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index e2b3686ddf0..04fff237bb4 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -62,8 +62,8 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch { } fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext<'tcx>) { + let expr = strip_singleton_blocks(arm.body); if_chain! { - let expr = strip_singleton_blocks(arm.body); if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind; // the outer arm pattern and the inner match if expr_in.span.ctxt() == arm.pat.span.ctxt(); diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 568a174445c..8a2146d93e8 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -84,22 +84,21 @@ impl LateLintPass<'_> for Default { if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); // Detect and ignore ::default() because these calls do explicitly name the type. if let QPath::Resolved(None, _path) = qpath; + let expr_ty = cx.typeck_results().expr_ty(expr); + if let ty::Adt(def, ..) = expr_ty.kind(); then { - let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, ..) = expr_ty.kind() { - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); - span_lint_and_sugg( - cx, - DEFAULT_TRAIT_ACCESS, - expr.span, - &format!("calling `{}` is more clear than this expression", replacement), - "try", - replacement, - Applicability::Unspecified, // First resolve the TODO above - ); - } + // TODO: Work out a way to put "whatever the imported way of referencing + // this type in this file" rather than a fully-qualified type. + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); + span_lint_and_sugg( + cx, + DEFAULT_TRAIT_ACCESS, + expr.span, + &format!("calling `{}` is more clear than this expression", replacement), + "try", + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); } } } @@ -202,14 +201,14 @@ impl LateLintPass<'_> for Default { let binding_type = if_chain! { if let ty::Adt(adt_def, substs) = binding_type.kind(); if !substs.is_empty(); - let adt_def_ty_name = cx.tcx.item_name(adt_def.did); - let generic_args = substs.iter().collect::>(); - let tys_str = generic_args - .iter() - .map(ToString::to_string) - .collect::>() - .join(", "); then { + let adt_def_ty_name = cx.tcx.item_name(adt_def.did); + let generic_args = substs.iter().collect::>(); + let tys_str = generic_args + .iter() + .map(ToString::to_string) + .collect::>() + .join(", "); format!("{}::<{}>", adt_def_ty_name, &tys_str) } else { binding_type.to_string() diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index d136db9373c..42bafc3442e 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -130,8 +130,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { }, ExprKind::Struct(_, fields, base) => { + let ty = self.cx.typeck_results().expr_ty(expr); if_chain! { - let ty = self.cx.typeck_results().expr_ty(expr); if let Some(adt_def) = ty.ty_adt_def(); if adt_def.is_struct(); if let Some(variant) = adt_def.variants.iter().next(); diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 635b6d83eab..84fac998662 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -32,16 +32,14 @@ impl<'tcx> LateLintPass<'tcx> for Exit { if let ExprKind::Path(ref path) = path_expr.kind; if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::EXIT); + let parent = cx.tcx.hir().get_parent_item(e.hir_id); + if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find(parent); + // If the next item up is a function we check if it is an entry point + // and only then emit a linter warning + let def_id = cx.tcx.hir().local_def_id(parent); + if !is_entrypoint_fn(cx, def_id.to_def_id()); then { - let parent = cx.tcx.hir().get_parent_item(e.hir_id); - if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find(parent) { - // If the next item up is a function we check if it is an entry point - // and only then emit a linter warning - let def_id = cx.tcx.hir().local_def_id(parent); - if !is_entrypoint_fn(cx, def_id.to_def_id()) { - span_lint(cx, EXIT, e.span, "usage of `process::exit`"); - } - } + span_lint(cx, EXIT, e.span, "usage of `process::exit`"); } } } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 1ca5c685a75..7968e7b764d 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -61,8 +61,8 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]); impl<'tcx> LateLintPass<'tcx> for FloatLiteral { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + let ty = cx.typeck_results().expr_ty(expr); if_chain! { - let ty = cx.typeck_results().expr_ty(expr); if let ty::Float(fty) = *ty.kind(); if let hir::ExprKind::Lit(ref lit) = expr.kind; if let LitKind::Float(sym, lit_float_ty) = lit.node; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index b10e83c0ea8..48612befc68 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -217,9 +217,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if let Some(else_snippet) = snippet_opt(cx, else_span); if let Some(else_pos) = else_snippet.find("else"); if else_snippet[else_pos..].contains('\n'); - let else_desc = if is_if(else_) { "if" } else { "{..}" }; - then { + let else_desc = if is_if(else_) { "if" } else { "{..}" }; span_lint_and_note( cx, SUSPICIOUS_ELSE_FORMATTING, diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 4aab43256bf..56dfcc6a506 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -94,13 +94,10 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if_chain! { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr); - then { - self.found_mutex = Some(mutex); - self.mutex_lock_called = true; - return; - } + if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { + self.found_mutex = Some(mutex); + self.mutex_lock_called = true; + return; } visit::walk_expr(self, expr); } @@ -121,13 +118,10 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if_chain! { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr); - then { - self.found_mutex = Some(mutex); - self.mutex_lock_called = true; - return; - } + if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { + self.found_mutex = Some(mutex); + self.mutex_lock_called = true; + return; } visit::walk_expr(self, expr); } diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 8d2b9cccba4..574ad8c0f29 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -46,9 +46,8 @@ pub(super) fn check<'tcx>( let some_ctor = is_some_ctor(cx, path.res); let ok_ctor = is_ok_ctor(cx, path.res); if some_ctor || ok_ctor; - let if_let_type = if some_ctor { "Some" } else { "Ok" }; - then { + let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type); diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index af6d56a89af..3c5abb7a3c4 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -61,8 +61,8 @@ pub(super) fn check<'tcx>( if_chain! { if let ExprKind::Index(base_left, idx_left) = lhs.kind; if let ExprKind::Index(base_right, idx_right) = rhs.kind; - if is_slice_like(cx, cx.typeck_results().expr_ty(base_left)) - && is_slice_like(cx, cx.typeck_results().expr_ty(base_right)); + if is_slice_like(cx, cx.typeck_results().expr_ty(base_left)); + if is_slice_like(cx, cx.typeck_results().expr_ty(base_right)); if let Some((start_left, offset_left)) = get_details_from_idx(cx, &idx_left, &starts); if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts); diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 5594fc7b046..d23d3c508fa 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -26,60 +26,59 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); if let Some(ref generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); + let ty = cx.typeck_results().node_type(ty.hir_id); + if is_type_diagnostic_item(cx, ty, sym::vec_type) + || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) + || match_type(cx, ty, &paths::BTREEMAP) + || is_type_diagnostic_item(cx, ty, sym::hashmap_type); then { - let ty = cx.typeck_results().node_type(ty.hir_id); - if is_type_diagnostic_item(cx, ty, sym::vec_type) || - is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || - match_type(cx, ty, &paths::BTREEMAP) || - is_type_diagnostic_item(cx, ty, sym::hashmap_type) { - if method.ident.name == sym!(len) { - let span = shorten_needless_collect_span(expr); - span_lint_and_sugg( - cx, - NEEDLESS_COLLECT, - span, - NEEDLESS_COLLECT_MSG, - "replace with", - "count()".to_string(), - Applicability::MachineApplicable, - ); - } - if method.ident.name == sym!(is_empty) { - let span = shorten_needless_collect_span(expr); - span_lint_and_sugg( - cx, - NEEDLESS_COLLECT, - span, - NEEDLESS_COLLECT_MSG, - "replace with", - "next().is_none()".to_string(), - Applicability::MachineApplicable, - ); - } - if method.ident.name == sym!(contains) { - let contains_arg = snippet(cx, args[1].span, "??"); - let span = shorten_needless_collect_span(expr); - span_lint_and_then( - cx, - NEEDLESS_COLLECT, - span, - NEEDLESS_COLLECT_MSG, - |diag| { - let (arg, pred) = contains_arg - .strip_prefix('&') - .map_or(("&x", &*contains_arg), |s| ("x", s)); - diag.span_suggestion( - span, - "replace with", - format!( - "any(|{}| x == {})", - arg, pred - ), - Applicability::MachineApplicable, - ); - } - ); - } + if method.ident.name == sym!(len) { + let span = shorten_needless_collect_span(expr); + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + span, + NEEDLESS_COLLECT_MSG, + "replace with", + "count()".to_string(), + Applicability::MachineApplicable, + ); + } + if method.ident.name == sym!(is_empty) { + let span = shorten_needless_collect_span(expr); + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + span, + NEEDLESS_COLLECT_MSG, + "replace with", + "next().is_none()".to_string(), + Applicability::MachineApplicable, + ); + } + if method.ident.name == sym!(contains) { + let contains_arg = snippet(cx, args[1].span, "??"); + let span = shorten_needless_collect_span(expr); + span_lint_and_then( + cx, + NEEDLESS_COLLECT, + span, + NEEDLESS_COLLECT_MSG, + |diag| { + let (arg, pred) = contains_arg + .strip_prefix('&') + .map_or(("&x", &*contains_arg), |s| ("x", s)); + diag.span_suggestion( + span, + "replace with", + format!( + "any(|{}| x == {})", + arg, pred + ), + Applicability::MachineApplicable, + ); + } + ); } } } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 3c40d54cb42..60afa449a45 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -256,49 +256,47 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if let ExprKind::Path(ref seqpath) = seqexpr.kind; if let QPath::Resolved(None, ref seqvar) = *seqpath; if seqvar.segments.len() == 1; + let index_used_directly = path_to_local_id(idx, self.var); + let indexed_indirectly = { + let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var); + walk_expr(&mut used_visitor, idx); + used_visitor.used + }; + if indexed_indirectly || index_used_directly; then { - let index_used_directly = path_to_local_id(idx, self.var); - let indexed_indirectly = { - let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var); - walk_expr(&mut used_visitor, idx); - used_visitor.used - }; - - if indexed_indirectly || index_used_directly { - if self.prefer_mutable { - self.indexed_mut.insert(seqvar.segments[0].ident.name); + if self.prefer_mutable { + self.indexed_mut.insert(seqvar.segments[0].ident.name); + } + let res = self.cx.qpath_res(seqpath, seqexpr.hir_id); + match res { + Res::Local(hir_id) => { + let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id); + let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id); + let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id); + if indexed_indirectly { + self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent)); + } + if index_used_directly { + self.indexed_directly.insert( + seqvar.segments[0].ident.name, + (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), + ); + } + return false; // no need to walk further *on the variable* } - let res = self.cx.qpath_res(seqpath, seqexpr.hir_id); - match res { - Res::Local(hir_id) => { - let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id); - let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id); - let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id); - if indexed_indirectly { - self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent)); - } - if index_used_directly { - self.indexed_directly.insert( - seqvar.segments[0].ident.name, - (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), - ); - } - return false; // no need to walk further *on the variable* + Res::Def(DefKind::Static | DefKind::Const, ..) => { + if indexed_indirectly { + self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); } - Res::Def(DefKind::Static | DefKind::Const, ..) => { - if indexed_indirectly { - self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); - } - if index_used_directly { - self.indexed_directly.insert( - seqvar.segments[0].ident.name, - (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), - ); - } - return false; // no need to walk further *on the variable* + if index_used_directly { + self.indexed_directly.insert( + seqvar.segments[0].ident.name, + (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), + ); } - _ => (), + return false; // no need to walk further *on the variable* } + _ => (), } } } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 849d7ec718c..62c131968e7 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -63,8 +63,8 @@ pub(super) fn check<'tcx>( match cx.qpath_res(qpath, pushed_item.hir_id) { // immutable bindings that are initialized with literal or constant Res::Local(hir_id) => { + let node = cx.tcx.hir().get(hir_id); if_chain! { - let node = cx.tcx.hir().get(hir_id); if let Node::Binding(pat) = node; if let PatKind::Binding(bind_ann, ..) = pat.kind; if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index cad9ff8489a..7d697b2bf00 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -103,9 +103,8 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { if_chain! { if let ExprKind::Path(ref qpath) = ex.kind; if let QPath::Resolved(None, _) = *qpath; - let res = self.cx.qpath_res(qpath, ex.hir_id); then { - match res { + match self.cx.qpath_res(qpath, ex.hir_id) { Res::Local(hir_id) => { self.ids.insert(hir_id); }, diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 95261580b8e..5a3f0f27bc6 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -113,8 +113,8 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants } } + let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v)); if_chain! { - let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v)); if let Some(marker) = markers.next(); if markers.count() == 0 && variants.len() > 1; then { diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index cfcc705eabc..9f1ab1f695d 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -58,9 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { let ty = cx.typeck_results().expr_ty(&args[0]); if is_type_diagnostic_item(cx, ty, sym::option_type) || is_trait_method(cx, e, sym::Iterator); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; - let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); then { + let closure_body = cx.tcx.hir().body(body_id); + let closure_expr = remove_blocks(&closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(ref inner, hir::Mutability::Not) => if let hir::PatKind::Binding( hir::BindingAnnotation::Unannotated, .., name, None diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index d4764b5ccff..5cc16244a0d 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -168,17 +168,15 @@ fn unit_closure<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> { - if let hir::ExprKind::Closure(_, ref decl, inner_expr_id, _, _) = expr.kind { + if_chain! { + if let hir::ExprKind::Closure(_, ref decl, inner_expr_id, _, _) = expr.kind; let body = cx.tcx.hir().body(inner_expr_id); let body_expr = &body.value; - - if_chain! { - if decl.inputs.len() == 1; - if is_unit_expression(cx, body_expr); - if let Some(binding) = iter_input_pats(&decl, body).next(); - then { - return Some((binding, body_expr)); - } + if decl.inputs.len() == 1; + if is_unit_expression(cx, body_expr); + if let Some(binding) = iter_input_pats(&decl, body).next(); + then { + return Some((binding, body_expr)); } } None diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 8c6c30a1881..4a3be67dd75 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -732,8 +732,8 @@ fn report_single_match_single_pattern( format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span))) }); + let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); let (msg, sugg) = if_chain! { - let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind; let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex)); if let Some(trait_id) = cx.tcx.lang_items().structural_peq_trait(); @@ -1480,8 +1480,8 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A /// Returns true if the `ex` match expression is in a local (`let`) statement fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> { + let map = &cx.tcx.hir(); if_chain! { - let map = &cx.tcx.hir(); if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)); if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id)); then { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 426c108d89f..0418c616efa 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -225,34 +225,33 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< } fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - if let ExprKind::Call(ref repl_func, _) = src.kind { - if_chain! { - if !in_external_macro(cx.tcx.sess, expr_span); - if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); + if_chain! { + if let ExprKind::Call(ref repl_func, _) = src.kind; + if !in_external_macro(cx.tcx.sess, expr_span); + if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; + if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); + if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default) + || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); - then { - span_lint_and_then( - cx, - MEM_REPLACE_WITH_DEFAULT, - expr_span, - "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", - |diag| { - if !in_macro(expr_span) { - let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); + then { + span_lint_and_then( + cx, + MEM_REPLACE_WITH_DEFAULT, + expr_span, + "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", + |diag| { + if !in_macro(expr_span) { + let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); - diag.span_suggestion( - expr_span, - "consider using", - suggestion, - Applicability::MachineApplicable - ); - } + diag.span_suggestion( + expr_span, + "consider using", + suggestion, + Applicability::MachineApplicable + ); } - ); - } + } + ); } } } diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 77f140510b6..2ad3e673c57 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -10,31 +9,26 @@ use rustc_span::sym; use super::BYTES_NTH; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) { - if_chain! { - let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) { - Some("String") - } else if ty.is_str() { - Some("str") - } else { - None - }; - if let Some(caller_type) = caller_type; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_NTH, - expr.span, - &format!("called `.byte().nth()` on a `{}`", caller_type), - "try", - format!( - "{}.as_bytes().get({})", - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - snippet_with_applicability(cx, n_arg.span, "..", &mut applicability) - ), - applicability, - ); - } - } + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + let caller_type = if ty.is_str() { + "str" + } else if is_type_diagnostic_item(cx, ty, sym::string_type) { + "String" + } else { + return; + }; + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_NTH, + expr.span, + &format!("called `.byte().nth()` on a `{}`", caller_type), + "try", + format!( + "{}.as_bytes().get({})", + snippet_with_applicability(cx, recv.span, "..", &mut applicability), + snippet_with_applicability(cx, n_arg.span, "..", &mut applicability) + ), + applicability, + ); } diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 15cf5674313..707c54f7a3c 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -40,8 +40,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp } fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + let call_site = expr.span.source_callsite(); if_chain! { - let call_site = expr.span.source_callsite(); if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); let snippet_split = snippet.split("::").collect::>(); if let Some((_, elements)) = snippet_split.split_last(); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9a95354db7a..70acf9f6e73 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1882,11 +1882,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if_chain! { if let TraitItemKind::Fn(ref sig, _) = item.kind; if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); - let first_arg_span = first_arg_ty.span; - let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); - then { + let first_arg_span = first_arg_ty.span; + let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); wrong_self_convention::check( cx, &item.ident.name.as_str(), diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index dac7e039e37..8e637e12393 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::usage::mutated_variables; use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; -use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; @@ -54,18 +53,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) { match &expr.kind { hir::ExprKind::Call(ref func, ref args) => { - if_chain! { - if let hir::ExprKind::Path(ref path) = func.kind; - then { - if match_qpath(path, &paths::OPTION_SOME) { - if path_to_local_id(&args[0], arg_id) { - return (false, false) - } - return (true, false); + if let hir::ExprKind::Path(ref path) = func.kind { + if match_qpath(path, &paths::OPTION_SOME) { + if path_to_local_id(&args[0], arg_id) { + return (false, false); } - // We don't know. It might do anything. - return (true, true); + return (true, false); } + // We don't know. It might do anything. + return (true, true); } (true, true) }, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 026ea50936a..c23643cb2f5 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -308,46 +308,45 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if let PatKind::Binding(an, .., name, None) = local.pat.kind; if let Some(ref init) = local.init; if !higher::is_from_for_desugar(local); + if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; then { - if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut { - // use the macro callsite when the init span (but not the whole local span) - // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` - let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, init, "..") - } else { - Sugg::hir(cx, init, "..") - }; - let (mutopt, initref) = if an == BindingAnnotation::RefMut { - ("mut ", sugg_init.mut_addr()) - } else { - ("", sugg_init.addr()) - }; - let tyopt = if let Some(ref ty) = local.ty { - format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "..")) - } else { - String::new() - }; - span_lint_hir_and_then( - cx, - TOPLEVEL_REF_ARG, - init.hir_id, - local.pat.span, - "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead", - |diag| { - diag.span_suggestion( - stmt.span, - "try", - format!( - "let {name}{tyopt} = {initref};", - name=snippet(cx, name.span, ".."), - tyopt=tyopt, - initref=initref, - ), - Applicability::MachineApplicable, - ); - } - ); - } + // use the macro callsite when the init span (but not the whole local span) + // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` + let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { + Sugg::hir_with_macro_callsite(cx, init, "..") + } else { + Sugg::hir(cx, init, "..") + }; + let (mutopt, initref) = if an == BindingAnnotation::RefMut { + ("mut ", sugg_init.mut_addr()) + } else { + ("", sugg_init.addr()) + }; + let tyopt = if let Some(ref ty) = local.ty { + format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "..")) + } else { + String::new() + }; + span_lint_hir_and_then( + cx, + TOPLEVEL_REF_ARG, + init.hir_id, + local.pat.span, + "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead", + |diag| { + diag.span_suggestion( + stmt.span, + "try", + format!( + "let {name}{tyopt} = {initref};", + name=snippet(cx, name.span, ".."), + tyopt=tyopt, + initref=initref, + ), + Applicability::MachineApplicable, + ); + } + ); } }; if_chain! { @@ -462,21 +461,18 @@ fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) { if_chain! { if !in_constant(cx, cmp_expr.hir_id); if let Some((value, _)) = constant(cx, cx.typeck_results(), expr); + if match value { + Constant::F32(num) => num.is_nan(), + Constant::F64(num) => num.is_nan(), + _ => false, + }; then { - let needs_lint = match value { - Constant::F32(num) => num.is_nan(), - Constant::F64(num) => num.is_nan(), - _ => false, - }; - - if needs_lint { - span_lint( - cx, - CMP_NAN, - cmp_expr.span, - "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead", - ); - } + span_lint( + cx, + CMP_NAN, + cmp_expr.span, + "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead", + ); } } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 3789572ad43..a5f91eb035f 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -97,60 +97,60 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // impl of `Default` return; } - if sig.decl.inputs.is_empty() && name == sym::new && cx.access_levels.is_reachable(id) { + if_chain! { + if sig.decl.inputs.is_empty(); + if name == sym::new; + if cx.access_levels.is_reachable(id); let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); let self_ty = cx.tcx.type_of(self_def_id); - if_chain! { - if TyS::same_type(self_ty, return_ty(cx, id)); - if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); - then { - if self.impling_types.is_none() { - let mut impls = HirIdSet::default(); - cx.tcx.for_each_impl(default_trait_id, |d| { - if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() { - if let Some(local_def_id) = ty_def.did.as_local() { - impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id)); - } - } - }); - self.impling_types = Some(impls); - } - - // Check if a Default implementation exists for the Self type, regardless of - // generics - if_chain! { - if let Some(ref impling_types) = self.impling_types; - if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def(); - if let Some(self_local_did) = self_def.did.as_local(); - then { - let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); - if impling_types.contains(&self_id) { - return; + if TyS::same_type(self_ty, return_ty(cx, id)); + if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); + then { + if self.impling_types.is_none() { + let mut impls = HirIdSet::default(); + cx.tcx.for_each_impl(default_trait_id, |d| { + if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() { + if let Some(local_def_id) = ty_def.did.as_local() { + impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id)); } } - } + }); + self.impling_types = Some(impls); + } - let generics_sugg = snippet(cx, generics.span, ""); - span_lint_hir_and_then( - cx, - NEW_WITHOUT_DEFAULT, - id, - impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{}`", - self_ty - ), - |diag| { - diag.suggest_prepend_item( - cx, - item.span, - "try this", - &create_new_without_default_suggest_msg(self_ty, &generics_sugg), - Applicability::MaybeIncorrect, - ); - }, - ); + // Check if a Default implementation exists for the Self type, regardless of + // generics + if_chain! { + if let Some(ref impling_types) = self.impling_types; + if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def(); + if let Some(self_local_did) = self_def.did.as_local(); + let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); + if impling_types.contains(&self_id); + then { + return; + } } + + let generics_sugg = snippet(cx, generics.span, ""); + span_lint_hir_and_then( + cx, + NEW_WITHOUT_DEFAULT, + id, + impl_item.span, + &format!( + "you should consider adding a `Default` implementation for `{}`", + self_ty + ), + |diag| { + diag.suggest_prepend_item( + cx, + item.span, + "try this", + &create_new_without_default_suggest_msg(self_ty, &generics_sugg), + Applicability::MaybeIncorrect, + ); + }, + ); } } } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index aa1d8fbe300..d775cd7c7f7 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -307,19 +307,17 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // we should use here as a frozen variant is a potential to be frozen // similar to unknown layouts. // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` + let ty = hir_ty_to_ty(cx.tcx, hir_ty); + let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + if is_unfrozen(cx, normalized); + if is_value_unfrozen_poly(cx, *body_id, normalized); then { - let ty = hir_ty_to_ty(cx.tcx, hir_ty); - let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if is_unfrozen(cx, normalized) - && is_value_unfrozen_poly(cx, *body_id, normalized) - { - lint( - cx, - Source::Assoc { - item: impl_item.span, - }, - ); - } + lint( + cx, + Source::Assoc { + item: impl_item.span, + }, + ); } } }, diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index d06e7f8fe1e..1e946858947 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -97,11 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn get_outer_span(expr: &Expr<'_>) -> Span { if_chain! { if expr.span.from_expansion(); - let first = expr.span.ctxt().outer_expn_data(); - if first.call_site.from_expansion(); - let second = first.call_site.ctxt().outer_expn_data(); + let first = expr.span.ctxt().outer_expn_data().call_site; + if first.from_expansion(); then { - second.call_site + first.ctxt().outer_expn_data().call_site } else { expr.span } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index be686b1b0cd..6e530d0ffb0 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -271,19 +271,18 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: GenericArg::Type(ty) => Some(ty), _ => None, }); + let replacement = snippet_opt(cx, inner.span); + if let Some(r) = replacement; then { - let replacement = snippet_opt(cx, inner.span); - if let Some(r) = replacement { - span_lint_and_sugg( - cx, - PTR_ARG, - arg.span, - "using a reference to `Cow` is not recommended", - "change this to", - "&".to_owned() + &r, - Applicability::Unspecified, - ); - } + span_lint_and_sugg( + cx, + PTR_ARG, + arg.span, + "using a reference to `Cow` is not recommended", + "change this to", + "&".to_owned() + &r, + Applicability::Unspecified, + ); } } } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 95b21489eb5..79692abb6ac 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -320,32 +320,29 @@ fn match_ident(e: &Expr<'_>) -> Option { } fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) { - let name = path.ident.as_str(); - if name == "zip" && args.len() == 2 { - let iter = &args[0].kind; - let zip_arg = &args[1]; - if_chain! { - // `.iter()` call - if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = *iter; - if iter_path.ident.name == sym::iter; - // range expression in `.zip()` call: `0..x.len()` - if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg); - if is_integer_const(cx, start, 0); - // `.len()` call - if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind; - if len_path.ident.name == sym!(len) && len_args.len() == 1; - // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].kind; - if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].kind; - if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments); - then { - span_lint(cx, - RANGE_ZIP_WITH_LEN, - span, - &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, iter_args[0].span, "_")) - ); - } + if_chain! { + if path.ident.as_str() == "zip"; + if let [iter, zip_arg] = args; + // `.iter()` call + if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = iter.kind; + if iter_path.ident.name == sym::iter; + // range expression in `.zip()` call: `0..x.len()` + if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg); + if is_integer_const(cx, start, 0); + // `.len()` call + if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind; + if len_path.ident.name == sym!(len) && len_args.len() == 1; + // `.iter()` and `.len()` called on same `Path` + if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].kind; + if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments); + then { + span_lint(cx, + RANGE_ZIP_WITH_LEN, + span, + &format!("it is more idiomatic to use `{}.iter().enumerate()`", + snippet(cx, iter_args[0].span, "_")) + ); } } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 2977a108d14..5429d389610 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -113,8 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if_chain! { if let hir::ExprKind::Call(ref closure, _) = expr.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind; - if self.path.segments[0].ident == path.segments[0].ident - && self.path.res == path.res; + if self.path.segments[0].ident == path.segments[0].ident; + if self.path.res == path.res; then { self.count += 1; } diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 99e3d818b79..512abde11a6 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -68,14 +68,13 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { // Check for more than one binary operation in the implemented function // Linting when multiple operations are involved can result in false positives + let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id); if_chain! { - let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id); if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get(parent_fn); if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind; - let body = cx.tcx.hir().body(body_id); - let mut visitor = BinaryExprVisitor { nb_binops: 0 }; - then { + let body = cx.tcx.hir().body(body_id); + let mut visitor = BinaryExprVisitor { nb_binops: 0 }; walk_expr(&mut visitor, &body.value); if visitor.nb_binops > 1 { return; diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 72489f27cd3..1a6124e9ddb 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -36,10 +36,10 @@ pub(super) fn check<'tcx>( if_chain! { // if the expression is a float literal and it is unsuffixed then // add a suffix so the suggestion is valid and unambiguous - let op = format!("{}{}", arg, float_ty.name_str()).into(); if let ExprKind::Lit(lit) = &expr.kind; if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node; then { + let op = format!("{}{}", arg, float_ty.name_str()).into(); match arg { sugg::Sugg::MaybeParen(_) => arg = sugg::Sugg::MaybeParen(op), _ => arg = sugg::Sugg::NonParen(op) diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index e61058c2749..e4799790d35 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -138,9 +138,8 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option< if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); if cx.tcx.is_diagnostic_item(sym::result_type, ready_def.did); - let err_ty = ready_subst.type_at(1); - then { - Some(err_ty) + Some(ready_subst.type_at(1)) } else { None } @@ -179,10 +176,8 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> if let ty::Adt(some_def, some_subst) = some_ty.kind(); if cx.tcx.is_diagnostic_item(sym::result_type, some_def.did); - let err_ty = some_subst.type_at(1); - then { - Some(err_ty) + Some(some_subst.type_at(1)) } else { None } diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index bad3e488bb6..cdc65abe47c 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -116,8 +116,8 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa let ty = cx.tcx.erase_late_bound_regions(ret_ty); if ty.is_unit(); then { + let body = cx.tcx.hir().body(body_id); if_chain! { - let body = cx.tcx.hir().body(body_id); if let ExprKind::Block(block, _) = body.value.kind; if block.expr.is_none(); if let Some(stmt) = block.stmts.last(); diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 925ab577099..f77d811c283 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -19,9 +19,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if is_questionmark_desugar_marked_call(expr) { return; } + let map = &cx.tcx.hir(); + let opt_parent_node = map.find(map.get_parent_node(expr.hir_id)); if_chain! { - let map = &cx.tcx.hir(); - let opt_parent_node = map.find(map.get_parent_node(expr.hir_id)); if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node; if is_questionmark_desugar_marked_call(parent_expr); then { diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index d5bc3de6698..9ceb2c3ffe2 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -116,8 +116,8 @@ impl LateLintPass<'_> for UnnamedAddress { if_chain! { if let ExprKind::Binary(binop, ref left, ref right) = expr.kind; if is_comparison(binop.node); - if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() && - cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr(); + if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr(); + if cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr(); if is_fn_def(cx, left) || is_fn_def(cx, right); then { span_lint( diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index aef4ce75915..15343cf90f2 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -49,21 +49,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { if assoc_item.fn_has_self_parameter; if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; let body = cx.tcx.hir().body(*body_id); - if !body.params.is_empty(); + if let [self_param, ..] = body.params; + let self_hir_id = self_param.pat.hir_id; + if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body); then { - let self_param = &body.params[0]; - let self_hir_id = self_param.pat.hir_id; - if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body) { - span_lint_and_help( - cx, - UNUSED_SELF, - self_param.span, - "unused `self` argument", - None, - "consider refactoring to a associated function", - ); - return; - } + span_lint_and_help( + cx, + UNUSED_SELF, + self_param.span, + "unused `self` argument", + None, + "consider refactoring to a associated function", + ); } } } diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 0d745813beb..d17aa6d8424 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -110,31 +110,27 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { } fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { - if_chain! { + if let ImplItemKind::Fn(_, body_id) = impl_item.kind { + let body = cx.tcx.hir().body(body_id); + let mut fpu = FindExpectUnwrap { + lcx: cx, + typeck_results: cx.tcx.typeck(impl_item.def_id), + result: Vec::new(), + }; + fpu.visit_expr(&body.value); - if let ImplItemKind::Fn(_, body_id) = impl_item.kind; - then { - let body = cx.tcx.hir().body(body_id); - let mut fpu = FindExpectUnwrap { - lcx: cx, - typeck_results: cx.tcx.typeck(impl_item.def_id), - result: Vec::new(), - }; - fpu.visit_expr(&body.value); - - // if we've found one, lint - if !fpu.result.is_empty() { - span_lint_and_then( - cx, - UNWRAP_IN_RESULT, - impl_span, - "used unwrap or expect in a function that returns result or option", - move |diag| { - diag.help( - "unwrap and expect should not be used in a function that returns result or option" ); - diag.span_note(fpu.result, "potential non-recoverable error(s)"); - }); - } + // if we've found one, lint + if !fpu.result.is_empty() { + span_lint_and_then( + cx, + UNWRAP_IN_RESULT, + impl_span, + "used unwrap or expect in a function that returns result or option", + move |diag| { + diag.help("unwrap and expect should not be used in a function that returns result or option"); + diag.span_note(fpu.result, "potential non-recoverable error(s)"); + }, + ); } } } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3e1b69e676b..d893b271a20 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -103,25 +103,23 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" { - if_chain! { - let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, a, sym::result_type); - if let ty::Adt(_, substs) = a.kind(); - if let Some(a_type) = substs.types().next(); - if TyS::same_type(a_type, b); - - then { - span_lint_and_help( - cx, - USELESS_CONVERSION, - e.span, - &format!("useless conversion to the same type: `{}`", b), - None, - "consider removing `.try_into()`", - ); - } + if_chain! { + if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into"; + let a = cx.typeck_results().expr_ty(e); + let b = cx.typeck_results().expr_ty(&args[0]); + if is_type_diagnostic_item(cx, a, sym::result_type); + if let ty::Adt(_, substs) = a.kind(); + if let Some(a_type) = substs.types().next(); + if TyS::same_type(a_type, b); + then { + span_lint_and_help( + cx, + USELESS_CONVERSION, + e.span, + &format!("useless conversion to the same type: `{}`", b), + None, + "consider removing `.try_into()`", + ); } } }, @@ -131,10 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if args.len() == 1; if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); - then { + let a = cx.typeck_results().expr_ty(e); + let b = cx.typeck_results().expr_ty(&args[0]); if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); if is_type_diagnostic_item(cx, a, sym::result_type); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 266b88beeec..d5a13c135b1 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -588,9 +588,9 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { if stmts.len() == 1 && block.expr.is_none(); if let StmtKind::Semi(only_expr) = &stmts[0].kind; if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind; - let and_then_snippets = get_and_then_snippets(cx, and_then_args); - let mut sle = SpanlessEq::new(cx).deny_side_effects(); then { + let and_then_snippets = get_and_then_snippets(cx, and_then_args); + let mut sle = SpanlessEq::new(cx).deny_side_effects(); match &*ps.ident.as_str() { "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args)); diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 8b696ed1c84..c7190e2f979 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -108,22 +108,21 @@ impl LateLintPass<'_> for VecInitThenPush { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if self.searcher.is_none() { - if_chain! { - if !in_external_macro(cx.sess(), expr.span); - if let ExprKind::Assign(left, right, _) = expr.kind; - if let Some(id) = path_to_local(left); - if let Some(init_kind) = get_vec_init_kind(cx, right); - then { - self.searcher = Some(VecPushSearcher { - local_id: id, - init: init_kind, - lhs_is_local: false, - lhs_span: left.span, - err_span: expr.span, - found: 0, - }); - } + if_chain! { + if self.searcher.is_none(); + if !in_external_macro(cx.sess(), expr.span); + if let ExprKind::Assign(left, right, _) = expr.kind; + if let Some(id) = path_to_local(left); + if let Some(init_kind) = get_vec_init_kind(cx, right); + then { + self.searcher = Some(VecPushSearcher { + local_id: id, + init: init_kind, + lhs_is_local: false, + lhs_span: left.span, + err_span: expr.span, + found: 0, + }); } } } -- cgit 1.4.1-3-g733a5 From 08a8ad3a366ff28e4d89997de69ddb3a6ceb1a18 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 1 Apr 2021 12:15:47 -0500 Subject: Remove paths from bind_instead_of_map --- clippy_lints/src/methods/bind_instead_of_map.rs | 159 ++++++++++++------------ 1 file changed, 78 insertions(+), 81 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 8ccb8f4268c..46d4c674648 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,80 +1,66 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; -use clippy_utils::ty::match_type; -use clippy_utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions}; +use clippy_utils::{in_macro, remove_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::{LangItem, QPath}; use rustc_lint::LateContext; +use rustc_middle::ty::DefIdTree; use rustc_span::Span; pub(crate) struct OptionAndThenSome; impl BindInsteadOfMap for OptionAndThenSome { - const TYPE_NAME: &'static str = "Option"; - const TYPE_QPATH: &'static [&'static str] = &paths::OPTION; - + const VARIANT_LANG_ITEM: LangItem = LangItem::OptionSome; const BAD_METHOD_NAME: &'static str = "and_then"; - const BAD_VARIANT_NAME: &'static str = "Some"; - const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::OPTION_SOME; - const GOOD_METHOD_NAME: &'static str = "map"; } pub(crate) struct ResultAndThenOk; impl BindInsteadOfMap for ResultAndThenOk { - const TYPE_NAME: &'static str = "Result"; - const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; - + const VARIANT_LANG_ITEM: LangItem = LangItem::ResultOk; const BAD_METHOD_NAME: &'static str = "and_then"; - const BAD_VARIANT_NAME: &'static str = "Ok"; - const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_OK; - const GOOD_METHOD_NAME: &'static str = "map"; } pub(crate) struct ResultOrElseErrInfo; impl BindInsteadOfMap for ResultOrElseErrInfo { - const TYPE_NAME: &'static str = "Result"; - const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; - + const VARIANT_LANG_ITEM: LangItem = LangItem::ResultErr; const BAD_METHOD_NAME: &'static str = "or_else"; - const BAD_VARIANT_NAME: &'static str = "Err"; - const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_ERR; - const GOOD_METHOD_NAME: &'static str = "map_err"; } pub(crate) trait BindInsteadOfMap { - const TYPE_NAME: &'static str; - const TYPE_QPATH: &'static [&'static str]; - + const VARIANT_LANG_ITEM: LangItem; const BAD_METHOD_NAME: &'static str; - const BAD_VARIANT_NAME: &'static str; - const BAD_VARIANT_QPATH: &'static [&'static str]; - const GOOD_METHOD_NAME: &'static str; - fn no_op_msg() -> String { - format!( + fn no_op_msg(cx: &LateContext<'_>) -> Option { + let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?; + let item_id = cx.tcx.parent(variant_id)?; + Some(format!( "using `{}.{}({})`, which is a no-op", - Self::TYPE_NAME, + cx.tcx.item_name(item_id), Self::BAD_METHOD_NAME, - Self::BAD_VARIANT_NAME - ) + cx.tcx.item_name(variant_id), + )) } - fn lint_msg() -> String { - format!( + fn lint_msg(cx: &LateContext<'_>) -> Option { + let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?; + let item_id = cx.tcx.parent(variant_id)?; + Some(format!( "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`", - Self::TYPE_NAME, + cx.tcx.item_name(item_id), Self::BAD_METHOD_NAME, - Self::BAD_VARIANT_NAME, + cx.tcx.item_name(variant_id), Self::GOOD_METHOD_NAME - ) + )) } fn lint_closure_autofixable( @@ -85,17 +71,12 @@ pub(crate) trait BindInsteadOfMap { closure_args_span: Span, ) -> bool { if_chain! { - if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.kind; - if let hir::ExprKind::Path(ref qpath) = some_expr.kind; - if match_qpath(qpath, Self::BAD_VARIANT_QPATH); - if some_args.len() == 1; + if let hir::ExprKind::Call(ref some_expr, [inner_expr]) = closure_expr.kind; + if let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind; + if Self::is_variant(cx, path.res); + if !contains_return(inner_expr); + if let Some(msg) = Self::lint_msg(cx); then { - let inner_expr = &some_args[0]; - - if contains_return(inner_expr) { - return false; - } - let some_inner_snip = if inner_expr.span.from_expansion() { snippet_with_macro_callsite(cx, inner_expr.span, "_") } else { @@ -109,7 +90,7 @@ pub(crate) trait BindInsteadOfMap { cx, BIND_INSTEAD_OF_MAP, expr.span, - Self::lint_msg().as_ref(), + &msg, "try this", note, Applicability::MachineApplicable, @@ -126,41 +107,46 @@ pub(crate) trait BindInsteadOfMap { let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| { if_chain! { if !in_macro(ret_expr.span); - if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind; - if let hir::ExprKind::Path(ref qpath) = func_path.kind; - if match_qpath(qpath, Self::BAD_VARIANT_QPATH); - if args.len() == 1; - if !contains_return(&args[0]); + if let hir::ExprKind::Call(ref func_path, [arg]) = ret_expr.kind; + if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind; + if Self::is_variant(cx, path.res); + if !contains_return(arg); then { - suggs.push((ret_expr.span, args[0].span.source_callsite())); + suggs.push((ret_expr.span, arg.span.source_callsite())); true } else { false } } }); - - if can_sugg { - span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, Self::lint_msg().as_ref(), |diag| { - multispan_sugg_with_applicability( - diag, - "try this", - Applicability::MachineApplicable, - std::iter::once((*method_calls(expr, 1).2.get(0).unwrap(), Self::GOOD_METHOD_NAME.into())).chain( - suggs - .into_iter() - .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), - ), - ) - }); - } - can_sugg + let (span, msg) = if_chain! { + if can_sugg; + if let hir::ExprKind::MethodCall(_, span, ..) = expr.kind; + if let Some(msg) = Self::lint_msg(cx); + then { (span, msg) } else { return false; } + }; + span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| { + multispan_sugg_with_applicability( + diag, + "try this", + Applicability::MachineApplicable, + std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain( + suggs + .into_iter() + .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), + ), + ) + }); + true } /// Lint use of `_.and_then(|x| Some(y))` for `Option`s fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool { - if !match_type(cx, cx.typeck_results().expr_ty(recv), Self::TYPE_QPATH) { - return false; + if_chain! { + if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def(); + if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM); + if Some(adt.did) == cx.tcx.parent(vid); + then {} else { return false; } } match arg.kind { @@ -175,19 +161,30 @@ pub(crate) trait BindInsteadOfMap { } }, // `_.and_then(Some)` case, which is no-op. - hir::ExprKind::Path(ref qpath) if match_qpath(qpath, Self::BAD_VARIANT_QPATH) => { - span_lint_and_sugg( - cx, - BIND_INSTEAD_OF_MAP, - expr.span, - Self::no_op_msg().as_ref(), - "use the expression directly", - snippet(cx, recv.span, "..").into(), - Applicability::MachineApplicable, - ); + hir::ExprKind::Path(QPath::Resolved(_, path)) if Self::is_variant(cx, path.res) => { + if let Some(msg) = Self::no_op_msg(cx) { + span_lint_and_sugg( + cx, + BIND_INSTEAD_OF_MAP, + expr.span, + &msg, + "use the expression directly", + snippet(cx, recv.span, "..").into(), + Applicability::MachineApplicable, + ); + } true }, _ => false, } } + + fn is_variant(cx: &LateContext<'_>, res: Res) -> bool { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { + if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) { + return cx.tcx.parent(id) == Some(variant_id); + } + } + false + } } -- cgit 1.4.1-3-g733a5 From d1df73228a7cdadb4d635c6ed77daeeaebbe10ff Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 11 Dec 2020 22:29:53 +0000 Subject: A new lint for shared code in if blocks * Added expression check for shared_code_in_if_blocks * Finishing touches for the shared_code_in_if_blocks lint * Applying PR suggestions * Update lints yay * Moved test into subfolder --- CHANGELOG.md | 1 + clippy_lints/src/copies.rs | 305 +++++++++++++++++++-- clippy_lints/src/lib.rs | 2 + clippy_lints/src/literal_representation.rs | 40 ++- .../src/methods/manual_saturating_arithmetic.rs | 48 ++-- clippy_utils/src/hir_utils.rs | 9 + tests/ui/checked_unwrap/complex_conditionals.rs | 2 +- tests/ui/if_same_then_else.rs | 3 +- tests/ui/if_same_then_else.stderr | 88 +++--- tests/ui/if_same_then_else2.rs | 3 +- tests/ui/if_same_then_else2.stderr | 80 +++--- tests/ui/let_if_seq.rs | 3 +- tests/ui/let_if_seq.stderr | 8 +- tests/ui/shared_code_in_if_blocks/shared_at_bot.rs | 47 ++++ tests/ui/shared_code_in_if_blocks/shared_at_top.rs | 83 ++++++ .../shared_at_top_and_bot.rs | 22 ++ .../ui/shared_code_in_if_blocks/valid_if_blocks.rs | 157 +++++++++++ 17 files changed, 737 insertions(+), 164 deletions(-) create mode 100644 tests/ui/shared_code_in_if_blocks/shared_at_bot.rs create mode 100644 tests/ui/shared_code_in_if_blocks/shared_at_top.rs create mode 100644 tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs create mode 100644 tests/ui/shared_code_in_if_blocks/valid_if_blocks.rs (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index fb4a0b500f2..790bca4ac18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2455,6 +2455,7 @@ Released 2018-09-13 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same [`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated +[`shared_code_in_if_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#shared_code_in_if_blocks [`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 46093a16571..29ff1970705 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -3,7 +3,10 @@ use clippy_utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHas use clippy_utils::{get_parent_expr, if_sequence}; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Span; +use std::borrow::Cow; declare_clippy_lint! { /// **What it does:** Checks for consecutive `if`s with the same condition. @@ -104,7 +107,45 @@ declare_clippy_lint! { "`if` with the same `then` and `else` blocks" } -declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE]); +declare_clippy_lint! { + /// **What it does:** Checks if the `if` and `else` block contain shared code that can be + /// moved out of the blocks. + /// + /// **Why is this bad?** Duplicate code is less maintainable. + /// + /// **Known problems:** Hopefully none. + /// + /// **Example:** + /// ```ignore + /// let foo = if … { + /// println!("Hello World"); + /// 13 + /// } else { + /// println!("Hello World"); + /// 42 + /// }; + /// ``` + /// + /// Could be written as: + /// ```ignore + /// println!("Hello World"); + /// let foo = if … { + /// 13 + /// } else { + /// 42 + /// }; + /// ``` + pub SHARED_CODE_IN_IF_BLOCKS, + pedantic, + "`if` statement with shared code in all blocks" +} + +declare_lint_pass!(CopyAndPaste => [ + IFS_SAME_COND, + SAME_FUNCTIONS_IN_IF_CONDITION, + IF_SAME_THEN_ELSE, + SHARED_CODE_IN_IF_BLOCKS +]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -121,30 +162,256 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { } let (conds, blocks) = if_sequence(expr); - lint_same_then_else(cx, &blocks); + // Conditions lint_same_cond(cx, &conds); lint_same_fns_in_if_cond(cx, &conds); + // Block duplication + lint_same_then_else(cx, &blocks, conds.len() != blocks.len(), expr); } } } -/// Implementation of `IF_SAME_THEN_ELSE`. -fn lint_same_then_else(cx: &LateContext<'_>, blocks: &[&Block<'_>]) { - let eq: &dyn Fn(&&Block<'_>, &&Block<'_>) -> bool = - &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; +/// Implementation of `SHARED_CODE_IN_IF_BLOCKS` and `IF_SAME_THEN_ELSE` if the blocks are equal. +fn lint_same_then_else<'tcx>( + cx: &LateContext<'tcx>, + blocks: &[&Block<'tcx>], + has_unconditional_else: bool, + expr: &'tcx Expr<'_>, +) { + // We only lint ifs with multiple blocks + // TODO xFrednet 2021-01-01: Check if it's an else if block + if blocks.len() < 2 { + return; + } - if let Some((i, j)) = search_same_sequenced(blocks, eq) { - span_lint_and_note( + let has_expr = blocks[0].expr.is_some(); + + // Check if each block has shared code + let mut start_eq = usize::MAX; + let mut end_eq = usize::MAX; + let mut expr_eq = true; + for (index, win) in blocks.windows(2).enumerate() { + let l_stmts = win[0].stmts; + let r_stmts = win[1].stmts; + + let mut evaluator = SpanlessEq::new(cx); + let current_start_eq = count_eq(&mut l_stmts.iter(), &mut r_stmts.iter(), |l, r| evaluator.eq_stmt(l, r)); + let current_end_eq = count_eq(&mut l_stmts.iter().rev(), &mut r_stmts.iter().rev(), |l, r| { + evaluator.eq_stmt(l, r) + }); + let block_expr_eq = both(&win[0].expr, &win[1].expr, |l, r| evaluator.eq_expr(l, r)); + + // IF_SAME_THEN_ELSE + // We only lint the first two blocks (index == 0). Further blocks will be linted when that if + // statement is checked + if index == 0 && block_expr_eq && l_stmts.len() == r_stmts.len() && l_stmts.len() == current_start_eq { + span_lint_and_note( + cx, + IF_SAME_THEN_ELSE, + win[0].span, + "this `if` has identical blocks", + Some(win[1].span), + "same as this", + ); + + return; + } + + start_eq = start_eq.min(current_start_eq); + end_eq = end_eq.min(current_end_eq); + expr_eq &= block_expr_eq; + + // We can return if the eq count is 0 from both sides or if it has no unconditional else case + if !has_unconditional_else || (start_eq == 0 && end_eq == 0 && (has_expr && !expr_eq)) { + return; + } + } + + if has_expr && !expr_eq { + end_eq = 0; + } + + // Check if the regions are overlapping. Set `end_eq` to prevent the overlap + let min_block_size = blocks.iter().map(|x| x.stmts.len()).min().unwrap(); + if (start_eq + end_eq) > min_block_size { + end_eq = min_block_size - start_eq; + } + + // Only the start is the same + if start_eq != 0 && end_eq == 0 && (!has_expr || !expr_eq) { + emit_shared_code_in_if_blocks_lint(cx, start_eq, 0, false, blocks, expr); + } else if end_eq != 0 && (!has_expr || !expr_eq) { + let block = blocks[blocks.len() - 1]; + let stmts = block.stmts.split_at(start_eq).1; + let (block_stmts, moved_stmts) = stmts.split_at(stmts.len() - end_eq); + + // Scan block + let mut walker = SymbolFinderVisitor::new(cx); + for stmt in block_stmts { + intravisit::walk_stmt(&mut walker, stmt); + } + let mut block_defs = walker.defs; + + // Scan moved stmts + let mut moved_start: Option = None; + let mut walker = SymbolFinderVisitor::new(cx); + for (index, stmt) in moved_stmts.iter().enumerate() { + intravisit::walk_stmt(&mut walker, stmt); + + for value in &walker.uses { + // Well we can't move this and all prev statements. So reset + if block_defs.contains(&value) { + moved_start = Some(index + 1); + walker.defs.drain().for_each(|x| { + block_defs.insert(x); + }); + } + } + + walker.uses.clear(); + } + + if let Some(moved_start) = moved_start { + end_eq -= moved_start; + } + + let mut end_linable = true; + if let Some(expr) = block.expr { + intravisit::walk_expr(&mut walker, expr); + end_linable = walker.uses.iter().any(|x| !block_defs.contains(x)); + } + + emit_shared_code_in_if_blocks_lint(cx, start_eq, end_eq, end_linable, blocks, expr); + } +} + +fn emit_shared_code_in_if_blocks_lint( + cx: &LateContext<'tcx>, + start_stmts: usize, + end_stmts: usize, + lint_end: bool, + blocks: &[&Block<'tcx>], + if_expr: &'tcx Expr<'_>, +) { + if start_stmts == 0 && !lint_end { + return; + } + + // (help, span, suggestion) + let mut suggestions: Vec<(&str, Span, String)> = vec![]; + + if start_stmts > 0 { + let block = blocks[0]; + let span_start = first_line_of_span(cx, if_expr.span).shrink_to_lo(); + let span_end = block.stmts[start_stmts - 1].span.source_callsite(); + + let cond_span = first_line_of_span(cx, if_expr.span).until(block.span); + let cond_snippet = reindent_multiline(snippet(cx, cond_span, "_"), false, None); + let cond_indent = indent_of(cx, cond_span); + let moved_span = block.stmts[0].span.source_callsite().to(span_end); + let moved_snippet = reindent_multiline(snippet(cx, moved_span, "_"), true, None); + let suggestion = moved_snippet.to_string() + "\n" + &cond_snippet + "{"; + let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, cond_indent); + + let span = span_start.to(span_end); + suggestions.push(("START HELP", span, suggestion.to_string())); + } + + if lint_end { + let block = blocks[blocks.len() - 1]; + let span_end = block.span.shrink_to_hi(); + + let moved_start = if end_stmts == 0 && block.expr.is_some() { + block.expr.unwrap().span + } else { + block.stmts[block.stmts.len() - end_stmts].span + } + .source_callsite(); + let moved_end = if let Some(expr) = block.expr { + expr.span + } else { + block.stmts[block.stmts.len() - 1].span + } + .source_callsite(); + + let moved_span = moved_start.to(moved_end); + let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None); + let indent = indent_of(cx, if_expr.span.shrink_to_hi()); + let suggestion = "}\n".to_string() + &moved_snipped; + let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, indent); + + let span = moved_start.to(span_end); + suggestions.push(("END_RANGE", span, suggestion.to_string())); + } + + if suggestions.len() == 1 { + let (_, span, sugg) = &suggestions[0]; + span_lint_and_sugg( cx, - IF_SAME_THEN_ELSE, - j.span, - "this `if` has identical blocks", - Some(i.span), - "same as this", + SHARED_CODE_IN_IF_BLOCKS, + *span, + "All code blocks contain the same code", + "Consider moving the code out like this", + sugg.clone(), + Applicability::Unspecified, + ); + } else { + span_lint_and_then( + cx, + SHARED_CODE_IN_IF_BLOCKS, + if_expr.span, + "All if blocks contain the same code", + move |diag| { + for (help, span, sugg) in suggestions { + diag.span_suggestion(span, help, sugg, Applicability::Unspecified); + } + }, ); } } +pub struct SymbolFinderVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + defs: FxHashSet, + uses: FxHashSet, +} + +impl<'a, 'tcx> SymbolFinderVisitor<'a, 'tcx> { + fn new(cx: &'a LateContext<'tcx>) -> Self { + SymbolFinderVisitor { + cx, + defs: FxHashSet::default(), + uses: FxHashSet::default(), + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for SymbolFinderVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::All(self.cx.tcx.hir()) + } + + fn visit_local(&mut self, l: &'tcx rustc_hir::Local<'tcx>) { + let local_id = l.pat.hir_id; + self.defs.insert(local_id); + if let Some(expr) = l.init { + intravisit::walk_expr(self, expr); + } + } + + fn visit_qpath(&mut self, qpath: &'tcx rustc_hir::QPath<'tcx>, id: HirId, _span: rustc_span::Span) { + if let rustc_hir::QPath::Resolved(_, ref path) = *qpath { + if path.segments.len() == 1 { + if let rustc_hir::def::Res::Local(var) = self.cx.qpath_res(qpath, id) { + self.uses.insert(var); + } + } + } + } +} + /// Implementation of `IFS_SAME_COND`. fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 { @@ -198,15 +465,3 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { ); } } - -fn search_same_sequenced(exprs: &[T], eq: Eq) -> Option<(&T, &T)> -where - Eq: Fn(&T, &T) -> bool, -{ - for win in exprs.windows(2) { - if eq(&win[0], &win[1]) { - return Some((&win[0], &win[1])); - } - } - None -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b93e6b5b2e8..ba98a2a2607 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -616,6 +616,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &copies::IFS_SAME_COND, &copies::IF_SAME_THEN_ELSE, &copies::SAME_FUNCTIONS_IN_IF_CONDITION, + &copies::SHARED_CODE_IN_IF_BLOCKS, ©_iterator::COPY_ITERATOR, &create_dir::CREATE_DIR, &dbg_macro::DBG_MACRO, @@ -1365,6 +1366,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&casts::PTR_AS_PTR), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), + LintId::of(&copies::SHARED_CODE_IN_IF_BLOCKS), LintId::of(©_iterator::COPY_ITERATOR), LintId::of(&default::DEFAULT_TRAIT_ACCESS), LintId::of(&dereference::EXPLICIT_DEREF_METHODS), diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7fd55151226..b736eeff6bf 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -464,32 +464,28 @@ impl DecimalLiteralRepresentation { { return Err(WarningType::DecimalRepresentation); } - } else if digits.len() < 4 { - // Lint for Literals with a hex-representation of 2 or 3 digits - let f = &digits[0..1]; // first digit - let s = &digits[1..]; // suffix - - // Powers of 2 - if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && s.chars().all(|c| c == '0')) - // Powers of 2 minus 1 - || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && s.chars().all(|c| c == 'F')) - { - return Err(WarningType::DecimalRepresentation); - } } else { - // Lint for Literals with a hex-representation of 4 digits or more let f = &digits[0..1]; // first digit let m = &digits[1..digits.len() - 1]; // middle digits, except last let s = &digits[1..]; // suffix - - // Powers of 2 with a margin of +15/-16 - if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0')) - || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F')) - // Lint for representations with only 0s and Fs, while allowing 7 as the first - // digit - || ((f.eq("7") || f.eq("F")) && s.chars().all(|c| c == '0' || c == 'F')) - { - return Err(WarningType::DecimalRepresentation); + if digits.len() < 4 { + // Powers of 2 + if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && s.chars().all(|c| c == '0')) + // Powers of 2 minus 1 + || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && s.chars().all(|c| c == 'F')) + { + return Err(WarningType::DecimalRepresentation); + } + } else { + // Powers of 2 with a margin of +15/-16 + if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0')) + || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F')) + // Lint for representations with only 0s and Fs, while allowing 7 as the first + // digit + || ((f.eq("7") || f.eq("F")) && s.chars().all(|c| c == '0' || c == 'F')) + { + return Err(WarningType::DecimalRepresentation); + } } } diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 6c5a842a912..ecb8b72ef46 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -44,44 +44,28 @@ pub fn check( // "mul" is omitted because lhs can be negative. _ => return, } - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - super::MANUAL_SATURATING_ARITHMETIC, - expr.span, - "manual saturating arithmetic", - &format!("try using `saturating_{}`", arith), - format!( - "{}.saturating_{}({})", - snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), - arith, - snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), - ), - applicability, - ); } else { match (mm, arith) { (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (), _ => return, } - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - super::MANUAL_SATURATING_ARITHMETIC, - expr.span, - "manual saturating arithmetic", - &format!("try using `saturating_{}`", arith), - format!( - "{}.saturating_{}({})", - snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), - arith, - snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), - ), - applicability, - ); } + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + super::MANUAL_SATURATING_ARITHMETIC, + expr.span, + "manual saturating arithmetic", + &format!("try using `saturating_{}`", arith), + format!( + "{}.saturating_{}({})", + snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), + arith, + snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), + ), + applicability, + ); } #[derive(PartialEq, Eq)] diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 0c3b8b89171..8b90fedbafe 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -483,6 +483,15 @@ pub fn over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } +/// Counts how many elements of the slices are equal as per `eq_fn`. +pub fn count_eq( + left: &mut dyn Iterator, + right: &mut dyn Iterator, + mut eq_fn: impl FnMut(&X, &X) -> bool, +) -> usize { + left.zip(right).take_while(|(l, r)| eq_fn(l, r)).count() +} + /// Checks if two expressions evaluate to the same value, and don't contain any side effects. pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool { SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right) diff --git a/tests/ui/checked_unwrap/complex_conditionals.rs b/tests/ui/checked_unwrap/complex_conditionals.rs index c986c992a07..bb5b6f5ec04 100644 --- a/tests/ui/checked_unwrap/complex_conditionals.rs +++ b/tests/ui/checked_unwrap/complex_conditionals.rs @@ -1,5 +1,5 @@ #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)] fn test_complex_conditions() { let x: Result<(), ()> = Ok(()); diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 9c5fe02f751..35a2e139c11 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -5,7 +5,8 @@ clippy::never_loop, clippy::no_effect, clippy::unused_unit, - clippy::zero_divided_by_zero + clippy::zero_divided_by_zero, + clippy::shared_code_in_if_blocks )] struct Foo { diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr index d9fdf06fa8b..2f38052fc20 100644 --- a/tests/ui/if_same_then_else.stderr +++ b/tests/ui/if_same_then_else.stderr @@ -1,111 +1,111 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:28:12 + --> $DIR/if_same_then_else.rs:21:13 | -LL | } else { - | ____________^ -LL | | //~ ERROR same body as `if` block +LL | if true { + | _____________^ LL | | Foo { bar: 42 }; LL | | 0..10; +LL | | ..; ... | LL | | foo(); -LL | | } +LL | | } else { | |_____^ | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/if_same_then_else.rs:20:13 + --> $DIR/if_same_then_else.rs:29:12 | -LL | if true { - | _____________^ +LL | } else { + | ____________^ +LL | | //~ ERROR same body as `if` block LL | | Foo { bar: 42 }; LL | | 0..10; -LL | | ..; ... | LL | | foo(); -LL | | } else { +LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:66:12 - | -LL | } else { - | ____________^ -LL | | //~ ERROR same body as `if` block -LL | | 0.0 -LL | | }; - | |_____^ - | -note: same as this - --> $DIR/if_same_then_else.rs:64:21 + --> $DIR/if_same_then_else.rs:65:21 | LL | let _ = if true { | _____________________^ LL | | 0.0 LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:73:12 + | +note: same as this + --> $DIR/if_same_then_else.rs:67:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block -LL | | -0.0 +LL | | 0.0 LL | | }; | |_____^ - | -note: same as this - --> $DIR/if_same_then_else.rs:71:21 + +error: this `if` has identical blocks + --> $DIR/if_same_then_else.rs:72:21 | LL | let _ = if true { | _____________________^ LL | | -0.0 LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:89:12 + | +note: same as this + --> $DIR/if_same_then_else.rs:74:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block -LL | | 42 +LL | | -0.0 LL | | }; | |_____^ - | -note: same as this - --> $DIR/if_same_then_else.rs:87:21 + +error: this `if` has identical blocks + --> $DIR/if_same_then_else.rs:88:21 | LL | let _ = if true { | _____________________^ LL | | 42 LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:101:12 + | +note: same as this + --> $DIR/if_same_then_else.rs:90:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block +LL | | 42 +LL | | }; + | |_____^ + +error: this `if` has identical blocks + --> $DIR/if_same_then_else.rs:95:13 + | +LL | if true { + | _____________^ LL | | let bar = if true { 42 } else { 43 }; LL | | +LL | | while foo() { ... | LL | | bar + 1; -LL | | } +LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:94:13 + --> $DIR/if_same_then_else.rs:102:12 | -LL | if true { - | _____________^ +LL | } else { + | ____________^ +LL | | //~ ERROR same body as `if` block LL | | let bar = if true { 42 } else { 43 }; LL | | -LL | | while foo() { ... | LL | | bar + 1; -LL | | } else { +LL | | } | |_____^ error: aborting due to 5 previous errors diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index a2ff1b741ca..8164b125570 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -5,7 +5,8 @@ clippy::collapsible_if, clippy::ifs_same_cond, clippy::needless_return, - clippy::single_element_loop + clippy::single_element_loop, + clippy::shared_code_in_if_blocks )] fn if_same_then_else2() -> Result<&'static str, ()> { diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index 454322d8aac..941b92f23f3 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -24,18 +24,22 @@ LL | | if foo.is_some() { LL | | } LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:35:12 + | + = note: `-D clippy::if-same-then-else` implied by `-D warnings` +note: same as this + --> $DIR/if_same_then_else2.rs:21:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block -LL | | if let Some(a) = Some(42) {} +LL | | for _ in &[42] { +LL | | let foo: &Option<_> = &Some::(42); +... | +LL | | } LL | | } | |_____^ - | -note: same as this + +error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:33:13 | LL | if true { @@ -43,18 +47,18 @@ LL | if true { LL | | if let Some(a) = Some(42) {} LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:42:12 + | +note: same as this + --> $DIR/if_same_then_else2.rs:35:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block -LL | | if let (1, .., 3) = (1, 2, 3) {} +LL | | if let Some(a) = Some(42) {} LL | | } | |_____^ - | -note: same as this + +error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:40:13 | LL | if true { @@ -62,18 +66,18 @@ LL | if true { LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:92:12 + | +note: same as this + --> $DIR/if_same_then_else2.rs:42:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block -LL | | f32::NAN -LL | | }; +LL | | if let (1, .., 3) = (1, 2, 3) {} +LL | | } | |_____^ - | -note: same as this + +error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:90:21 | LL | let _ = if true { @@ -81,18 +85,18 @@ LL | let _ = if true { LL | | f32::NAN LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:99:12 + | +note: same as this + --> $DIR/if_same_then_else2.rs:92:12 | LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block -LL | | Ok("foo")?; -LL | | } +LL | | f32::NAN +LL | | }; | |_____^ - | -note: same as this + +error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:97:13 | LL | if true { @@ -100,18 +104,18 @@ LL | if true { LL | | Ok("foo")?; LL | | } else { | |_____^ - -error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:124:12 + | +note: same as this + --> $DIR/if_same_then_else2.rs:99:12 | LL | } else { | ____________^ -LL | | let foo = ""; -LL | | return Ok(&foo[0..]); +LL | | //~ ERROR same body as `if` block +LL | | Ok("foo")?; LL | | } | |_____^ - | -note: same as this + +error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:121:20 | LL | } else if true { @@ -120,6 +124,16 @@ LL | | let foo = ""; LL | | return Ok(&foo[0..]); LL | | } else { | |_____^ + | +note: same as this + --> $DIR/if_same_then_else2.rs:124:12 + | +LL | } else { + | ____________^ +LL | | let foo = ""; +LL | | return Ok(&foo[0..]); +LL | | } + | |_____^ error: aborting due to 6 previous errors diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 32a67f181df..9fd3f875a5f 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -2,7 +2,8 @@ unused_variables, unused_assignments, clippy::similar_names, - clippy::blacklisted_name + clippy::blacklisted_name, + clippy::shared_code_in_if_blocks )] #![warn(clippy::useless_let_if_seq)] diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index 7de560c7348..9cf2e10a5ee 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -1,5 +1,5 @@ error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:64:5 + --> $DIR/let_if_seq.rs:65:5 | LL | / let mut foo = 0; LL | | if f() { @@ -11,7 +11,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:69:5 + --> $DIR/let_if_seq.rs:70:5 | LL | / let mut bar = 0; LL | | if f() { @@ -25,7 +25,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:77:5 + --> $DIR/let_if_seq.rs:78:5 | LL | / let quz; LL | | if f() { @@ -36,7 +36,7 @@ LL | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:106:5 + --> $DIR/let_if_seq.rs:107:5 | LL | / let mut baz = 0; LL | | if f() { diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs b/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs new file mode 100644 index 00000000000..22f1fe95f79 --- /dev/null +++ b/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs @@ -0,0 +1,47 @@ +#![allow(dead_code)] +#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)] + +// This tests the shared_code_in_if_blocks lint at the end of blocks + +fn simple_examples() { + // TODO xFrednet 2021-01-06: Test with const literals at the end + let x = 1; + + let _ = if x == 7 { + println!("Branch I"); + let start_value = 0; + println!("=^.^="); + + // Same but not moveable due to `start_value` + let _ = start_value; + + // The rest is self contained and moveable => Only lint the rest + let result = false; + println!("Block end!"); + result + } else { + println!("Branch II"); + let start_value = 8; + println!("xD"); + + // Same but not moveable due to `start_value` + let _ = start_value; + + // The rest is self contained and moveable => Only lint the rest + let result = false; + println!("Block end!"); + result + }; +} + +/// Simple examples where the move can cause some problems due to moved values +fn simple_but_suggestion_is_invalid() { + // TODO xFrednet 2021-01-12: This +} + +/// Tests where the blocks are not linted due to the used value scope +fn not_moveable_due_to_value_scope() { + // TODO xFrednet 2021-01-12: This +} + +fn main() {} diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_top.rs b/tests/ui/shared_code_in_if_blocks/shared_at_top.rs new file mode 100644 index 00000000000..0a6828127e9 --- /dev/null +++ b/tests/ui/shared_code_in_if_blocks/shared_at_top.rs @@ -0,0 +1,83 @@ +#![allow(dead_code, clippy::eval_order_dependence)] +#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)] + +// This tests the shared_code_in_if_blocks lint at the start of blocks + +fn simple_examples() { + let x = 0; + + // Simple + if true { + println!("Hello World!"); + println!("I'm branch nr: 1"); + } else { + println!("Hello World!"); + println!("I'm branch nr: 2"); + } + + // Else if + if x == 0 { + let y = 9; + println!("The value y was set to: `{}`", y); + let _z = y; + + println!("I'm the true start index of arrays"); + } else if x == 1 { + let y = 9; + println!("The value y was set to: `{}`", y); + let _z = y; + + println!("I start counting from 1 so my array starts from `1`"); + } else { + let y = 9; + println!("The value y was set to: `{}`", y); + let _z = y; + + println!("Ha, Pascal allows you to start the array where you want") + } + + // Return a value + let _ = if x == 7 { + let y = 16; + println!("What can I say except: \"you're welcome?\""); + let _ = y; + x + } else { + let y = 16; + println!("Thank you"); + y + }; +} + +/// Simple examples where the move can cause some problems due to moved values +fn simple_but_suggestion_is_invalid() { + let x = 10; + + // Can't be automatically moved because used_value_name is getting used again + let used_value_name = 19; + if x == 10 { + let used_value_name = "Different type"; + println!("Str: {}", used_value_name); + let _ = 1; + } else { + let used_value_name = "Different type"; + println!("Str: {}", used_value_name); + let _ = 2; + } + let _ = used_value_name; + + // This can be automatically moved as `can_be_overridden` is not used again + let can_be_overridden = 8; + let _ = can_be_overridden; + if x == 11 { + let can_be_overridden = "Move me"; + println!("I'm also moveable"); + let _ = 111; + } else { + let can_be_overridden = "Move me"; + println!("I'm also moveable"); + let _ = 222; + } +} + +fn main() {} diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs b/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs new file mode 100644 index 00000000000..8de69623e5d --- /dev/null +++ b/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs @@ -0,0 +1,22 @@ +#![allow(dead_code)] +#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)] + +// shared_code_in_if_blocks at the top and bottom of the if blocks + +fn main() { + // TODO xFrednet 2021-01-12: This +} + +// General TODOs By xFrednet: + +// +// * Make a test with overlapping eq regions (else ifs) +// * Test if as function parameter, tuple constructor, index, while loop condition +// * Test where only the expression is the same +// * Test where the block only has an expression +// * Test with let on a previous line let _ = \n if... +// * Tests with unreadable formatting (Inline if, Not indented) +// * Test multiline condition if x == 9 \n x == 8 {} +// * Test if for return/break (Only move to front) +// * Test in inline closures +// * Test with structs and tuples diff --git a/tests/ui/shared_code_in_if_blocks/valid_if_blocks.rs b/tests/ui/shared_code_in_if_blocks/valid_if_blocks.rs new file mode 100644 index 00000000000..1f12e9348d4 --- /dev/null +++ b/tests/ui/shared_code_in_if_blocks/valid_if_blocks.rs @@ -0,0 +1,157 @@ +#![allow(dead_code, clippy::eval_order_dependence)] +#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)] + +// This tests the shared_code_in_if_blocks lint at the start of blocks + +// Tests with value references are includes in "shared_code_at_bot.rs" + +fn valid_examples() { + let x = 2; + + // The edge statements are different + if x == 9 { + let y = 1 << 5; + + println!("This is the same: vvv"); + let _z = y; + println!("The block expression is different"); + + println!("Different end 1"); + } else { + let y = 1 << 7; + + println!("This is the same: vvv"); + let _z = y; + println!("The block expression is different"); + + println!("Different end 2"); + } + + // No else + if x == 2 { + println!("Hello world!"); + println!("Hello back, how are you?"); + + // This is different vvvv + println!("Howdy stranger =^.^="); + + println!("Bye Bye World"); + } else if x == 9 { + println!("Hello world!"); + println!("Hello back, how are you?"); + + // This is different vvvv + println!("Hello reviewer :D"); + + println!("Bye Bye World"); + } + + // Overlapping statements only in else if blocks -> Don't lint + if x == 0 { + println!("I'm important!") + } else if x == 17 { + println!("I share code in else if"); + + println!("x is 17"); + } else { + println!("I share code in else if"); + + println!("x is nether x nor 17"); + } + + // Mutability is different + if x == 13 { + let mut y = 9; + println!("Value y is: {}", y); + y += 16; + let _z1 = y; + } else { + let y = 9; + println!("Value y is: {}", y); + let _z2 = y; + } + + // Same blocks but at start and bottom so no `if_same_then_else` lint + if x == 418 { + let y = 9; + let z = 8; + let _ = (x, y, z); + // Don't tell the programmer, my code is also in the else block + } else if x == 419 { + println!("+-----------+"); + println!("| |"); + println!("| O O |"); + println!("| ° |"); + println!("| \\_____/ |"); + println!("| |"); + println!("+-----------+"); + } else { + let y = 9; + let z = 8; + let _ = (x, y, z); + // I'm so much better than the x == 418 block. Trust me + } +} + +/// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint +fn trigger_other_lint() { + let x = 0; + let y = 1; + + // Same block + if x == 0 { + let u = 19; + println!("How are u today?"); + let _ = "This is a string"; + } else { + let u = 19; + println!("How are u today?"); + let _ = "This is a string"; + } + + // More complex same blocks + if x == 17 { + #[derive(Debug)] + struct Duck { + num: u64, + }; + let pet = Duck { num: 18 }; + println!("{:?}", pet); + } else { + #[derive(Debug)] + struct Duck { + num: u64, + }; + let pet = Duck { num: 18 }; + println!("{:?}", pet); + } + + // Only same expression + let _ = if x == 6 { 7 } else { 7 }; + + // Same in else if block + let _ = if x == 67 { + println!("Well I'm the most important block"); + "I'm a pretty string" + } else if x == 68 { + println!("I'm a doppelgänger"); + // Don't listen to my clone below + + if y == 90 { + "=^.^=" + } else { + ":D" + } + } else { + // Don't listen to my clone above + println!("I'm a doppelgänger"); + + if y == 90 { + "=^.^=" + } else { + ":D" + } + }; +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 12fce557669a0de230399cf8e6eee4f5307bf87b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 2 Apr 2021 17:35:32 -0400 Subject: Fix all occurences of `needless_borrow` internally --- clippy_dev/src/fmt.rs | 2 +- clippy_dev/src/lib.rs | 16 +- clippy_lints/src/absurd_extreme_comparisons.rs | 4 +- clippy_lints/src/assertions_on_constants.rs | 12 +- clippy_lints/src/atomic_ordering.rs | 6 +- clippy_lints/src/attrs.rs | 4 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/bytecount.rs | 14 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 6 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/checked_conversions.rs | 16 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/comparison_chain.rs | 6 +- clippy_lints/src/copies.rs | 6 +- clippy_lints/src/create_dir.rs | 2 +- clippy_lints/src/default.rs | 10 +- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/doc.rs | 4 +- clippy_lints/src/double_comparison.rs | 4 +- clippy_lints/src/double_parens.rs | 6 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/duration_subsec.rs | 4 +- clippy_lints/src/entry.rs | 16 +- clippy_lints/src/eq_op.rs | 14 +- clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/eta_reduction.rs | 18 +- clippy_lints/src/eval_order_dependence.rs | 18 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/explicit_write.rs | 10 +- clippy_lints/src/fallible_impl_from.rs | 4 +- clippy_lints/src/float_equality_without_abs.rs | 6 +- clippy_lints/src/floating_point_arithmetic.rs | 42 +- clippy_lints/src/format.rs | 38 +- clippy_lints/src/functions/must_use.rs | 28 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 6 +- clippy_lints/src/functions/result_unit_err.rs | 8 +- clippy_lints/src/functions/too_many_arguments.rs | 2 +- clippy_lints/src/get_last_with_len.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 6 +- clippy_lints/src/if_let_some_result.rs | 6 +- clippy_lints/src/if_then_some_else_none.rs | 12 +- clippy_lints/src/implicit_hasher.rs | 6 +- clippy_lints/src/implicit_return.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 16 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/infinite_iter.rs | 12 +- clippy_lints/src/invalid_upcast_comparisons.rs | 6 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/len_zero.rs | 15 +- clippy_lints/src/let_if_seq.rs | 24 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/lib.rs | 2446 ++++++++++---------- clippy_lints/src/lifetimes.rs | 20 +- clippy_lints/src/literal_representation.rs | 4 +- clippy_lints/src/loops/explicit_counter_loop.rs | 2 +- clippy_lints/src/loops/for_kv_map.rs | 4 +- clippy_lints/src/loops/manual_flatten.rs | 4 +- clippy_lints/src/loops/manual_memcpy.rs | 10 +- clippy_lints/src/loops/mod.rs | 6 +- clippy_lints/src/loops/needless_collect.rs | 24 +- clippy_lints/src/loops/needless_range_loop.rs | 18 +- clippy_lints/src/loops/never_loop.rs | 46 +- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/loops/single_element_loop.rs | 4 +- clippy_lints/src/loops/utils.rs | 16 +- clippy_lints/src/loops/while_let_loop.rs | 12 +- clippy_lints/src/loops/while_let_on_iterator.rs | 12 +- clippy_lints/src/manual_strip.rs | 4 +- clippy_lints/src/map_clone.rs | 10 +- clippy_lints/src/map_err_ignore.rs | 2 +- clippy_lints/src/map_identity.rs | 12 +- clippy_lints/src/map_unit_fn.rs | 12 +- clippy_lints/src/match_on_vec_items.rs | 4 +- clippy_lints/src/matches.rs | 81 +- clippy_lints/src/mem_discriminant.rs | 4 +- clippy_lints/src/mem_forget.rs | 2 +- clippy_lints/src/mem_replace.rs | 16 +- clippy_lints/src/methods/bind_instead_of_map.rs | 4 +- clippy_lints/src/methods/chars_cmp.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 8 +- clippy_lints/src/methods/filter_map.rs | 6 +- clippy_lints/src/methods/flat_map_identity.rs | 2 +- clippy_lints/src/methods/implicit_clone.rs | 2 +- clippy_lints/src/methods/iter_next_slice.rs | 2 +- clippy_lints/src/methods/mod.rs | 22 +- clippy_lints/src/methods/option_as_ref_deref.rs | 6 +- clippy_lints/src/methods/or_fun_call.rs | 6 +- clippy_lints/src/methods/search_is_some.rs | 6 +- clippy_lints/src/methods/uninit_assumed_init.rs | 8 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 14 +- clippy_lints/src/methods/unnecessary_fold.rs | 6 +- clippy_lints/src/methods/utils.rs | 2 +- clippy_lints/src/methods/zst_offset.rs | 2 +- clippy_lints/src/minmax.rs | 4 +- clippy_lints/src/misc.rs | 26 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/mut_key.rs | 6 +- clippy_lints/src/mut_mut.rs | 4 +- clippy_lints/src/mut_reference.rs | 4 +- clippy_lints/src/needless_bool.rs | 18 +- clippy_lints/src/needless_borrow.rs | 2 +- clippy_lints/src/needless_borrowed_ref.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 +- clippy_lints/src/neg_multiply.rs | 6 +- clippy_lints/src/no_effect.rs | 58 +- clippy_lints/src/non_octal_unix_permissions.rs | 4 +- clippy_lints/src/open_options.rs | 4 +- clippy_lints/src/option_if_let_else.rs | 8 +- clippy_lints/src/overflow_check_conditional.rs | 20 +- clippy_lints/src/pass_by_ref_or_value.rs | 4 +- clippy_lints/src/path_buf_push_overwrite.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 18 +- clippy_lints/src/ptr.rs | 22 +- clippy_lints/src/ptr_eq.rs | 8 +- clippy_lints/src/ptr_offset_with_cast.rs | 6 +- clippy_lints/src/question_mark.rs | 8 +- clippy_lints/src/ranges.rs | 24 +- clippy_lints/src/redundant_clone.rs | 10 +- clippy_lints/src/redundant_closure_call.rs | 16 +- clippy_lints/src/ref_option_ref.rs | 2 +- clippy_lints/src/regex.rs | 4 +- clippy_lints/src/repeat_once.rs | 4 +- clippy_lints/src/returns.rs | 16 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 2 +- clippy_lints/src/shadow.rs | 69 +- clippy_lints/src/slow_vector_initialization.rs | 42 +- clippy_lints/src/strings.rs | 14 +- clippy_lints/src/suspicious_operation_groupings.rs | 16 +- clippy_lints/src/swap.rs | 30 +- clippy_lints/src/tabs_in_doc_comments.rs | 2 +- clippy_lints/src/to_string_in_display.rs | 2 +- clippy_lints/src/trait_bounds.rs | 4 +- clippy_lints/src/transmute/mod.rs | 2 +- .../src/transmute/transmute_float_to_int.rs | 2 +- clippy_lints/src/transmute/utils.rs | 2 +- clippy_lints/src/transmuting_null.rs | 6 +- clippy_lints/src/try_err.rs | 14 +- clippy_lints/src/types/borrowed_box.rs | 8 +- clippy_lints/src/types/mod.rs | 28 +- clippy_lints/src/types/type_complexity.rs | 4 +- clippy_lints/src/types/utils.rs | 2 +- clippy_lints/src/types/vec_box.rs | 4 +- clippy_lints/src/undropped_manually_drops.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/let_unit_value.rs | 4 +- clippy_lints/src/unit_types/unit_arg.rs | 2 +- clippy_lints/src/unit_types/unit_cmp.rs | 4 +- clippy_lints/src/unit_types/utils.rs | 2 +- clippy_lints/src/unnamed_address.rs | 6 +- clippy_lints/src/unnecessary_sort_by.rs | 16 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/unused_io_amount.rs | 10 +- clippy_lints/src/unused_unit.rs | 2 +- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/use_self.rs | 6 +- clippy_lints/src/useless_conversion.rs | 12 +- clippy_lints/src/utils/author.rs | 96 +- clippy_lints/src/utils/inspector.rs | 90 +- clippy_lints/src/utils/internal_lints.rs | 18 +- clippy_lints/src/vec.rs | 2 +- clippy_lints/src/vec_resize_to_zero.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- src/driver.rs | 12 +- tests/compile-test.rs | 16 +- tests/ui/borrow_interior_mutable_const/others.rs | 6 +- .../ui/borrow_interior_mutable_const/others.stderr | 28 +- tests/ui/collapsible_match2.rs | 7 +- tests/ui/collapsible_match2.stderr | 20 +- tests/ui/escape_analysis.rs | 4 +- tests/ui/implicit_clone.rs | 2 +- tests/ui/into_iter_on_ref.fixed | 2 +- tests/ui/into_iter_on_ref.rs | 2 +- tests/ui/ref_option_ref.rs | 2 +- tests/ui/ref_option_ref.stderr | 2 +- tests/ui/stable_sort_primitive.fixed | 2 +- tests/ui/stable_sort_primitive.rs | 2 +- 183 files changed, 2150 insertions(+), 2162 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 111c79c332d..1517cdc9419 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -68,7 +68,7 @@ pub fn run(check: bool, verbose: bool) { continue; } - success &= rustfmt(context, &path)?; + success &= rustfmt(context, path)?; } Ok(success) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index a5e94683878..1e5a140e964 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -101,7 +101,7 @@ impl Lint { #[must_use] pub fn gen_lint_group_list<'a>(lints: impl Iterator) -> Vec { lints - .map(|l| format!(" LintId::of(&{}::{}),", l.module, l.name.to_uppercase())) + .map(|l| format!(" LintId::of({}::{}),", l.module, l.name.to_uppercase())) .sorted() .collect::>() } @@ -154,17 +154,17 @@ pub fn gen_register_lint_list<'a>( let header = " store.register_lints(&[".to_string(); let footer = " ]);".to_string(); let internal_lints = internal_lints - .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) + .sorted_by_key(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) .map(|l| { format!( - " #[cfg(feature = \"internal-lints\")]\n &{}::{},", + " #[cfg(feature = \"internal-lints\")]\n {}::{},", l.module, l.name.to_uppercase() ) }); let other_lints = usable_lints - .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) - .map(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) + .sorted_by_key(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) + .map(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) .sorted(); let mut lint_list = vec![header]; lint_list.extend(internal_lints); @@ -550,9 +550,9 @@ fn test_gen_lint_group_list() { Lint::new("internal", "internal_style", "abc", None, "module_name"), ]; let expected = vec![ - " LintId::of(&module_name::ABC),".to_string(), - " LintId::of(&module_name::INTERNAL),".to_string(), - " LintId::of(&module_name::SHOULD_ASSERT_EQ),".to_string(), + " LintId::of(module_name::ABC),".to_string(), + " LintId::of(module_name::INTERNAL),".to_string(), + " LintId::of(module_name::SHOULD_ASSERT_EQ),".to_string(), ]; assert_eq!(expected, gen_lint_group_list(lints.iter())); } diff --git a/clippy_lints/src/absurd_extreme_comparisons.rs b/clippy_lints/src/absurd_extreme_comparisons.rs index 33c720c666e..5fbf4bdbd18 100644 --- a/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/absurd_extreme_comparisons.rs @@ -44,7 +44,7 @@ declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]); impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind { + if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind { if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { if !expr.span.from_expansion() { let msg = "this comparison involving the minimum or maximum element for this \ @@ -95,7 +95,7 @@ enum AbsurdComparisonResult { } fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - if let ExprKind::Cast(ref cast_exp, _) = expr.kind { + if let ExprKind::Cast(cast_exp, _) = expr.kind { let precast_ty = cx.typeck_results().expr_ty(cast_exp); let cast_ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 16905781c56..a0993bb6913 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { return; } if_chain! { - if let ExprKind::Unary(_, ref lit) = e.kind; + if let ExprKind::Unary(_, lit) = e.kind; if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit); if is_true; then { @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { if assert_span.from_expansion() { return; } - if let Some(assert_match) = match_assert_with_message(&cx, e) { + if let Some(assert_match) = match_assert_with_message(cx, e) { match assert_match { // matched assert but not message AssertKind::WithoutMessage(false) => lint_false_without_message(), @@ -113,17 +113,17 @@ enum AssertKind { /// where `message` is any expression and `c` is a constant bool. fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { if_chain! { - if let ExprKind::If(ref cond, ref then, _) = expr.kind; - if let ExprKind::Unary(UnOp::Not, ref expr) = cond.kind; + if let ExprKind::If(cond, then, _) = expr.kind; + if let ExprKind::Unary(UnOp::Not, expr) = cond.kind; // bind the first argument of the `assert!` macro if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr); // block - if let ExprKind::Block(ref block, _) = then.kind; + if let ExprKind::Block(block, _) = then.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; // inner block is optional. unwrap it if it exists, or use the expression as is otherwise. if let Some(begin_panic_call) = match block_expr.kind { - ExprKind::Block(ref inner_block, _) => &inner_block.expr, + ExprKind::Block(inner_block, _) => &inner_block.expr, _ => &block.expr, }; // function call diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index dfb18199325..7ceb01f5590 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -85,7 +85,7 @@ fn match_ordering_def_path(cx: &LateContext<'_>, did: DefId, orderings: &[&str]) fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind; + if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind; let method = method_path.ident.name.as_str(); if type_is_atomic(cx, &args[0]); if method == "load" || method == "store"; @@ -120,7 +120,7 @@ fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Call(func, args) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if ["fence", "compiler_fence"] @@ -152,7 +152,7 @@ fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind; + if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind; let method = method_path.ident.name.as_str(); if type_is_atomic(cx, &args[0]); if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update"; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 0ce46e1c214..382fb03d920 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -602,7 +602,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { if let NestedMetaItem::MetaItem(meta) = item { match &meta.kind { MetaItemKind::List(list) => { - mismatched.extend(find_mismatched_target_os(&list)); + mismatched.extend(find_mismatched_target_os(list)); }, MetaItemKind::Word => { if_chain! { @@ -629,7 +629,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { then { let mess = "operating system used in target family position"; - span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, &mess, |diag| { + span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { // Avoid showing the unix suggestion multiple times in case // we have more than one mismatch for unix-like systems let mut unix_suggested = false; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 68eee0520b3..1739a57a240 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -101,7 +101,7 @@ impl LateLintPass<'_> for AwaitHolding { let typeck_results = cx.tcx.typeck_body(body_id); check_interior_types( cx, - &typeck_results.generator_interior_types.as_ref().skip_binder(), + typeck_results.generator_interior_types.as_ref().skip_binder(), body.value.span, ); } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 1546d823167..877ae002d36 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -38,17 +38,17 @@ declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]); impl<'tcx> LateLintPass<'tcx> for ByteCount { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref count, _, ref count_args, _) = expr.kind; + if let ExprKind::MethodCall(count, _, count_args, _) = expr.kind; if count.ident.name == sym!(count); if count_args.len() == 1; - if let ExprKind::MethodCall(ref filter, _, ref filter_args, _) = count_args[0].kind; + if let ExprKind::MethodCall(filter, _, filter_args, _) = count_args[0].kind; if filter.ident.name == sym!(filter); if filter_args.len() == 2; if let ExprKind::Closure(_, _, body_id, _, _) = filter_args[1].kind; let body = cx.tcx.hir().body(body_id); if body.params.len() == 1; - if let Some(argname) = get_pat_name(&body.params[0].pat); - if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind; + if let Some(argname) = get_pat_name(body.params[0].pat); + if let ExprKind::Binary(ref op, l, r) = body.value.kind; if op.node == BinOpKind::Eq; if match_type(cx, cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(), @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() { return; } - let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = + let haystack = if let ExprKind::MethodCall(path, _, args, _) = filter_args[0].kind { let p = path.ident.name; if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { @@ -98,10 +98,10 @@ fn check_arg(name: Symbol, arg: Symbol, needle: &Expr<'_>) -> bool { fn get_path_name(expr: &Expr<'_>) -> Option { match expr.kind { - ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) | ExprKind::Unary(UnOp::Deref, ref e) => { + ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) | ExprKind::Unary(UnOp::Deref, e) => { get_path_name(e) }, - ExprKind::Block(ref b, _) => { + ExprKind::Block(b, _) => { if b.stmts.is_empty() { b.expr.as_ref().and_then(|p| get_path_name(p)) } else { diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 5208156ffd2..62a119d662b 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -10,7 +10,7 @@ use rustc_target::abi::LayoutOf; use super::CAST_PTR_ALIGNMENT; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Cast(ref cast_expr, cast_to) = expr.kind { + if let ExprKind::Cast(cast_expr, cast_to) = expr.kind { if is_hir_ty_cfg_dependant(cx, cast_to) { return; } diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index bf722d0a3f4..040e0ca8864 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -30,7 +30,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast } // Don't lint for positive constants. - let const_val = constant(cx, &cx.typeck_results(), cast_op); + let const_val = constant(cx, cx.typeck_results(), cast_op); if_chain! { if let Some((Constant::Int(n), _)) = const_val; if let ty::Int(ity) = *cast_from.kind(); @@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast } // Don't lint for the result of methods that always return non-negative values. - if let ExprKind::MethodCall(ref path, _, _, _) = cast_op.kind { + if let ExprKind::MethodCall(path, _, _, _) = cast_op.kind { let mut method_name = path.ident.name.as_str(); let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; if_chain! { if method_name == "unwrap"; if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]); - if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind; + if let ExprKind::MethodCall(inner_path, _, _, _) = &arglist[0][0].kind; then { method_name = inner_path.ident.name.as_str(); } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d9e172c01a7..ae4fdd12c41 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -372,7 +372,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { return; } - if let ExprKind::Cast(ref cast_expr, cast_to) = expr.kind { + if let ExprKind::Cast(cast_expr, cast_to) = expr.kind { if is_hir_ty_cfg_dependant(cx, cast_to) { return; } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index b38c70bcc41..d7136f84cc3 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { let result = if_chain! { if !in_external_macro(cx.sess(), item.span); - if let ExprKind::Binary(op, ref left, ref right) = &item.kind; + if let ExprKind::Binary(op, left, right) = &item.kind; then { match op.node { @@ -200,7 +200,7 @@ impl ConversionType { /// Check for `expr <= (to_type::MAX as from_type)` fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { if_chain! { - if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind; + if let ExprKind::Binary(ref op, left, right) = &expr.kind; if let Some((candidate, check)) = normalize_le_ge(op, left, right); if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX"); @@ -219,7 +219,7 @@ fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { } // First of we need a binary containing the expression & the cast - if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind { + if let ExprKind::Binary(ref op, left, right) = &expr.kind { normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r)) } else { None @@ -260,7 +260,7 @@ fn get_types_from_cast<'a>( // or `to_type::MAX as from_type` let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! { // to_type::max_value(), from_type - if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind; + if let ExprKind::Cast(limit, from_type) = &expr.kind; if let TyKind::Path(ref from_type_path) = &from_type.kind; if let Some(from_sym) = int_ty_to_sym(from_type_path); @@ -275,7 +275,7 @@ fn get_types_from_cast<'a>( let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { if_chain! { // `from_type::from, to_type::max_value()` - if let ExprKind::Call(ref from_func, ref args) = &expr.kind; + if let ExprKind::Call(from_func, args) = &expr.kind; // `to_type::max_value()` if args.len() == 1; if let limit = &args[0]; @@ -317,9 +317,9 @@ fn get_types_from_cast<'a>( /// Gets the type which implements the called function fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> { if_chain! { - if let QPath::TypeRelative(ref ty, ref path) = &path; + if let QPath::TypeRelative(ty, path) = &path; if path.ident.name.as_str() == function; - if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind; + if let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind; if let [int] = &*tp.segments; then { let name = &int.ident.name.as_str(); @@ -333,7 +333,7 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: /// Gets the type as a string, if it is a supported integer fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { if_chain! { - if let QPath::Resolved(_, ref path) = *path; + if let QPath::Resolved(_, path) = *path; if let [ty] = &*path.segments; then { let name = &ty.ident.name.as_str(); diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 4cc542f723c..f62c6a9c325 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -152,7 +152,7 @@ impl<'tcx> Visitor<'tcx> for CcHelper { ExprKind::If(_, _, _) => { self.cc += 1; }, - ExprKind::Match(_, ref arms, _) => { + ExprKind::Match(_, arms, _) => { if arms.len() > 1 { self.cc += 1; } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index d601cb7c224..31ae63b5184 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -71,10 +71,8 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { } for cond in conds.windows(2) { - if let ( - &ExprKind::Binary(ref kind1, ref lhs1, ref rhs1), - &ExprKind::Binary(ref kind2, ref lhs2, ref rhs2), - ) = (&cond[0].kind, &cond[1].kind) + if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) = + (&cond[0].kind, &cond[1].kind) { if !kind_is_cmp(kind1.node) || !kind_is_cmp(kind2.node) { return; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 1b982221b06..8b503c9a030 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { if let ExprKind::If(_, _, _) = expr.kind { // skip ifs directly in else, it will be checked in the parent if if let Some(&Expr { - kind: ExprKind::If(_, _, Some(ref else_expr)), + kind: ExprKind::If(_, _, Some(else_expr)), .. }) = get_parent_expr(cx, expr) { @@ -247,7 +247,7 @@ fn lint_same_then_else<'tcx>( for value in &end_walker.uses { // Well we can't move this and all prev statements. So reset - if block_defs.contains(&value) { + if block_defs.contains(value) { moved_start = Some(index + 1); end_walker.defs.drain().for_each(|x| { block_defs.insert(x); @@ -555,7 +555,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedValueFinderVisitor<'a, 'tcx> { } fn visit_qpath(&mut self, qpath: &'tcx rustc_hir::QPath<'tcx>, id: HirId, _span: rustc_span::Span) { - if let rustc_hir::QPath::Resolved(_, ref path) = *qpath { + if let rustc_hir::QPath::Resolved(_, path) = *qpath { if path.segments.len() == 1 { if let rustc_hir::def::Res::Local(var) = self.cx.qpath_res(qpath, id) { self.uses.insert(var); diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index ac890c90c97..7b5cce6462a 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -33,7 +33,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Call(func, args) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 8a2146d93e8..710da8fe9e0 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -77,7 +77,7 @@ impl LateLintPass<'_> for Default { if_chain! { // Avoid cases already linted by `field_reassign_with_default` if !self.reassigned_linted.contains(&expr.span); - if let ExprKind::Call(ref path, ..) = expr.kind; + if let ExprKind::Call(path, ..) = expr.kind; if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); @@ -246,7 +246,7 @@ impl LateLintPass<'_> for Default { /// Checks if the given expression is the `default` method belonging to the `Default` trait. fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { if_chain! { - if let ExprKind::Call(ref fn_expr, _) = &expr.kind; + if let ExprKind::Call(fn_expr, _) = &expr.kind; if let ExprKind::Path(qpath) = &fn_expr.kind; if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); then { @@ -262,11 +262,11 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> { if_chain! { // only take assignments - if let StmtKind::Semi(ref later_expr) = this.kind; - if let ExprKind::Assign(ref assign_lhs, ref assign_rhs, _) = later_expr.kind; + if let StmtKind::Semi(later_expr) = this.kind; + if let ExprKind::Assign(assign_lhs, assign_rhs, _) = later_expr.kind; // only take assignments to fields where the left-hand side field is a field of // the same binding as the previous statement - if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind; + if let ExprKind::Field(binding, field_ident) = assign_lhs.kind; if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind; if let Some(second_binding_name) = path.segments.last(); if second_binding_name.ident.name == binding_name; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 9fad85f8ef4..647af3bdc04 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -199,7 +199,7 @@ fn check_hash_peq<'tcx>( then { // Look for the PartialEq implementations for `ty` cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { - let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id)); + let peq_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id)); if peq_is_automatically_derived == hash_is_automatically_derived { return; @@ -253,7 +253,7 @@ fn check_ord_partial_ord<'tcx>( then { // Look for the PartialOrd implementations for `ty` cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { - let partial_ord_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id)); + let partial_ord_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id)); if partial_ord_is_automatically_derived == ord_is_automatically_derived { return; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index b5796ccf43f..fb53b55ebd6 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -710,8 +710,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { // check for `begin_panic` if_chain! { - if let ExprKind::Call(ref func_expr, _) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind; + if let ExprKind::Call(func_expr, _) = expr.kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind; if let Some(path_def_id) = path.res.opt_def_id(); if match_panic_def_id(self.cx, path_def_id); if is_expn_of(expr.span, "unreachable").is_none(); diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 1d291565ec1..58543ae6e4e 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -47,7 +47,7 @@ impl<'tcx> DoubleComparisons { }, _ => return, }; - if !(eq_expr_value(cx, &llhs, &rlhs) && eq_expr_value(cx, &lrhs, &rrhs)) { + if !(eq_expr_value(cx, llhs, rlhs) && eq_expr_value(cx, lrhs, rrhs)) { return; } macro_rules! lint_double_comparison { @@ -88,7 +88,7 @@ impl<'tcx> DoubleComparisons { impl<'tcx> LateLintPass<'tcx> for DoubleComparisons { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.kind { + if let ExprKind::Binary(ref kind, lhs, rhs) = expr.kind { Self::check_binop(cx, kind.node, lhs, rhs, expr.span); } } diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 5afdcb3c09f..e4e4a93b011 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -50,7 +50,7 @@ impl EarlyLintPass for DoubleParens { match expr.kind { ExprKind::Paren(ref in_paren) => match in_paren.kind { ExprKind::Paren(_) | ExprKind::Tup(_) => { - span_lint(cx, DOUBLE_PARENS, expr.span, &msg); + span_lint(cx, DOUBLE_PARENS, expr.span, msg); }, _ => {}, }, @@ -58,7 +58,7 @@ impl EarlyLintPass for DoubleParens { if params.len() == 1 { let param = ¶ms[0]; if let ExprKind::Paren(_) = param.kind { - span_lint(cx, DOUBLE_PARENS, param.span, &msg); + span_lint(cx, DOUBLE_PARENS, param.span, msg); } } }, @@ -66,7 +66,7 @@ impl EarlyLintPass for DoubleParens { if params.len() == 2 { let param = ¶ms[1]; if let ExprKind::Paren(_) = param.kind { - span_lint(cx, DOUBLE_PARENS, param.span, &msg); + span_lint(cx, DOUBLE_PARENS, param.span, msg); } } }, diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 7e7ec017bbb..b5b29760636 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -113,7 +113,7 @@ declare_lint_pass!(DropForgetRef => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COP impl<'tcx> LateLintPass<'tcx> for DropForgetRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(ref path, ref args) = expr.kind; + if let ExprKind::Call(path, args) = expr.kind; if let ExprKind::Path(ref qpath) = path.kind; if args.len() == 1; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 746c1f6df91..529807770f3 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -43,8 +43,8 @@ declare_lint_pass!(DurationSubsec => [DURATION_SUBSEC]); impl<'tcx> LateLintPass<'tcx> for DurationSubsec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind; - if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind; + if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, left, right) = expr.kind; + if let ExprKind::MethodCall(method_path, _ , args, _) = left.kind; if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right); then { diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 25eb048448c..a815df1691a 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -57,14 +57,14 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]); impl<'tcx> LateLintPass<'tcx> for HashMapPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::If(ref check, ref then_block, ref else_block) = expr.kind { - if let ExprKind::Unary(UnOp::Not, ref check) = check.kind { + if let ExprKind::If(check, then_block, ref else_block) = expr.kind { + if let ExprKind::Unary(UnOp::Not, check) = check.kind { if let Some((ty, map, key)) = check_cond(cx, check) { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` // we can give a better error message let sole_expr = { else_block.is_none() - && if let ExprKind::Block(ref then_block, _) = then_block.kind { + && if let ExprKind::Block(then_block, _) = then_block.kind { (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 } else { true @@ -81,9 +81,9 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { sole_expr, }; - walk_expr(&mut visitor, &**then_block); + walk_expr(&mut visitor, then_block); } - } else if let Some(ref else_block) = *else_block { + } else if let Some(else_block) = *else_block { if let Some((ty, map, key)) = check_cond(cx, check) { let mut visitor = InsertVisitor { cx, @@ -103,10 +103,10 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static str, &'a Expr<'a>, &'a Expr<'a>)> { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref params, _) = check.kind; + if let ExprKind::MethodCall(path, _, params, _) = check.kind; if params.len() >= 2; if path.ident.name == sym!(contains_key); - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, key) = params[1].kind; then { let map = ¶ms[0]; let obj_ty = cx.typeck_results().expr_ty(map).peel_refs(); @@ -140,7 +140,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref params, _) = expr.kind; + if let ExprKind::MethodCall(path, _, params, _) = expr.kind; if params.len() == 3; if path.ident.name == sym!(insert); if get_item_name(self.cx, self.map) == get_item_name(self.cx, ¶ms[0]); diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 6d7046ac8b7..90f391b5f5c 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -65,12 +65,12 @@ const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_e impl<'tcx> LateLintPass<'tcx> for EqOp { #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Block(ref block, _) = e.kind { + if let ExprKind::Block(block, _) = e.kind { for stmt in block.stmts { for amn in &ASSERT_MACRO_NAMES { if_chain! { if is_expn_of(stmt.span, amn).is_some(); - if let StmtKind::Semi(ref matchexpr) = stmt.kind; + if let StmtKind::Semi(matchexpr) = stmt.kind; if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr); if macro_args.len() == 2; let (lhs, rhs) = (macro_args[0], macro_args[1]); @@ -88,12 +88,12 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } } } - if let ExprKind::Binary(op, ref left, ref right) = e.kind { + if let ExprKind::Binary(op, left, right) = e.kind { if e.span.from_expansion() { return; } let macro_with_not_op = |expr_kind: &ExprKind<'_>| { - if let ExprKind::Unary(_, ref expr) = *expr_kind { + if let ExprKind::Unary(_, expr) = *expr_kind { in_macro(expr.span) } else { false @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { // do not suggest to dereference literals (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {}, // &foo == &bar - (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => { + (&ExprKind::AddrOf(BorrowKind::Ref, _, l), &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { let lty = cx.typeck_results().expr_ty(l); let rty = cx.typeck_results().expr_ty(r); let lcpy = is_copy(cx, lty); @@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } }, // &foo == bar - (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => { + (&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => { let lty = cx.typeck_results().expr_ty(l); let lcpy = is_copy(cx, lty); if (requires_ref || lcpy) @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } }, // foo == &bar - (_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => { + (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { let rty = cx.typeck_results().expr_ty(r); let rcpy = is_copy(cx, rty); if (requires_ref || rcpy) diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 59602616781..f95ca86a2d0 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -34,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for ErasingOp { if e.span.from_expansion() { return; } - if let ExprKind::Binary(ref cmp, ref left, ref right) = e.kind { + if let ExprKind::Binary(ref cmp, left, right) = e.kind { match cmp.node { BinOpKind::Mul | BinOpKind::BitAnd => { check(cx, left, e.span); diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 99253555a95..2f1aa53236d 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { } fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.kind { + if let ExprKind::Closure(_, decl, eid, _, _) = expr.kind { let body = cx.tcx.hir().body(eid); let ex = &body.value; @@ -109,7 +109,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { } if_chain!( - if let ExprKind::Call(ref caller, ref args) = ex.kind; + if let ExprKind::Call(caller, args) = ex.kind; if let ExprKind::Path(_) = caller.kind; @@ -142,7 +142,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { ); if_chain!( - if let ExprKind::MethodCall(ref path, _, ref args, _) = ex.kind; + if let ExprKind::MethodCall(path, _, args, _) = ex.kind; // Not the same number of arguments, there is no way the closure is the same as the function return; if args.len() == decl.inputs.len(); @@ -178,7 +178,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a let actual_type_of_self = &cx.typeck_results().node_type(self_arg.hir_id); if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) { - if match_borrow_depth(expected_type_of_self, &actual_type_of_self) + if match_borrow_depth(expected_type_of_self, actual_type_of_self) && implements_trait(cx, actual_type_of_self, trait_id, &[]) { return Some(cx.tcx.def_path_str(trait_id)); @@ -187,8 +187,8 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a cx.tcx.impl_of_method(method_def_id).and_then(|_| { //a type may implicitly implement other type's methods (e.g. Deref) - if match_types(expected_type_of_self, &actual_type_of_self) { - return Some(get_type_name(cx, &actual_type_of_self)); + if match_types(expected_type_of_self, actual_type_of_self) { + return Some(get_type_name(cx, actual_type_of_self)); } None }) @@ -196,7 +196,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { match (&lhs.kind(), &rhs.kind()) { - (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2), + (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(t1, t2), (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))), } } @@ -218,7 +218,7 @@ fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool { fn get_type_name(cx: &LateContext<'_>, ty: Ty<'_>) -> String { match ty.kind() { ty::Adt(t, _) => cx.tcx.def_path_str(t.did), - ty::Ref(_, r, _) => get_type_name(cx, &r), + ty::Ref(_, r, _) => get_type_name(cx, r), _ => ty.to_string(), } } @@ -230,7 +230,7 @@ fn compare_inputs( for (closure_input, function_arg) in closure_inputs.zip(call_args) { if let PatKind::Binding(_, _, ident, _) = closure_input.pat.kind { // XXXManishearth Should I be checking the binding mode here? - if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.kind { + if let ExprKind::Path(QPath::Resolved(None, p)) = function_arg.kind { if p.segments.len() != 1 { // If it's a proper path, it can't be a local variable return false; diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index ea33a4d98fd..762f64fe37a 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Find a write to a local variable. match expr.kind { - ExprKind::Assign(ref lhs, ..) | ExprKind::AssignOp(_, ref lhs, _) => { + ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) => { if let Some(var) = path_to_local(lhs) { let mut visitor = ReadVisitor { cx, @@ -87,12 +87,12 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(ref local) => { - if let Local { init: Some(ref e), .. } = **local { + StmtKind::Local(local) => { + if let Local { init: Some(e), .. } = local { DivergenceVisitor { cx }.visit_expr(e); } }, - StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => DivergenceVisitor { cx }.maybe_walk_expr(e), + StmtKind::Expr(e) | StmtKind::Semi(e) => DivergenceVisitor { cx }.maybe_walk_expr(e), StmtKind::Item(..) => {}, } } @@ -106,7 +106,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { ExprKind::Closure(..) => {}, - ExprKind::Match(ref e, arms, _) => { + ExprKind::Match(e, arms, _) => { self.visit_expr(e); for arm in arms { if let Some(Guard::If(if_expr)) = arm.guard { @@ -130,7 +130,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e), - ExprKind::Call(ref func, _) => { + ExprKind::Call(func, _) => { let typ = self.cx.typeck_results().expr_ty(func); match typ.kind() { ty::FnDef(..) | ty::FnPtr(_) => { @@ -266,10 +266,10 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) - fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly { match stmt.kind { - StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => check_expr(vis, expr), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr), // If the declaration is of a local variable, check its initializer // expression if it has one. Otherwise, keep going. - StmtKind::Local(ref local) => local + StmtKind::Local(local) => local .init .as_ref() .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)), @@ -343,7 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { /// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`. fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) { - if let ExprKind::Assign(ref lhs, ..) = parent.kind { + if let ExprKind::Assign(lhs, ..) = parent.kind { return lhs.hir_id == expr.hir_id; } } diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 84fac998662..16246e548b6 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -28,7 +28,7 @@ declare_lint_pass!(Exit => [EXIT]); impl<'tcx> LateLintPass<'tcx> for Exit { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(ref path_expr, ref _args) = e.kind; + if let ExprKind::Call(path_expr, _args) = e.kind; if let ExprKind::Path(ref path) = path_expr.kind; if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::EXIT); diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 4146b7baa10..da4936ff25b 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -34,11 +34,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // match call to unwrap - if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args, _) = expr.kind; + if let ExprKind::MethodCall(unwrap_fun, _, unwrap_args, _) = expr.kind; if unwrap_fun.ident.name == sym::unwrap; // match call to write_fmt if !unwrap_args.is_empty(); - if let ExprKind::MethodCall(ref write_fun, _, write_args, _) = + if let ExprKind::MethodCall(write_fun, _, write_args, _) = unwrap_args[0].kind; if write_fun.ident.name == sym!(write_fmt); // match calls to std::io::stdout() / std::io::stderr () @@ -135,10 +135,10 @@ fn write_output_string(write_args: &[Expr<'_>]) -> Option { if_chain! { // Obtain the string that should be printed if write_args.len() > 1; - if let ExprKind::Call(_, ref output_args) = write_args[1].kind; + if let ExprKind::Call(_, output_args) = write_args[1].kind; if !output_args.is_empty(); - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref output_string_expr) = output_args[0].kind; - if let ExprKind::Array(ref string_exprs) = output_string_expr.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, output_string_expr) = output_args[0].kind; + if let ExprKind::Array(string_exprs) = output_string_expr.kind; // we only want to provide an automatic suggestion for simple (non-format) strings if string_exprs.len() == 1; if let ExprKind::Lit(ref lit) = string_exprs[0].kind; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 52a5a7acf0d..2937fcb9ca0 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -81,8 +81,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // check for `begin_panic` if_chain! { - if let ExprKind::Call(ref func_expr, _) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind; + if let ExprKind::Call(func_expr, _) = expr.kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind; if let Some(path_def_id) = path.res.opt_def_id(); if match_panic_def_id(self.lcx, path_def_id); if is_expn_of(expr.span, "unreachable").is_none(); diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index 0c59db360f9..b5ebe5f90ba 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs { let rhs; // check if expr is a binary expression with a lt or gt operator - if let ExprKind::Binary(op, ref left, ref right) = expr.kind { + if let ExprKind::Binary(op, left, right) = expr.kind { match op.node { BinOpKind::Lt => { lhs = left; @@ -88,8 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs { if let ty::Float(_) = t_val_r.kind(); then { - let sug_l = sugg::Sugg::hir(cx, &val_l, ".."); - let sug_r = sugg::Sugg::hir(cx, &val_r, ".."); + let sug_l = sugg::Sugg::hir(cx, val_l, ".."); + let sug_r = sugg::Sugg::hir(cx, val_r, ".."); // format the suggestion let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); // spans the lint diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 0b5f0379ce6..e0b687b0205 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -131,7 +131,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su let mut suggestion = Sugg::hir(cx, expr, ".."); if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind { - expr = &inner_expr; + expr = inner_expr; } if_chain! { @@ -313,8 +313,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { Spanned { node: BinOpKind::Add, .. }, - ref lhs, - ref rhs, + lhs, + rhs, ) = parent.kind { let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; @@ -329,7 +329,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "{}.mul_add({}, {})", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], ".."), - Sugg::hir(cx, &other_addend, ".."), + Sugg::hir(cx, other_addend, ".."), ), Applicability::MachineApplicable, ); @@ -356,18 +356,18 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { Spanned { node: BinOpKind::Add, .. }, - ref add_lhs, - ref add_rhs, + add_lhs, + add_rhs, ) = args[0].kind { // check if expression of the form x * x + y * y if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind; - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind; + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind; + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind; if eq_expr_value(cx, lmul_lhs, lmul_rhs); if eq_expr_value(cx, rmul_lhs, rmul_rhs); then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, ".."))); + return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, ".."), Sugg::hir(cx, rmul_lhs, ".."))); } } @@ -376,13 +376,13 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { if let ExprKind::MethodCall( PathSegment { ident: lmethod_name, .. }, ref _lspan, - ref largs, + largs, _ ) = add_lhs.kind; if let ExprKind::MethodCall( PathSegment { ident: rmethod_name, .. }, ref _rspan, - ref rargs, + rargs, _ ) = add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; @@ -416,11 +416,11 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // and suggest usage of `x.exp_m1() - (y - 1)` instead fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind; + if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind; if cx.typeck_results().expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(ref path, _, ref method_args, _) = lhs.kind; + if let ExprKind::MethodCall(path, _, method_args, _) = lhs.kind; if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point(); if path.ident.name.as_str() == "exp"; then { @@ -442,7 +442,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lhs, ref rhs) = &expr.kind; + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind; if cx.typeck_results().expr_ty(lhs).is_floating_point(); if cx.typeck_results().expr_ty(rhs).is_floating_point(); then { @@ -604,8 +604,8 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, ref args_a, _) = expr_a.kind; - if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref args_b, _) = expr_b.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind; then { return method_name_a.as_str() == method_name_b.as_str() && args_a.len() == args_b.len() && @@ -630,8 +630,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind; if are_same_base_logs(cx, lhs, rhs); - if let ExprKind::MethodCall(_, _, ref largs, _) = lhs.kind; - if let ExprKind::MethodCall(_, _, ref rargs, _) = rhs.kind; + if let ExprKind::MethodCall(_, _, largs, _) = lhs.kind; + if let ExprKind::MethodCall(_, _, rargs, _) = rhs.kind; then { span_lint_and_sugg( cx, @@ -675,7 +675,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "conversion to degrees can be done more accurately", "consider using", - format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")), + format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")), Applicability::MachineApplicable, ); } else if @@ -688,7 +688,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "conversion to radians can be done more accurately", "consider using", - format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")), + format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")), Applicability::MachineApplicable, ); } @@ -698,7 +698,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind { + if let ExprKind::MethodCall(path, _, args, _) = &expr.kind { let recv_ty = cx.typeck_results().expr_ty(&args[0]); if recv_ty.is_floating_point() { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index a33f987b423..4729abbd8e3 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -78,8 +78,8 @@ fn span_useless_format(cx: &T, span: Span, help: &str, mut sugg: fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) -> Option { if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref format_args) = expr.kind; - if let ExprKind::Array(ref elems) = arms[0].body.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, format_args) = expr.kind; + if let ExprKind::Array(elems) = arms[0].body.kind; if elems.len() == 1; if let Some(args) = match_function_call(cx, &elems[0], &paths::FMT_ARGUMENTV1_NEW); // matches `core::fmt::Display::fmt` @@ -88,10 +88,10 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & if let Some(did) = cx.qpath_res(qpath, args[1].hir_id).opt_def_id(); if match_def_path(cx, did, &paths::DISPLAY_FMT_METHOD); // check `(arg0,)` in match block - if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind; + if let PatKind::Tuple(pats, None) = arms[0].pat.kind; if pats.len() == 1; then { - let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs(); + let ty = cx.typeck_results().pat_ty(pats[0]).peel_refs(); if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym::string_type) { return None; } @@ -101,7 +101,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & } } else { let snip = snippet(cx, format_args.span, ""); - if let ExprKind::MethodCall(ref path, _, _, _) = format_args.kind { + if let ExprKind::MethodCall(path, _, _, _) = format_args.kind { if path.ident.name == sym!(to_string) { return Some(format!("{}", snip)); } @@ -120,16 +120,16 @@ fn on_new_v1<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option [], }` if tup.is_empty() { @@ -152,16 +152,16 @@ fn on_new_v1_fmt<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option) -> bool { if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) = expr.kind; - if let ExprKind::Array(ref exprs) = expr.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; + if let ExprKind::Array(exprs) = expr.kind; if exprs.len() == 1; // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, ref fields, _) = exprs[0].kind; + if let ExprKind::Struct(_, fields, _) = exprs[0].kind; if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); // struct `core::fmt::rt::v1::FormatSpec` - if let ExprKind::Struct(_, ref fields, _) = format_field.expr.kind; + if let ExprKind::Struct(_, fields, _) = format_field.expr.kind; if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision); if let ExprKind::Path(ref precision_path) = precision_field.expr.kind; if last_path_segment(precision_path).ident.name == sym::Implied; diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 9e943c647fe..db5fe90b663 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -25,12 +25,12 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let is_public = cx.access_levels.is_exported(item.hir_id()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { - check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); return; } else if is_public && !is_proc_macro(cx.sess(), attrs) && attr_by_name(attrs, "no_mangle").is_none() { check_must_use_candidate( cx, - &sig.decl, + sig.decl, cx.tcx.hir().body(*body_id), item.span, item.hir_id(), @@ -48,11 +48,11 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem< let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = must_use_attr(attrs); if let Some(attr) = attr { - check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.hir_id()).is_none() { check_must_use_candidate( cx, - &sig.decl, + sig.decl, cx.tcx.hir().body(*body_id), item.span, item.hir_id(), @@ -71,13 +71,13 @@ pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = must_use_attr(attrs); if let Some(attr) = attr { - check_needless_must_use(cx, &sig.decl, item.hir_id(), item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { check_must_use_candidate( cx, - &sig.decl, + sig.decl, body, item.span, item.hir_id(), @@ -160,8 +160,8 @@ fn check_must_use_candidate<'tcx>( fn returns_unit(decl: &hir::FnDecl<'_>) -> bool { match decl.output { hir::FnRetTy::DefaultReturn(_) => true, - hir::FnRetTy::Return(ref ty) => match ty.kind { - hir::TyKind::Tup(ref tys) => tys.is_empty(), + hir::FnRetTy::Return(ty) => match ty.kind { + hir::TyKind::Tup(tys) => tys.is_empty(), hir::TyKind::Never => true, _ => false, }, @@ -170,7 +170,7 @@ fn returns_unit(decl: &hir::FnDecl<'_>) -> bool { fn has_mutable_arg(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { let mut tys = DefIdSet::default(); - body.params.iter().any(|param| is_mutable_pat(cx, ¶m.pat, &mut tys)) + body.params.iter().any(|param| is_mutable_pat(cx, param.pat, &mut tys)) } fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) -> bool { @@ -178,7 +178,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) return false; // ignore `_` patterns } if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) { - is_mutable_ty(cx, &cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys) + is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys) } else { false } @@ -190,12 +190,12 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m match *ty.kind() { // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, - ty::Adt(ref adt, ref substs) => { + ty::Adt(adt, substs) => { tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env) || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path)) && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)) }, - ty::Tuple(ref substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)), + ty::Tuple(substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)), ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys), ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => { mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys) @@ -239,7 +239,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { tys.clear(); } }, - Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => { + Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { self.mutates_static |= is_mutated_static(target) }, _ => {}, @@ -257,7 +257,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool { match e.kind { Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), Path(_) => true, - Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(inner), + Field(inner, _) | Index(inner, _) => is_mutated_static(inner), _ => false, } } diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index cc69f4aed0c..b8ea6990866 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -27,7 +27,7 @@ pub(super) fn check_fn( pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind { let body = cx.tcx.hir().body(eid); - check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id()); + check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.hir_id()); } } @@ -77,7 +77,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { match expr.kind { - hir::ExprKind::Call(ref f, args) => { + hir::ExprKind::Call(f, args) => { let ty = self.typeck_results.expr_ty(f); if type_is_unsafe_function(self.cx, ty) { @@ -96,7 +96,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } } }, - hir::ExprKind::Unary(hir::UnOp::Deref, ref ptr) => self.check_arg(ptr), + hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => self.check_arg(ptr), _ => (), } diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs index 3d1092ce21f..c073f312d38 100644 --- a/clippy_lints/src/functions/result_unit_err.rs +++ b/clippy_lints/src/functions/result_unit_err.rs @@ -18,7 +18,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let is_public = cx.access_levels.is_exported(item.hir_id()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if is_public { - check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); + check_result_unit_err(cx, sig.decl, item.span, fn_header_span); } } } @@ -28,7 +28,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem< let is_public = cx.access_levels.is_exported(item.hir_id()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() { - check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); + check_result_unit_err(cx, sig.decl, item.span, fn_header_span); } } } @@ -38,7 +38,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte let is_public = cx.access_levels.is_exported(item.hir_id()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if is_public { - check_result_unit_err(cx, &sig.decl, item.span, fn_header_span); + check_result_unit_err(cx, sig.decl, item.span, fn_header_span); } } } @@ -46,7 +46,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) { if_chain! { if !in_external_macro(cx.sess(), item_span); - if let hir::FnRetTy::Return(ref ty) = decl.output; + if let hir::FnRetTy::Return(ty) = decl.output; let ty = hir_ty_to_ty(cx.tcx, ty); if is_type_diagnostic_item(cx, ty, sym::result_type); if let ty::Adt(_, substs) = ty.kind(); diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs index 62b1e6bd7ca..63a14d8d4cd 100644 --- a/clippy_lints/src/functions/too_many_arguments.rs +++ b/clippy_lints/src/functions/too_many_arguments.rs @@ -49,7 +49,7 @@ pub(super) fn check_trait_item( if sig.header.abi == Abi::Rust { check_arg_number( cx, - &sig.decl, + sig.decl, item.span.with_hi(sig.decl.output.span().hi()), too_many_arguments_threshold, ); diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index cbcef567c53..3707e792177 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for GetLastWithLen { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // Is a method call - if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, args, _) = expr.kind; // Method name is "get" if path.ident.name == sym!(get); diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 8bed5e1bf64..366b3b46a8a 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -35,7 +35,7 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp { if e.span.from_expansion() { return; } - if let ExprKind::Binary(cmp, ref left, ref right) = e.kind { + if let ExprKind::Binary(cmp, left, right) = e.kind { if is_allowed(cx, cmp, left, right) { return; } diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 56dfcc6a506..f661f7ede82 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -55,8 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { cx, }; if let ExprKind::Match( - ref op, - ref arms, + op, + arms, MatchSource::IfLetDesugar { contains_else_clause: true, }, @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { { op_visit.visit_expr(op); if op_visit.mutex_lock_called { - for arm in *arms { + for arm in arms { arm_visit.visit_arm(arm); } diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 6e9280c8c7e..611da3744ee 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -44,9 +44,9 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); impl<'tcx> LateLintPass<'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables - if let ExprKind::Match(ref op, ref body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let - if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) - if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation + if let ExprKind::Match(op, body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let + if let ExprKind::MethodCall(_, ok_span, result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) + if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type); if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0b5bf060d4c..ee16519692f 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -72,15 +72,15 @@ impl LateLintPass<'_> for IfThenSomeElseNone { } if_chain! { - if let ExprKind::If(ref cond, ref then, Some(ref els)) = expr.kind; - if let ExprKind::Block(ref then_block, _) = then.kind; - if let Some(ref then_expr) = then_block.expr; - if let ExprKind::Call(ref then_call, [then_arg]) = then_expr.kind; + if let ExprKind::If(cond, then, Some(els)) = expr.kind; + if let ExprKind::Block(then_block, _) = then.kind; + if let Some(then_expr) = then_block.expr; + if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind; if let ExprKind::Path(ref then_call_qpath) = then_call.kind; if match_qpath(then_call_qpath, &clippy_utils::paths::OPTION_SOME); - if let ExprKind::Block(ref els_block, _) = els.kind; + if let ExprKind::Block(els_block, _) = els.kind; if els_block.stmts.is_empty(); - if let Some(ref els_expr) = els_block.expr; + if let Some(els_expr) = els_block.expr; if let ExprKind::Path(ref els_call_qpath) = els_expr.kind; if match_qpath(els_call_qpath, &clippy_utils::paths::OPTION_NONE); then { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 0b748b4d72d..77a38544edc 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -207,7 +207,7 @@ enum ImplicitHasherType<'tcx> { impl<'tcx> ImplicitHasherType<'tcx> { /// Checks that `ty` is a target type without a `BuildHasher`. fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option { - if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.kind { + if let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind { let params: Vec<_> = path .segments .last() @@ -330,8 +330,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(ref fun, ref args) = e.kind; - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind; + if let ExprKind::Call(fun, args) = e.kind; + if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind; if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; then { if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 6863645a92d..6b379b0d59b 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -100,10 +100,10 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { if check_all_arms { for arm in arms { - expr_match(cx, &arm.body); + expr_match(cx, arm.body); } } else { - expr_match(cx, &arms.first().expect("`if let` doesn't have a single arm").body); + expr_match(cx, arms.first().expect("`if let` doesn't have a single arm").body); } }, // skip if it already has a return statement diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 5207c628987..cba3183e869 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -46,21 +46,21 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let ExprKind::If(cond, then, None) = &expr.kind; // Check if the conditional expression is a binary operation - if let ExprKind::Binary(ref cond_op, ref cond_left, ref cond_right) = cond.kind; + if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind; // Ensure that the binary operator is >, != and < if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node; // Check if the true condition block has only one statement - if let ExprKind::Block(ref block, _) = then.kind; + if let ExprKind::Block(block, _) = then.kind; if block.stmts.len() == 1 && block.expr.is_none(); // Check if assign operation is done - if let StmtKind::Semi(ref e) = block.stmts[0].kind; + if let StmtKind::Semi(e) = block.stmts[0].kind; if let Some(target) = subtracts_one(cx, e); // Extracting out the variable name - if let ExprKind::Path(QPath::Resolved(_, ref ares_path)) = target.kind; + if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind; then { // Handle symmetric conditions in the if statement @@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { print_lint_and_sugg(cx, &var_name, expr); }; }, - ExprKind::Call(ref func, _) => { + ExprKind::Call(func, _) => { if let ExprKind::Path(ref cond_num_path) = func.kind { if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) { print_lint_and_sugg(cx, &var_name, expr); @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'a>> { match expr.kind { - ExprKind::AssignOp(ref op1, ref target, ref value) => { + ExprKind::AssignOp(ref op1, target, value) => { if_chain! { if BinOpKind::Sub == op1.node; // Check if literal being subtracted is one @@ -133,9 +133,9 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<' } } }, - ExprKind::Assign(ref target, ref value, _) => { + ExprKind::Assign(target, value, _) => { if_chain! { - if let ExprKind::Binary(ref op1, ref left1, ref right1) = value.kind; + if let ExprKind::Binary(ref op1, left1, right1) = value.kind; if BinOpKind::Sub == op1.node; if SpanlessEq::new(cx).eq_expr(left1, target); diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 94d39019608..1c54599abc4 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -88,7 +88,7 @@ declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING] impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Index(ref array, ref index) = &expr.kind { + if let ExprKind::Index(array, index) = &expr.kind { let ty = cx.typeck_results().expr_ty(array).peel_refs(); if let Some(range) = higher::range(index) { // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index fb35bc1e780..bbb4ddc613a 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -139,7 +139,7 @@ const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(ref method, _, ref args, _) => { + ExprKind::MethodCall(method, _, args, _) => { for &(name, len, heuristic, cap) in &HEURISTICS { if method.ident.name.as_str() == name && args.len() == len { return (match heuristic { @@ -159,9 +159,9 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } Finite }, - ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), - ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) => is_infinite(cx, e), - ExprKind::Call(ref path, _) => { + ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), + ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), + ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind { match_qpath(qpath, &paths::REPEAT).into() } else { @@ -215,7 +215,7 @@ const INFINITE_COLLECTORS: [&[&str]; 8] = [ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(ref method, _, ref args, _) => { + ExprKind::MethodCall(method, _, args, _) => { for &(name, len) in &COMPLETING_METHODS { if method.ident.name.as_str() == name && args.len() == len { return is_infinite(cx, &args[0]); @@ -240,7 +240,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } }, - ExprKind::Binary(op, ref l, ref r) => { + ExprKind::Binary(op, l, r) => { if op.node.is_comparison() { return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite); } diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index d183fc41f31..c67c02eefa5 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -86,7 +86,7 @@ impl Ord for FullInt { } fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> { - if let ExprKind::Cast(ref cast_exp, _) = expr.kind { + if let ExprKind::Cast(cast_exp, _) = expr.kind { let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp); let cast_ty = cx.typeck_results().expr_ty(expr); // if it's a cast from i32 to u32 wrapping will invalidate all these checks @@ -131,7 +131,7 @@ fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> } fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) { - if let ExprKind::Cast(ref cast_val, _) = expr.kind { + if let ExprKind::Cast(cast_val, _) = expr.kind { span_lint( cx, INVALID_UPCAST_COMPARISONS, @@ -203,7 +203,7 @@ fn upcast_comparison_bounds_err<'tcx>( impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind { + if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind { let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs); let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { val diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 76584dc1822..f166748d86b 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { ); if variant.fields.len() == 1 { let span = match def.variants[i].data { - VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, ..) => { + VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) => { fields[0].ty.span }, VariantData::Unit(..) => unreachable!(), diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 78152ad9019..bb57adff7be 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { return; } - if let ItemKind::Trait(_, _, _, _, ref trait_items) = item.kind { + if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind { check_trait_items(cx, item, trait_items); } } @@ -162,7 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { return; } - if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.kind { + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { match cmp { BinOpKind::Eq => { check_cmp(cx, expr.span, left, right, "", 0); // len == 0 @@ -372,8 +372,7 @@ fn check_for_is_empty( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) - { + if let (&ExprKind::MethodCall(method_path, _, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -451,7 +450,7 @@ fn is_empty_string(expr: &Expr<'_>) -> bool { } fn is_empty_array(expr: &Expr<'_>) -> bool { - if let ExprKind::Array(ref arr) = expr.kind { + if let ExprKind::Array(arr) = expr.kind { return arr.is_empty(); } false @@ -480,17 +479,17 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { cx.tcx .associated_items(*imp) .in_definition_order() - .any(|item| is_is_empty(cx, &item)) + .any(|item| is_is_empty(cx, item)) }) } let ty = &cx.typeck_results().expr_ty(expr).peel_refs(); match ty.kind() { - ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { + ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| { cx.tcx .associated_items(principal.def_id()) .in_definition_order() - .any(|item| is_is_empty(cx, &item)) + .any(|item| is_is_empty(cx, item)) }), ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), ty::Adt(id, _) => has_is_empty_impl(cx, id.did), diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 2d7d9c9befb..67eae4d87bb 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -61,13 +61,13 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { while let Some(stmt) = it.next() { if_chain! { if let Some(expr) = it.peek(); - if let hir::StmtKind::Local(ref local) = stmt.kind; + if let hir::StmtKind::Local(local) = stmt.kind; if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; - if let hir::StmtKind::Expr(ref if_) = expr.kind; - if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind; + if let hir::StmtKind::Expr(if_) = expr.kind; + if let hir::ExprKind::If(cond, then, ref else_) = if_.kind; let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id); if !used_visitor.check_expr(cond); - if let hir::ExprKind::Block(ref then, _) = then.kind; + if let hir::ExprKind::Block(then, _) = then.kind; if let Some(value) = check_assign(cx, canonical_id, &*then); if !used_visitor.check_expr(value); then { @@ -79,20 +79,20 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { ); if has_interior_mutability { return; } - let (default_multi_stmts, default) = if let Some(ref else_) = *else_ { - if let hir::ExprKind::Block(ref else_, _) = else_.kind { + let (default_multi_stmts, default) = if let Some(else_) = *else_ { + if let hir::ExprKind::Block(else_, _) = else_.kind { if let Some(default) = check_assign(cx, canonical_id, else_) { (else_.stmts.len() > 1, default) - } else if let Some(ref default) = local.init { - (true, &**default) + } else if let Some(default) = local.init { + (true, default) } else { continue; } } else { continue; } - } else if let Some(ref default) = local.init { - (false, &**default) + } else if let Some(default) = local.init { + (false, default) } else { continue; }; @@ -144,8 +144,8 @@ fn check_assign<'tcx>( if_chain! { if block.expr.is_none(); if let Some(expr) = block.stmts.iter().last(); - if let hir::StmtKind::Semi(ref expr) = expr.kind; - if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind; + if let hir::StmtKind::Semi(expr) = expr.kind; + if let hir::ExprKind::Assign(var, value, _) = expr.kind; if path_to_local_id(var, decl); then { let mut v = LocalUsedVisitor::new(cx, decl); diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 7e3a76ded2c..17e23781db7 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if_chain! { if let PatKind::Wild = local.pat.kind; - if let Some(ref init) = local.init; + if let Some(init) = local.init; then { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 43e89c2475f..cd92b551abd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -541,482 +541,482 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: // begin register lints, do not remove this comment, it’s used in `update_lints` store.register_lints(&[ #[cfg(feature = "internal-lints")] - &utils::internal_lints::CLIPPY_LINTS_INTERNAL, + utils::internal_lints::CLIPPY_LINTS_INTERNAL, #[cfg(feature = "internal-lints")] - &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, + utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, #[cfg(feature = "internal-lints")] - &utils::internal_lints::COMPILER_LINT_FUNCTIONS, + utils::internal_lints::COMPILER_LINT_FUNCTIONS, #[cfg(feature = "internal-lints")] - &utils::internal_lints::DEFAULT_LINT, + utils::internal_lints::DEFAULT_LINT, #[cfg(feature = "internal-lints")] - &utils::internal_lints::IF_CHAIN_STYLE, + utils::internal_lints::IF_CHAIN_STYLE, #[cfg(feature = "internal-lints")] - &utils::internal_lints::INTERNING_DEFINED_SYMBOL, + utils::internal_lints::INTERNING_DEFINED_SYMBOL, #[cfg(feature = "internal-lints")] - &utils::internal_lints::INVALID_PATHS, + utils::internal_lints::INVALID_PATHS, #[cfg(feature = "internal-lints")] - &utils::internal_lints::LINT_WITHOUT_LINT_PASS, + utils::internal_lints::LINT_WITHOUT_LINT_PASS, #[cfg(feature = "internal-lints")] - &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, #[cfg(feature = "internal-lints")] - &utils::internal_lints::OUTER_EXPN_EXPN_DATA, + utils::internal_lints::OUTER_EXPN_EXPN_DATA, #[cfg(feature = "internal-lints")] - &utils::internal_lints::PRODUCE_ICE, + utils::internal_lints::PRODUCE_ICE, #[cfg(feature = "internal-lints")] - &utils::internal_lints::UNNECESSARY_SYMBOL_STR, - &absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, - &approx_const::APPROX_CONSTANT, - &arithmetic::FLOAT_ARITHMETIC, - &arithmetic::INTEGER_ARITHMETIC, - &as_conversions::AS_CONVERSIONS, - &asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, - &asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, - &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - &assign_ops::ASSIGN_OP_PATTERN, - &assign_ops::MISREFACTORED_ASSIGN_OP, - &async_yields_async::ASYNC_YIELDS_ASYNC, - &atomic_ordering::INVALID_ATOMIC_ORDERING, - &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, - &attrs::DEPRECATED_CFG_ATTR, - &attrs::DEPRECATED_SEMVER, - &attrs::EMPTY_LINE_AFTER_OUTER_ATTR, - &attrs::INLINE_ALWAYS, - &attrs::MISMATCHED_TARGET_OS, - &attrs::USELESS_ATTRIBUTE, - &await_holding_invalid::AWAIT_HOLDING_LOCK, - &await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - &bit_mask::BAD_BIT_MASK, - &bit_mask::INEFFECTIVE_BIT_MASK, - &bit_mask::VERBOSE_BIT_MASK, - &blacklisted_name::BLACKLISTED_NAME, - &blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, - &booleans::LOGIC_BUG, - &booleans::NONMINIMAL_BOOL, - &bytecount::NAIVE_BYTECOUNT, - &cargo_common_metadata::CARGO_COMMON_METADATA, - &case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - &casts::CAST_LOSSLESS, - &casts::CAST_POSSIBLE_TRUNCATION, - &casts::CAST_POSSIBLE_WRAP, - &casts::CAST_PRECISION_LOSS, - &casts::CAST_PTR_ALIGNMENT, - &casts::CAST_REF_TO_MUT, - &casts::CAST_SIGN_LOSS, - &casts::CHAR_LIT_AS_U8, - &casts::FN_TO_NUMERIC_CAST, - &casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - &casts::PTR_AS_PTR, - &casts::UNNECESSARY_CAST, - &checked_conversions::CHECKED_CONVERSIONS, - &cognitive_complexity::COGNITIVE_COMPLEXITY, - &collapsible_if::COLLAPSIBLE_ELSE_IF, - &collapsible_if::COLLAPSIBLE_IF, - &collapsible_match::COLLAPSIBLE_MATCH, - &comparison_chain::COMPARISON_CHAIN, - &copies::BRANCHES_SHARING_CODE, - &copies::IFS_SAME_COND, - &copies::IF_SAME_THEN_ELSE, - &copies::SAME_FUNCTIONS_IN_IF_CONDITION, - ©_iterator::COPY_ITERATOR, - &create_dir::CREATE_DIR, - &dbg_macro::DBG_MACRO, - &default::DEFAULT_TRAIT_ACCESS, - &default::FIELD_REASSIGN_WITH_DEFAULT, - &default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, - &dereference::EXPLICIT_DEREF_METHODS, - &derive::DERIVE_HASH_XOR_EQ, - &derive::DERIVE_ORD_XOR_PARTIAL_ORD, - &derive::EXPL_IMPL_CLONE_ON_COPY, - &derive::UNSAFE_DERIVE_DESERIALIZE, - &disallowed_method::DISALLOWED_METHOD, - &doc::DOC_MARKDOWN, - &doc::MISSING_ERRORS_DOC, - &doc::MISSING_PANICS_DOC, - &doc::MISSING_SAFETY_DOC, - &doc::NEEDLESS_DOCTEST_MAIN, - &double_comparison::DOUBLE_COMPARISONS, - &double_parens::DOUBLE_PARENS, - &drop_forget_ref::DROP_COPY, - &drop_forget_ref::DROP_REF, - &drop_forget_ref::FORGET_COPY, - &drop_forget_ref::FORGET_REF, - &duration_subsec::DURATION_SUBSEC, - &else_if_without_else::ELSE_IF_WITHOUT_ELSE, - &empty_enum::EMPTY_ENUM, - &entry::MAP_ENTRY, - &enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - &enum_variants::ENUM_VARIANT_NAMES, - &enum_variants::MODULE_INCEPTION, - &enum_variants::MODULE_NAME_REPETITIONS, - &enum_variants::PUB_ENUM_VARIANT_NAMES, - &eq_op::EQ_OP, - &eq_op::OP_REF, - &erasing_op::ERASING_OP, - &escape::BOXED_LOCAL, - &eta_reduction::REDUNDANT_CLOSURE, - &eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, - &eval_order_dependence::DIVERGING_SUB_EXPRESSION, - &eval_order_dependence::EVAL_ORDER_DEPENDENCE, - &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, - &excessive_bools::STRUCT_EXCESSIVE_BOOLS, - &exhaustive_items::EXHAUSTIVE_ENUMS, - &exhaustive_items::EXHAUSTIVE_STRUCTS, - &exit::EXIT, - &explicit_write::EXPLICIT_WRITE, - &fallible_impl_from::FALLIBLE_IMPL_FROM, - &float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, - &float_literal::EXCESSIVE_PRECISION, - &float_literal::LOSSY_FLOAT_LITERAL, - &floating_point_arithmetic::IMPRECISE_FLOPS, - &floating_point_arithmetic::SUBOPTIMAL_FLOPS, - &format::USELESS_FORMAT, - &formatting::POSSIBLE_MISSING_COMMA, - &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, - &formatting::SUSPICIOUS_ELSE_FORMATTING, - &formatting::SUSPICIOUS_UNARY_OP_FORMATTING, - &from_over_into::FROM_OVER_INTO, - &from_str_radix_10::FROM_STR_RADIX_10, - &functions::DOUBLE_MUST_USE, - &functions::MUST_USE_CANDIDATE, - &functions::MUST_USE_UNIT, - &functions::NOT_UNSAFE_PTR_ARG_DEREF, - &functions::RESULT_UNIT_ERR, - &functions::TOO_MANY_ARGUMENTS, - &functions::TOO_MANY_LINES, - &future_not_send::FUTURE_NOT_SEND, - &get_last_with_len::GET_LAST_WITH_LEN, - &identity_op::IDENTITY_OP, - &if_let_mutex::IF_LET_MUTEX, - &if_let_some_result::IF_LET_SOME_RESULT, - &if_not_else::IF_NOT_ELSE, - &if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, - &implicit_hasher::IMPLICIT_HASHER, - &implicit_return::IMPLICIT_RETURN, - &implicit_saturating_sub::IMPLICIT_SATURATING_SUB, - &inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, - &indexing_slicing::INDEXING_SLICING, - &indexing_slicing::OUT_OF_BOUNDS_INDEXING, - &infinite_iter::INFINITE_ITER, - &infinite_iter::MAYBE_INFINITE_ITER, - &inherent_impl::MULTIPLE_INHERENT_IMPL, - &inherent_to_string::INHERENT_TO_STRING, - &inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, - &inline_fn_without_body::INLINE_FN_WITHOUT_BODY, - &int_plus_one::INT_PLUS_ONE, - &integer_division::INTEGER_DIVISION, - &invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, - &items_after_statements::ITEMS_AFTER_STATEMENTS, - &large_const_arrays::LARGE_CONST_ARRAYS, - &large_enum_variant::LARGE_ENUM_VARIANT, - &large_stack_arrays::LARGE_STACK_ARRAYS, - &len_zero::COMPARISON_TO_EMPTY, - &len_zero::LEN_WITHOUT_IS_EMPTY, - &len_zero::LEN_ZERO, - &let_if_seq::USELESS_LET_IF_SEQ, - &let_underscore::LET_UNDERSCORE_DROP, - &let_underscore::LET_UNDERSCORE_LOCK, - &let_underscore::LET_UNDERSCORE_MUST_USE, - &lifetimes::EXTRA_UNUSED_LIFETIMES, - &lifetimes::NEEDLESS_LIFETIMES, - &literal_representation::DECIMAL_LITERAL_REPRESENTATION, - &literal_representation::INCONSISTENT_DIGIT_GROUPING, - &literal_representation::LARGE_DIGIT_GROUPS, - &literal_representation::MISTYPED_LITERAL_SUFFIXES, - &literal_representation::UNREADABLE_LITERAL, - &literal_representation::UNUSUAL_BYTE_GROUPINGS, - &loops::EMPTY_LOOP, - &loops::EXPLICIT_COUNTER_LOOP, - &loops::EXPLICIT_INTO_ITER_LOOP, - &loops::EXPLICIT_ITER_LOOP, - &loops::FOR_KV_MAP, - &loops::FOR_LOOPS_OVER_FALLIBLES, - &loops::ITER_NEXT_LOOP, - &loops::MANUAL_FLATTEN, - &loops::MANUAL_MEMCPY, - &loops::MUT_RANGE_BOUND, - &loops::NEEDLESS_COLLECT, - &loops::NEEDLESS_RANGE_LOOP, - &loops::NEVER_LOOP, - &loops::SAME_ITEM_PUSH, - &loops::SINGLE_ELEMENT_LOOP, - &loops::WHILE_IMMUTABLE_CONDITION, - &loops::WHILE_LET_LOOP, - &loops::WHILE_LET_ON_ITERATOR, - ¯o_use::MACRO_USE_IMPORTS, - &main_recursion::MAIN_RECURSION, - &manual_async_fn::MANUAL_ASYNC_FN, - &manual_map::MANUAL_MAP, - &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, - &manual_ok_or::MANUAL_OK_OR, - &manual_strip::MANUAL_STRIP, - &manual_unwrap_or::MANUAL_UNWRAP_OR, - &map_clone::MAP_CLONE, - &map_err_ignore::MAP_ERR_IGNORE, - &map_identity::MAP_IDENTITY, - &map_unit_fn::OPTION_MAP_UNIT_FN, - &map_unit_fn::RESULT_MAP_UNIT_FN, - &match_on_vec_items::MATCH_ON_VEC_ITEMS, - &matches::INFALLIBLE_DESTRUCTURING_MATCH, - &matches::MATCH_AS_REF, - &matches::MATCH_BOOL, - &matches::MATCH_LIKE_MATCHES_MACRO, - &matches::MATCH_OVERLAPPING_ARM, - &matches::MATCH_REF_PATS, - &matches::MATCH_SAME_ARMS, - &matches::MATCH_SINGLE_BINDING, - &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, - &matches::MATCH_WILD_ERR_ARM, - &matches::REDUNDANT_PATTERN_MATCHING, - &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, - &matches::SINGLE_MATCH, - &matches::SINGLE_MATCH_ELSE, - &matches::WILDCARD_ENUM_MATCH_ARM, - &matches::WILDCARD_IN_OR_PATTERNS, - &mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, - &mem_forget::MEM_FORGET, - &mem_replace::MEM_REPLACE_OPTION_WITH_NONE, - &mem_replace::MEM_REPLACE_WITH_DEFAULT, - &mem_replace::MEM_REPLACE_WITH_UNINIT, - &methods::BIND_INSTEAD_OF_MAP, - &methods::BYTES_NTH, - &methods::CHARS_LAST_CMP, - &methods::CHARS_NEXT_CMP, - &methods::CLONE_DOUBLE_REF, - &methods::CLONE_ON_COPY, - &methods::CLONE_ON_REF_PTR, - &methods::EXPECT_FUN_CALL, - &methods::EXPECT_USED, - &methods::FILETYPE_IS_FILE, - &methods::FILTER_MAP, - &methods::FILTER_MAP_IDENTITY, - &methods::FILTER_MAP_NEXT, - &methods::FILTER_NEXT, - &methods::FLAT_MAP_IDENTITY, - &methods::FROM_ITER_INSTEAD_OF_COLLECT, - &methods::GET_UNWRAP, - &methods::IMPLICIT_CLONE, - &methods::INEFFICIENT_TO_STRING, - &methods::INSPECT_FOR_EACH, - &methods::INTO_ITER_ON_REF, - &methods::ITERATOR_STEP_BY_ZERO, - &methods::ITER_CLONED_COLLECT, - &methods::ITER_COUNT, - &methods::ITER_NEXT_SLICE, - &methods::ITER_NTH, - &methods::ITER_NTH_ZERO, - &methods::ITER_SKIP_NEXT, - &methods::MANUAL_FILTER_MAP, - &methods::MANUAL_FIND_MAP, - &methods::MANUAL_SATURATING_ARITHMETIC, - &methods::MAP_COLLECT_RESULT_UNIT, - &methods::MAP_FLATTEN, - &methods::MAP_UNWRAP_OR, - &methods::NEW_RET_NO_SELF, - &methods::OK_EXPECT, - &methods::OPTION_AS_REF_DEREF, - &methods::OPTION_FILTER_MAP, - &methods::OPTION_MAP_OR_NONE, - &methods::OR_FUN_CALL, - &methods::RESULT_MAP_OR_INTO_OPTION, - &methods::SEARCH_IS_SOME, - &methods::SHOULD_IMPLEMENT_TRAIT, - &methods::SINGLE_CHAR_ADD_STR, - &methods::SINGLE_CHAR_PATTERN, - &methods::SKIP_WHILE_NEXT, - &methods::STRING_EXTEND_CHARS, - &methods::SUSPICIOUS_MAP, - &methods::UNINIT_ASSUMED_INIT, - &methods::UNNECESSARY_FILTER_MAP, - &methods::UNNECESSARY_FOLD, - &methods::UNNECESSARY_LAZY_EVALUATIONS, - &methods::UNWRAP_USED, - &methods::USELESS_ASREF, - &methods::WRONG_PUB_SELF_CONVENTION, - &methods::WRONG_SELF_CONVENTION, - &methods::ZST_OFFSET, - &minmax::MIN_MAX, - &misc::CMP_NAN, - &misc::CMP_OWNED, - &misc::FLOAT_CMP, - &misc::FLOAT_CMP_CONST, - &misc::MODULO_ONE, - &misc::SHORT_CIRCUIT_STATEMENT, - &misc::TOPLEVEL_REF_ARG, - &misc::USED_UNDERSCORE_BINDING, - &misc::ZERO_PTR, - &misc_early::BUILTIN_TYPE_SHADOW, - &misc_early::DOUBLE_NEG, - &misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, - &misc_early::MIXED_CASE_HEX_LITERALS, - &misc_early::REDUNDANT_PATTERN, - &misc_early::UNNEEDED_FIELD_PATTERN, - &misc_early::UNNEEDED_WILDCARD_PATTERN, - &misc_early::UNSEPARATED_LITERAL_SUFFIX, - &misc_early::ZERO_PREFIXED_LITERAL, - &missing_const_for_fn::MISSING_CONST_FOR_FN, - &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, - &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, - &modulo_arithmetic::MODULO_ARITHMETIC, - &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, - &mut_key::MUTABLE_KEY_TYPE, - &mut_mut::MUT_MUT, - &mut_mutex_lock::MUT_MUTEX_LOCK, - &mut_reference::UNNECESSARY_MUT_PASSED, - &mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, - &mutex_atomic::MUTEX_ATOMIC, - &mutex_atomic::MUTEX_INTEGER, - &needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, - &needless_bool::BOOL_COMPARISON, - &needless_bool::NEEDLESS_BOOL, - &needless_borrow::NEEDLESS_BORROW, - &needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, - &needless_continue::NEEDLESS_CONTINUE, - &needless_for_each::NEEDLESS_FOR_EACH, - &needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, - &needless_question_mark::NEEDLESS_QUESTION_MARK, - &needless_update::NEEDLESS_UPDATE, - &neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, - &neg_multiply::NEG_MULTIPLY, - &new_without_default::NEW_WITHOUT_DEFAULT, - &no_effect::NO_EFFECT, - &no_effect::UNNECESSARY_OPERATION, - &non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, - &non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, - &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, - &non_expressive_names::MANY_SINGLE_CHAR_NAMES, - &non_expressive_names::SIMILAR_NAMES, - &non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, - &open_options::NONSENSICAL_OPEN_OPTIONS, - &option_env_unwrap::OPTION_ENV_UNWRAP, - &option_if_let_else::OPTION_IF_LET_ELSE, - &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - &panic_in_result_fn::PANIC_IN_RESULT_FN, - &panic_unimplemented::PANIC, - &panic_unimplemented::TODO, - &panic_unimplemented::UNIMPLEMENTED, - &panic_unimplemented::UNREACHABLE, - &partialeq_ne_impl::PARTIALEQ_NE_IMPL, - &pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, - &pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, - &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, - &pattern_type_mismatch::PATTERN_TYPE_MISMATCH, - &precedence::PRECEDENCE, - &ptr::CMP_NULL, - &ptr::MUT_FROM_REF, - &ptr::PTR_ARG, - &ptr_eq::PTR_EQ, - &ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, - &question_mark::QUESTION_MARK, - &ranges::MANUAL_RANGE_CONTAINS, - &ranges::RANGE_MINUS_ONE, - &ranges::RANGE_PLUS_ONE, - &ranges::RANGE_ZIP_WITH_LEN, - &ranges::REVERSED_EMPTY_RANGES, - &redundant_clone::REDUNDANT_CLONE, - &redundant_closure_call::REDUNDANT_CLOSURE_CALL, - &redundant_else::REDUNDANT_ELSE, - &redundant_field_names::REDUNDANT_FIELD_NAMES, - &redundant_pub_crate::REDUNDANT_PUB_CRATE, - &redundant_slicing::REDUNDANT_SLICING, - &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, - &ref_option_ref::REF_OPTION_REF, - &reference::DEREF_ADDROF, - &reference::REF_IN_DEREF, - ®ex::INVALID_REGEX, - ®ex::TRIVIAL_REGEX, - &repeat_once::REPEAT_ONCE, - &returns::LET_AND_RETURN, - &returns::NEEDLESS_RETURN, - &self_assignment::SELF_ASSIGNMENT, - &semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, - &serde_api::SERDE_API_MISUSE, - &shadow::SHADOW_REUSE, - &shadow::SHADOW_SAME, - &shadow::SHADOW_UNRELATED, - &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, - &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, - &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - &stable_sort_primitive::STABLE_SORT_PRIMITIVE, - &strings::STRING_ADD, - &strings::STRING_ADD_ASSIGN, - &strings::STRING_FROM_UTF8_AS_BYTES, - &strings::STRING_LIT_AS_BYTES, - &strings::STRING_TO_STRING, - &strings::STR_TO_STRING, - &suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, - &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, - &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, - &swap::ALMOST_SWAPPED, - &swap::MANUAL_SWAP, - &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, - &temporary_assignment::TEMPORARY_ASSIGNMENT, - &to_digit_is_some::TO_DIGIT_IS_SOME, - &to_string_in_display::TO_STRING_IN_DISPLAY, - &trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, - &trait_bounds::TYPE_REPETITION_IN_BOUNDS, - &transmute::CROSSPOINTER_TRANSMUTE, - &transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, - &transmute::TRANSMUTE_BYTES_TO_STR, - &transmute::TRANSMUTE_FLOAT_TO_INT, - &transmute::TRANSMUTE_INT_TO_BOOL, - &transmute::TRANSMUTE_INT_TO_CHAR, - &transmute::TRANSMUTE_INT_TO_FLOAT, - &transmute::TRANSMUTE_PTR_TO_PTR, - &transmute::TRANSMUTE_PTR_TO_REF, - &transmute::UNSOUND_COLLECTION_TRANSMUTE, - &transmute::USELESS_TRANSMUTE, - &transmute::WRONG_TRANSMUTE, - &transmuting_null::TRANSMUTING_NULL, - &try_err::TRY_ERR, - &types::BORROWED_BOX, - &types::BOX_VEC, - &types::LINKEDLIST, - &types::OPTION_OPTION, - &types::RC_BUFFER, - &types::REDUNDANT_ALLOCATION, - &types::TYPE_COMPLEXITY, - &types::VEC_BOX, - &undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, - &unicode::INVISIBLE_CHARACTERS, - &unicode::NON_ASCII_LITERAL, - &unicode::UNICODE_NOT_NFC, - &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, - &unit_types::LET_UNIT_VALUE, - &unit_types::UNIT_ARG, - &unit_types::UNIT_CMP, - &unnamed_address::FN_ADDRESS_COMPARISONS, - &unnamed_address::VTABLE_ADDRESS_COMPARISONS, - &unnecessary_sort_by::UNNECESSARY_SORT_BY, - &unnecessary_wraps::UNNECESSARY_WRAPS, - &unnested_or_patterns::UNNESTED_OR_PATTERNS, - &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - &unused_io_amount::UNUSED_IO_AMOUNT, - &unused_self::UNUSED_SELF, - &unused_unit::UNUSED_UNIT, - &unwrap::PANICKING_UNWRAP, - &unwrap::UNNECESSARY_UNWRAP, - &unwrap_in_result::UNWRAP_IN_RESULT, - &upper_case_acronyms::UPPER_CASE_ACRONYMS, - &use_self::USE_SELF, - &useless_conversion::USELESS_CONVERSION, - &vec::USELESS_VEC, - &vec_init_then_push::VEC_INIT_THEN_PUSH, - &vec_resize_to_zero::VEC_RESIZE_TO_ZERO, - &verbose_file_reads::VERBOSE_FILE_READS, - &wildcard_dependencies::WILDCARD_DEPENDENCIES, - &wildcard_imports::ENUM_GLOB_USE, - &wildcard_imports::WILDCARD_IMPORTS, - &write::PRINTLN_EMPTY_STRING, - &write::PRINT_LITERAL, - &write::PRINT_STDERR, - &write::PRINT_STDOUT, - &write::PRINT_WITH_NEWLINE, - &write::USE_DEBUG, - &write::WRITELN_EMPTY_STRING, - &write::WRITE_LITERAL, - &write::WRITE_WITH_NEWLINE, - &zero_div_zero::ZERO_DIVIDED_BY_ZERO, - &zero_sized_map_values::ZERO_SIZED_MAP_VALUES, + utils::internal_lints::UNNECESSARY_SYMBOL_STR, + absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, + approx_const::APPROX_CONSTANT, + arithmetic::FLOAT_ARITHMETIC, + arithmetic::INTEGER_ARITHMETIC, + as_conversions::AS_CONVERSIONS, + asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, + asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, + assertions_on_constants::ASSERTIONS_ON_CONSTANTS, + assign_ops::ASSIGN_OP_PATTERN, + assign_ops::MISREFACTORED_ASSIGN_OP, + async_yields_async::ASYNC_YIELDS_ASYNC, + atomic_ordering::INVALID_ATOMIC_ORDERING, + attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, + attrs::DEPRECATED_CFG_ATTR, + attrs::DEPRECATED_SEMVER, + attrs::EMPTY_LINE_AFTER_OUTER_ATTR, + attrs::INLINE_ALWAYS, + attrs::MISMATCHED_TARGET_OS, + attrs::USELESS_ATTRIBUTE, + await_holding_invalid::AWAIT_HOLDING_LOCK, + await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, + bit_mask::BAD_BIT_MASK, + bit_mask::INEFFECTIVE_BIT_MASK, + bit_mask::VERBOSE_BIT_MASK, + blacklisted_name::BLACKLISTED_NAME, + blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, + booleans::LOGIC_BUG, + booleans::NONMINIMAL_BOOL, + bytecount::NAIVE_BYTECOUNT, + cargo_common_metadata::CARGO_COMMON_METADATA, + case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::CAST_LOSSLESS, + casts::CAST_POSSIBLE_TRUNCATION, + casts::CAST_POSSIBLE_WRAP, + casts::CAST_PRECISION_LOSS, + casts::CAST_PTR_ALIGNMENT, + casts::CAST_REF_TO_MUT, + casts::CAST_SIGN_LOSS, + casts::CHAR_LIT_AS_U8, + casts::FN_TO_NUMERIC_CAST, + casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + casts::PTR_AS_PTR, + casts::UNNECESSARY_CAST, + checked_conversions::CHECKED_CONVERSIONS, + cognitive_complexity::COGNITIVE_COMPLEXITY, + collapsible_if::COLLAPSIBLE_ELSE_IF, + collapsible_if::COLLAPSIBLE_IF, + collapsible_match::COLLAPSIBLE_MATCH, + comparison_chain::COMPARISON_CHAIN, + copies::BRANCHES_SHARING_CODE, + copies::IFS_SAME_COND, + copies::IF_SAME_THEN_ELSE, + copies::SAME_FUNCTIONS_IN_IF_CONDITION, + copy_iterator::COPY_ITERATOR, + create_dir::CREATE_DIR, + dbg_macro::DBG_MACRO, + default::DEFAULT_TRAIT_ACCESS, + default::FIELD_REASSIGN_WITH_DEFAULT, + default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, + dereference::EXPLICIT_DEREF_METHODS, + derive::DERIVE_HASH_XOR_EQ, + derive::DERIVE_ORD_XOR_PARTIAL_ORD, + derive::EXPL_IMPL_CLONE_ON_COPY, + derive::UNSAFE_DERIVE_DESERIALIZE, + disallowed_method::DISALLOWED_METHOD, + doc::DOC_MARKDOWN, + doc::MISSING_ERRORS_DOC, + doc::MISSING_PANICS_DOC, + doc::MISSING_SAFETY_DOC, + doc::NEEDLESS_DOCTEST_MAIN, + double_comparison::DOUBLE_COMPARISONS, + double_parens::DOUBLE_PARENS, + drop_forget_ref::DROP_COPY, + drop_forget_ref::DROP_REF, + drop_forget_ref::FORGET_COPY, + drop_forget_ref::FORGET_REF, + duration_subsec::DURATION_SUBSEC, + else_if_without_else::ELSE_IF_WITHOUT_ELSE, + empty_enum::EMPTY_ENUM, + entry::MAP_ENTRY, + enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, + enum_variants::ENUM_VARIANT_NAMES, + enum_variants::MODULE_INCEPTION, + enum_variants::MODULE_NAME_REPETITIONS, + enum_variants::PUB_ENUM_VARIANT_NAMES, + eq_op::EQ_OP, + eq_op::OP_REF, + erasing_op::ERASING_OP, + escape::BOXED_LOCAL, + eta_reduction::REDUNDANT_CLOSURE, + eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, + eval_order_dependence::DIVERGING_SUB_EXPRESSION, + eval_order_dependence::EVAL_ORDER_DEPENDENCE, + excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, + excessive_bools::STRUCT_EXCESSIVE_BOOLS, + exhaustive_items::EXHAUSTIVE_ENUMS, + exhaustive_items::EXHAUSTIVE_STRUCTS, + exit::EXIT, + explicit_write::EXPLICIT_WRITE, + fallible_impl_from::FALLIBLE_IMPL_FROM, + float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, + float_literal::EXCESSIVE_PRECISION, + float_literal::LOSSY_FLOAT_LITERAL, + floating_point_arithmetic::IMPRECISE_FLOPS, + floating_point_arithmetic::SUBOPTIMAL_FLOPS, + format::USELESS_FORMAT, + formatting::POSSIBLE_MISSING_COMMA, + formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, + formatting::SUSPICIOUS_ELSE_FORMATTING, + formatting::SUSPICIOUS_UNARY_OP_FORMATTING, + from_over_into::FROM_OVER_INTO, + from_str_radix_10::FROM_STR_RADIX_10, + functions::DOUBLE_MUST_USE, + functions::MUST_USE_CANDIDATE, + functions::MUST_USE_UNIT, + functions::NOT_UNSAFE_PTR_ARG_DEREF, + functions::RESULT_UNIT_ERR, + functions::TOO_MANY_ARGUMENTS, + functions::TOO_MANY_LINES, + future_not_send::FUTURE_NOT_SEND, + get_last_with_len::GET_LAST_WITH_LEN, + identity_op::IDENTITY_OP, + if_let_mutex::IF_LET_MUTEX, + if_let_some_result::IF_LET_SOME_RESULT, + if_not_else::IF_NOT_ELSE, + if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, + implicit_hasher::IMPLICIT_HASHER, + implicit_return::IMPLICIT_RETURN, + implicit_saturating_sub::IMPLICIT_SATURATING_SUB, + inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, + indexing_slicing::INDEXING_SLICING, + indexing_slicing::OUT_OF_BOUNDS_INDEXING, + infinite_iter::INFINITE_ITER, + infinite_iter::MAYBE_INFINITE_ITER, + inherent_impl::MULTIPLE_INHERENT_IMPL, + inherent_to_string::INHERENT_TO_STRING, + inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, + inline_fn_without_body::INLINE_FN_WITHOUT_BODY, + int_plus_one::INT_PLUS_ONE, + integer_division::INTEGER_DIVISION, + invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, + items_after_statements::ITEMS_AFTER_STATEMENTS, + large_const_arrays::LARGE_CONST_ARRAYS, + large_enum_variant::LARGE_ENUM_VARIANT, + large_stack_arrays::LARGE_STACK_ARRAYS, + len_zero::COMPARISON_TO_EMPTY, + len_zero::LEN_WITHOUT_IS_EMPTY, + len_zero::LEN_ZERO, + let_if_seq::USELESS_LET_IF_SEQ, + let_underscore::LET_UNDERSCORE_DROP, + let_underscore::LET_UNDERSCORE_LOCK, + let_underscore::LET_UNDERSCORE_MUST_USE, + lifetimes::EXTRA_UNUSED_LIFETIMES, + lifetimes::NEEDLESS_LIFETIMES, + literal_representation::DECIMAL_LITERAL_REPRESENTATION, + literal_representation::INCONSISTENT_DIGIT_GROUPING, + literal_representation::LARGE_DIGIT_GROUPS, + literal_representation::MISTYPED_LITERAL_SUFFIXES, + literal_representation::UNREADABLE_LITERAL, + literal_representation::UNUSUAL_BYTE_GROUPINGS, + loops::EMPTY_LOOP, + loops::EXPLICIT_COUNTER_LOOP, + loops::EXPLICIT_INTO_ITER_LOOP, + loops::EXPLICIT_ITER_LOOP, + loops::FOR_KV_MAP, + loops::FOR_LOOPS_OVER_FALLIBLES, + loops::ITER_NEXT_LOOP, + loops::MANUAL_FLATTEN, + loops::MANUAL_MEMCPY, + loops::MUT_RANGE_BOUND, + loops::NEEDLESS_COLLECT, + loops::NEEDLESS_RANGE_LOOP, + loops::NEVER_LOOP, + loops::SAME_ITEM_PUSH, + loops::SINGLE_ELEMENT_LOOP, + loops::WHILE_IMMUTABLE_CONDITION, + loops::WHILE_LET_LOOP, + loops::WHILE_LET_ON_ITERATOR, + macro_use::MACRO_USE_IMPORTS, + main_recursion::MAIN_RECURSION, + manual_async_fn::MANUAL_ASYNC_FN, + manual_map::MANUAL_MAP, + manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, + manual_ok_or::MANUAL_OK_OR, + manual_strip::MANUAL_STRIP, + manual_unwrap_or::MANUAL_UNWRAP_OR, + map_clone::MAP_CLONE, + map_err_ignore::MAP_ERR_IGNORE, + map_identity::MAP_IDENTITY, + map_unit_fn::OPTION_MAP_UNIT_FN, + map_unit_fn::RESULT_MAP_UNIT_FN, + match_on_vec_items::MATCH_ON_VEC_ITEMS, + matches::INFALLIBLE_DESTRUCTURING_MATCH, + matches::MATCH_AS_REF, + matches::MATCH_BOOL, + matches::MATCH_LIKE_MATCHES_MACRO, + matches::MATCH_OVERLAPPING_ARM, + matches::MATCH_REF_PATS, + matches::MATCH_SAME_ARMS, + matches::MATCH_SINGLE_BINDING, + matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + matches::MATCH_WILD_ERR_ARM, + matches::REDUNDANT_PATTERN_MATCHING, + matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, + matches::SINGLE_MATCH, + matches::SINGLE_MATCH_ELSE, + matches::WILDCARD_ENUM_MATCH_ARM, + matches::WILDCARD_IN_OR_PATTERNS, + mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, + mem_forget::MEM_FORGET, + mem_replace::MEM_REPLACE_OPTION_WITH_NONE, + mem_replace::MEM_REPLACE_WITH_DEFAULT, + mem_replace::MEM_REPLACE_WITH_UNINIT, + methods::BIND_INSTEAD_OF_MAP, + methods::BYTES_NTH, + methods::CHARS_LAST_CMP, + methods::CHARS_NEXT_CMP, + methods::CLONE_DOUBLE_REF, + methods::CLONE_ON_COPY, + methods::CLONE_ON_REF_PTR, + methods::EXPECT_FUN_CALL, + methods::EXPECT_USED, + methods::FILETYPE_IS_FILE, + methods::FILTER_MAP, + methods::FILTER_MAP_IDENTITY, + methods::FILTER_MAP_NEXT, + methods::FILTER_NEXT, + methods::FLAT_MAP_IDENTITY, + methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_UNWRAP, + methods::IMPLICIT_CLONE, + methods::INEFFICIENT_TO_STRING, + methods::INSPECT_FOR_EACH, + methods::INTO_ITER_ON_REF, + methods::ITERATOR_STEP_BY_ZERO, + methods::ITER_CLONED_COLLECT, + methods::ITER_COUNT, + methods::ITER_NEXT_SLICE, + methods::ITER_NTH, + methods::ITER_NTH_ZERO, + methods::ITER_SKIP_NEXT, + methods::MANUAL_FILTER_MAP, + methods::MANUAL_FIND_MAP, + methods::MANUAL_SATURATING_ARITHMETIC, + methods::MAP_COLLECT_RESULT_UNIT, + methods::MAP_FLATTEN, + methods::MAP_UNWRAP_OR, + methods::NEW_RET_NO_SELF, + methods::OK_EXPECT, + methods::OPTION_AS_REF_DEREF, + methods::OPTION_FILTER_MAP, + methods::OPTION_MAP_OR_NONE, + methods::OR_FUN_CALL, + methods::RESULT_MAP_OR_INTO_OPTION, + methods::SEARCH_IS_SOME, + methods::SHOULD_IMPLEMENT_TRAIT, + methods::SINGLE_CHAR_ADD_STR, + methods::SINGLE_CHAR_PATTERN, + methods::SKIP_WHILE_NEXT, + methods::STRING_EXTEND_CHARS, + methods::SUSPICIOUS_MAP, + methods::UNINIT_ASSUMED_INIT, + methods::UNNECESSARY_FILTER_MAP, + methods::UNNECESSARY_FOLD, + methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNWRAP_USED, + methods::USELESS_ASREF, + methods::WRONG_PUB_SELF_CONVENTION, + methods::WRONG_SELF_CONVENTION, + methods::ZST_OFFSET, + minmax::MIN_MAX, + misc::CMP_NAN, + misc::CMP_OWNED, + misc::FLOAT_CMP, + misc::FLOAT_CMP_CONST, + misc::MODULO_ONE, + misc::SHORT_CIRCUIT_STATEMENT, + misc::TOPLEVEL_REF_ARG, + misc::USED_UNDERSCORE_BINDING, + misc::ZERO_PTR, + misc_early::BUILTIN_TYPE_SHADOW, + misc_early::DOUBLE_NEG, + misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + misc_early::MIXED_CASE_HEX_LITERALS, + misc_early::REDUNDANT_PATTERN, + misc_early::UNNEEDED_FIELD_PATTERN, + misc_early::UNNEEDED_WILDCARD_PATTERN, + misc_early::UNSEPARATED_LITERAL_SUFFIX, + misc_early::ZERO_PREFIXED_LITERAL, + missing_const_for_fn::MISSING_CONST_FOR_FN, + missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, + missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + modulo_arithmetic::MODULO_ARITHMETIC, + multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, + mut_key::MUTABLE_KEY_TYPE, + mut_mut::MUT_MUT, + mut_mutex_lock::MUT_MUTEX_LOCK, + mut_reference::UNNECESSARY_MUT_PASSED, + mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, + mutex_atomic::MUTEX_ATOMIC, + mutex_atomic::MUTEX_INTEGER, + needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, + needless_bool::BOOL_COMPARISON, + needless_bool::NEEDLESS_BOOL, + needless_borrow::NEEDLESS_BORROW, + needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, + needless_continue::NEEDLESS_CONTINUE, + needless_for_each::NEEDLESS_FOR_EACH, + needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, + needless_question_mark::NEEDLESS_QUESTION_MARK, + needless_update::NEEDLESS_UPDATE, + neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, + neg_multiply::NEG_MULTIPLY, + new_without_default::NEW_WITHOUT_DEFAULT, + no_effect::NO_EFFECT, + no_effect::UNNECESSARY_OPERATION, + non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, + non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, + non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, + non_expressive_names::MANY_SINGLE_CHAR_NAMES, + non_expressive_names::SIMILAR_NAMES, + non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, + open_options::NONSENSICAL_OPEN_OPTIONS, + option_env_unwrap::OPTION_ENV_UNWRAP, + option_if_let_else::OPTION_IF_LET_ELSE, + overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, + panic_in_result_fn::PANIC_IN_RESULT_FN, + panic_unimplemented::PANIC, + panic_unimplemented::TODO, + panic_unimplemented::UNIMPLEMENTED, + panic_unimplemented::UNREACHABLE, + partialeq_ne_impl::PARTIALEQ_NE_IMPL, + pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, + pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, + path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + pattern_type_mismatch::PATTERN_TYPE_MISMATCH, + precedence::PRECEDENCE, + ptr::CMP_NULL, + ptr::MUT_FROM_REF, + ptr::PTR_ARG, + ptr_eq::PTR_EQ, + ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, + question_mark::QUESTION_MARK, + ranges::MANUAL_RANGE_CONTAINS, + ranges::RANGE_MINUS_ONE, + ranges::RANGE_PLUS_ONE, + ranges::RANGE_ZIP_WITH_LEN, + ranges::REVERSED_EMPTY_RANGES, + redundant_clone::REDUNDANT_CLONE, + redundant_closure_call::REDUNDANT_CLOSURE_CALL, + redundant_else::REDUNDANT_ELSE, + redundant_field_names::REDUNDANT_FIELD_NAMES, + redundant_pub_crate::REDUNDANT_PUB_CRATE, + redundant_slicing::REDUNDANT_SLICING, + redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, + ref_option_ref::REF_OPTION_REF, + reference::DEREF_ADDROF, + reference::REF_IN_DEREF, + regex::INVALID_REGEX, + regex::TRIVIAL_REGEX, + repeat_once::REPEAT_ONCE, + returns::LET_AND_RETURN, + returns::NEEDLESS_RETURN, + self_assignment::SELF_ASSIGNMENT, + semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, + serde_api::SERDE_API_MISUSE, + shadow::SHADOW_REUSE, + shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, + single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, + size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, + slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, + stable_sort_primitive::STABLE_SORT_PRIMITIVE, + strings::STRING_ADD, + strings::STRING_ADD_ASSIGN, + strings::STRING_FROM_UTF8_AS_BYTES, + strings::STRING_LIT_AS_BYTES, + strings::STRING_TO_STRING, + strings::STR_TO_STRING, + suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, + suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, + suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, + swap::ALMOST_SWAPPED, + swap::MANUAL_SWAP, + tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, + temporary_assignment::TEMPORARY_ASSIGNMENT, + to_digit_is_some::TO_DIGIT_IS_SOME, + to_string_in_display::TO_STRING_IN_DISPLAY, + trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, + trait_bounds::TYPE_REPETITION_IN_BOUNDS, + transmute::CROSSPOINTER_TRANSMUTE, + transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, + transmute::TRANSMUTE_BYTES_TO_STR, + transmute::TRANSMUTE_FLOAT_TO_INT, + transmute::TRANSMUTE_INT_TO_BOOL, + transmute::TRANSMUTE_INT_TO_CHAR, + transmute::TRANSMUTE_INT_TO_FLOAT, + transmute::TRANSMUTE_PTR_TO_PTR, + transmute::TRANSMUTE_PTR_TO_REF, + transmute::UNSOUND_COLLECTION_TRANSMUTE, + transmute::USELESS_TRANSMUTE, + transmute::WRONG_TRANSMUTE, + transmuting_null::TRANSMUTING_NULL, + try_err::TRY_ERR, + types::BORROWED_BOX, + types::BOX_VEC, + types::LINKEDLIST, + types::OPTION_OPTION, + types::RC_BUFFER, + types::REDUNDANT_ALLOCATION, + types::TYPE_COMPLEXITY, + types::VEC_BOX, + undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, + unicode::INVISIBLE_CHARACTERS, + unicode::NON_ASCII_LITERAL, + unicode::UNICODE_NOT_NFC, + unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, + unit_types::LET_UNIT_VALUE, + unit_types::UNIT_ARG, + unit_types::UNIT_CMP, + unnamed_address::FN_ADDRESS_COMPARISONS, + unnamed_address::VTABLE_ADDRESS_COMPARISONS, + unnecessary_sort_by::UNNECESSARY_SORT_BY, + unnecessary_wraps::UNNECESSARY_WRAPS, + unnested_or_patterns::UNNESTED_OR_PATTERNS, + unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_io_amount::UNUSED_IO_AMOUNT, + unused_self::UNUSED_SELF, + unused_unit::UNUSED_UNIT, + unwrap::PANICKING_UNWRAP, + unwrap::UNNECESSARY_UNWRAP, + unwrap_in_result::UNWRAP_IN_RESULT, + upper_case_acronyms::UPPER_CASE_ACRONYMS, + use_self::USE_SELF, + useless_conversion::USELESS_CONVERSION, + vec::USELESS_VEC, + vec_init_then_push::VEC_INIT_THEN_PUSH, + vec_resize_to_zero::VEC_RESIZE_TO_ZERO, + verbose_file_reads::VERBOSE_FILE_READS, + wildcard_dependencies::WILDCARD_DEPENDENCIES, + wildcard_imports::ENUM_GLOB_USE, + wildcard_imports::WILDCARD_IMPORTS, + write::PRINTLN_EMPTY_STRING, + write::PRINT_LITERAL, + write::PRINT_STDERR, + write::PRINT_STDOUT, + write::PRINT_WITH_NEWLINE, + write::USE_DEBUG, + write::WRITELN_EMPTY_STRING, + write::WRITE_LITERAL, + write::WRITE_WITH_NEWLINE, + zero_div_zero::ZERO_DIVIDED_BY_ZERO, + zero_sized_map_values::ZERO_SIZED_MAP_VALUES, ]); // end register lints, do not remove this comment, it’s used in `update_lints` @@ -1295,792 +1295,792 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv)); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ - LintId::of(&arithmetic::FLOAT_ARITHMETIC), - LintId::of(&arithmetic::INTEGER_ARITHMETIC), - LintId::of(&as_conversions::AS_CONVERSIONS), - LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), - LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), - LintId::of(&create_dir::CREATE_DIR), - LintId::of(&dbg_macro::DBG_MACRO), - LintId::of(&default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), - LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), - LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS), - LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS), - LintId::of(&exit::EXIT), - LintId::of(&float_literal::LOSSY_FLOAT_LITERAL), - LintId::of(&if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), - LintId::of(&implicit_return::IMPLICIT_RETURN), - LintId::of(&indexing_slicing::INDEXING_SLICING), - LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL), - LintId::of(&integer_division::INTEGER_DIVISION), - LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), - LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(&map_err_ignore::MAP_ERR_IGNORE), - LintId::of(&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), - LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), - LintId::of(&mem_forget::MEM_FORGET), - LintId::of(&methods::CLONE_ON_REF_PTR), - LintId::of(&methods::EXPECT_USED), - LintId::of(&methods::FILETYPE_IS_FILE), - LintId::of(&methods::GET_UNWRAP), - LintId::of(&methods::UNWRAP_USED), - LintId::of(&methods::WRONG_PUB_SELF_CONVENTION), - LintId::of(&misc::FLOAT_CMP_CONST), - LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), - LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), - LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), - LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), - LintId::of(&panic_in_result_fn::PANIC_IN_RESULT_FN), - LintId::of(&panic_unimplemented::PANIC), - LintId::of(&panic_unimplemented::TODO), - LintId::of(&panic_unimplemented::UNIMPLEMENTED), - LintId::of(&panic_unimplemented::UNREACHABLE), - LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH), - LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), - LintId::of(&shadow::SHADOW_REUSE), - LintId::of(&shadow::SHADOW_SAME), - LintId::of(&strings::STRING_ADD), - LintId::of(&strings::STRING_TO_STRING), - LintId::of(&strings::STR_TO_STRING), - LintId::of(&types::RC_BUFFER), - LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT), - LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), - LintId::of(&write::PRINT_STDERR), - LintId::of(&write::PRINT_STDOUT), - LintId::of(&write::USE_DEBUG), + LintId::of(arithmetic::FLOAT_ARITHMETIC), + LintId::of(arithmetic::INTEGER_ARITHMETIC), + LintId::of(as_conversions::AS_CONVERSIONS), + LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), + LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(create_dir::CREATE_DIR), + LintId::of(dbg_macro::DBG_MACRO), + LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), + LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE), + LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS), + LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS), + LintId::of(exit::EXIT), + LintId::of(float_literal::LOSSY_FLOAT_LITERAL), + LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), + LintId::of(implicit_return::IMPLICIT_RETURN), + LintId::of(indexing_slicing::INDEXING_SLICING), + LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), + LintId::of(integer_division::INTEGER_DIVISION), + LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), + LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(map_err_ignore::MAP_ERR_IGNORE), + LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), + LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), + LintId::of(mem_forget::MEM_FORGET), + LintId::of(methods::CLONE_ON_REF_PTR), + LintId::of(methods::EXPECT_USED), + LintId::of(methods::FILETYPE_IS_FILE), + LintId::of(methods::GET_UNWRAP), + LintId::of(methods::UNWRAP_USED), + LintId::of(methods::WRONG_PUB_SELF_CONVENTION), + LintId::of(misc::FLOAT_CMP_CONST), + LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), + LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), + LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), + LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), + LintId::of(panic_unimplemented::PANIC), + LintId::of(panic_unimplemented::TODO), + LintId::of(panic_unimplemented::UNIMPLEMENTED), + LintId::of(panic_unimplemented::UNREACHABLE), + LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), + LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), + LintId::of(shadow::SHADOW_REUSE), + LintId::of(shadow::SHADOW_SAME), + LintId::of(strings::STRING_ADD), + LintId::of(strings::STRING_TO_STRING), + LintId::of(strings::STR_TO_STRING), + LintId::of(types::RC_BUFFER), + LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), + LintId::of(verbose_file_reads::VERBOSE_FILE_READS), + LintId::of(write::PRINT_STDERR), + LintId::of(write::PRINT_STDOUT), + LintId::of(write::USE_DEBUG), ]); store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ - LintId::of(&attrs::INLINE_ALWAYS), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(&bit_mask::VERBOSE_BIT_MASK), - LintId::of(&bytecount::NAIVE_BYTECOUNT), - LintId::of(&case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), - LintId::of(&casts::CAST_LOSSLESS), - LintId::of(&casts::CAST_POSSIBLE_TRUNCATION), - LintId::of(&casts::CAST_POSSIBLE_WRAP), - LintId::of(&casts::CAST_PRECISION_LOSS), - LintId::of(&casts::CAST_PTR_ALIGNMENT), - LintId::of(&casts::CAST_SIGN_LOSS), - LintId::of(&casts::PTR_AS_PTR), - LintId::of(&checked_conversions::CHECKED_CONVERSIONS), - LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), - LintId::of(©_iterator::COPY_ITERATOR), - LintId::of(&default::DEFAULT_TRAIT_ACCESS), - LintId::of(&dereference::EXPLICIT_DEREF_METHODS), - LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), - LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), - LintId::of(&doc::DOC_MARKDOWN), - LintId::of(&doc::MISSING_ERRORS_DOC), - LintId::of(&doc::MISSING_PANICS_DOC), - LintId::of(&empty_enum::EMPTY_ENUM), - LintId::of(&enum_variants::MODULE_NAME_REPETITIONS), - LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES), - LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), - LintId::of(&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), - LintId::of(&excessive_bools::STRUCT_EXCESSIVE_BOOLS), - LintId::of(&functions::MUST_USE_CANDIDATE), - LintId::of(&functions::TOO_MANY_LINES), - LintId::of(&if_not_else::IF_NOT_ELSE), - LintId::of(&implicit_hasher::IMPLICIT_HASHER), - LintId::of(&implicit_saturating_sub::IMPLICIT_SATURATING_SUB), - LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), - LintId::of(&invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), - LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), - LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), - LintId::of(&let_underscore::LET_UNDERSCORE_DROP), - LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), - LintId::of(&literal_representation::UNREADABLE_LITERAL), - LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), - LintId::of(&loops::EXPLICIT_ITER_LOOP), - LintId::of(¯o_use::MACRO_USE_IMPORTS), - LintId::of(&manual_ok_or::MANUAL_OK_OR), - LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), - LintId::of(&matches::MATCH_BOOL), - LintId::of(&matches::MATCH_SAME_ARMS), - LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), - LintId::of(&matches::MATCH_WILD_ERR_ARM), - LintId::of(&matches::SINGLE_MATCH_ELSE), - LintId::of(&methods::FILTER_MAP), - LintId::of(&methods::FILTER_MAP_NEXT), - LintId::of(&methods::IMPLICIT_CLONE), - LintId::of(&methods::INEFFICIENT_TO_STRING), - LintId::of(&methods::MAP_FLATTEN), - LintId::of(&methods::MAP_UNWRAP_OR), - LintId::of(&misc::USED_UNDERSCORE_BINDING), - LintId::of(&misc_early::UNSEPARATED_LITERAL_SUFFIX), - LintId::of(&mut_mut::MUT_MUT), - LintId::of(&needless_continue::NEEDLESS_CONTINUE), - LintId::of(&needless_for_each::NEEDLESS_FOR_EACH), - LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), - LintId::of(&non_expressive_names::SIMILAR_NAMES), - LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE), - LintId::of(&pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), - LintId::of(&pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), - LintId::of(&ranges::RANGE_MINUS_ONE), - LintId::of(&ranges::RANGE_PLUS_ONE), - LintId::of(&redundant_else::REDUNDANT_ELSE), - LintId::of(&ref_option_ref::REF_OPTION_REF), - LintId::of(&shadow::SHADOW_UNRELATED), - LintId::of(&strings::STRING_ADD_ASSIGN), - LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), - LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS), - LintId::of(&types::LINKEDLIST), - LintId::of(&types::OPTION_OPTION), - LintId::of(&unicode::NON_ASCII_LITERAL), - LintId::of(&unicode::UNICODE_NOT_NFC), - LintId::of(&unit_types::LET_UNIT_VALUE), - LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), - LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS), - LintId::of(&unused_self::UNUSED_SELF), - LintId::of(&wildcard_imports::ENUM_GLOB_USE), - LintId::of(&wildcard_imports::WILDCARD_IMPORTS), - LintId::of(&zero_sized_map_values::ZERO_SIZED_MAP_VALUES), + LintId::of(attrs::INLINE_ALWAYS), + LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), + LintId::of(bit_mask::VERBOSE_BIT_MASK), + LintId::of(bytecount::NAIVE_BYTECOUNT), + LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), + LintId::of(casts::CAST_LOSSLESS), + LintId::of(casts::CAST_POSSIBLE_TRUNCATION), + LintId::of(casts::CAST_POSSIBLE_WRAP), + LintId::of(casts::CAST_PRECISION_LOSS), + LintId::of(casts::CAST_PTR_ALIGNMENT), + LintId::of(casts::CAST_SIGN_LOSS), + LintId::of(casts::PTR_AS_PTR), + LintId::of(checked_conversions::CHECKED_CONVERSIONS), + LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION), + LintId::of(copy_iterator::COPY_ITERATOR), + LintId::of(default::DEFAULT_TRAIT_ACCESS), + LintId::of(dereference::EXPLICIT_DEREF_METHODS), + LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY), + LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE), + LintId::of(doc::DOC_MARKDOWN), + LintId::of(doc::MISSING_ERRORS_DOC), + LintId::of(doc::MISSING_PANICS_DOC), + LintId::of(empty_enum::EMPTY_ENUM), + LintId::of(enum_variants::MODULE_NAME_REPETITIONS), + LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES), + LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), + LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), + LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), + LintId::of(functions::MUST_USE_CANDIDATE), + LintId::of(functions::TOO_MANY_LINES), + LintId::of(if_not_else::IF_NOT_ELSE), + LintId::of(implicit_hasher::IMPLICIT_HASHER), + LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), + LintId::of(infinite_iter::MAYBE_INFINITE_ITER), + LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), + LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), + LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(let_underscore::LET_UNDERSCORE_DROP), + LintId::of(literal_representation::LARGE_DIGIT_GROUPS), + LintId::of(literal_representation::UNREADABLE_LITERAL), + LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), + LintId::of(loops::EXPLICIT_ITER_LOOP), + LintId::of(macro_use::MACRO_USE_IMPORTS), + LintId::of(manual_ok_or::MANUAL_OK_OR), + LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), + LintId::of(matches::MATCH_BOOL), + LintId::of(matches::MATCH_SAME_ARMS), + LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), + LintId::of(matches::MATCH_WILD_ERR_ARM), + LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::FILTER_MAP), + LintId::of(methods::FILTER_MAP_NEXT), + LintId::of(methods::IMPLICIT_CLONE), + LintId::of(methods::INEFFICIENT_TO_STRING), + LintId::of(methods::MAP_FLATTEN), + LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(misc::USED_UNDERSCORE_BINDING), + LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), + LintId::of(mut_mut::MUT_MUT), + LintId::of(needless_continue::NEEDLESS_CONTINUE), + LintId::of(needless_for_each::NEEDLESS_FOR_EACH), + LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), + LintId::of(non_expressive_names::SIMILAR_NAMES), + LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), + LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), + LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), + LintId::of(ranges::RANGE_MINUS_ONE), + LintId::of(ranges::RANGE_PLUS_ONE), + LintId::of(redundant_else::REDUNDANT_ELSE), + LintId::of(ref_option_ref::REF_OPTION_REF), + LintId::of(shadow::SHADOW_UNRELATED), + LintId::of(strings::STRING_ADD_ASSIGN), + LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), + LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), + LintId::of(types::LINKEDLIST), + LintId::of(types::OPTION_OPTION), + LintId::of(unicode::NON_ASCII_LITERAL), + LintId::of(unicode::UNICODE_NOT_NFC), + LintId::of(unit_types::LET_UNIT_VALUE), + LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), + LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS), + LintId::of(unused_self::UNUSED_SELF), + LintId::of(wildcard_imports::ENUM_GLOB_USE), + LintId::of(wildcard_imports::WILDCARD_IMPORTS), + LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES), ]); #[cfg(feature = "internal-lints")] store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ - LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL), - LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), - LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), - LintId::of(&utils::internal_lints::DEFAULT_LINT), - LintId::of(&utils::internal_lints::IF_CHAIN_STYLE), - LintId::of(&utils::internal_lints::INTERNING_DEFINED_SYMBOL), - LintId::of(&utils::internal_lints::INVALID_PATHS), - LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), - LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), - LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA), - LintId::of(&utils::internal_lints::PRODUCE_ICE), - LintId::of(&utils::internal_lints::UNNECESSARY_SYMBOL_STR), + LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL), + LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), + LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS), + LintId::of(utils::internal_lints::DEFAULT_LINT), + LintId::of(utils::internal_lints::IF_CHAIN_STYLE), + LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL), + LintId::of(utils::internal_lints::INVALID_PATHS), + LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), + LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), + LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), + LintId::of(utils::internal_lints::PRODUCE_ICE), + LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), ]); store.register_group(true, "clippy::all", Some("clippy"), vec![ - LintId::of(&absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), - LintId::of(&approx_const::APPROX_CONSTANT), - LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(&assign_ops::ASSIGN_OP_PATTERN), - LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), - LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), - LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), - LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), - LintId::of(&attrs::DEPRECATED_CFG_ATTR), - LintId::of(&attrs::DEPRECATED_SEMVER), - LintId::of(&attrs::MISMATCHED_TARGET_OS), - LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&bit_mask::BAD_BIT_MASK), - LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(&blacklisted_name::BLACKLISTED_NAME), - LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), - LintId::of(&booleans::LOGIC_BUG), - LintId::of(&booleans::NONMINIMAL_BOOL), - LintId::of(&casts::CAST_REF_TO_MUT), - LintId::of(&casts::CHAR_LIT_AS_U8), - LintId::of(&casts::FN_TO_NUMERIC_CAST), - LintId::of(&casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(&casts::UNNECESSARY_CAST), - LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF), - LintId::of(&collapsible_if::COLLAPSIBLE_IF), - LintId::of(&collapsible_match::COLLAPSIBLE_MATCH), - LintId::of(&comparison_chain::COMPARISON_CHAIN), - LintId::of(&copies::BRANCHES_SHARING_CODE), - LintId::of(&copies::IFS_SAME_COND), - LintId::of(&copies::IF_SAME_THEN_ELSE), - LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT), - LintId::of(&derive::DERIVE_HASH_XOR_EQ), - LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(&doc::MISSING_SAFETY_DOC), - LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(&double_comparison::DOUBLE_COMPARISONS), - LintId::of(&double_parens::DOUBLE_PARENS), - LintId::of(&drop_forget_ref::DROP_COPY), - LintId::of(&drop_forget_ref::DROP_REF), - LintId::of(&drop_forget_ref::FORGET_COPY), - LintId::of(&drop_forget_ref::FORGET_REF), - LintId::of(&duration_subsec::DURATION_SUBSEC), - LintId::of(&entry::MAP_ENTRY), - LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(&enum_variants::ENUM_VARIANT_NAMES), - LintId::of(&enum_variants::MODULE_INCEPTION), - LintId::of(&eq_op::EQ_OP), - LintId::of(&eq_op::OP_REF), - LintId::of(&erasing_op::ERASING_OP), - LintId::of(&escape::BOXED_LOCAL), - LintId::of(&eta_reduction::REDUNDANT_CLOSURE), - LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(&explicit_write::EXPLICIT_WRITE), - LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), - LintId::of(&float_literal::EXCESSIVE_PRECISION), - LintId::of(&format::USELESS_FORMAT), - LintId::of(&formatting::POSSIBLE_MISSING_COMMA), - LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), - LintId::of(&from_over_into::FROM_OVER_INTO), - LintId::of(&from_str_radix_10::FROM_STR_RADIX_10), - LintId::of(&functions::DOUBLE_MUST_USE), - LintId::of(&functions::MUST_USE_UNIT), - LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), - LintId::of(&functions::RESULT_UNIT_ERR), - LintId::of(&functions::TOO_MANY_ARGUMENTS), - LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(&identity_op::IDENTITY_OP), - LintId::of(&if_let_mutex::IF_LET_MUTEX), - LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), - LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(&infinite_iter::INFINITE_ITER), - LintId::of(&inherent_to_string::INHERENT_TO_STRING), - LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), - LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(&int_plus_one::INT_PLUS_ONE), - LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS), - LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), - LintId::of(&len_zero::COMPARISON_TO_EMPTY), - LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), - LintId::of(&len_zero::LEN_ZERO), - LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), - LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), - LintId::of(&lifetimes::NEEDLESS_LIFETIMES), - LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(&literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(&loops::EMPTY_LOOP), - LintId::of(&loops::EXPLICIT_COUNTER_LOOP), - LintId::of(&loops::FOR_KV_MAP), - LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), - LintId::of(&loops::ITER_NEXT_LOOP), - LintId::of(&loops::MANUAL_FLATTEN), - LintId::of(&loops::MANUAL_MEMCPY), - LintId::of(&loops::MUT_RANGE_BOUND), - LintId::of(&loops::NEEDLESS_COLLECT), - LintId::of(&loops::NEEDLESS_RANGE_LOOP), - LintId::of(&loops::NEVER_LOOP), - LintId::of(&loops::SAME_ITEM_PUSH), - LintId::of(&loops::SINGLE_ELEMENT_LOOP), - LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(&loops::WHILE_LET_LOOP), - LintId::of(&loops::WHILE_LET_ON_ITERATOR), - LintId::of(&main_recursion::MAIN_RECURSION), - LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), - LintId::of(&manual_map::MANUAL_MAP), - LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(&manual_strip::MANUAL_STRIP), - LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(&map_clone::MAP_CLONE), - LintId::of(&map_identity::MAP_IDENTITY), - LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), - LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(&matches::MATCH_AS_REF), - LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), - LintId::of(&matches::MATCH_OVERLAPPING_ARM), - LintId::of(&matches::MATCH_REF_PATS), - LintId::of(&matches::MATCH_SINGLE_BINDING), - LintId::of(&matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(&matches::SINGLE_MATCH), - LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), - LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), - LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), - LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(&methods::BIND_INSTEAD_OF_MAP), - LintId::of(&methods::BYTES_NTH), - LintId::of(&methods::CHARS_LAST_CMP), - LintId::of(&methods::CHARS_NEXT_CMP), - LintId::of(&methods::CLONE_DOUBLE_REF), - LintId::of(&methods::CLONE_ON_COPY), - LintId::of(&methods::EXPECT_FUN_CALL), - LintId::of(&methods::FILTER_MAP_IDENTITY), - LintId::of(&methods::FILTER_NEXT), - LintId::of(&methods::FLAT_MAP_IDENTITY), - LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), - LintId::of(&methods::INSPECT_FOR_EACH), - LintId::of(&methods::INTO_ITER_ON_REF), - LintId::of(&methods::ITERATOR_STEP_BY_ZERO), - LintId::of(&methods::ITER_CLONED_COLLECT), - LintId::of(&methods::ITER_COUNT), - LintId::of(&methods::ITER_NEXT_SLICE), - LintId::of(&methods::ITER_NTH), - LintId::of(&methods::ITER_NTH_ZERO), - LintId::of(&methods::ITER_SKIP_NEXT), - LintId::of(&methods::MANUAL_FILTER_MAP), - LintId::of(&methods::MANUAL_FIND_MAP), - LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), - LintId::of(&methods::NEW_RET_NO_SELF), - LintId::of(&methods::OK_EXPECT), - LintId::of(&methods::OPTION_AS_REF_DEREF), - LintId::of(&methods::OPTION_FILTER_MAP), - LintId::of(&methods::OPTION_MAP_OR_NONE), - LintId::of(&methods::OR_FUN_CALL), - LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), - LintId::of(&methods::SEARCH_IS_SOME), - LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(&methods::SINGLE_CHAR_ADD_STR), - LintId::of(&methods::SINGLE_CHAR_PATTERN), - LintId::of(&methods::SKIP_WHILE_NEXT), - LintId::of(&methods::STRING_EXTEND_CHARS), - LintId::of(&methods::SUSPICIOUS_MAP), - LintId::of(&methods::UNINIT_ASSUMED_INIT), - LintId::of(&methods::UNNECESSARY_FILTER_MAP), - LintId::of(&methods::UNNECESSARY_FOLD), - LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), - LintId::of(&methods::USELESS_ASREF), - LintId::of(&methods::WRONG_SELF_CONVENTION), - LintId::of(&methods::ZST_OFFSET), - LintId::of(&minmax::MIN_MAX), - LintId::of(&misc::CMP_NAN), - LintId::of(&misc::CMP_OWNED), - LintId::of(&misc::FLOAT_CMP), - LintId::of(&misc::MODULO_ONE), - LintId::of(&misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(&misc::TOPLEVEL_REF_ARG), - LintId::of(&misc::ZERO_PTR), - LintId::of(&misc_early::BUILTIN_TYPE_SHADOW), - LintId::of(&misc_early::DOUBLE_NEG), - LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), - LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS), - LintId::of(&misc_early::REDUNDANT_PATTERN), - LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), - LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(&mut_key::MUTABLE_KEY_TYPE), - LintId::of(&mut_mutex_lock::MUT_MUTEX_LOCK), - LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(&mutex_atomic::MUTEX_ATOMIC), - LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), - LintId::of(&needless_bool::BOOL_COMPARISON), - LintId::of(&needless_bool::NEEDLESS_BOOL), - LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK), - LintId::of(&needless_update::NEEDLESS_UPDATE), - LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), - LintId::of(&neg_multiply::NEG_MULTIPLY), - LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), - LintId::of(&no_effect::NO_EFFECT), - LintId::of(&no_effect::UNNECESSARY_OPERATION), - LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), - LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), - LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), - LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), - LintId::of(&precedence::PRECEDENCE), - LintId::of(&ptr::CMP_NULL), - LintId::of(&ptr::MUT_FROM_REF), - LintId::of(&ptr::PTR_ARG), - LintId::of(&ptr_eq::PTR_EQ), - LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(&question_mark::QUESTION_MARK), - LintId::of(&ranges::MANUAL_RANGE_CONTAINS), - LintId::of(&ranges::RANGE_ZIP_WITH_LEN), - LintId::of(&ranges::REVERSED_EMPTY_RANGES), - LintId::of(&redundant_clone::REDUNDANT_CLONE), - LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL), - LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(&redundant_slicing::REDUNDANT_SLICING), - LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(&reference::DEREF_ADDROF), - LintId::of(&reference::REF_IN_DEREF), - LintId::of(®ex::INVALID_REGEX), - LintId::of(&repeat_once::REPEAT_ONCE), - LintId::of(&returns::LET_AND_RETURN), - LintId::of(&returns::NEEDLESS_RETURN), - LintId::of(&self_assignment::SELF_ASSIGNMENT), - LintId::of(&serde_api::SERDE_API_MISUSE), - LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), - LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), - LintId::of(&swap::ALMOST_SWAPPED), - LintId::of(&swap::MANUAL_SWAP), - LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), - LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), - LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), - LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), - LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), - LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT), - LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), - LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR), - LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), - LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR), - LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(&transmute::WRONG_TRANSMUTE), - LintId::of(&transmuting_null::TRANSMUTING_NULL), - LintId::of(&try_err::TRY_ERR), - LintId::of(&types::BORROWED_BOX), - LintId::of(&types::BOX_VEC), - LintId::of(&types::REDUNDANT_ALLOCATION), - LintId::of(&types::TYPE_COMPLEXITY), - LintId::of(&types::VEC_BOX), - LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), - LintId::of(&unicode::INVISIBLE_CHARACTERS), - LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), - LintId::of(&unit_types::UNIT_ARG), - LintId::of(&unit_types::UNIT_CMP), - LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), - LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(&unused_unit::UNUSED_UNIT), - LintId::of(&unwrap::PANICKING_UNWRAP), - LintId::of(&unwrap::UNNECESSARY_UNWRAP), - LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS), - LintId::of(&useless_conversion::USELESS_CONVERSION), - LintId::of(&vec::USELESS_VEC), - LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), - LintId::of(&write::PRINTLN_EMPTY_STRING), - LintId::of(&write::PRINT_LITERAL), - LintId::of(&write::PRINT_WITH_NEWLINE), - LintId::of(&write::WRITELN_EMPTY_STRING), - LintId::of(&write::WRITE_LITERAL), - LintId::of(&write::WRITE_WITH_NEWLINE), - LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), + LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(approx_const::APPROX_CONSTANT), + LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assign_ops::ASSIGN_OP_PATTERN), + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), + LintId::of(atomic_ordering::INVALID_ATOMIC_ORDERING), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(attrs::DEPRECATED_CFG_ATTR), + LintId::of(attrs::DEPRECATED_SEMVER), + LintId::of(attrs::MISMATCHED_TARGET_OS), + LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(bit_mask::BAD_BIT_MASK), + LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(blacklisted_name::BLACKLISTED_NAME), + LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), + LintId::of(booleans::LOGIC_BUG), + LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CAST_REF_TO_MUT), + LintId::of(casts::CHAR_LIT_AS_U8), + LintId::of(casts::FN_TO_NUMERIC_CAST), + LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(casts::UNNECESSARY_CAST), + LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), + LintId::of(collapsible_if::COLLAPSIBLE_IF), + LintId::of(collapsible_match::COLLAPSIBLE_MATCH), + LintId::of(comparison_chain::COMPARISON_CHAIN), + LintId::of(copies::BRANCHES_SHARING_CODE), + LintId::of(copies::IFS_SAME_COND), + LintId::of(copies::IF_SAME_THEN_ELSE), + LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(derive::DERIVE_HASH_XOR_EQ), + LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(doc::MISSING_SAFETY_DOC), + LintId::of(doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(double_comparison::DOUBLE_COMPARISONS), + LintId::of(double_parens::DOUBLE_PARENS), + LintId::of(drop_forget_ref::DROP_COPY), + LintId::of(drop_forget_ref::DROP_REF), + LintId::of(drop_forget_ref::FORGET_COPY), + LintId::of(drop_forget_ref::FORGET_REF), + LintId::of(duration_subsec::DURATION_SUBSEC), + LintId::of(entry::MAP_ENTRY), + LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(enum_variants::ENUM_VARIANT_NAMES), + LintId::of(enum_variants::MODULE_INCEPTION), + LintId::of(eq_op::EQ_OP), + LintId::of(eq_op::OP_REF), + LintId::of(erasing_op::ERASING_OP), + LintId::of(escape::BOXED_LOCAL), + LintId::of(eta_reduction::REDUNDANT_CLOSURE), + LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(explicit_write::EXPLICIT_WRITE), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(float_literal::EXCESSIVE_PRECISION), + LintId::of(format::USELESS_FORMAT), + LintId::of(formatting::POSSIBLE_MISSING_COMMA), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(from_over_into::FROM_OVER_INTO), + LintId::of(from_str_radix_10::FROM_STR_RADIX_10), + LintId::of(functions::DOUBLE_MUST_USE), + LintId::of(functions::MUST_USE_UNIT), + LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(functions::RESULT_UNIT_ERR), + LintId::of(functions::TOO_MANY_ARGUMENTS), + LintId::of(get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(identity_op::IDENTITY_OP), + LintId::of(if_let_mutex::IF_LET_MUTEX), + LintId::of(if_let_some_result::IF_LET_SOME_RESULT), + LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), + LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(infinite_iter::INFINITE_ITER), + LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(int_plus_one::INT_PLUS_ONE), + LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), + LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(len_zero::COMPARISON_TO_EMPTY), + LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(len_zero::LEN_ZERO), + LintId::of(let_underscore::LET_UNDERSCORE_LOCK), + LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(lifetimes::NEEDLESS_LIFETIMES), + LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::FOR_KV_MAP), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::MANUAL_FLATTEN), + LintId::of(loops::MANUAL_MEMCPY), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(loops::NEEDLESS_RANGE_LOOP), + LintId::of(loops::NEVER_LOOP), + LintId::of(loops::SAME_ITEM_PUSH), + LintId::of(loops::SINGLE_ELEMENT_LOOP), + LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(loops::WHILE_LET_LOOP), + LintId::of(loops::WHILE_LET_ON_ITERATOR), + LintId::of(main_recursion::MAIN_RECURSION), + LintId::of(manual_async_fn::MANUAL_ASYNC_FN), + LintId::of(manual_map::MANUAL_MAP), + LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(manual_strip::MANUAL_STRIP), + LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), + LintId::of(map_clone::MAP_CLONE), + LintId::of(map_identity::MAP_IDENTITY), + LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(matches::MATCH_AS_REF), + LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), + LintId::of(matches::MATCH_OVERLAPPING_ARM), + LintId::of(matches::MATCH_REF_PATS), + LintId::of(matches::MATCH_SINGLE_BINDING), + LintId::of(matches::REDUNDANT_PATTERN_MATCHING), + LintId::of(matches::SINGLE_MATCH), + LintId::of(matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), + LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_NTH), + LintId::of(methods::CHARS_LAST_CMP), + LintId::of(methods::CHARS_NEXT_CMP), + LintId::of(methods::CLONE_DOUBLE_REF), + LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::FILTER_MAP_IDENTITY), + LintId::of(methods::FILTER_NEXT), + LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), + LintId::of(methods::INSPECT_FOR_EACH), + LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::ITER_CLONED_COLLECT), + LintId::of(methods::ITER_COUNT), + LintId::of(methods::ITER_NEXT_SLICE), + LintId::of(methods::ITER_NTH), + LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_SKIP_NEXT), + LintId::of(methods::MANUAL_FILTER_MAP), + LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OK_EXPECT), + LintId::of(methods::OPTION_AS_REF_DEREF), + LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::OPTION_MAP_OR_NONE), + LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), + LintId::of(methods::SEARCH_IS_SOME), + LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(methods::SINGLE_CHAR_ADD_STR), + LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(methods::SKIP_WHILE_NEXT), + LintId::of(methods::STRING_EXTEND_CHARS), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNNECESSARY_FILTER_MAP), + LintId::of(methods::UNNECESSARY_FOLD), + LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::USELESS_ASREF), + LintId::of(methods::WRONG_SELF_CONVENTION), + LintId::of(methods::ZST_OFFSET), + LintId::of(minmax::MIN_MAX), + LintId::of(misc::CMP_NAN), + LintId::of(misc::CMP_OWNED), + LintId::of(misc::FLOAT_CMP), + LintId::of(misc::MODULO_ONE), + LintId::of(misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(misc::TOPLEVEL_REF_ARG), + LintId::of(misc::ZERO_PTR), + LintId::of(misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(misc_early::DOUBLE_NEG), + LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(misc_early::REDUNDANT_PATTERN), + LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), + LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(mutex_atomic::MUTEX_ATOMIC), + LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), + LintId::of(needless_bool::BOOL_COMPARISON), + LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), + LintId::of(needless_update::NEEDLESS_UPDATE), + LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(neg_multiply::NEG_MULTIPLY), + LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(no_effect::NO_EFFECT), + LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), + LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), + LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(precedence::PRECEDENCE), + LintId::of(ptr::CMP_NULL), + LintId::of(ptr::MUT_FROM_REF), + LintId::of(ptr::PTR_ARG), + LintId::of(ptr_eq::PTR_EQ), + LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(question_mark::QUESTION_MARK), + LintId::of(ranges::MANUAL_RANGE_CONTAINS), + LintId::of(ranges::RANGE_ZIP_WITH_LEN), + LintId::of(ranges::REVERSED_EMPTY_RANGES), + LintId::of(redundant_clone::REDUNDANT_CLONE), + LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), + LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(redundant_slicing::REDUNDANT_SLICING), + LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(reference::DEREF_ADDROF), + LintId::of(reference::REF_IN_DEREF), + LintId::of(regex::INVALID_REGEX), + LintId::of(repeat_once::REPEAT_ONCE), + LintId::of(returns::LET_AND_RETURN), + LintId::of(returns::NEEDLESS_RETURN), + LintId::of(self_assignment::SELF_ASSIGNMENT), + LintId::of(serde_api::SERDE_API_MISUSE), + LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), + LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + LintId::of(swap::ALMOST_SWAPPED), + LintId::of(swap::MANUAL_SWAP), + LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), + LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), + LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), + LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), + LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(transmute::WRONG_TRANSMUTE), + LintId::of(transmuting_null::TRANSMUTING_NULL), + LintId::of(try_err::TRY_ERR), + LintId::of(types::BORROWED_BOX), + LintId::of(types::BOX_VEC), + LintId::of(types::REDUNDANT_ALLOCATION), + LintId::of(types::TYPE_COMPLEXITY), + LintId::of(types::VEC_BOX), + LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), + LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(unit_types::UNIT_ARG), + LintId::of(unit_types::UNIT_CMP), + LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unused_unit::UNUSED_UNIT), + LintId::of(unwrap::PANICKING_UNWRAP), + LintId::of(unwrap::UNNECESSARY_UNWRAP), + LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), + LintId::of(useless_conversion::USELESS_CONVERSION), + LintId::of(vec::USELESS_VEC), + LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), + LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), + LintId::of(write::PRINTLN_EMPTY_STRING), + LintId::of(write::PRINT_LITERAL), + LintId::of(write::PRINT_WITH_NEWLINE), + LintId::of(write::WRITELN_EMPTY_STRING), + LintId::of(write::WRITE_LITERAL), + LintId::of(write::WRITE_WITH_NEWLINE), + LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); store.register_group(true, "clippy::style", Some("clippy_style"), vec![ - LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(&assign_ops::ASSIGN_OP_PATTERN), - LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), - LintId::of(&blacklisted_name::BLACKLISTED_NAME), - LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), - LintId::of(&casts::FN_TO_NUMERIC_CAST), - LintId::of(&casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF), - LintId::of(&collapsible_if::COLLAPSIBLE_IF), - LintId::of(&collapsible_match::COLLAPSIBLE_MATCH), - LintId::of(&comparison_chain::COMPARISON_CHAIN), - LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT), - LintId::of(&doc::MISSING_SAFETY_DOC), - LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(&enum_variants::ENUM_VARIANT_NAMES), - LintId::of(&enum_variants::MODULE_INCEPTION), - LintId::of(&eq_op::OP_REF), - LintId::of(&eta_reduction::REDUNDANT_CLOSURE), - LintId::of(&float_literal::EXCESSIVE_PRECISION), - LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), - LintId::of(&from_over_into::FROM_OVER_INTO), - LintId::of(&from_str_radix_10::FROM_STR_RADIX_10), - LintId::of(&functions::DOUBLE_MUST_USE), - LintId::of(&functions::MUST_USE_UNIT), - LintId::of(&functions::RESULT_UNIT_ERR), - LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), - LintId::of(&inherent_to_string::INHERENT_TO_STRING), - LintId::of(&len_zero::COMPARISON_TO_EMPTY), - LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), - LintId::of(&len_zero::LEN_ZERO), - LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(&literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(&loops::EMPTY_LOOP), - LintId::of(&loops::FOR_KV_MAP), - LintId::of(&loops::NEEDLESS_RANGE_LOOP), - LintId::of(&loops::SAME_ITEM_PUSH), - LintId::of(&loops::WHILE_LET_ON_ITERATOR), - LintId::of(&main_recursion::MAIN_RECURSION), - LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), - LintId::of(&manual_map::MANUAL_MAP), - LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(&map_clone::MAP_CLONE), - LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO), - LintId::of(&matches::MATCH_OVERLAPPING_ARM), - LintId::of(&matches::MATCH_REF_PATS), - LintId::of(&matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(&matches::SINGLE_MATCH), - LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), - LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), - LintId::of(&methods::BYTES_NTH), - LintId::of(&methods::CHARS_LAST_CMP), - LintId::of(&methods::CHARS_NEXT_CMP), - LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), - LintId::of(&methods::INTO_ITER_ON_REF), - LintId::of(&methods::ITER_CLONED_COLLECT), - LintId::of(&methods::ITER_NEXT_SLICE), - LintId::of(&methods::ITER_NTH_ZERO), - LintId::of(&methods::ITER_SKIP_NEXT), - LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), - LintId::of(&methods::NEW_RET_NO_SELF), - LintId::of(&methods::OK_EXPECT), - LintId::of(&methods::OPTION_MAP_OR_NONE), - LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), - LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(&methods::SINGLE_CHAR_ADD_STR), - LintId::of(&methods::STRING_EXTEND_CHARS), - LintId::of(&methods::UNNECESSARY_FOLD), - LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), - LintId::of(&methods::WRONG_SELF_CONVENTION), - LintId::of(&misc::TOPLEVEL_REF_ARG), - LintId::of(&misc::ZERO_PTR), - LintId::of(&misc_early::BUILTIN_TYPE_SHADOW), - LintId::of(&misc_early::DOUBLE_NEG), - LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), - LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS), - LintId::of(&misc_early::REDUNDANT_PATTERN), - LintId::of(&mut_mutex_lock::MUT_MUTEX_LOCK), - LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(&neg_multiply::NEG_MULTIPLY), - LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), - LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), - LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), - LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&ptr::CMP_NULL), - LintId::of(&ptr::PTR_ARG), - LintId::of(&ptr_eq::PTR_EQ), - LintId::of(&question_mark::QUESTION_MARK), - LintId::of(&ranges::MANUAL_RANGE_CONTAINS), - LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(&returns::LET_AND_RETURN), - LintId::of(&returns::NEEDLESS_RETURN), - LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), - LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), - LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(&try_err::TRY_ERR), - LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(&unused_unit::UNUSED_UNIT), - LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS), - LintId::of(&write::PRINTLN_EMPTY_STRING), - LintId::of(&write::PRINT_LITERAL), - LintId::of(&write::PRINT_WITH_NEWLINE), - LintId::of(&write::WRITELN_EMPTY_STRING), - LintId::of(&write::WRITE_LITERAL), - LintId::of(&write::WRITE_WITH_NEWLINE), + LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assign_ops::ASSIGN_OP_PATTERN), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(blacklisted_name::BLACKLISTED_NAME), + LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), + LintId::of(casts::FN_TO_NUMERIC_CAST), + LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), + LintId::of(collapsible_if::COLLAPSIBLE_IF), + LintId::of(collapsible_match::COLLAPSIBLE_MATCH), + LintId::of(comparison_chain::COMPARISON_CHAIN), + LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(doc::MISSING_SAFETY_DOC), + LintId::of(doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(enum_variants::ENUM_VARIANT_NAMES), + LintId::of(enum_variants::MODULE_INCEPTION), + LintId::of(eq_op::OP_REF), + LintId::of(eta_reduction::REDUNDANT_CLOSURE), + LintId::of(float_literal::EXCESSIVE_PRECISION), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(from_over_into::FROM_OVER_INTO), + LintId::of(from_str_radix_10::FROM_STR_RADIX_10), + LintId::of(functions::DOUBLE_MUST_USE), + LintId::of(functions::MUST_USE_UNIT), + LintId::of(functions::RESULT_UNIT_ERR), + LintId::of(if_let_some_result::IF_LET_SOME_RESULT), + LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), + LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(len_zero::COMPARISON_TO_EMPTY), + LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(len_zero::LEN_ZERO), + LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::FOR_KV_MAP), + LintId::of(loops::NEEDLESS_RANGE_LOOP), + LintId::of(loops::SAME_ITEM_PUSH), + LintId::of(loops::WHILE_LET_ON_ITERATOR), + LintId::of(main_recursion::MAIN_RECURSION), + LintId::of(manual_async_fn::MANUAL_ASYNC_FN), + LintId::of(manual_map::MANUAL_MAP), + LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(map_clone::MAP_CLONE), + LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), + LintId::of(matches::MATCH_OVERLAPPING_ARM), + LintId::of(matches::MATCH_REF_PATS), + LintId::of(matches::REDUNDANT_PATTERN_MATCHING), + LintId::of(matches::SINGLE_MATCH), + LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(methods::BYTES_NTH), + LintId::of(methods::CHARS_LAST_CMP), + LintId::of(methods::CHARS_NEXT_CMP), + LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), + LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::ITER_CLONED_COLLECT), + LintId::of(methods::ITER_NEXT_SLICE), + LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_SKIP_NEXT), + LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OK_EXPECT), + LintId::of(methods::OPTION_MAP_OR_NONE), + LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), + LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(methods::SINGLE_CHAR_ADD_STR), + LintId::of(methods::STRING_EXTEND_CHARS), + LintId::of(methods::UNNECESSARY_FOLD), + LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::WRONG_SELF_CONVENTION), + LintId::of(misc::TOPLEVEL_REF_ARG), + LintId::of(misc::ZERO_PTR), + LintId::of(misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(misc_early::DOUBLE_NEG), + LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(misc_early::REDUNDANT_PATTERN), + LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), + LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(neg_multiply::NEG_MULTIPLY), + LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), + LintId::of(ptr::CMP_NULL), + LintId::of(ptr::PTR_ARG), + LintId::of(ptr_eq::PTR_EQ), + LintId::of(question_mark::QUESTION_MARK), + LintId::of(ranges::MANUAL_RANGE_CONTAINS), + LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(returns::LET_AND_RETURN), + LintId::of(returns::NEEDLESS_RETURN), + LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), + LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), + LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(try_err::TRY_ERR), + LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(unused_unit::UNUSED_UNIT), + LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), + LintId::of(write::PRINTLN_EMPTY_STRING), + LintId::of(write::PRINT_LITERAL), + LintId::of(write::PRINT_WITH_NEWLINE), + LintId::of(write::WRITELN_EMPTY_STRING), + LintId::of(write::WRITE_LITERAL), + LintId::of(write::WRITE_WITH_NEWLINE), ]); store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ - LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), - LintId::of(&attrs::DEPRECATED_CFG_ATTR), - LintId::of(&booleans::NONMINIMAL_BOOL), - LintId::of(&casts::CHAR_LIT_AS_U8), - LintId::of(&casts::UNNECESSARY_CAST), - LintId::of(&copies::BRANCHES_SHARING_CODE), - LintId::of(&double_comparison::DOUBLE_COMPARISONS), - LintId::of(&double_parens::DOUBLE_PARENS), - LintId::of(&duration_subsec::DURATION_SUBSEC), - LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(&explicit_write::EXPLICIT_WRITE), - LintId::of(&format::USELESS_FORMAT), - LintId::of(&functions::TOO_MANY_ARGUMENTS), - LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(&identity_op::IDENTITY_OP), - LintId::of(&int_plus_one::INT_PLUS_ONE), - LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), - LintId::of(&lifetimes::NEEDLESS_LIFETIMES), - LintId::of(&loops::EXPLICIT_COUNTER_LOOP), - LintId::of(&loops::MANUAL_FLATTEN), - LintId::of(&loops::MUT_RANGE_BOUND), - LintId::of(&loops::SINGLE_ELEMENT_LOOP), - LintId::of(&loops::WHILE_LET_LOOP), - LintId::of(&manual_strip::MANUAL_STRIP), - LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(&map_identity::MAP_IDENTITY), - LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), - LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(&matches::MATCH_AS_REF), - LintId::of(&matches::MATCH_SINGLE_BINDING), - LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(&methods::BIND_INSTEAD_OF_MAP), - LintId::of(&methods::CLONE_ON_COPY), - LintId::of(&methods::FILTER_MAP_IDENTITY), - LintId::of(&methods::FILTER_NEXT), - LintId::of(&methods::FLAT_MAP_IDENTITY), - LintId::of(&methods::INSPECT_FOR_EACH), - LintId::of(&methods::ITER_COUNT), - LintId::of(&methods::MANUAL_FILTER_MAP), - LintId::of(&methods::MANUAL_FIND_MAP), - LintId::of(&methods::OPTION_AS_REF_DEREF), - LintId::of(&methods::OPTION_FILTER_MAP), - LintId::of(&methods::SEARCH_IS_SOME), - LintId::of(&methods::SKIP_WHILE_NEXT), - LintId::of(&methods::SUSPICIOUS_MAP), - LintId::of(&methods::UNNECESSARY_FILTER_MAP), - LintId::of(&methods::USELESS_ASREF), - LintId::of(&misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), - LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), - LintId::of(&needless_bool::BOOL_COMPARISON), - LintId::of(&needless_bool::NEEDLESS_BOOL), - LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK), - LintId::of(&needless_update::NEEDLESS_UPDATE), - LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), - LintId::of(&no_effect::NO_EFFECT), - LintId::of(&no_effect::UNNECESSARY_OPERATION), - LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), - LintId::of(&precedence::PRECEDENCE), - LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(&ranges::RANGE_ZIP_WITH_LEN), - LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL), - LintId::of(&redundant_slicing::REDUNDANT_SLICING), - LintId::of(&reference::DEREF_ADDROF), - LintId::of(&reference::REF_IN_DEREF), - LintId::of(&repeat_once::REPEAT_ONCE), - LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(&swap::MANUAL_SWAP), - LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), - LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), - LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), - LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), - LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT), - LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), - LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR), - LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), - LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR), - LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(&types::BORROWED_BOX), - LintId::of(&types::TYPE_COMPLEXITY), - LintId::of(&types::VEC_BOX), - LintId::of(&unit_types::UNIT_ARG), - LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(&unwrap::UNNECESSARY_UNWRAP), - LintId::of(&useless_conversion::USELESS_CONVERSION), - LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(attrs::DEPRECATED_CFG_ATTR), + LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CHAR_LIT_AS_U8), + LintId::of(casts::UNNECESSARY_CAST), + LintId::of(copies::BRANCHES_SHARING_CODE), + LintId::of(double_comparison::DOUBLE_COMPARISONS), + LintId::of(double_parens::DOUBLE_PARENS), + LintId::of(duration_subsec::DURATION_SUBSEC), + LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(explicit_write::EXPLICIT_WRITE), + LintId::of(format::USELESS_FORMAT), + LintId::of(functions::TOO_MANY_ARGUMENTS), + LintId::of(get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(identity_op::IDENTITY_OP), + LintId::of(int_plus_one::INT_PLUS_ONE), + LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(lifetimes::NEEDLESS_LIFETIMES), + LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::MANUAL_FLATTEN), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(loops::SINGLE_ELEMENT_LOOP), + LintId::of(loops::WHILE_LET_LOOP), + LintId::of(manual_strip::MANUAL_STRIP), + LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), + LintId::of(map_identity::MAP_IDENTITY), + LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(matches::MATCH_AS_REF), + LintId::of(matches::MATCH_SINGLE_BINDING), + LintId::of(matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::FILTER_MAP_IDENTITY), + LintId::of(methods::FILTER_NEXT), + LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::INSPECT_FOR_EACH), + LintId::of(methods::ITER_COUNT), + LintId::of(methods::MANUAL_FILTER_MAP), + LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::OPTION_AS_REF_DEREF), + LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::SEARCH_IS_SOME), + LintId::of(methods::SKIP_WHILE_NEXT), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::UNNECESSARY_FILTER_MAP), + LintId::of(methods::USELESS_ASREF), + LintId::of(misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), + LintId::of(needless_bool::BOOL_COMPARISON), + LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), + LintId::of(needless_update::NEEDLESS_UPDATE), + LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(no_effect::NO_EFFECT), + LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(precedence::PRECEDENCE), + LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(ranges::RANGE_ZIP_WITH_LEN), + LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), + LintId::of(redundant_slicing::REDUNDANT_SLICING), + LintId::of(reference::DEREF_ADDROF), + LintId::of(reference::REF_IN_DEREF), + LintId::of(repeat_once::REPEAT_ONCE), + LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(swap::MANUAL_SWAP), + LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), + LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), + LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), + LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(types::BORROWED_BOX), + LintId::of(types::TYPE_COMPLEXITY), + LintId::of(types::VEC_BOX), + LintId::of(unit_types::UNIT_ARG), + LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(unwrap::UNNECESSARY_UNWRAP), + LintId::of(useless_conversion::USELESS_CONVERSION), + LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ - LintId::of(&absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), - LintId::of(&approx_const::APPROX_CONSTANT), - LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), - LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), - LintId::of(&attrs::DEPRECATED_SEMVER), - LintId::of(&attrs::MISMATCHED_TARGET_OS), - LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&bit_mask::BAD_BIT_MASK), - LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(&booleans::LOGIC_BUG), - LintId::of(&casts::CAST_REF_TO_MUT), - LintId::of(&copies::IFS_SAME_COND), - LintId::of(&copies::IF_SAME_THEN_ELSE), - LintId::of(&derive::DERIVE_HASH_XOR_EQ), - LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(&drop_forget_ref::DROP_COPY), - LintId::of(&drop_forget_ref::DROP_REF), - LintId::of(&drop_forget_ref::FORGET_COPY), - LintId::of(&drop_forget_ref::FORGET_REF), - LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(&eq_op::EQ_OP), - LintId::of(&erasing_op::ERASING_OP), - LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), - LintId::of(&formatting::POSSIBLE_MISSING_COMMA), - LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), - LintId::of(&if_let_mutex::IF_LET_MUTEX), - LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(&infinite_iter::INFINITE_ITER), - LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), - LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), - LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), - LintId::of(&loops::ITER_NEXT_LOOP), - LintId::of(&loops::NEVER_LOOP), - LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), - LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(&methods::CLONE_DOUBLE_REF), - LintId::of(&methods::ITERATOR_STEP_BY_ZERO), - LintId::of(&methods::UNINIT_ASSUMED_INIT), - LintId::of(&methods::ZST_OFFSET), - LintId::of(&minmax::MIN_MAX), - LintId::of(&misc::CMP_NAN), - LintId::of(&misc::FLOAT_CMP), - LintId::of(&misc::MODULO_ONE), - LintId::of(&mut_key::MUTABLE_KEY_TYPE), - LintId::of(&non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), - LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(&ptr::MUT_FROM_REF), - LintId::of(&ranges::REVERSED_EMPTY_RANGES), - LintId::of(®ex::INVALID_REGEX), - LintId::of(&self_assignment::SELF_ASSIGNMENT), - LintId::of(&serde_api::SERDE_API_MISUSE), - LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), - LintId::of(&swap::ALMOST_SWAPPED), - LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(&transmute::WRONG_TRANSMUTE), - LintId::of(&transmuting_null::TRANSMUTING_NULL), - LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), - LintId::of(&unicode::INVISIBLE_CHARACTERS), - LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), - LintId::of(&unit_types::UNIT_CMP), - LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), - LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(&unwrap::PANICKING_UNWRAP), - LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), + LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(approx_const::APPROX_CONSTANT), + LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), + LintId::of(atomic_ordering::INVALID_ATOMIC_ORDERING), + LintId::of(attrs::DEPRECATED_SEMVER), + LintId::of(attrs::MISMATCHED_TARGET_OS), + LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(bit_mask::BAD_BIT_MASK), + LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(booleans::LOGIC_BUG), + LintId::of(casts::CAST_REF_TO_MUT), + LintId::of(copies::IFS_SAME_COND), + LintId::of(copies::IF_SAME_THEN_ELSE), + LintId::of(derive::DERIVE_HASH_XOR_EQ), + LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(drop_forget_ref::DROP_COPY), + LintId::of(drop_forget_ref::DROP_REF), + LintId::of(drop_forget_ref::FORGET_COPY), + LintId::of(drop_forget_ref::FORGET_REF), + LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(eq_op::EQ_OP), + LintId::of(erasing_op::ERASING_OP), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(formatting::POSSIBLE_MISSING_COMMA), + LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(if_let_mutex::IF_LET_MUTEX), + LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(infinite_iter::INFINITE_ITER), + LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(let_underscore::LET_UNDERSCORE_LOCK), + LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::NEVER_LOOP), + LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), + LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::CLONE_DOUBLE_REF), + LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::ZST_OFFSET), + LintId::of(minmax::MIN_MAX), + LintId::of(misc::CMP_NAN), + LintId::of(misc::FLOAT_CMP), + LintId::of(misc::MODULO_ONE), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), + LintId::of(ptr::MUT_FROM_REF), + LintId::of(ranges::REVERSED_EMPTY_RANGES), + LintId::of(regex::INVALID_REGEX), + LintId::of(self_assignment::SELF_ASSIGNMENT), + LintId::of(serde_api::SERDE_API_MISUSE), + LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + LintId::of(swap::ALMOST_SWAPPED), + LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(transmute::WRONG_TRANSMUTE), + LintId::of(transmuting_null::TRANSMUTING_NULL), + LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), + LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(unit_types::UNIT_CMP), + LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unwrap::PANICKING_UNWRAP), + LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]); store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ - LintId::of(&entry::MAP_ENTRY), - LintId::of(&escape::BOXED_LOCAL), - LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS), - LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), - LintId::of(&loops::MANUAL_MEMCPY), - LintId::of(&loops::NEEDLESS_COLLECT), - LintId::of(&methods::EXPECT_FUN_CALL), - LintId::of(&methods::ITER_NTH), - LintId::of(&methods::OR_FUN_CALL), - LintId::of(&methods::SINGLE_CHAR_PATTERN), - LintId::of(&misc::CMP_OWNED), - LintId::of(&mutex_atomic::MUTEX_ATOMIC), - LintId::of(&redundant_clone::REDUNDANT_CLONE), - LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(&types::BOX_VEC), - LintId::of(&types::REDUNDANT_ALLOCATION), - LintId::of(&vec::USELESS_VEC), - LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH), + LintId::of(entry::MAP_ENTRY), + LintId::of(escape::BOXED_LOCAL), + LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), + LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(loops::MANUAL_MEMCPY), + LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::ITER_NTH), + LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(misc::CMP_OWNED), + LintId::of(mutex_atomic::MUTEX_ATOMIC), + LintId::of(redundant_clone::REDUNDANT_CLONE), + LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(types::BOX_VEC), + LintId::of(types::REDUNDANT_ALLOCATION), + LintId::of(vec::USELESS_VEC), + LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), ]); store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ - LintId::of(&cargo_common_metadata::CARGO_COMMON_METADATA), - LintId::of(&multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), - LintId::of(&wildcard_dependencies::WILDCARD_DEPENDENCIES), + LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA), + LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), + LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES), ]); store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ - LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), - LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), - LintId::of(&disallowed_method::DISALLOWED_METHOD), - LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), - LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), - LintId::of(&future_not_send::FUTURE_NOT_SEND), - LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), - LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), - LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), - LintId::of(&mutex_atomic::MUTEX_INTEGER), - LintId::of(&needless_borrow::NEEDLESS_BORROW), - LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), - LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), - LintId::of(®ex::TRIVIAL_REGEX), - LintId::of(&strings::STRING_LIT_AS_BYTES), - LintId::of(&transmute::USELESS_TRANSMUTE), - LintId::of(&use_self::USE_SELF), + LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), + LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY), + LintId::of(disallowed_method::DISALLOWED_METHOD), + LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), + LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), + LintId::of(future_not_send::FUTURE_NOT_SEND), + LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), + LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), + LintId::of(mutex_atomic::MUTEX_INTEGER), + LintId::of(needless_borrow::NEEDLESS_BORROW), + LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), + LintId::of(regex::TRIVIAL_REGEX), + LintId::of(strings::STRING_LIT_AS_BYTES), + LintId::of(transmute::USELESS_TRANSMUTE), + LintId::of(use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index e3b3fa21cab..116ad072837 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -81,7 +81,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, ref generics, id) = item.kind { - check_fn_inner(cx, &sig.decl, Some(id), generics, item.span, true); + check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true); } } @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { let report_extra_lifetimes = trait_ref_of_method(cx, item.hir_id()).is_none(); check_fn_inner( cx, - &sig.decl, + sig.decl, Some(id), &item.generics, item.span, @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { TraitFn::Required(_) => None, TraitFn::Provided(id) => Some(id), }; - check_fn_inner(cx, &sig.decl, body, &item.generics, item.span, true); + check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true); } } } @@ -149,7 +149,7 @@ fn check_fn_inner<'tcx>( .last() .expect("a path must have at least one segment") .args; - if let Some(ref params) = *params { + if let Some(params) = *params { let lifetimes = params.args.iter().filter_map(|arg| match arg { GenericArg::Lifetime(lt) => Some(lt), _ => None, @@ -163,7 +163,7 @@ fn check_fn_inner<'tcx>( } } } - if could_use_elision(cx, decl, body, &generics.params) { + if could_use_elision(cx, decl, body, generics.params) { span_lint( cx, NEEDLESS_LIFETIMES, @@ -201,7 +201,7 @@ fn could_use_elision<'tcx>( input_visitor.visit_ty(arg); } // extract lifetimes in output type - if let Return(ref ty) = func.output { + if let Return(ty) = func.output { output_visitor.visit_ty(ty); } for lt in named_generics { @@ -416,12 +416,12 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl // a predicate like F: Trait or F: for<'a> Trait<'a> let mut visitor = RefVisitor::new(cx); // walk the type F, it may not contain LT refs - walk_ty(&mut visitor, &pred.bounded_ty); + walk_ty(&mut visitor, pred.bounded_ty); if !visitor.all_lts().is_empty() { return true; } // if the bounds define new lifetimes, they are fine to occur - let allowed_lts = allowed_lts_from(&pred.bound_generic_params); + let allowed_lts = allowed_lts_from(pred.bound_generic_params); // now walk the bounds for bound in pred.bounds.iter() { walk_param_bound(&mut visitor, bound); @@ -433,8 +433,8 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl }, WherePredicate::EqPredicate(ref pred) => { let mut visitor = RefVisitor::new(cx); - walk_ty(&mut visitor, &pred.lhs_ty); - walk_ty(&mut visitor, &pred.rhs_ty); + walk_ty(&mut visitor, pred.lhs_ty); + walk_ty(&mut visitor, pred.rhs_ty); if !visitor.lts.is_empty() { return true; } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7fd55151226..1d63af25803 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -248,7 +248,7 @@ impl LiteralDigitGrouping { fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { if_chain! { if let Some(src) = snippet_opt(cx, lit.span); - if let Some(mut num_lit) = NumericLiteral::from_lit(&src, &lit); + if let Some(mut num_lit) = NumericLiteral::from_lit(&src, lit); then { if !Self::check_for_mistyped_suffix(cx, lit.span, &mut num_lit) { return; @@ -438,7 +438,7 @@ impl DecimalLiteralRepresentation { if_chain! { if let LitKind::Int(val, _) = lit.kind; if let Some(src) = snippet_opt(cx, lit.span); - if let Some(num_lit) = NumericLiteral::from_lit(&src, &lit); + if let Some(num_lit) = NumericLiteral::from_lit(&src, lit); if num_lit.radix == Radix::Decimal; if val >= u128::from(self.threshold); then { diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index f14dbb1d642..98e60f7ed85 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. - if let Some(block) = get_enclosing_block(&cx, expr.hir_id) { + if let Some(block) = get_enclosing_block(cx, expr.hir_id) { for id in increment_visitor.into_results() { let mut initialize_visitor = InitializeVisitor::new(cx, expr, id); walk_block(&mut initialize_visitor, block); diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 8f18f54119b..666b8c58728 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( ) { let pat_span = pat.span; - if let PatKind::Tuple(ref pat, _) = pat.kind { + if let PatKind::Tuple(pat, _) = pat.kind { if pat.len() == 2 { let arg_span = arg.span; let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() { @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( Mutability::Mut => "_mut", }; let arg = match arg.kind { - ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) => &**expr, + ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr, _ => arg, }; diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 574ad8c0f29..94743cfcf46 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -18,7 +18,7 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, span: Span, ) { - if let ExprKind::Block(ref block, _) = body.kind { + if let ExprKind::Block(block, _) = body.kind { // Ensure the `if let` statement is the only expression or statement in the for-loop let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() { let match_stmt = &block.stmts[0]; @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(inner_expr) = inner_expr; if let ExprKind::Match( - ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false } + match_expr, match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false } ) = inner_expr.kind; // Ensure match_expr in `if let` statement is the same as the pat from the for-loop if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 3c5abb7a3c4..47005aba388 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -63,8 +63,8 @@ pub(super) fn check<'tcx>( if let ExprKind::Index(base_right, idx_right) = rhs.kind; if is_slice_like(cx, cx.typeck_results().expr_ty(base_left)); if is_slice_like(cx, cx.typeck_results().expr_ty(base_right)); - if let Some((start_left, offset_left)) = get_details_from_idx(cx, &idx_left, &starts); - if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts); + if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts); + if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts); // Source and destination must be different if path_to_local(base_left) != path_to_local(base_right); @@ -168,8 +168,8 @@ fn build_manual_memcpy_suggestion<'tcx>( }, }; - let (dst_offset, dst_limit) = print_offset_and_limit(&dst); - let (src_offset, src_limit) = print_offset_and_limit(&src); + let (dst_offset, dst_limit) = print_offset_and_limit(dst); + let (src_offset, src_limit) = print_offset_and_limit(src); let dst_base_str = snippet(cx, dst.base.span, "???"); let src_base_str = snippet(cx, src.base.span, "???"); @@ -435,7 +435,7 @@ fn get_loop_counters<'a, 'tcx>( // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. - get_enclosing_block(&cx, expr.hir_id).and_then(|block| { + get_enclosing_block(cx, expr.hir_id).and_then(|block| { increment_visitor .into_results() .filter_map(move |var_id| { diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 20291491998..28acefd51fe 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -562,7 +562,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { // check for `loop { if let {} else break }` that could be `while let` // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) - if let ExprKind::Loop(ref block, _, LoopSource::Loop, _) = expr.kind { + if let ExprKind::Loop(block, _, LoopSource::Loop, _) = expr.kind { // also check for empty `loop {}` statements, skipping those in #[panic_handler] empty_loop::check(cx, expr, block); while_let_loop::check(cx, expr, block); @@ -570,7 +570,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { while_let_on_iterator::check(cx, expr); - if let Some((cond, body)) = higher::while_loop(&expr) { + if let Some((cond, body)) = higher::while_loop(expr) { while_immutable_condition::check(cx, cond, body); } @@ -602,7 +602,7 @@ fn check_for_loop<'tcx>( fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprKind::MethodCall(ref method, _, ref args, _) = arg.kind { + if let ExprKind::MethodCall(method, _, args, _) = arg.kind { // just the receiver, no arguments if args.len() == 1 { let method_name = &*method.ident.as_str(); diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index e0c5caf5136..4d73aef76e8 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -21,10 +21,10 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { } fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { if_chain! { - if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; - if let ExprKind::MethodCall(ref chain_method, method0_span, _, _) = args[0].kind; + if let ExprKind::MethodCall(method, _, args, _) = expr.kind; + if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind; if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); - if let Some(ref generic_args) = chain_method.args; + if let Some(generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); let ty = cx.typeck_results().node_type(ty.hir_id); if is_type_diagnostic_item(cx, ty, sym::vec_type) @@ -58,16 +58,16 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont } fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - if let ExprKind::Block(ref block, _) = expr.kind { - for ref stmt in block.stmts { + if let ExprKind::Block(block, _) = expr.kind { + for stmt in block.stmts { if_chain! { if let StmtKind::Local( Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. }, - init: Some(ref init_expr), .. } + init: Some(init_expr), .. } ) = stmt.kind; - if let ExprKind::MethodCall(ref method_name, collect_span, &[ref iter_source], ..) = init_expr.kind; - if method_name.ident.name == sym!(collect) && is_trait_method(cx, &init_expr, sym::Iterator); - if let Some(ref generic_args) = method_name.args; + if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind; + if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); + if let Some(generic_args) = method_name.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); if let ty = cx.typeck_results().node_type(ty.hir_id); if is_type_diagnostic_item(cx, ty, sym::vec_type) || @@ -165,8 +165,8 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection if_chain! { - if let ExprKind::MethodCall(method_name, _, ref args, _) = &expr.kind; - if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. }) = args.get(0); + if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind; + if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0); if let &[name] = &path.segments; if name.ident == self.target; then { @@ -193,7 +193,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor { } // Check if the collection is used for anything else if_chain! { - if let Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. } = expr; + if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr; if let &[name] = &path.segments; if name.ident == self.target; then { diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 60afa449a45..56141fb3837 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -96,7 +96,7 @@ pub(super) fn check<'tcx>( let take = if let Some(end) = *end { let mut take_expr = end; - if let ExprKind::Binary(ref op, ref left, ref right) = end.kind { + if let ExprKind::Binary(ref op, left, right) = end.kind { if let BinOpKind::Add = op.node { let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left); let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right); @@ -190,10 +190,10 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(ref method, _, ref len_args, _) = expr.kind; + if let ExprKind::MethodCall(method, _, len_args, _) = expr.kind; if len_args.len() == 1; if method.ident.name == sym!(len); - if let ExprKind::Path(QPath::Resolved(_, ref path)) = len_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind; if path.segments.len() == 1; if path.segments[0].ident.name == var; then { @@ -254,7 +254,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if_chain! { // the indexed container is referenced by a name if let ExprKind::Path(ref seqpath) = seqexpr.kind; - if let QPath::Resolved(None, ref seqvar) = *seqpath; + if let QPath::Resolved(None, seqvar) = *seqpath; if seqvar.segments.len() == 1; let index_used_directly = path_to_local_id(idx, self.var); let indexed_indirectly = { @@ -310,7 +310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(meth, _, args, _) = expr.kind; if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(&args[1], &args[0], expr); @@ -319,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // an index op - if let ExprKind::Index(ref seqexpr, ref idx) = expr.kind; + if let ExprKind::Index(seqexpr, idx) = expr.kind; if !self.check(idx, seqexpr, expr); then { return } } @@ -340,19 +340,19 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { let old = self.prefer_mutable; match expr.kind { - ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs, _) => { + ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => { self.prefer_mutable = true; self.visit_expr(lhs); self.prefer_mutable = false; self.visit_expr(rhs); }, - ExprKind::AddrOf(BorrowKind::Ref, mutbl, ref expr) => { + ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => { if mutbl == Mutability::Mut { self.prefer_mutable = true; } self.visit_expr(expr); }, - ExprKind::Call(ref f, args) => { + ExprKind::Call(f, args) => { self.visit_expr(f); for expr in args { let ty = self.cx.typeck_results().expr_ty_adjusted(expr); diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index f63a3761a0d..e2cb4638018 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -5,7 +5,7 @@ use rustc_lint::LateContext; use std::iter::{once, Iterator}; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Loop(ref block, _, _, _) = expr.kind { + if let ExprKind::Loop(block, _, _, _) = expr.kind { match never_loop_block(block, expr.hir_id) { NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"), NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (), @@ -76,36 +76,36 @@ fn never_loop_expr_seq<'a, T: Iterator>>(es: &mut T, main_lo fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { match stmt.kind { - StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e), - StmtKind::Local(ref local) => local.init.as_deref(), + StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e), + StmtKind::Local(local) => local.init.as_deref(), StmtKind::Item(..) => None, } } fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { match expr.kind { - ExprKind::Box(ref e) - | ExprKind::Unary(_, ref e) - | ExprKind::Cast(ref e, _) - | ExprKind::Type(ref e, _) - | ExprKind::Field(ref e, _) - | ExprKind::AddrOf(_, _, ref e) - | ExprKind::Struct(_, _, Some(ref e)) - | ExprKind::Repeat(ref e, _) - | ExprKind::DropTemps(ref e) => never_loop_expr(e, main_loop_id), - ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es, _) | ExprKind::Tup(ref es) => { + ExprKind::Box(e) + | ExprKind::Unary(_, e) + | ExprKind::Cast(e, _) + | ExprKind::Type(e, _) + | ExprKind::Field(e, _) + | ExprKind::AddrOf(_, _, e) + | ExprKind::Struct(_, _, Some(e)) + | ExprKind::Repeat(e, _) + | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id), + ExprKind::Array(es) | ExprKind::MethodCall(_, _, es, _) | ExprKind::Tup(es) => { never_loop_expr_all(&mut es.iter(), main_loop_id) }, - ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id), - ExprKind::Binary(_, ref e1, ref e2) - | ExprKind::Assign(ref e1, ref e2, _) - | ExprKind::AssignOp(_, ref e1, ref e2) - | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id), - ExprKind::Loop(ref b, _, _, _) => { + ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), main_loop_id), + ExprKind::Binary(_, e1, e2) + | ExprKind::Assign(e1, e2, _) + | ExprKind::AssignOp(_, e1, e2) + | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().cloned(), main_loop_id), + ExprKind::Loop(b, _, _, _) => { // Break can come from the inner loop so remove them. absorb_break(&never_loop_block(b, main_loop_id)) }, - ExprKind::If(ref e, ref e2, ref e3) => { + ExprKind::If(e, e2, ref e3) => { let e1 = never_loop_expr(e, main_loop_id); let e2 = never_loop_expr(e2, main_loop_id); let e3 = e3 @@ -113,7 +113,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { .map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id)); combine_seq(e1, combine_branches(e2, e3)) }, - ExprKind::Match(ref e, ref arms, _) => { + ExprKind::Match(e, arms, _) => { let e = never_loop_expr(e, main_loop_id); if arms.is_empty() { e @@ -122,7 +122,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { combine_seq(e, arms) } }, - ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id), + ExprKind::Block(b, _) => never_loop_block(b, main_loop_id), ExprKind::Continue(d) => { let id = d .target_id @@ -136,7 +136,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| { combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak) }), - ExprKind::InlineAsm(ref asm) => asm + ExprKind::InlineAsm(asm) => asm .operands .iter() .map(|(o, _)| match o { diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index b3d784474c8..cb2c83e9029 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -161,7 +161,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { if vec_push_option.is_none() { // Current statement is not a push so visit inside match &s.kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(&expr), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr), _ => {}, } } else { diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 8451c1c6130..fc067e81bca 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -15,12 +15,12 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'_>, ) { if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg_expr) = arg.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg_expr) = arg.kind; if let PatKind::Binding(.., target, _) = pat.kind; if let ExprKind::Array([arg_expression]) = arg_expr.kind; if let ExprKind::Path(ref list_item) = arg_expression.kind; if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name); - if let ExprKind::Block(ref block, _) = body.kind; + if let ExprKind::Block(block, _) = body.kind; if !block.stmts.is_empty(); then { diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index fc287d51249..4db6644b9d7 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } match parent.kind { - ExprKind::AssignOp(op, ref lhs, ref rhs) => { + ExprKind::AssignOp(op, lhs, rhs) => { if lhs.hir_id == expr.hir_id { *state = if op.node == BinOpKind::Add && is_integer_const(self.cx, rhs, 1) @@ -79,7 +79,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { }; } }, - ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => { + ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => { *state = IncrementVisitorVarState::DontWarn }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { @@ -153,7 +153,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { // Look for declarations of the variable if_chain! { - if let StmtKind::Local(ref local) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if local.pat.hir_id == self.var_id; if let PatKind::Binding(.., ident, _) = local.pat.kind; then { @@ -191,10 +191,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if let Some(parent) = get_parent_expr(self.cx, expr) { match parent.kind { - ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => { + ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == expr.hir_id => { self.state = InitializeVisitorState::DontWarn; }, - ExprKind::Assign(ref lhs, ref rhs, _) if lhs.hir_id == expr.hir_id => { + ExprKind::Assign(lhs, rhs, _) if lhs.hir_id == expr.hir_id => { self.state = if_chain! { if self.depth == 0; if let InitializeVisitorState::Declared(name) @@ -273,7 +273,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } match expr.kind { - ExprKind::Assign(ref path, _, _) | ExprKind::AssignOp(_, ref path, _) => { + ExprKind::Assign(path, _, _) | ExprKind::AssignOp(_, path, _) => { if path_to_local_id(path, self.iterator) { self.nesting = RuledOut; } @@ -327,7 +327,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic // (&mut x).into_iter() ==> x.iter_mut() match &arg.kind { ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner) - if has_iter_method(cx, cx.typeck_results().expr_ty(&arg_inner)).is_some() => + if has_iter_method(cx, cx.typeck_results().expr_ty(arg_inner)).is_some() => { let meth_name = match mutability { Mutability::Mut => "iter_mut", @@ -335,7 +335,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic }; format!( "{}.{}()", - sugg::Sugg::hir_with_applicability(cx, &arg_inner, "_", applic_ref).maybe_par(), + sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(), meth_name, ) } diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index ffe8c0c5494..9c172079852 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -11,14 +11,14 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &' let inner_stmt_expr = extract_expr_from_first_stmt(loop_block); // or extract the first expression (if any) from the block if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(loop_block)) { - if let ExprKind::Match(ref matchexpr, ref arms, ref source) = inner.kind { + if let ExprKind::Match(matchexpr, arms, ref source) = inner.kind { // ensure "if let" compatible match structure match *source { MatchSource::Normal | MatchSource::IfLetDesugar { .. } => { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() - && is_simple_break_expr(&arms[1].body) + && is_simple_break_expr(arms[1].body) { if in_external_macro(cx.sess(), expr.span) { return; @@ -57,7 +57,7 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr< if block.stmts.is_empty() { return None; } - if let StmtKind::Local(ref local) = block.stmts[0].kind { + if let StmtKind::Local(local) = block.stmts[0].kind { local.init //.map(|expr| expr) } else { None @@ -67,9 +67,9 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr< /// If a block begins with an expression (with or without semicolon), return it. fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { match block.expr { - Some(ref expr) if block.stmts.is_empty() => Some(expr), + Some(expr) if block.stmts.is_empty() => Some(expr), None if !block.stmts.is_empty() => match block.stmts[0].kind { - StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => Some(expr), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some(expr), StmtKind::Local(..) | StmtKind::Item(..) => None, }, _ => None, @@ -82,7 +82,7 @@ fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn is_simple_break_expr(expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true, - ExprKind::Block(ref b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)), + ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)), _ => false, } } diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 57fc6250a9a..82715d9bafa 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -16,12 +16,10 @@ use rustc_middle::hir::map::Map; use rustc_span::symbol::sym; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.kind { + if let ExprKind::Match(match_expr, arms, MatchSource::WhileLetDesugar) = expr.kind { let pat = &arms[0].pat.kind; - if let ( - &PatKind::TupleStruct(ref qpath, ref pat_args, _), - &ExprKind::MethodCall(ref method_path, _, ref method_args, _), - ) = (pat, &match_expr.kind) + if let (&PatKind::TupleStruct(ref qpath, pat_args, _), &ExprKind::MethodCall(method_path, _, method_args, _)) = + (pat, &match_expr.kind) { let iter_expr = &method_args[0]; @@ -40,8 +38,8 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { && is_trait_method(cx, match_expr, sym::Iterator) && lhs_constructor.ident.name == sym::Some && (pat_args.is_empty() - || !is_refutable(cx, &pat_args[0]) - && !is_used_inside(cx, iter_expr, &arms[0].body) + || !is_refutable(cx, pat_args[0]) + && !is_used_inside(cx, iter_expr, arms[0].body) && !is_iterator_used_after_while_let(cx, iter_expr) && !is_nested(cx, expr, &method_args[0])) { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 9da37efddac..dfa464ddb81 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { } else { return; }; - let target_res = cx.qpath_res(&target_path, target_arg.hir_id); + let target_res = cx.qpath_res(target_path, target_arg.hir_id); if target_res == Res::Err { return; }; @@ -174,7 +174,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t // Tests if `expr` is a `&str`. fn is_ref_str(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match cx.typeck_results().expr_ty_adjusted(&expr).kind() { + match cx.typeck_results().expr_ty_adjusted(expr).kind() { ty::Ref(_, ty, _) => ty.is_str(), _ => false, } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 9f1ab1f695d..99c35ae3bbf 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { } if_chain! { - if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind; + if let hir::ExprKind::MethodCall(method, _, args, _) = e.kind; if args.len() == 2; if method.ident.name == sym::map; let ty = cx.typeck_results().expr_ty(&args[0]); @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); match closure_body.params[0].pat.kind { - hir::PatKind::Ref(ref inner, hir::Mutability::Not) => if let hir::PatKind::Binding( + hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( hir::BindingAnnotation::Unannotated, .., name, None ) = inner.kind { if ident_eq(name, closure_expr) { @@ -71,14 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { }, hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) => { + hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { if ident_eq(name, inner) { if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { lint(cx, e.span, args[0].span, true); } } }, - hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! { + hir::ExprKind::MethodCall(method, _, [obj], _) => if_chain! { if ident_eq(name, obj) && method.ident.name == sym::clone; if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { } fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.kind { + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { path.segments.len() == 1 && path.segments[0].ident == name } else { false diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index a6a63961be5..425a9734e5f 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { } // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(ref method, _t_span, ref args, _) = e.kind { + if let ExprKind::MethodCall(method, _t_span, args, _) = e.kind { // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] // Enum::Variant[2])) if method.ident.as_str() == "map_err" && args.len() == 2 { diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 75191e1f9ee..e7719e7663d 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for MapIdentity { /// map(). Otherwise, returns None. fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> { if_chain! { - if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(method, _, args, _) = expr.kind; if args.len() == 2 && method.ident.name == sym::map; let caller_ty = cx.typeck_results().expr_ty(&args[0]); if is_trait_method(cx, expr, sym::Iterator) @@ -80,7 +80,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), - ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY), + ExprKind::Path(QPath::Resolved(_, path)) => match_path(path, &paths::STD_CONVERT_IDENTITY), _ => false, } } @@ -99,12 +99,12 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { match body.kind { ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat), - ExprKind::Ret(Some(ref ret_val)) => match_expr_param(cx, ret_val, params[0].pat), - ExprKind::Block(ref block, _) => { + ExprKind::Ret(Some(ret_val)) => match_expr_param(cx, ret_val, params[0].pat), + ExprKind::Block(block, _) => { if_chain! { if block.stmts.len() == 1; - if let StmtKind::Semi(ref expr) | StmtKind::Expr(ref expr) = block.stmts[0].kind; - if let ExprKind::Ret(Some(ref ret_val)) = expr.kind; + if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block.stmts[0].kind; + if let ExprKind::Ret(Some(ret_val)) = expr.kind; then { match_expr_param(cx, ret_val, params[0].pat) } else { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 5cc16244a0d..57cd907e77e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -133,7 +133,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> // Calls can't be reduced any more Some(expr.span) }, - hir::ExprKind::Block(ref block, _) => { + hir::ExprKind::Block(block, _) => { match (block.stmts, block.expr.as_ref()) { (&[], Some(inner_expr)) => { // If block only contains an expression, @@ -144,8 +144,8 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { - hir::StmtKind::Local(ref local) => Some(local.span), - hir::StmtKind::Expr(ref e) => Some(e.span), + hir::StmtKind::Local(local) => Some(local.span), + hir::StmtKind::Expr(e) => Some(e.span), hir::StmtKind::Semi(..) => Some(inner_stmt.span), hir::StmtKind::Item(..) => None, } @@ -169,12 +169,12 @@ fn unit_closure<'tcx>( expr: &hir::Expr<'_>, ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> { if_chain! { - if let hir::ExprKind::Closure(_, ref decl, inner_expr_id, _, _) = expr.kind; + if let hir::ExprKind::Closure(_, decl, inner_expr_id, _, _) = expr.kind; let body = cx.tcx.hir().body(inner_expr_id); let body_expr = &body.value; if decl.inputs.len() == 1; if is_unit_expression(cx, body_expr); - if let Some(binding) = iter_input_pats(&decl, body).next(); + if let Some(binding) = iter_input_pats(decl, body).next(); then { return Some((binding, body_expr)); } @@ -267,7 +267,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnit { return; } - if let hir::StmtKind::Semi(ref expr) = stmt.kind { + if let hir::StmtKind::Semi(expr) = stmt.kind { if let Some(arglists) = method_chain_args(expr, &["map"]) { lint_map_unit_fn(cx, stmt, expr, arglists[0]); } diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index ccaa5e98c83..ca6fb0831fe 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchOnVecItems { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if !in_external_macro(cx.sess(), expr.span); - if let ExprKind::Match(ref match_expr, _, MatchSource::Normal) = expr.kind; + if let ExprKind::Match(match_expr, _, MatchSource::Normal) = expr.kind; if let Some(idx_expr) = is_vec_indexing(cx, match_expr); if let ExprKind::Index(vec, idx) = idx_expr.kind; @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchOnVecItems { fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::Index(ref array, ref index) = expr.kind; + if let ExprKind::Index(array, index) = expr.kind; if is_vector(cx, array); if !is_full_range(cx, index); diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index c68ae00be01..a892e24482b 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -589,7 +589,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { lint_match_arms(cx, expr); } - if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind { + if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { check_single_match(cx, ex, arms, expr); check_match_bool(cx, ex, arms, expr); check_overlapping_arms(cx, ex, arms); @@ -604,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { check_match_single_binding(cx, ex, arms, expr); } } - if let ExprKind::Match(ref ex, ref arms, _) = expr.kind { + if let ExprKind::Match(ex, arms, _) = expr.kind { check_match_ref_pats(cx, ex, arms, expr); } } @@ -613,14 +613,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_chain! { if !in_external_macro(cx.sess(), local.span); if !in_macro(local.span); - if let Some(ref expr) = local.init; - if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind; + if let Some(expr) = local.init; + if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind; if arms.len() == 1 && arms[0].guard.is_none(); if let PatKind::TupleStruct( - QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind; + QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind; if args.len() == 1; - if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind; - let body = remove_blocks(&arms[0].body); + if let PatKind::Binding(_, arg, ..) = strip_pat_refs(args[0]).kind; + let body = remove_blocks(arms[0].body); if path_to_local_id(body, arg); then { @@ -649,7 +649,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_chain! { if !in_external_macro(cx.sess(), pat.span); if !in_macro(pat.span); - if let PatKind::Struct(QPath::Resolved(_, ref path), fields, true) = pat.kind; + if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); let ty = cx.tcx.type_of(def_id); if let ty::Adt(def, _) = ty.kind(); @@ -761,7 +761,7 @@ fn report_single_match_single_pattern( // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), - expr_block(cx, &arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, None, "..", Some(expr.span)), els_str, ); (msg, sugg) @@ -771,7 +771,7 @@ fn report_single_match_single_pattern( "if let {} = {} {}{}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, None, "..", Some(expr.span)), els_str, ); (msg, sugg) @@ -809,7 +809,7 @@ fn check_single_match_opt_like( ]; let path = match arms[1].pat.kind { - PatKind::TupleStruct(ref path, ref inner, _) => { + PatKind::TupleStruct(ref path, inner, _) => { // Contains any non wildcard patterns (e.g., `Err(err)`)? if !inner.iter().all(is_wild) { return; @@ -841,7 +841,7 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: move |diag| { if arms.len() == 2 { // no guards - let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pat.kind { + let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { if let ExprKind::Lit(ref lit) = arm_bool.kind { match lit.node { LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), @@ -917,7 +917,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); if is_type_diagnostic_item(cx, ex_ty, sym::result_type) { for arm in arms { - if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind { + if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); @@ -937,7 +937,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm } if_chain! { if matching_wild; - if let ExprKind::Block(ref block, _) = arm.body.kind; + if let ExprKind::Block(block, _) = arm.body.kind; if is_panic_block(block); then { // `Err(_)` or `Err(_e)` arm with `panic!` found @@ -1143,9 +1143,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) // If the block contains only a `panic!` macro (as expression or statement) fn is_panic_block(block: &Block<'_>) -> bool { match (&block.expr, block.stmts.len(), block.stmts.first()) { - (&Some(ref exp), 0, _) => { - is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none() - }, + (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(), (&None, 1, Some(stmt)) => { is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none() }, @@ -1156,7 +1154,7 @@ fn is_panic_block(block: &Block<'_>) -> bool { fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if has_only_ref_pats(arms) { let mut suggs = Vec::with_capacity(arms.len() + 1); - let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = ex.kind { + let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind { let span = ex.span.source_callsite(); suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string())); ( @@ -1173,7 +1171,7 @@ fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], e }; suggs.extend(arms.iter().filter_map(|a| { - if let PatKind::Ref(ref refp, _) = a.pat.kind { + if let PatKind::Ref(refp, _) = a.pat.kind { Some((a.pat.span, snippet(cx, refp.span, "..").to_string())) } else { None @@ -1242,7 +1240,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) { for arm in arms { - if let PatKind::Or(ref fields) = arm.pat.kind { + if let PatKind::Or(fields) = arm.pat.kind { // look for multiple fields in this arm that contains at least one Wild pattern if fields.len() > 1 && fields.iter().any(is_wild) { span_lint_and_help( @@ -1308,7 +1306,7 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr // strip potential borrows (#6503), but only if the type is a reference let mut ex_new = ex; if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind { - if let ty::Ref(..) = cx.typeck_results().expr_ty(&ex_inner).kind() { + if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() { ex_new = ex_inner; } }; @@ -1385,7 +1383,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A let matched_vars = ex.span; let bind_names = arms[0].pat.span; - let match_body = remove_blocks(&arms[0].body); + let match_body = remove_blocks(arms[0].body); let mut snippet_body = if match_body.span.from_expansion() { Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string() } else { @@ -1396,13 +1394,13 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A match match_body.kind { ExprKind::Block(block, _) => { // macro + expr_ty(body) == () - if block.span.from_expansion() && cx.typeck_results().expr_ty(&match_body).is_unit() { + if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { snippet_body.push(';'); } }, _ => { // expr_ty(body) == () - if cx.typeck_results().expr_ty(&match_body).is_unit() { + if cx.typeck_results().expr_ty(match_body).is_unit() { snippet_body.push(';'); } }, @@ -1502,10 +1500,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<' fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec> { arms.iter() .flat_map(|arm| { - if let Arm { - ref pat, guard: None, .. - } = *arm - { + if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs = match lhs { Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, @@ -1525,7 +1520,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) }); } - if let PatKind::Lit(ref value) = pat.kind { + if let PatKind::Lit(value) = pat.kind { let value = constant(cx, cx.typeck_results(), value)?.0; return Some(SpannedRange { span: pat.span, @@ -1572,8 +1567,8 @@ fn type_ranges(ranges: &[SpannedRange]) -> TypedRanges { fn is_unit_expr(expr: &Expr<'_>) -> bool { match expr.kind { - ExprKind::Tup(ref v) if v.is_empty() => true, - ExprKind::Block(ref b, _) if b.stmts.is_empty() && b.expr.is_none() => true, + ExprKind::Tup(v) if v.is_empty() => true, + ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none() => true, _ => false, } } @@ -1586,14 +1581,14 @@ fn is_none_arm(arm: &Arm<'_>) -> bool { // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) fn is_ref_some_arm(arm: &Arm<'_>) -> Option { if_chain! { - if let PatKind::TupleStruct(ref path, ref pats, _) = arm.pat.kind; + if let PatKind::TupleStruct(ref path, pats, _) = arm.pat.kind; if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME); if let PatKind::Binding(rb, .., ident, _) = pats[0].kind; if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut; - if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).kind; + if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1; - if let ExprKind::Path(QPath::Resolved(_, ref path2)) = args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { return Some(rb) @@ -1685,7 +1680,7 @@ where (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (), _ => { // skip if the range `a` is completely included into the range `b` - if let Ordering::Equal | Ordering::Less = a.cmp(&b) { + if let Ordering::Equal | Ordering::Less = a.cmp(b) { let kind_a = Kind::End(a.range().node.1, a.range()); let kind_b = Kind::End(b.range().node.1, b.range()); if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) { @@ -1737,7 +1732,7 @@ mod redundant_pattern_match { kind = &inner.kind; } let good_method = match kind { - PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { + PatKind::TupleStruct(ref path, patterns, _) if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { if match_qpath(path, &paths::RESULT_OK) { "is_ok()" @@ -1818,8 +1813,8 @@ mod redundant_pattern_match { let found_good_method = match node_pair { ( - PatKind::TupleStruct(ref path_left, ref patterns_left, _), - PatKind::TupleStruct(ref path_right, ref patterns_right, _), + PatKind::TupleStruct(ref path_left, patterns_left, _), + PatKind::TupleStruct(ref path_right, patterns_right, _), ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { find_good_method_for_match( @@ -1846,8 +1841,8 @@ mod redundant_pattern_match { None } }, - (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right)) - | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _)) + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) + | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { @@ -1969,10 +1964,10 @@ fn test_overlapping() { /// Implementation of `MATCH_SAME_ARMS`. fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind { + if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind { let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 { let mut h = SpanlessHash::new(cx); - h.hash_expr(&arm.body); + h.hash_expr(arm.body); h.finish() }; @@ -2008,7 +2003,7 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) { (min_index..=max_index).all(|index| arms[index].guard.is_none()) && SpanlessEq::new(cx) .expr_fallback(eq_fallback) - .eq_expr(&lhs.body, &rhs.body) + .eq_expr(lhs.body, rhs.body) // these checks could be removed to allow unused bindings && bindings_eq(lhs.pat, local_map.keys().copied().collect()) && bindings_eq(rhs.pat, local_map.values().copied().collect()) diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index 7895ba9f1e0..a735c616f6e 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -34,7 +34,7 @@ declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]); impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(ref func, ref func_args) = expr.kind; + if let ExprKind::Call(func, func_args) = expr.kind; // is `mem::discriminant` if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { let mut derefs_needed = ptr_depth; let mut cur_expr = param; while derefs_needed > 0 { - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref inner_expr) = cur_expr.kind { + if let ExprKind::AddrOf(BorrowKind::Ref, _, inner_expr) = cur_expr.kind { derefs_needed -= 1; cur_expr = inner_expr; } else { diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index c13802e3953..a28cb5f32fe 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -28,7 +28,7 @@ declare_lint_pass!(MemForget => [MEM_FORGET]); impl<'tcx> LateLintPass<'tcx> for MemForget { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Call(ref path_expr, ref args) = e.kind { + if let ExprKind::Call(path_expr, args) = e.kind { if let ExprKind::Path(ref qpath) = path_expr.kind { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() { if match_def_path(cx, def_id, &paths::MEM_FORGET) { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 0418c616efa..e1d351aee45 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -109,14 +109,14 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E // argument's type. All that's left is to get // replacee's path. let replaced_path = match dest.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref replaced) => { - if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.kind { + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { + if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { replaced_path } else { return; } }, - ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path, + ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, _ => return, }; @@ -161,7 +161,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' } if_chain! { - if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind; + if let ExprKind::Call(repl_func, repl_args) = src.kind; if repl_args.is_empty(); if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); @@ -214,7 +214,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< .iter() .any(|symbol| is_diagnostic_assoc_item(cx, def_id, *symbol)) { - if let QPath::TypeRelative(_, ref method) = path { + if let QPath::TypeRelative(_, method) = path { if method.ident.name == sym::new { return true; } @@ -226,7 +226,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if_chain! { - if let ExprKind::Call(ref repl_func, _) = src.kind; + if let ExprKind::Call(repl_func, _) = src.kind; if !in_external_macro(cx.tcx.sess, expr_span); if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); @@ -273,11 +273,11 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // Check that `expr` is a call to `mem::replace()` - if let ExprKind::Call(ref func, ref func_args) = expr.kind; + if let ExprKind::Call(func, func_args) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::MEM_REPLACE); - if let [dest, src] = &**func_args; + if let [dest, src] = func_args; then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 46d4c674648..287bff886bf 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -71,7 +71,7 @@ pub(crate) trait BindInsteadOfMap { closure_args_span: Span, ) -> bool { if_chain! { - if let hir::ExprKind::Call(ref some_expr, [inner_expr]) = closure_expr.kind; + if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind; if let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind; if Self::is_variant(cx, path.res); if !contains_return(inner_expr); @@ -107,7 +107,7 @@ pub(crate) trait BindInsteadOfMap { let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| { if_chain! { if !in_macro(ret_expr.span); - if let hir::ExprKind::Call(ref func_path, [arg]) = ret_expr.kind; + if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind; if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind; if Self::is_variant(cx, path.res); if !contains_return(arg); diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index c668fe52781..514c4118765 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -19,7 +19,7 @@ pub(super) fn check( ) -> bool { if_chain! { if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind; + if let hir::ExprKind::Call(fun, arg_char) = info.other.kind; if arg_char.len() == 1; if let hir::ExprKind::Path(ref qpath) = fun.kind; if let Some(segment) = single_segment_path(qpath); diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index e7bffa66b3f..03cb41697d5 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -100,9 +100,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa applicability: &mut Applicability, ) -> Vec { if_chain! { - if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind; - if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind; - if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind; + if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, format_arg) = a.kind; + if let hir::ExprKind::Match(format_arg_expr, _, _) = format_arg.kind; + if let hir::ExprKind::Tup(format_arg_expr_tup) = format_arg_expr.kind; then { format_arg_expr_tup @@ -155,7 +155,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa if block.stmts.len() == 1; if let hir::StmtKind::Local(local) = &block.stmts[0].kind; if let Some(arg_root) = &local.init; - if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind; + if let hir::ExprKind::Call(inner_fun, inner_args) = arg_root.kind; if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1; if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind; then { diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 45d1ed953b4..35fae450eeb 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -19,7 +19,7 @@ use super::OPTION_FILTER_MAP; fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { match &expr.kind { - hir::ExprKind::Path(QPath::TypeRelative(_, ref mname)) => mname.ident.name == method_name, + hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, hir::ExprKind::Path(QPath::Resolved(_, segments)) => { segments.segments.last().unwrap().ident.name == method_name }, @@ -28,7 +28,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy let closure_expr = remove_blocks(&body.value); let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, ref args, _) => { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, args, _) => { if_chain! { if ident.name == method_name; if let hir::ExprKind::Path(path) = &args[0].kind; @@ -61,7 +61,7 @@ fn lint_filter_some_map_unwrap( methods_span: Span, ) { let iterator = is_trait_method(cx, expr, sym::Iterator); - let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&filter_recv), sym::option_type); + let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::option_type); if (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) { let msg = "`filter` for `Some` followed by `unwrap`"; let help = "consider using `flatten` instead"; diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 664885a2f0e..dd613d0cd63 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( let body = cx.tcx.hir().body(*body_id); if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind; if path.segments.len() == 1; if path.segments[0].ident.name == binding_ident.name; diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 04461ad5c3a..1211e2f2bf7 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -13,7 +13,7 @@ use clippy_utils::is_diagnostic_assoc_item; pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, trait_diagnostic: Symbol) { if_chain! { if let ExprKind::MethodCall(method_path, _, [arg], _) = &expr.kind; - let return_type = cx.typeck_results().expr_ty(&expr); + let return_type = cx.typeck_results().expr_ty(expr); let input_type = cx.typeck_results().expr_ty(arg).peel_refs(); if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index dab0a43a096..a49851de38e 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() { // caller is a Slice if_chain! { - if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind; + if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind; if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) = higher::range(index_expr); if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fa6323b56e1..b1ade5addd6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1740,10 +1740,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { check_methods(cx, expr, self.msrv.as_ref()); match expr.kind { - hir::ExprKind::Call(ref func, ref args) => { + hir::ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, &func.kind); }, - hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { + hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); clone_on_copy::check(cx, expr, method_call.ident.name, args); @@ -1753,9 +1753,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args); single_char_pattern::check(cx, expr, method_call.ident.name, args); }, - hir::ExprKind::Binary(op, ref lhs, ref rhs) - if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => - { + hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { expr, chain: lhs, @@ -1763,7 +1761,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { eq: op.node == hir::BinOpKind::Eq, }; lint_binary_expr_with_method_call(cx, &mut info); - } + }, _ => (), } } @@ -1781,7 +1779,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); if_chain! { if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; - if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next(); + if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next(); let method_sig = cx.tcx.fn_sig(impl_item.def_id); let method_sig = cx.tcx.erase_late_bound_regions(method_sig); @@ -1801,7 +1799,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { method_config.output_type.matches(&sig.decl.output) && method_config.self_kind.matches(cx, self_ty, first_arg_ty) && fn_header_equals(method_config.fn_header, sig.header) && - method_config.lifetime_param_cond(&impl_item) + method_config.lifetime_param_cond(impl_item) { span_lint_and_help( cx, @@ -2272,10 +2270,10 @@ impl OutType { let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[])); match (self, ty) { (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true, - (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true, - (Self::Bool, &hir::FnRetTy::Return(ref ty)) if is_bool(ty) => true, - (Self::Any, &hir::FnRetTy::Return(ref ty)) if !is_unit(ty) => true, - (Self::Ref, &hir::FnRetTy::Return(ref ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)), + (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true, + (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true, + (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true, + (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)), _ => false, } } diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 1367a0c21d8..7e9c8fa829d 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -77,10 +77,10 @@ pub(super) fn check<'tcx>( } } }, - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, inner) if same_mutability(m) => { if_chain! { - if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind; - if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind; then { path_to_local_id(inner2, closure_body.params[0].pat.hir_id) } else { diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 89dedc5f0d8..df89da5d3e0 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -86,7 +86,7 @@ pub(super) fn check<'tcx>( (&paths::RESULT, true, &["or", "unwrap_or"], "else"), ]; - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { + if let hir::ExprKind::MethodCall(path, _, args, _) = &arg.kind { if path.ident.as_str() == "len" { let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); @@ -105,7 +105,7 @@ pub(super) fn check<'tcx>( if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); if is_lazyness_candidate(cx, arg); - if !contains_return(&arg); + if !contains_return(arg); let self_ty = cx.typeck_results().expr_ty(self_expr); @@ -158,7 +158,7 @@ pub(super) fn check<'tcx>( if args.len() == 2 { match args[1].kind { - hir::ExprKind::Call(ref fun, ref or_args) => { + hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 8a94d7f4155..ecec6fc3bb7 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind { + } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(closure_arg.pat).kind { let name = &*ident.name.as_str(); Some(search_snippet.replace(&format!("*{}", name), name)) } else { @@ -108,8 +108,8 @@ pub(super) fn check<'tcx>( } }; if_chain! { - if is_string_or_str_slice(&search_recv); - if is_string_or_str_slice(&search_arg); + if is_string_or_str_slice(search_recv); + if is_string_or_str_slice(search_arg); then { let msg = format!("called `{}()` after calling `find()` on a string", option_check_method); match option_check_method { diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 3cc1912b15a..0ae65c0c01d 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -10,7 +10,7 @@ use super::UNINIT_ASSUMED_INIT; /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter) pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::Call(ref callee, ref args) = recv.kind; + if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); if let hir::ExprKind::Path(ref path) = callee.kind; if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); @@ -28,9 +28,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { match ty.kind() { - ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component), - ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), - ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), + ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component), + ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), + ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), _ => false, } } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 8e637e12393..0f28bfdf09e 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -20,9 +20,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< let mutates_arg = mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id)); - let (mut found_mapping, mut found_filtering) = check_expression(&cx, arg_id, &body.value); + let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value); - let mut return_visitor = ReturnVisitor::new(&cx, arg_id); + let mut return_visitor = ReturnVisitor::new(cx, arg_id); return_visitor.visit_expr(&body.value); found_mapping |= return_visitor.found_mapping; found_filtering |= return_visitor.found_filtering; @@ -52,7 +52,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< // returns (found_mapping, found_filtering) fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) { match &expr.kind { - hir::ExprKind::Call(ref func, ref args) => { + hir::ExprKind::Call(func, args) => { if let hir::ExprKind::Path(ref path) = func.kind { if match_qpath(path, &paths::OPTION_SOME) { if path_to_local_id(&args[0], arg_id) { @@ -65,22 +65,22 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } (true, true) }, - hir::ExprKind::Block(ref block, _) => block + hir::ExprKind::Block(block, _) => block .expr .as_ref() - .map_or((false, false), |expr| check_expression(cx, arg_id, &expr)), + .map_or((false, false), |expr| check_expression(cx, arg_id, expr)), hir::ExprKind::Match(_, arms, _) => { let mut found_mapping = false; let mut found_filtering = false; for arm in *arms { - let (m, f) = check_expression(cx, arg_id, &arm.body); + let (m, f) = check_expression(cx, arg_id, arm.body); found_mapping |= m; found_filtering |= f; } (found_mapping, found_filtering) }, // There must be an else_arm or there will be a type error - hir::ExprKind::If(_, ref if_arm, Some(ref else_arm)) => { + hir::ExprKind::If(_, if_arm, Some(else_arm)) => { let if_check = check_expression(cx, arg_id, if_arm); let else_check = check_expression(cx, arg_id, else_arm); (if_check.0 | else_check.0, if_check.1 | else_check.1) diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 7c16470348f..75517c48a21 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -34,13 +34,13 @@ pub(super) fn check( let closure_expr = remove_blocks(&closure_body.value); // Check if the closure body is of the form `acc some_expr(x)` - if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind; + if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; if bin_op.node == op; // Extract the names of the two arguments to the closure if let [param_a, param_b] = closure_body.params; - if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(¶m_a.pat).kind; - if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(¶m_b.pat).kind; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; if path_to_local_id(left_expr, first_arg_id); if replacement_has_args || path_to_local_id(right_expr, second_arg_id); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index ac6b55396da..f6bf37e08b9 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -26,7 +26,7 @@ pub(super) fn derefs_to_slice<'tcx>( } } - if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { + if let hir::ExprKind::MethodCall(path, _, args, _) = expr.kind { if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { Some(&args[0]) } else { diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index 0489d0f6fcf..866cf616679 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -8,7 +8,7 @@ use super::ZST_OFFSET; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { - if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(recv).kind(); + if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind(); if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); if layout.is_zst(); then { diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 776f4c7b741..45948f4d926 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -67,7 +67,7 @@ enum MinMax { fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> { match expr.kind { - ExprKind::Call(ref path, ref args) => { + ExprKind::Call(path, args) => { if let ExprKind::Path(ref qpath) = path.kind { cx.typeck_results() .qpath_res(qpath, path.hir_id) @@ -85,7 +85,7 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons None } }, - ExprKind::MethodCall(ref path, _, ref args, _) => { + ExprKind::MethodCall(path, _, args, _) => { if_chain! { if let [obj, _] = args; if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index c23643cb2f5..afced5a5ce5 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -304,9 +304,9 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, stmt.span); - if let StmtKind::Local(ref local) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(an, .., name, None) = local.pat.kind; - if let Some(ref init) = local.init; + if let Some(init) = local.init; if !higher::is_from_for_desugar(local); if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; then { @@ -322,7 +322,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } else { ("", sugg_init.addr()) }; - let tyopt = if let Some(ref ty) = local.ty { + let tyopt = if let Some(ty) = local.ty { format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "..")) } else { String::new() @@ -350,8 +350,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } }; if_chain! { - if let StmtKind::Semi(ref expr) = stmt.kind; - if let ExprKind::Binary(ref binop, ref a, ref b) = expr.kind; + if let StmtKind::Semi(expr) = stmt.kind; + if let ExprKind::Binary(ref binop, a, b) = expr.kind; if binop.node == BinOpKind::And || binop.node == BinOpKind::Or; if let Some(sugg) = Sugg::hir_opt(cx, a); then { @@ -378,11 +378,11 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match expr.kind { - ExprKind::Cast(ref e, ref ty) => { + ExprKind::Cast(e, ty) => { check_cast(cx, expr.span, e, ty); return; }, - ExprKind::Binary(ref cmp, ref left, ref right) => { + ExprKind::Binary(ref cmp, left, right) => { check_binary(cx, expr, cmp, left, right); return; }, @@ -501,12 +501,12 @@ fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { // Return true if `expr` is the result of `signum()` invoked on a float value. fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { // The negation of a signum is still a signum - if let ExprKind::Unary(UnOp::Neg, ref child_expr) = expr.kind { - return is_signum(cx, &child_expr); + if let ExprKind::Unary(UnOp::Neg, child_expr) = expr.kind { + return is_signum(cx, child_expr); } if_chain! { - if let ExprKind::MethodCall(ref method_name, _, ref expressions, _) = expr.kind; + if let ExprKind::MethodCall(method_name, _, expressions, _) = expr.kind; if sym!(signum) == method_name.ident.name; // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) @@ -552,7 +552,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: } let (arg_ty, snip) = match expr.kind { - ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => { + ExprKind::MethodCall(.., args, _) if args.len() == 1 => { if_chain!( if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString) @@ -564,7 +564,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: } ) }, - ExprKind::Call(ref path, ref v) if v.len() == 1 => { + ExprKind::Call(path, v) if v.len() == 1 => { if let ExprKind::Path(ref path) = path.kind { if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) @@ -649,7 +649,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: /// of what it means for an expression to be "used". fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind { - ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr), + ExprKind::Assign(_, rhs, _) | ExprKind::AssignOp(_, _, rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr), _ => is_used(cx, parent), }) } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 23554669d97..0dc02431ad5 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Err((span, err)) = is_min_const_fn(cx.tcx, &mir) { + if let Err((span, err)) = is_min_const_fn(cx.tcx, mir) { if rustc_mir::const_eval::is_min_const_fn(cx.tcx, def_id.to_def_id()) { cx.tcx.sess.span_err(span, &err); } diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index dd4488f3f02..041fe64a1a9 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let attrs = cx.tcx.hir().attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); }, - hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, trait_items) => { + hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, _bounds, trait_items) => { // note: we need to check if the trait is exported so we can't use // `LateLintPass::check_trait_item` here. for tit in trait_items { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 41bd07bcf1e..ed7b9cd62dc 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -58,21 +58,21 @@ declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]); impl<'tcx> LateLintPass<'tcx> for MutableKeyType { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { if let hir::ItemKind::Fn(ref sig, ..) = item.kind { - check_sig(cx, item.hir_id(), &sig.decl); + check_sig(cx, item.hir_id(), sig.decl); } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) { if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind { if trait_ref_of_method(cx, item.hir_id()).is_none() { - check_sig(cx, item.hir_id(), &sig.decl); + check_sig(cx, item.hir_id(), sig.decl); } } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) { if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { - check_sig(cx, item.hir_id(), &sig.decl); + check_sig(cx, item.hir_id(), sig.decl); } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index ef33e41a5fa..4b9c51d0c16 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { // Let's ignore the generated code. intravisit::walk_expr(self, arg); intravisit::walk_expr(self, body); - } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, ref e) = expr.kind { + } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e) = expr.kind { if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) = e.kind { span_lint( self.cx, @@ -85,7 +85,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { if let hir::TyKind::Rptr( _, hir::MutTy { - ty: ref pty, + ty: pty, mutbl: hir::Mutability::Mut, }, ) = ty.kind diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 0c09ddb8073..b85cc4b9548 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -32,7 +32,7 @@ declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]); impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { match e.kind { - ExprKind::Call(ref fn_expr, ref arguments) => { + ExprKind::Call(fn_expr, arguments) => { if let ExprKind::Path(ref path) = fn_expr.kind { check_arguments( cx, @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { ); } }, - ExprKind::MethodCall(ref path, _, ref arguments, _) => { + ExprKind::MethodCall(path, _, arguments, _) => { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index db7b3423ad9..96a58d1410f 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -71,7 +71,7 @@ declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]); impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; - if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.kind { + if let ExprKind::If(pred, then_block, Some(else_expr)) = e.kind { let reduce = |ret, not| { let mut applicability = Applicability::MachineApplicable; let snip = Sugg::hir_with_applicability(cx, pred, "", &mut applicability); @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { snip = snip.make_return(); } - if parent_node_is_if_expr(&e, &cx) { + if parent_node_is_if_expr(e, cx) { snip = snip.blockify() } @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { applicability, ); }; - if let ExprKind::Block(ref then_block, _) = then_block.kind { + if let ExprKind::Block(then_block, _) = then_block.kind { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => { span_lint( @@ -225,7 +225,7 @@ fn check_comparison<'a, 'tcx>( ) { use self::Expression::{Bool, Other}; - if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind { + if let ExprKind::Binary(op, left_side, right_side) = e.kind { let (l_ty, r_ty) = ( cx.typeck_results().expr_ty(left_side), cx.typeck_results().expr_ty(right_side), @@ -237,7 +237,7 @@ fn check_comparison<'a, 'tcx>( let mut applicability = Applicability::MachineApplicable; if let BinOpKind::Eq = op.node { - let expression_info = one_side_is_unary_not(&left_side, &right_side); + let expression_info = one_side_is_unary_not(left_side, right_side); if expression_info.one_side_is_unary_not { span_lint_and_sugg( cx, @@ -324,9 +324,9 @@ fn fetch_bool_block(block: &Block<'_>) -> Expression { match (&*block.stmts, block.expr.as_ref()) { (&[], Some(e)) => fetch_bool_expr(&**e), (&[ref e], None) => { - if let StmtKind::Semi(ref e) = e.kind { + if let StmtKind::Semi(e) = e.kind { if let ExprKind::Ret(_) = e.kind { - fetch_bool_expr(&**e) + fetch_bool_expr(e) } else { Expression::Other } @@ -340,7 +340,7 @@ fn fetch_bool_block(block: &Block<'_>) -> Expression { fn fetch_bool_expr(expr: &Expr<'_>) -> Expression { match expr.kind { - ExprKind::Block(ref block, _) => fetch_bool_block(block), + ExprKind::Block(block, _) => fetch_bool_block(block), ExprKind::Lit(ref lit_ptr) => { if let LitKind::Bool(value) = lit_ptr.node { Expression::Bool(value) @@ -348,7 +348,7 @@ fn fetch_bool_expr(expr: &Expr<'_>) -> Expression { Expression::Other } }, - ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) { + ExprKind::Ret(Some(expr)) => match fetch_bool_expr(expr) { Expression::Bool(value) => Expression::RetBool(value), _ => Expression::Other, }, diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 79d84da2dfc..eef3c16730b 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { if e.span.from_expansion() || self.derived_item.is_some() { return; } - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { if let [Adjustment { diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 7fbffe04a3f..0e976b130eb 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { if_chain! { // Only lint immutable refs, because `&mut ref T` may be useful. - if let PatKind::Ref(ref sub_pat, Mutability::Not) = pat.kind; + if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind; // Check sub_pat got a `ref` keyword (excluding `ref mut`). if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind; diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 2ea871990f1..079b6642d58 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -70,7 +70,7 @@ impl LateLintPass<'_> for NeedlessForEach { ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..) ); // Checks the type of the `iter` method receiver is NOT a user defined type. - if has_iter_method(cx, cx.typeck_results().expr_ty(&iter_recv)).is_some(); + if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some(); // Skip the lint if the body is not block because this is simpler than `for` loop. // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. if let ExprKind::Closure(_, _, body_id, ..) = for_each_arg.kind; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 7370ba39922..780e2241293 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if is_type_diagnostic_item(cx, ty, sym::vec_type); if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]); - if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind; + if let TyKind::Path(QPath::Resolved(_, path)) = input.kind; if let Some(elem_ty) = path.segments.iter() .find(|seg| seg.ident.name == sym::Vec) .and_then(|ps| ps.args.as_ref()) diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index e93de8a252a..8f325404deb 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -49,7 +49,7 @@ declare_lint_pass!(NeedlessUpdate => [NEEDLESS_UPDATE]); impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind { + if let ExprKind::Struct(_, fields, Some(base)) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, _) = ty.kind() { if fields.len() == def.non_enum_variant().fields.len() diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 4b935c7b906..0704173a011 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -51,8 +51,8 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { if_chain! { if !in_external_macro(cx.sess(), expr.span); - if let ExprKind::Unary(UnOp::Not, ref inner) = expr.kind; - if let ExprKind::Binary(ref op, ref left, _) = inner.kind; + if let ExprKind::Unary(UnOp::Not, inner) = expr.kind; + if let ExprKind::Binary(ref op, left, _) = inner.kind; if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node; then { diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 7b00879251f..34fd012572f 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -28,12 +28,12 @@ declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]); #[allow(clippy::match_same_arms)] impl<'tcx> LateLintPass<'tcx> for NegMultiply { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref op, ref left, ref right) = e.kind { + if let ExprKind::Binary(ref op, left, right) = e.kind { if BinOpKind::Mul == op.node { match (&left.kind, &right.kind) { (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {}, - (&ExprKind::Unary(UnOp::Neg, ref lit), _) => check_mul(cx, e.span, lit, right), - (_, &ExprKind::Unary(UnOp::Neg, ref lit)) => check_mul(cx, e.span, lit, left), + (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right), + (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left), _ => {}, } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 83953a16bc8..cfcaf509471 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -51,23 +51,21 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Lit(..) | ExprKind::Closure(..) => true, ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)), - ExprKind::Index(ref a, ref b) | ExprKind::Binary(_, ref a, ref b) => { - has_no_effect(cx, a) && has_no_effect(cx, b) - }, - ExprKind::Array(ref v) | ExprKind::Tup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), - ExprKind::Repeat(ref inner, _) - | ExprKind::Cast(ref inner, _) - | ExprKind::Type(ref inner, _) - | ExprKind::Unary(_, ref inner) - | ExprKind::Field(ref inner, _) - | ExprKind::AddrOf(_, _, ref inner) - | ExprKind::Box(ref inner) => has_no_effect(cx, inner), - ExprKind::Struct(_, ref fields, ref base) => { + ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), + ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)), + ExprKind::Repeat(inner, _) + | ExprKind::Cast(inner, _) + | ExprKind::Type(inner, _) + | ExprKind::Unary(_, inner) + | ExprKind::Field(inner, _) + | ExprKind::AddrOf(_, _, inner) + | ExprKind::Box(inner) => has_no_effect(cx, inner), + ExprKind::Struct(_, fields, ref base) => { !has_drop(cx, cx.typeck_results().expr_ty(expr)) - && fields.iter().all(|field| has_no_effect(cx, &field.expr)) + && fields.iter().all(|field| has_no_effect(cx, field.expr)) && base.as_ref().map_or(true, |base| has_no_effect(cx, base)) }, - ExprKind::Call(ref callee, ref args) => { + ExprKind::Call(callee, args) => { if let ExprKind::Path(ref qpath) = callee.kind { let res = cx.qpath_res(qpath, callee.hir_id); match res { @@ -81,7 +79,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { false } }, - ExprKind::Block(ref block, _) => { + ExprKind::Block(block, _) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| has_no_effect(cx, expr)) }, _ => false, @@ -92,7 +90,7 @@ declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]); impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Semi(ref expr) = stmt.kind { + if let StmtKind::Semi(expr) = stmt.kind { if has_no_effect(cx, expr) { span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect"); } else if let Some(reduced) = reduce_expression(cx, expr) { @@ -127,26 +125,26 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option Some(vec![&**a, &**b]), - ExprKind::Binary(ref binop, ref a, ref b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => { - Some(vec![&**a, &**b]) + ExprKind::Index(a, b) => Some(vec![a, b]), + ExprKind::Binary(ref binop, a, b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => { + Some(vec![a, b]) }, - ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()), - ExprKind::Repeat(ref inner, _) - | ExprKind::Cast(ref inner, _) - | ExprKind::Type(ref inner, _) - | ExprKind::Unary(_, ref inner) - | ExprKind::Field(ref inner, _) - | ExprKind::AddrOf(_, _, ref inner) - | ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), - ExprKind::Struct(_, ref fields, ref base) => { + ExprKind::Array(v) | ExprKind::Tup(v) => Some(v.iter().collect()), + ExprKind::Repeat(inner, _) + | ExprKind::Cast(inner, _) + | ExprKind::Type(inner, _) + | ExprKind::Unary(_, inner) + | ExprKind::Field(inner, _) + | ExprKind::AddrOf(_, _, inner) + | ExprKind::Box(inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), + ExprKind::Struct(_, fields, ref base) => { if has_drop(cx, cx.typeck_results().expr_ty(expr)) { None } else { Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect()) } }, - ExprKind::Call(ref callee, ref args) => { + ExprKind::Call(callee, args) => { if let ExprKind::Path(ref qpath) = callee.kind { let res = cx.qpath_res(qpath, callee.hir_id); match res { @@ -161,7 +159,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option { + ExprKind::Block(block, _) => { if block.stmts.is_empty() { block.expr.as_ref().and_then(|e| { match block.rules { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 6d45e7bc6cf..a83daea97bf 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -44,7 +44,7 @@ impl LateLintPass<'_> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { ExprKind::MethodCall(path, _, [func, param], _) => { - let obj_ty = cx.typeck_results().expr_ty(&func).peel_refs(); + let obj_ty = cx.typeck_results().expr_ty(func).peel_refs(); if_chain! { if (path.ident.name == sym!(mode) @@ -65,7 +65,7 @@ impl LateLintPass<'_> for NonOctalUnixPermissions { } } }, - ExprKind::Call(ref func, [param]) => { + ExprKind::Call(func, [param]) => { if_chain! { if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index c61dff4b8e0..9efe45336bf 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -31,7 +31,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); impl<'tcx> LateLintPass<'tcx> for OpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind { + if let ExprKind::MethodCall(path, _, arguments, _) = e.kind { let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); @@ -59,7 +59,7 @@ enum OpenOption { } fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind { + if let ExprKind::MethodCall(path, _, arguments, _) = argument.kind { let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index a76a4a33f1f..1b9120ae45f 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -66,9 +66,9 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); /// Returns true iff the given expression is the result of calling `Result::ok` fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { - if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { + if let ExprKind::MethodCall(path, _, &[ref receiver], _) = &expr.kind { path.ident.name.as_str() == "ok" - && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::result_type) } else { false } @@ -97,9 +97,9 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { ) = &arm.body.kind { if let [] = statements { - Some(&expr) + Some(expr) } else { - Some(&arm.body) + Some(arm.body) } } else { None diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index cf667c6e805..e222782c2cc 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -31,11 +31,11 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r); if_chain! { - if let ExprKind::Binary(ref op, ref first, ref second) = expr.kind; - if let ExprKind::Binary(ref op2, ref ident1, ref ident2) = first.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path1)) = ident1.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path3)) = second.kind; + if let ExprKind::Binary(ref op, first, second) = expr.kind; + if let ExprKind::Binary(ref op2, ident1, ident2) = first.kind; + if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind; + if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind; + if let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind; if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]); if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); @@ -56,11 +56,11 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { } if_chain! { - if let ExprKind::Binary(ref op, ref first, ref second) = expr.kind; - if let ExprKind::Binary(ref op2, ref ident1, ref ident2) = second.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path1)) = ident1.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind; - if let ExprKind::Path(QPath::Resolved(_, ref path3)) = first.kind; + if let ExprKind::Binary(ref op, first, second) = expr.kind; + if let ExprKind::Binary(ref op2, ident1, ident2) = second.kind; + if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind; + if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind; + if let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind; if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]); if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 9a5b1c3b944..c86a847b2ee 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -141,11 +141,11 @@ impl<'tcx> PassByRefOrValue { }; if_chain! { - if !output_lts.contains(&input_lt); + if !output_lts.contains(input_lt); if is_copy(cx, ty); if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()); if size <= self.ref_min_size; - if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind; + if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind; then { let value_type = if is_self_ty(decl_ty) { "self".into() diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 95ffae28d8c..00245926381 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -45,7 +45,7 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if path.ident.name == sym!(push); if args.len() == 2; if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf); diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index 4550b367da4..8c198cecd6a 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -86,7 +86,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Local(ref local) = stmt.kind { + if let StmtKind::Local(local) = stmt.kind { if let Some(init) = &local.init { if let Some(init_ty) = cx.typeck_results().node_type_opt(init.hir_id) { let pat = &local.pat; @@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(ref expr, arms, source) = expr.kind { + if let ExprKind::Match(expr, arms, source) = expr.kind { match source { MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => { if let Some(expr_ty) = cx.typeck_results().node_type_opt(expr.hir_id) { @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { ) { if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) { for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) { - apply_lint(cx, ¶m.pat, ty, DerefPossible::Impossible); + apply_lint(cx, param.pat, ty, DerefPossible::Impossible); } } } @@ -187,7 +187,7 @@ fn find_first_mismatch<'tcx>( ty: Ty<'tcx>, level: Level, ) -> Option<(Span, Mutability, Level)> { - if let PatKind::Ref(ref sub_pat, _) = pat.kind { + if let PatKind::Ref(sub_pat, _) = pat.kind { if let TyKind::Ref(_, sub_ty, _) = ty.kind() { return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower); } @@ -199,8 +199,8 @@ fn find_first_mismatch<'tcx>( } } - if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind { - if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() { + if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind { + if let TyKind::Adt(adt_def, substs_ref) = ty.kind() { if let Some(variant) = get_variant(adt_def, qpath) { let field_defs = &variant.fields; return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref); @@ -208,8 +208,8 @@ fn find_first_mismatch<'tcx>( } } - if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind { - if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() { + if let PatKind::TupleStruct(ref qpath, pats, _) = pat.kind { + if let TyKind::Adt(adt_def, substs_ref) = ty.kind() { if let Some(variant) = get_variant(adt_def, qpath) { let field_defs = &variant.fields; let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref)); @@ -218,7 +218,7 @@ fn find_first_mismatch<'tcx>( } } - if let PatKind::Tuple(ref pats, _) = pat.kind { + if let PatKind::Tuple(pats, _) = pat.kind { if let TyKind::Tuple(..) = ty.kind() { return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields()); } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 6e530d0ffb0..09fcdb5faf8 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -124,7 +124,7 @@ declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]); impl<'tcx> LateLintPass<'tcx> for Ptr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, _, body_id) = item.kind { - check_fn(cx, &sig.decl, item.hir_id(), Some(body_id)); + check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); } } @@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { return; // ignore trait impls } } - check_fn(cx, &sig.decl, item.hir_id(), Some(body_id)); + check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); } } @@ -147,12 +147,12 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } else { None }; - check_fn(cx, &sig.decl, item.hir_id(), body_id); + check_fn(cx, sig.decl, item.hir_id(), body_id); } } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref op, ref l, ref r) = expr.kind { + if let ExprKind::Binary(ref op, l, r) = expr.kind { if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) { span_lint( cx, @@ -262,10 +262,10 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } } else if match_type(cx, ty, &paths::COW) { if_chain! { - if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind; - if let TyKind::Path(QPath::Resolved(None, ref pp)) = ty.kind; + if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind; + if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind; if let [ref bx] = *pp.segments; - if let Some(ref params) = bx.args; + if let Some(params) = bx.args; if !params.parenthesized; if let Some(inner) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), @@ -289,7 +289,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } } - if let FnRetTy::Return(ref ty) = decl.output { + if let FnRetTy::Return(ty) = decl.output { if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) { let mut immutables = vec![]; for (_, ref mutbl, ref argspan) in decl @@ -322,8 +322,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option { if_chain! { - if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind; - if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last(); + if let TyKind::Path(QPath::Resolved(_, path)) = walk_ptrs_hir_ty(arg).kind; + if let Some(&PathSegment{args: Some(parameters), ..}) = path.segments.last(); let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, @@ -346,7 +346,7 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, } fn is_null_path(expr: &Expr<'_>) -> bool { - if let ExprKind::Call(ref pathexp, ref args) = expr.kind { + if let ExprKind::Call(pathexp, args) = expr.kind { if args.is_empty() { if let ExprKind::Path(ref path) = pathexp.kind { return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT); diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 5796c59c8b3..77cfa3f6b17 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -46,11 +46,11 @@ impl LateLintPass<'_> for PtrEq { return; } - if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind { + if let ExprKind::Binary(ref op, left, right) = expr.kind { if BinOpKind::Eq == op.node { let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { (Some(lhs), Some(rhs)) => (lhs, rhs), - _ => (&**left, &**right), + _ => (left, right), }; if_chain! { @@ -79,7 +79,7 @@ impl LateLintPass<'_> for PtrEq { // E.g., `foo as *const _ as usize` returns `foo as *const _`. fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize { - if let ExprKind::Cast(ref expr, _) = cast_expr.kind { + if let ExprKind::Cast(expr, _) = cast_expr.kind { return Some(expr); } } @@ -90,7 +90,7 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_> // E.g., `foo as *const _` returns `foo`. fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() { - if let ExprKind::Cast(ref expr, _) = cast_expr.kind { + if let ExprKind::Cast(expr, _) = cast_expr.kind { return Some(expr); } } diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index c04b4255256..afb198f4955 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -78,8 +78,8 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { // If the given expression is a cast from a usize, return the lhs of the cast fn expr_as_cast_from_usize<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Cast(ref cast_lhs_expr, _) = expr.kind { - if is_expr_ty_usize(cx, &cast_lhs_expr) { + if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind { + if is_expr_ty_usize(cx, cast_lhs_expr) { return Some(cast_lhs_expr); } } @@ -92,7 +92,7 @@ fn expr_as_ptr_offset_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(ref path_segment, _, ref args, _) = expr.kind { + if let ExprKind::MethodCall(path_segment, _, args, _) = expr.kind { if is_expr_ty_raw_ptr(cx, &args[0]) { if path_segment.ident.name == sym::offset { return Some((&args[0], &args[1], Method::Offset)); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 2054255a7c9..6d720f43851 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -148,14 +148,14 @@ impl QuestionMark { fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { match expression.kind { - ExprKind::Block(ref block, _) => { + ExprKind::Block(block, _) => { if let Some(return_expression) = Self::return_expression(block) { - return Self::expression_returns_none(cx, &return_expression); + return Self::expression_returns_none(cx, return_expression); } false }, - ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr), + ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr), ExprKind::Path(ref qp) => { if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) = cx.qpath_res(qp, expression.hir_id) @@ -174,7 +174,7 @@ impl QuestionMark { if_chain! { if block.stmts.len() == 1; if let Some(expr) = block.stmts.iter().last(); - if let StmtKind::Semi(ref expr) = expr.kind; + if let StmtKind::Semi(expr) = expr.kind; if let ExprKind::Ret(Some(ret_expr)) = expr.kind; then { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 79692abb6ac..1c3c125e579 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -183,10 +183,10 @@ impl_lint_pass!(Ranges => [ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match expr.kind { - ExprKind::MethodCall(ref path, _, ref args, _) => { + ExprKind::MethodCall(path, _, args, _) => { check_range_zip_with_len(cx, path, args, expr.span); }, - ExprKind::Binary(ref op, ref l, ref r) => { + ExprKind::Binary(ref op, l, r) => { if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) { check_possible_range_contains(cx, op.node, l, r, expr); } @@ -287,7 +287,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' } fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> { - if let ExprKind::Binary(ref op, ref l, ref r) = ex.kind { + if let ExprKind::Binary(ref op, l, r) = ex.kind { let (inclusive, ordering) = match op.node { BinOpKind::Gt => (false, Ordering::Greater), BinOpKind::Ge => (true, Ordering::Greater), @@ -324,18 +324,18 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: if path.ident.as_str() == "zip"; if let [iter, zip_arg] = args; // `.iter()` call - if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = iter.kind; + if let ExprKind::MethodCall(iter_path, _, iter_args, _) = iter.kind; if iter_path.ident.name == sym::iter; // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind; + if let ExprKind::MethodCall(len_path, _, len_args, _) = end.kind; if len_path.ident.name == sym!(len) && len_args.len() == 1; // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].kind; - if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].kind; - if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments); + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind; + if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); then { span_lint(cx, RANGE_ZIP_WITH_LEN, @@ -508,8 +508,8 @@ fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<' Spanned { node: BinOpKind::Add, .. }, - ref lhs, - ref rhs, + lhs, + rhs, ) => { if is_integer_const(cx, lhs, 1) { Some(rhs) @@ -529,8 +529,8 @@ fn y_minus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr< Spanned { node: BinOpKind::Sub, .. }, - ref lhs, - ref rhs, + lhs, + rhs, ) if is_integer_const(cx, rhs, 1) => Some(lhs), _ => None, } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 9656ee64c81..19650c41b84 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { .into_results_cursor(mir); let mut possible_borrower = { let mut vis = PossibleBorrowerVisitor::new(cx, mir); - vis.visit_body(&mir); + vis.visit_body(mir); vis.into_map(cx, maybe_storage_live_result) }; @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { continue; } - if let ty::Adt(ref def, _) = arg_ty.kind() { + if let ty::Adt(def, _) = arg_ty.kind() { if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) { continue; } @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { clone_consumed_or_mutated: true, } } else { - let clone_usage = visit_clone_usage(local, ret_local, &mir, bb); + let clone_usage = visit_clone_usage(local, ret_local, mir, bb); if clone_usage.cloned_used && clone_usage.clone_consumed_or_mutated { // cloned value is used, and the clone is modified or moved continue; @@ -426,7 +426,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, // TODO: Actually check for mutation of non-temporaries. clone_consumed_or_mutated: mir.local_kind(clone) != mir::LocalKind::Temp, }; - traversal::ReversePostorder::new(&mir, bb) + traversal::ReversePostorder::new(mir, bb) .skip(1) .fold(init, |usage, (tbb, tdata)| { // Short-circuit @@ -588,7 +588,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { // If the call returns something with lifetimes, // let's conservatively assume the returned value contains lifetime of all the arguments. // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`. - if ContainsRegion.visit_ty(&self.body.local_decls[*dest].ty).is_continue() { + if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_continue() { return; } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 5429d389610..92921bedf4d 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -111,8 +111,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if_chain! { - if let hir::ExprKind::Call(ref closure, _) = expr.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind; + if let hir::ExprKind::Call(closure, _) = expr.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind; if self.path.segments[0].ident == path.segments[0].ident; if self.path.res == path.res; then { @@ -133,14 +133,14 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { for w in block.stmts.windows(2) { if_chain! { - if let hir::StmtKind::Local(ref local) = w[0].kind; - if let Option::Some(ref t) = local.init; + if let hir::StmtKind::Local(local) = w[0].kind; + if let Option::Some(t) = local.init; if let hir::ExprKind::Closure(..) = t.kind; if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind; - if let hir::StmtKind::Semi(ref second) = w[1].kind; - if let hir::ExprKind::Assign(_, ref call, _) = second.kind; - if let hir::ExprKind::Call(ref closure, _) = call.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind; + if let hir::StmtKind::Semi(second) = w[1].kind; + if let hir::ExprKind::Assign(_, call, _) = second.kind; + if let hir::ExprKind::Call(closure, _) = call.kind; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind; if ident == path.segments[0].ident; if count_closure_usage(cx, block, path) == 1; then { diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 0922cfa494e..0cf4e0ce7fe 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if let Some(def_id) = res.opt_def_id(); if cx.tcx.is_diagnostic_item(sym::option_type, def_id); - if let Some(ref params) = last_path_segment(qpath).args ; + if let Some(params) = last_path_segment(qpath).args ; if !params.parenthesized; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(inner_ty) => Some(inner_ty), diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 1cc332de894..4b5306de58e 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -60,7 +60,7 @@ impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(ref fun, ref args) = expr.kind; + if let ExprKind::Call(fun, args) = expr.kind; if let ExprKind::Path(ref qpath) = fun.kind; if args.len() == 1; if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); @@ -134,7 +134,7 @@ fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) = expr.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; if let ExprKind::Array(exprs) = expr.kind; then { for expr in exprs { diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 63e5ec69e66..560a5e7c920 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { if_chain! { if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind; if path.ident.name == sym!(repeat); - if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count); + if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(count); if !in_macro(receiver.span); then { - let ty = cx.typeck_results().expr_ty(&receiver).peel_refs(); + let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); if ty.is_str() { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 8995ae431ad..af772cf4a14 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { err.span_label(local.span, "unnecessary `let` binding"); if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { - if !cx.typeck_results().expr_adjustments(&retexpr).is_empty() { + if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { snippet.push_str(" as _"); } err.multipart_suggestion( @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { check_final_expr(cx, &body.value, Some(body.value.span), replacement) }, FnKind::ItemFn(..) | FnKind::Method(..) => { - if let ExprKind::Block(ref block, _) = body.value.kind { + if let ExprKind::Block(block, _) = body.value.kind { check_block_return(cx, block); } }, @@ -160,7 +160,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) { check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty); } else if let Some(stmt) = block.stmts.iter().last() { match stmt.kind { - StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty); }, _ => (), @@ -192,11 +192,11 @@ fn check_final_expr<'tcx>( } }, // a whole block? check it! - ExprKind::Block(ref block, _) => { + ExprKind::Block(block, _) => { check_block_return(cx, block); }, ExprKind::If(_, then, else_clause_opt) => { - if let ExprKind::Block(ref ifblock, _) = then.kind { + if let ExprKind::Block(ifblock, _) = then.kind { check_block_return(cx, ifblock); } if let Some(else_clause) = else_clause_opt { @@ -207,16 +207,16 @@ fn check_final_expr<'tcx>( // an if/if let expr, check both exprs // note, if without else is going to be a type checking error anyways // (except for unit type functions) so we don't match it - ExprKind::Match(_, ref arms, source) => match source { + ExprKind::Match(_, arms, source) => match source { MatchSource::Normal => { for arm in arms.iter() { - check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block); + check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block); } }, MatchSource::IfLetDesugar { contains_else_clause: true, } => { - if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind { + if let ExprKind::Block(ifblock, _) = arms[0].body.kind { check_block_return(cx, ifblock); } check_final_expr(cx, arms[1].body, None, RetReplacement::Empty); diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index f61af15fbed..553987a426b 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -51,7 +51,7 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned { return; } - let sugg = sugg::Sugg::hir_with_macro_callsite(cx, &expr, ".."); + let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); let suggestion = format!("{0};", sugg); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 612d2fd84cb..d6101bd5e36 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -130,12 +130,12 @@ fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: & let len = bindings.len(); for stmt in block.stmts { match stmt.kind { - StmtKind::Local(ref local) => check_local(cx, local, bindings), - StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => check_expr(cx, e, bindings), + StmtKind::Local(local) => check_local(cx, local, bindings), + StmtKind::Expr(e) | StmtKind::Semi(e) => check_expr(cx, e, bindings), StmtKind::Item(..) => {}, } } - if let Some(ref o) = block.expr { + if let Some(o) = block.expr { check_expr(cx, o, bindings); } bindings.truncate(len); @@ -149,16 +149,16 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & return; } let Local { - ref pat, + pat, ref ty, ref init, span, .. } = *local; - if let Some(ref t) = *ty { + if let Some(t) = *ty { check_ty(cx, t, bindings) } - if let Some(ref o) = *init { + if let Some(o) = *init { check_expr(cx, o, bindings); check_pat(cx, pat, Some(o), span, bindings); } else { @@ -196,34 +196,34 @@ fn check_pat<'tcx>( bindings.push((name, ident.span)); } } - if let Some(ref p) = *inner { + if let Some(p) = *inner { check_pat(cx, p, init, span, bindings); } }, PatKind::Struct(_, pfields, _) => { if let Some(init_struct) = init { - if let ExprKind::Struct(_, ref efields, _) = init_struct.kind { + if let ExprKind::Struct(_, efields, _) = init_struct.kind { for field in pfields { let name = field.ident.name; let efield = efields .iter() .find_map(|f| if f.ident.name == name { Some(&*f.expr) } else { None }); - check_pat(cx, &field.pat, efield, span, bindings); + check_pat(cx, field.pat, efield, span, bindings); } } else { for field in pfields { - check_pat(cx, &field.pat, init, span, bindings); + check_pat(cx, field.pat, init, span, bindings); } } } else { for field in pfields { - check_pat(cx, &field.pat, None, span, bindings); + check_pat(cx, field.pat, None, span, bindings); } } }, PatKind::Tuple(inner, _) => { if let Some(init_tup) = init { - if let ExprKind::Tup(ref tup) = init_tup.kind { + if let ExprKind::Tup(tup) = init_tup.kind { for (i, p) in inner.iter().enumerate() { check_pat(cx, p, Some(&tup[i]), p.span, bindings); } @@ -238,10 +238,10 @@ fn check_pat<'tcx>( } } }, - PatKind::Box(ref inner) => { + PatKind::Box(inner) => { if let Some(initp) = init { - if let ExprKind::Box(ref inner_init) = initp.kind { - check_pat(cx, inner, Some(&**inner_init), span, bindings); + if let ExprKind::Box(inner_init) = initp.kind { + check_pat(cx, inner, Some(inner_init), span, bindings); } else { check_pat(cx, inner, init, span, bindings); } @@ -249,7 +249,7 @@ fn check_pat<'tcx>( check_pat(cx, inner, init, span, bindings); } }, - PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings), + PatKind::Ref(inner, _) => check_pat(cx, inner, init, span, bindings), // PatVec(Vec>, Option>, Vec>), _ => (), } @@ -323,11 +323,10 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut return; } match expr.kind { - ExprKind::Unary(_, ref e) - | ExprKind::Field(ref e, _) - | ExprKind::AddrOf(_, _, ref e) - | ExprKind::Box(ref e) => check_expr(cx, e, bindings), - ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => check_block(cx, block, bindings), + ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => { + check_expr(cx, e, bindings) + }, + ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings), // ExprKind::Call // ExprKind::MethodCall ExprKind::Array(v) | ExprKind::Tup(v) => { @@ -335,18 +334,18 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut check_expr(cx, e, bindings) } }, - ExprKind::If(ref cond, ref then, ref otherwise) => { + ExprKind::If(cond, then, ref otherwise) => { check_expr(cx, cond, bindings); - check_expr(cx, &**then, bindings); - if let Some(ref o) = *otherwise { + check_expr(cx, then, bindings); + if let Some(o) = *otherwise { check_expr(cx, o, bindings); } }, - ExprKind::Match(ref init, arms, _) => { + ExprKind::Match(init, arms, _) => { check_expr(cx, init, bindings); let len = bindings.len(); for arm in arms { - check_pat(cx, &arm.pat, Some(&**init), arm.pat.span, bindings); + check_pat(cx, arm.pat, Some(init), arm.pat.span, bindings); // This is ugly, but needed to get the right type if let Some(ref guard) = arm.guard { match guard { @@ -357,7 +356,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut }, } } - check_expr(cx, &arm.body, bindings); + check_expr(cx, arm.body, bindings); bindings.truncate(len); } }, @@ -367,14 +366,12 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(Symbol, Span)>) { match ty.kind { - TyKind::Slice(ref sty) => check_ty(cx, sty, bindings), - TyKind::Array(ref fty, ref anon_const) => { + TyKind::Slice(sty) => check_ty(cx, sty, bindings), + TyKind::Array(fty, ref anon_const) => { check_ty(cx, fty, bindings); check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings); }, - TyKind::Ptr(MutTy { ty: ref mty, .. }) | TyKind::Rptr(_, MutTy { ty: ref mty, .. }) => { - check_ty(cx, mty, bindings) - }, + TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings), TyKind::Tup(tup) => { for t in tup { check_ty(cx, t, bindings) @@ -387,12 +384,12 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<( fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool { match expr.kind { - ExprKind::Box(ref inner) | ExprKind::AddrOf(_, _, ref inner) => is_self_shadow(name, inner), - ExprKind::Block(ref block, _) => { + ExprKind::Box(inner) | ExprKind::AddrOf(_, _, inner) => is_self_shadow(name, inner), + ExprKind::Block(block, _) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e)) }, - ExprKind::Unary(op, ref inner) => (UnOp::Deref == op) && is_self_shadow(name, inner), - ExprKind::Path(QPath::Resolved(_, ref path)) => path_eq_name(name, path), + ExprKind::Unary(op, inner) => (UnOp::Deref == op) && is_self_shadow(name, inner), + ExprKind::Path(QPath::Resolved(_, path)) => path_eq_name(name, path), _ => false, } } diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index d55a83f1613..8cf89ae456e 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -70,14 +70,14 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)` if_chain! { - if let ExprKind::Assign(ref left, ref right, _) = expr.kind; + if let ExprKind::Assign(left, right, _) = expr.kind; // Extract variable name - if let ExprKind::Path(QPath::Resolved(_, ref path)) = left.kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind; if let Some(variable_name) = path.segments.get(0); // Extract len argument - if let Some(ref len_arg) = Self::is_vec_with_capacity(right); + if let Some(len_arg) = Self::is_vec_with_capacity(right); then { let vi = VecAllocation { @@ -94,10 +94,10 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { - if let StmtKind::Local(ref local) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(BindingAnnotation::Mutable, .., variable_name, None) = local.pat.kind; - if let Some(ref init) = local.init; - if let Some(ref len_arg) = Self::is_vec_with_capacity(init); + if let Some(init) = local.init; + if let Some(len_arg) = Self::is_vec_with_capacity(init); then { let vi = VecAllocation { @@ -117,7 +117,7 @@ impl SlowVectorInit { /// of the first argument of `with_capacity` call if it matches or `None` if it does not. fn is_vec_with_capacity<'tcx>(expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Call(func, args) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if match_qpath(path, &["Vec", "with_capacity"]); if args.len() == 1; @@ -208,11 +208,11 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if let ExprKind::Path(ref qpath_subj) = args[0].kind; - if match_qpath(&qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); + if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); if path.ident.name == sym!(extend); - if let Some(ref extend_arg) = args.get(1); + if let Some(extend_arg) = args.get(1); if self.is_repeat_take(extend_arg); then { @@ -225,11 +225,11 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if let ExprKind::Path(ref qpath_subj) = args[0].kind; - if match_qpath(&qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); + if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); if path.ident.name == sym!(resize); - if let (Some(ref len_arg), Some(fill_arg)) = (args.get(1), args.get(2)); + if let (Some(len_arg), Some(fill_arg)) = (args.get(1), args.get(2)); // Check that is filled with 0 if let ExprKind::Lit(ref lit) = fill_arg.kind; @@ -247,15 +247,15 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(ref take_path, _, ref take_args, _) = expr.kind; + if let ExprKind::MethodCall(take_path, _, take_args, _) = expr.kind; if take_path.ident.name == sym!(take); // Check that take is applied to `repeat(0)` - if let Some(ref repeat_expr) = take_args.get(0); + if let Some(repeat_expr) = take_args.get(0); if Self::is_repeat_zero(repeat_expr); // Check that len expression is equals to `with_capacity` expression - if let Some(ref len_arg) = take_args.get(1); + if let Some(len_arg) = take_args.get(1); if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr); then { @@ -269,10 +269,10 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if given expression is `repeat(0)` fn is_repeat_zero(expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::Call(ref fn_expr, ref repeat_args) = expr.kind; + if let ExprKind::Call(fn_expr, repeat_args) = expr.kind; if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind; - if match_qpath(&qpath_repeat, &["repeat"]); - if let Some(ref repeat_arg) = repeat_args.get(0); + if match_qpath(qpath_repeat, &["repeat"]); + if let Some(repeat_arg) = repeat_args.get(0); if let ExprKind::Lit(ref lit) = repeat_arg.kind; if let LitKind::Int(0, _) = lit.node; @@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { if self.initialization_found { match stmt.kind { - StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { self.search_slow_extend_filling(expr); self.search_slow_resize_filling(expr); }, @@ -306,7 +306,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { - if let Some(ref s) = block.stmts.get(0) { + if let Some(s) = block.stmts.get(0) { self.visit_stmt(s) } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 99ca7ef77a5..9d91b53e1bb 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { Spanned { node: BinOpKind::Add, .. }, - ref left, + left, _, ) = e.kind { @@ -127,7 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { let parent = get_parent_expr(cx, e); if let Some(p) = parent { - if let ExprKind::Assign(ref target, _, _) = p.kind { + if let ExprKind::Assign(target, _, _) = p.kind { // avoid duplicate matches if SpanlessEq::new(cx).eq_expr(target, left) { return; @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { "you added something to a string. Consider using `String::push_str()` instead", ); } - } else if let ExprKind::Assign(ref target, ref src, _) = e.kind { + } else if let ExprKind::Assign(target, src, _) = e.kind { if is_string(cx, target) && is_add(cx, src, target) { span_lint( cx, @@ -166,10 +166,10 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { Spanned { node: BinOpKind::Add, .. }, - ref left, + left, _, ) => SpanlessEq::new(cx).eq_expr(target, left), - ExprKind::Block(ref block, _) => { + ExprKind::Block(block, _) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) }, _ => false, @@ -210,8 +210,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8); // Find string::as_bytes - if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind; - if let ExprKind::Index(ref left, ref right) = args.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind; + if let ExprKind::Index(left, right) = args.kind; let (method_names, expressions, _) = method_calls(left, 1); if method_names.len() == 1; if expressions.len() == 1; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 46f423204a2..cb2237e5312 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -225,7 +225,7 @@ fn attempt_to_emit_no_difference_lint( emit_suggestion( cx, binop.span, - replace_left_sugg(cx, &binop, &sugg, &mut applicability), + replace_left_sugg(cx, binop, &sugg, &mut applicability), applicability, ); return; @@ -247,7 +247,7 @@ fn attempt_to_emit_no_difference_lint( emit_suggestion( cx, binop.span, - replace_right_sugg(cx, &binop, &sugg, &mut applicability), + replace_right_sugg(cx, binop, &sugg, &mut applicability), applicability, ); return; @@ -276,8 +276,8 @@ fn ident_swap_sugg( location: IdentLocation, applicability: &mut Applicability, ) -> Option { - let left_ident = get_ident(&binop.left, location)?; - let right_ident = get_ident(&binop.right, location)?; + let left_ident = get_ident(binop.left, location)?; + let right_ident = get_ident(binop.right, location)?; let sugg = match ( paired_identifiers.contains(&left_ident), @@ -293,8 +293,7 @@ fn ident_swap_sugg( // ends up duplicating a clause, the `logic_bug` lint // should catch it. - let right_suggestion = - suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?; + let right_suggestion = suggestion_with_swapped_ident(cx, binop.right, location, left_ident, applicability)?; replace_right_sugg(cx, binop, &right_suggestion, applicability) }, @@ -302,15 +301,14 @@ fn ident_swap_sugg( // We haven't seen a pair involving the left one, so // it's probably what is wanted. - let right_suggestion = - suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?; + let right_suggestion = suggestion_with_swapped_ident(cx, binop.right, location, left_ident, applicability)?; replace_right_sugg(cx, binop, &right_suggestion, applicability) }, (true, false) => { // We haven't seen a pair involving the right one, so // it's probably what is wanted. - let left_suggestion = suggestion_with_swapped_ident(cx, &binop.left, location, right_ident, applicability)?; + let left_suggestion = suggestion_with_swapped_ident(cx, binop.left, location, right_ident, applicability)?; replace_left_sugg(cx, binop, &left_suggestion, applicability) }, diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 14519eaa962..19967e2c970 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -78,26 +78,26 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { for w in block.stmts.windows(3) { if_chain! { // let t = foo(); - if let StmtKind::Local(ref tmp) = w[0].kind; - if let Some(ref tmp_init) = tmp.init; + if let StmtKind::Local(tmp) = w[0].kind; + if let Some(tmp_init) = tmp.init; if let PatKind::Binding(.., ident, None) = tmp.pat.kind; // foo() = bar(); - if let StmtKind::Semi(ref first) = w[1].kind; - if let ExprKind::Assign(ref lhs1, ref rhs1, _) = first.kind; + if let StmtKind::Semi(first) = w[1].kind; + if let ExprKind::Assign(lhs1, rhs1, _) = first.kind; // bar() = t; - if let StmtKind::Semi(ref second) = w[2].kind; - if let ExprKind::Assign(ref lhs2, ref rhs2, _) = second.kind; - if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind; + if let StmtKind::Semi(second) = w[2].kind; + if let ExprKind::Assign(lhs2, rhs2, _) = second.kind; + if let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind; if rhs2.segments.len() == 1; if ident.name == rhs2.segments[0].ident.name; if eq_expr_value(cx, tmp_init, lhs1); if eq_expr_value(cx, rhs1, lhs2); then { - if let ExprKind::Field(ref lhs1, _) = lhs1.kind { - if let ExprKind::Field(ref lhs2, _) = lhs2.kind { + if let ExprKind::Field(lhs1, _) = lhs1.kind { + if let ExprKind::Field(lhs2, _) = lhs2.kind { if lhs1.hir_id.owner == lhs2.hir_id.owner { return; } @@ -192,8 +192,8 @@ enum Slice<'a> { /// Checks if both expressions are index operations into "slice-like" types. fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> { - if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind { - if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind { + if let ExprKind::Index(lhs1, idx1) = lhs1.kind { + if let ExprKind::Index(lhs2, idx2) = lhs2.kind { if eq_expr_value(cx, lhs1, lhs2) { let ty = cx.typeck_results().expr_ty(lhs1).peel_refs(); @@ -217,11 +217,11 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr< fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { for w in block.stmts.windows(2) { if_chain! { - if let StmtKind::Semi(ref first) = w[0].kind; - if let StmtKind::Semi(ref second) = w[1].kind; + if let StmtKind::Semi(first) = w[0].kind; + if let StmtKind::Semi(second) = w[1].kind; if !differing_macro_contexts(first.span, second.span); - if let ExprKind::Assign(ref lhs0, ref rhs0, _) = first.kind; - if let ExprKind::Assign(ref lhs1, ref rhs1, _) = second.kind; + if let ExprKind::Assign(lhs0, rhs0, _) = first.kind; + if let ExprKind::Assign(lhs1, rhs1, _) = second.kind; if eq_expr_value(cx, lhs0, rhs1); if eq_expr_value(cx, lhs1, rhs0); then { diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index 88bd2feaadd..a0492a88f91 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -86,7 +86,7 @@ impl TabsInDocComments { impl EarlyLintPass for TabsInDocComments { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attribute: &ast::Attribute) { - Self::warn_if_tabs_in_doc(cx, &attribute); + Self::warn_if_tabs_in_doc(cx, attribute); } } diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index 42ec14c31b5..ae05a8da37b 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -92,7 +92,7 @@ impl LateLintPass<'_> for ToStringInDisplay { if_chain! { if self.in_display_impl; if let Some(self_hir_id) = self.self_hir_id; - if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString); diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 3ff27c3bcf4..b0589b0512e 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -107,7 +107,7 @@ impl TraitBounds { if let WherePredicate::BoundPredicate(ref p) = bound; if p.bounds.len() as u64 <= self.max_trait_bounds; if !in_macro(p.span); - let h = hash(&p.bounded_ty); + let h = hash(p.bounded_ty); if let Some(ref v) = map.insert(h, p.bounds.iter().collect::>()); then { @@ -170,7 +170,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !in_macro(bound_predicate.span); - if let TyKind::Path(QPath::Resolved(_, Path { ref segments, .. })) = bound_predicate.bounded_ty.kind; + if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(segment) = segments.first(); if let Some(trait_resolutions_direct) = map.get(&segment.ident); then { diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 47d58bd30db..86ac916df6c 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -325,7 +325,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(ref path_expr, ref args) = e.kind; + if let ExprKind::Call(path_expr, args) = e.kind; if let ExprKind::Path(ref qpath) = path_expr.kind; if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::TRANSMUTE); diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 1a6124e9ddb..3aa3c393ba5 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( let mut arg = sugg::Sugg::hir(cx, expr, ".."); if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind { - expr = &inner_expr; + expr = inner_expr; } if_chain! { diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index c6d0d63b0b5..f359b606e45 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -16,7 +16,7 @@ use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited}; pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String { let seg = last_path_segment(path); if_chain! { - if let Some(ref params) = seg.args; + if let Some(params) = seg.args; if !params.parenthesized; if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index d42cdde110e..0be05d3e0cf 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { } if_chain! { - if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Call(func, args) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if match_qpath(path, &paths::STD_MEM_TRANSMUTE); if args.len() == 1; @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // Catching: // `std::mem::transmute(0 as *const i32)` if_chain! { - if let ExprKind::Cast(ref inner_expr, ref _cast_ty) = args[0].kind; + if let ExprKind::Cast(inner_expr, _cast_ty) = args[0].kind; if let ExprKind::Lit(ref lit) = inner_expr.kind; if let LitKind::Int(0, _) = lit.node; then { @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // Catching: // `std::mem::transmute(std::ptr::null::())` if_chain! { - if let ExprKind::Call(ref func1, ref args1) = args[0].kind; + if let ExprKind::Call(func1, args1) = args[0].kind; if let ExprKind::Path(ref path1) = func1.kind; if match_qpath(path1, &paths::STD_PTR_NULL); if args1.is_empty(); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index e4799790d35..23a1953ffac 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -60,13 +60,13 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { // }; if_chain! { if !in_external_macro(cx.tcx.sess, expr.span); - if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind; - if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind; + if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind; + if let ExprKind::Call(match_fun, try_args) = match_arg.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _)); - if let Some(ref try_arg) = try_args.get(0); - if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind; - if let Some(ref err_arg) = err_args.get(0); + if let Some(try_arg) = try_args.get(0); + if let ExprKind::Call(err_fun, err_args) = try_arg.kind; + if let Some(err_arg) = err_args.get(0); if let ExprKind::Path(ref err_fun_path) = err_fun.kind; if match_qpath(err_fun_path, &paths::RESULT_ERR); if let Some(return_ty) = find_return_type(cx, &expr.kind); @@ -123,9 +123,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { /// Finds function return type by examining return expressions in match arms. fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option> { - if let ExprKind::Match(_, ref arms, MatchSource::TryDesugar) = expr { + if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr { for arm in arms.iter() { - if let ExprKind::Ret(Some(ref ret)) = arm.body.kind { + if let ExprKind::Ret(Some(ret)) = arm.body.kind { return Some(cx.typeck_results().expr_ty(ret)); } } diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index d68c6db4e23..1425d8f3f37 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -19,9 +19,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m if_chain! { if let Some(def_id) = def.opt_def_id(); if Some(def_id) == cx.tcx.lang_items().owned_box(); - if let QPath::Resolved(None, ref path) = *qpath; + if let QPath::Resolved(None, path) = *qpath; if let [ref bx] = *path.segments; - if let Some(ref params) = bx.args; + if let Some(params) = bx.args; if !params.parenthesized; if let Some(inner) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), @@ -86,11 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m // Returns true if given type is `Any` trait. fn is_any_trait(t: &hir::Ty<'_>) -> bool { if_chain! { - if let TyKind::TraitObject(ref traits, ..) = t.kind; + if let TyKind::TraitObject(traits, ..) = t.kind; if !traits.is_empty(); // Only Send/Sync can be used as additional traits, so it is enough to // check only the first trait. - if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT); + if match_path(traits[0].trait_ref.path, &paths::ANY_TRAIT); then { return true; } diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 12e1eba2ca6..d9b47a699dc 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -278,9 +278,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { match item.kind { - ItemKind::Static(ref ty, _, _) | ItemKind::Const(ref ty, _) => { - self.check_ty(cx, ty, CheckTyContext::default()) - }, + ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(cx, ty, CheckTyContext::default()), // functions, enums, structs, impls and traits are covered _ => (), } @@ -288,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { match item.kind { - ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_ty( + ImplItemKind::Const(ty, _) | ImplItemKind::TyAlias(ty) => self.check_ty( cx, ty, CheckTyContext { @@ -302,21 +300,21 @@ impl<'tcx> LateLintPass<'tcx> for Types { } fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { - self.check_ty(cx, &field.ty, CheckTyContext::default()); + self.check_ty(cx, field.ty, CheckTyContext::default()); } fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { match item.kind { - TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => { + TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { self.check_ty(cx, ty, CheckTyContext::default()) }, - TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl, CheckTyContext::default()), + TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()), TraitItemKind::Type(..) => (), } } fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { - if let Some(ref ty) = local.ty { + if let Some(ty) = local.ty { self.check_ty( cx, ty, @@ -342,7 +340,7 @@ impl Types { self.check_ty(cx, input, context); } - if let FnRetTy::Return(ref ty) = decl.output { + if let FnRetTy::Return(ty) = decl.output { self.check_ty(cx, ty, context); } } @@ -383,7 +381,7 @@ impl Types { } } match *qpath { - QPath::Resolved(Some(ref ty), ref p) => { + QPath::Resolved(Some(ty), p) => { context.is_nested_call = true; self.check_ty(cx, ty, context); for ty in p.segments.iter().flat_map(|seg| { @@ -398,7 +396,7 @@ impl Types { self.check_ty(cx, ty, context); } }, - QPath::Resolved(None, ref p) => { + QPath::Resolved(None, p) => { context.is_nested_call = true; for ty in p.segments.iter().flat_map(|seg| { seg.args @@ -412,10 +410,10 @@ impl Types { self.check_ty(cx, ty, context); } }, - QPath::TypeRelative(ref ty, ref seg) => { + QPath::TypeRelative(ty, seg) => { context.is_nested_call = true; self.check_ty(cx, ty, context); - if let Some(ref params) = seg.args { + if let Some(params) = seg.args { for ty in params.args.iter().filter_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, @@ -430,10 +428,10 @@ impl Types { TyKind::Rptr(ref lt, ref mut_ty) => { context.is_nested_call = true; if !borrowed_box::check(cx, hir_ty, lt, mut_ty) { - self.check_ty(cx, &mut_ty.ty, context); + self.check_ty(cx, mut_ty.ty, context); } }, - TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => { + TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => { context.is_nested_call = true; self.check_ty(cx, ty, context) }, diff --git a/clippy_lints/src/types/type_complexity.rs b/clippy_lints/src/types/type_complexity.rs index 9a4e9da3e2b..d8c4b67520d 100644 --- a/clippy_lints/src/types/type_complexity.rs +++ b/clippy_lints/src/types/type_complexity.rs @@ -48,9 +48,9 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1), // function types bring a lot of overhead - TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1), + TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1), - TyKind::TraitObject(ref param_bounds, _, _) => { + TyKind::TraitObject(param_bounds, _, _) => { let has_lifetime_parameters = param_bounds.iter().any(|bound| { bound .bound_generic_params diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index 45f891ed718..0fa75f8f0a9 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::Span; pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option { let last = last_path_segment(qpath); if_chain! { - if let Some(ref params) = last.args; + if let Some(params) = last.args; if !params.parenthesized; if let Some(ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index d2c373db261..7a444174626 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -22,7 +22,7 @@ pub(super) fn check( if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) { if_chain! { // Get the _ part of Vec<_> - if let Some(ref last) = last_path_segment(qpath).args; + if let Some(last) = last_path_segment(qpath).args; if let Some(ty) = last.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, @@ -33,7 +33,7 @@ pub(super) fn check( if let Some(def_id) = res.opt_def_id(); if Some(def_id) == cx.tcx.lang_items().owned_box(); // At this point, we know ty is Box, now get T - if let Some(ref last) = last_path_segment(ty_qpath).args; + if let Some(last) = last_path_segment(ty_qpath).args; if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index b6749069176..f4f5e1233e3 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -35,7 +35,7 @@ declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]); impl LateLintPass<'tcx> for UndroppedManuallyDrops { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(ref args) = match_function_call(cx, expr, &paths::DROP) { + if let Some(args) = match_function_call(cx, expr, &paths::DROP) { let ty = cx.typeck_results().expr_ty(&args[0]); if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop) { span_lint_and_help( diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index cdc65abe47c..47b95b18ffb 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -138,7 +138,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind { + if let ExprKind::MethodCall(_, _, args, _) = expr.kind { let arg_indices = get_args_to_check(cx, expr); for (i, trait_name) in arg_indices { if i < args.len() { diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 8698a718bbd..fad647dfb26 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -9,8 +9,8 @@ use rustc_middle::lint::in_external_macro; use super::LET_UNIT_VALUE; pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(ref local) = stmt.kind { - if cx.typeck_results().pat_ty(&local.pat).is_unit() { + if let StmtKind::Local(local) = stmt.kind { + if cx.typeck_results().pat_ty(local.pat).is_unit() { if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() { return; } diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index f77d811c283..57be2d2f674 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -54,7 +54,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::DesugaringKind; - if let ExprKind::Call(ref callee, _) = expr.kind { + if let ExprKind::Call(callee, _) = expr.kind { callee.span.is_desugaring(DesugaringKind::QuestionMark) } else { false diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index b3077dec5d8..85257f3113c 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -9,7 +9,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if expr.span.from_expansion() { if let Some(callee) = expr.span.source_callee() { if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind { - if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { + if let ExprKind::Binary(ref cmp, left, _) = expr.kind { let op = cmp.node; if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { let result = match &*symbol.as_str() { @@ -34,7 +34,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { return; } - if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { + if let ExprKind::Binary(ref cmp, left, _) = expr.kind { let op = cmp.node; if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { let result = match op { diff --git a/clippy_lints/src/unit_types/utils.rs b/clippy_lints/src/unit_types/utils.rs index 4e194a05e8d..9a3750b2356 100644 --- a/clippy_lints/src/unit_types/utils.rs +++ b/clippy_lints/src/unit_types/utils.rs @@ -1,5 +1,5 @@ use rustc_hir::{Expr, ExprKind}; pub(super) fn is_unit_literal(expr: &Expr<'_>) -> bool { - matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty()) + matches!(expr.kind, ExprKind::Tup(slice) if slice.is_empty()) } diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 9ceb2c3ffe2..9cca05b1f1a 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -77,7 +77,7 @@ impl LateLintPass<'_> for UnnamedAddress { } if_chain! { - if let ExprKind::Binary(binop, ref left, ref right) = expr.kind; + if let ExprKind::Binary(binop, left, right) = expr.kind; if is_comparison(binop.node); if is_trait_ptr(cx, left) && is_trait_ptr(cx, right); then { @@ -93,7 +93,7 @@ impl LateLintPass<'_> for UnnamedAddress { } if_chain! { - if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind; + if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PTR_EQ) || @@ -114,7 +114,7 @@ impl LateLintPass<'_> for UnnamedAddress { } if_chain! { - if let ExprKind::Binary(binop, ref left, ref right) = expr.kind; + if let ExprKind::Binary(binop, left, right) = expr.kind; if is_comparison(binop.node); if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr(); if cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr(); diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index e23bab5eba0..03711eb5b65 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -187,15 +187,15 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if method_path.ident.name == sym::cmp; then { let (closure_body, closure_arg, reverse) = if mirrored_exprs( - &cx, - &left_expr, - &left_ident, - &right_expr, - &right_ident + cx, + left_expr, + left_ident, + right_expr, + right_ident ) { - (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string(), false) - } else if mirrored_exprs(&cx, &left_expr, &right_ident, &right_expr, &left_ident) { - (Sugg::hir(cx, &left_expr, "..").to_string(), right_ident.name.to_string(), true) + (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false) + } else if mirrored_exprs(cx, left_expr, right_ident, right_expr, left_ident) { + (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true) } else { return None; }; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index c2be457e9dc..5bb417cb1be 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if_chain! { if !in_macro(ret_expr.span); // Check if a function call. - if let ExprKind::Call(ref func, ref args) = ret_expr.kind; + if let ExprKind::Call(func, args) = ret_expr.kind; // Get the Path of the function call. if let ExprKind::Path(ref qpath) = func.kind; // Check if OPTION_SOME or RESULT_OK, depending on return type. diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 9990052e114..024ab03fd41 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -36,13 +36,13 @@ declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]); impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { let expr = match s.kind { - hir::StmtKind::Semi(ref expr) | hir::StmtKind::Expr(ref expr) => &**expr, + hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr, _ => return, }; match expr.kind { - hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => { - if let hir::ExprKind::Call(ref func, ref args) = res.kind { + hir::ExprKind::Match(res, _, _) if is_try(expr).is_some() => { + if let hir::ExprKind::Call(func, args) = res.kind { if matches!( func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _)) @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { } }, - hir::ExprKind::MethodCall(ref path, _, ref args, _) => match &*path.ident.as_str() { + hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { check_method_call(cx, &args[0], expr); }, @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { } fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { - if let hir::ExprKind::MethodCall(ref path, _, _, _) = call.kind { + if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind { let symbol = &*path.ident.as_str(); let read_trait = match_trait_method(cx, call, &paths::IO_READ); let write_trait = match_trait_method(cx, call, &paths::IO_WRITE); diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 329ea49024b..ce2d0b3ab2f 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -45,7 +45,7 @@ impl EarlyLintPass for UnusedUnit { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { if_chain! { - if let Some(ref stmt) = block.stmts.last(); + if let Some(stmt) = block.stmts.last(); if let ast::StmtKind::Expr(ref expr) = stmt.kind; if is_unit_expr(expr) && !stmt.span.from_expansion(); then { diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index fb29acca18a..d4efee56eff 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -166,8 +166,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { } else { // find `unwrap[_err]()` calls: if_chain! { - if let ExprKind::MethodCall(ref method_name, _, ref args, _) = expr.kind; - if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].kind; + if let ExprKind::MethodCall(method_name, _, args, _) = expr.kind; + if let ExprKind::Path(QPath::Resolved(None, path)) = args[0].kind; if [sym::unwrap, sym!(unwrap_err)].contains(&method_name.ident.name); let call_to_unwrap = method_name.ident.name == sym::unwrap; if let Some(unwrappable) = self.unwrappables.iter() diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 116cb8b1e1c..c6a3c58a9a2 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { of_trait, .. }) => { - let should_check = if let TyKind::Path(QPath::Resolved(_, ref item_path)) = hir_self_ty.kind { + let should_check = if let TyKind::Path(QPath::Resolved(_, item_path)) = hir_self_ty.kind { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; parameters.as_ref().map_or(true, |params| { !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) @@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) { if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) { let mut visitor = SkipTyCollector::default(); - visitor.visit_ty(&impl_hir_ty); + visitor.visit_ty(impl_hir_ty); types_to_skip.extend(visitor.types_to_skip); } } @@ -333,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { // unit enum variants (`Enum::A`) ExprKind::Path(qpath) => { if expr_ty_matches(cx, expr, self_ty) { - span_lint_on_qpath_resolved(cx, &qpath, true); + span_lint_on_qpath_resolved(cx, qpath, true); } }, _ => (), diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index d893b271a20..7edb280be73 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -53,17 +53,17 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } match e.kind { - ExprKind::Match(_, ref arms, MatchSource::TryDesugar) => { + ExprKind::Match(_, arms, MatchSource::TryDesugar) => { let e = match arms[0].body.kind { - ExprKind::Ret(Some(ref e)) | ExprKind::Break(_, Some(ref e)) => e, + ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e, _ => return, }; - if let ExprKind::Call(_, ref args) = e.kind { + if let ExprKind::Call(_, args) = e.kind { self.try_desugar_arm.push(args[0].hir_id); } }, - ExprKind::MethodCall(ref name, .., ref args, _) => { + ExprKind::MethodCall(name, .., args, _) => { if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } if match_trait_method(cx, e, &paths::INTO_ITERATOR) && name.ident.name == sym::into_iter { if let Some(parent_expr) = get_parent_expr(cx, e) { - if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind { + if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind { if parent_name.ident.name != sym::into_iter { return; } @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, - ExprKind::Call(ref path, ref args) => { + ExprKind::Call(path, args) => { if_chain! { if args.len() == 1; if let ExprKind::Path(ref qpath) = path.kind; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index a92c987014f..e70f8a09ebe 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -203,13 +203,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { print!(" if let ExprKind::"); let current = format!("{}.kind", self.current); match expr.kind { - ExprKind::Box(ref inner) => { + ExprKind::Box(inner) => { let inner_pat = self.next("inner"); println!("Box(ref {}) = {};", inner_pat, current); self.current = inner_pat; self.visit_expr(inner); }, - ExprKind::Array(ref elements) => { + ExprKind::Array(elements) => { let elements_pat = self.next("elements"); println!("Array(ref {}) = {};", elements_pat, current); println!(" if {}.len() == {};", elements_pat, elements.len()); @@ -218,7 +218,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.visit_expr(element); } }, - ExprKind::Call(ref func, ref args) => { + ExprKind::Call(func, args) => { let func_pat = self.next("func"); let args_pat = self.next("args"); println!("Call(ref {}, ref {}) = {};", func_pat, args_pat, current); @@ -230,14 +230,14 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.visit_expr(arg); } }, - ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => { + ExprKind::MethodCall(_method_name, ref _generics, _args, ref _fn_span) => { println!( "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};", current ); println!(" // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment"); }, - ExprKind::Tup(ref elements) => { + ExprKind::Tup(elements) => { let elements_pat = self.next("elements"); println!("Tup(ref {}) = {};", elements_pat, current); println!(" if {}.len() == {};", elements_pat, elements.len()); @@ -246,7 +246,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.visit_expr(element); } }, - ExprKind::Binary(ref op, ref left, ref right) => { + ExprKind::Binary(ref op, left, right) => { let op_pat = self.next("op"); let left_pat = self.next("left"); let right_pat = self.next("right"); @@ -260,7 +260,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = right_pat; self.visit_expr(right); }, - ExprKind::Unary(ref op, ref inner) => { + ExprKind::Unary(ref op, inner) => { let inner_pat = self.next("inner"); println!("Unary(UnOp::{:?}, ref {}) = {};", op, inner_pat, current); self.current = inner_pat; @@ -296,7 +296,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { }, } }, - ExprKind::Cast(ref expr, ref ty) => { + ExprKind::Cast(expr, ty) => { let cast_pat = self.next("expr"); let cast_ty = self.next("cast_ty"); let qp_label = self.next("qp"); @@ -310,13 +310,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = cast_pat; self.visit_expr(expr); }, - ExprKind::Type(ref expr, ref _ty) => { + ExprKind::Type(expr, _ty) => { let cast_pat = self.next("expr"); println!("Type(ref {}, _) = {};", cast_pat, current); self.current = cast_pat; self.visit_expr(expr); }, - ExprKind::Loop(ref body, _, desugaring, _) => { + ExprKind::Loop(body, _, desugaring, _) => { let body_pat = self.next("body"); let des = loop_desugaring_name(desugaring); let label_pat = self.next("label"); @@ -324,10 +324,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = body_pat; self.visit_block(body); }, - ExprKind::If(ref cond, ref then, ref opt_else) => { + ExprKind::If(cond, then, ref opt_else) => { let cond_pat = self.next("cond"); let then_pat = self.next("then"); - if let Some(ref else_) = *opt_else { + if let Some(else_) = *opt_else { let else_pat = self.next("else_"); println!( "If(ref {}, ref {}, Some(ref {})) = {};", @@ -343,7 +343,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = then_pat; self.visit_expr(then); }, - ExprKind::Match(ref expr, ref arms, desugaring) => { + ExprKind::Match(expr, arms, desugaring) => { let des = desugaring_name(desugaring); let expr_pat = self.next("expr"); let arms_pat = self.next("arms"); @@ -353,18 +353,18 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!(" if {}.len() == {};", arms_pat, arms.len()); for (i, arm) in arms.iter().enumerate() { self.current = format!("{}[{}].body", arms_pat, i); - self.visit_expr(&arm.body); + self.visit_expr(arm.body); if let Some(ref guard) = arm.guard { let guard_pat = self.next("guard"); println!(" if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i); match guard { - hir::Guard::If(ref if_expr) => { + hir::Guard::If(if_expr) => { let if_expr_pat = self.next("expr"); println!(" if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat); self.current = if_expr_pat; self.visit_expr(if_expr); }, - hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => { + hir::Guard::IfLet(if_let_pat, if_let_expr) => { let if_let_pat_pat = self.next("pat"); let if_let_expr_pat = self.next("expr"); println!( @@ -379,26 +379,26 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { } } self.current = format!("{}[{}].pat", arms_pat, i); - self.visit_pat(&arm.pat); + self.visit_pat(arm.pat); } }, - ExprKind::Closure(ref _capture_clause, ref _func, _, _, _) => { + ExprKind::Closure(ref _capture_clause, _func, _, _, _) => { println!("Closure(ref capture_clause, ref func, _, _, _) = {};", current); println!(" // unimplemented: `ExprKind::Closure` is not further destructured at the moment"); }, - ExprKind::Yield(ref sub, _) => { + ExprKind::Yield(sub, _) => { let sub_pat = self.next("sub"); println!("Yield(ref sub) = {};", current); self.current = sub_pat; self.visit_expr(sub); }, - ExprKind::Block(ref block, _) => { + ExprKind::Block(block, _) => { let block_pat = self.next("block"); println!("Block(ref {}) = {};", block_pat, current); self.current = block_pat; self.visit_block(block); }, - ExprKind::Assign(ref target, ref value, _) => { + ExprKind::Assign(target, value, _) => { let target_pat = self.next("target"); let value_pat = self.next("value"); println!( @@ -410,7 +410,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = value_pat; self.visit_expr(value); }, - ExprKind::AssignOp(ref op, ref target, ref value) => { + ExprKind::AssignOp(ref op, target, value) => { let op_pat = self.next("op"); let target_pat = self.next("target"); let value_pat = self.next("value"); @@ -424,7 +424,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = value_pat; self.visit_expr(value); }, - ExprKind::Field(ref object, ref field_ident) => { + ExprKind::Field(object, ref field_ident) => { let obj_pat = self.next("object"); let field_name_pat = self.next("field_name"); println!("Field(ref {}, ref {}) = {};", obj_pat, field_name_pat, current); @@ -432,7 +432,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = obj_pat; self.visit_expr(object); }, - ExprKind::Index(ref object, ref index) => { + ExprKind::Index(object, index) => { let object_pat = self.next("object"); let index_pat = self.next("index"); println!("Index(ref {}, ref {}) = {};", object_pat, index_pat, current); @@ -447,7 +447,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = path_pat; self.print_qpath(path); }, - ExprKind::AddrOf(kind, mutability, ref inner) => { + ExprKind::AddrOf(kind, mutability, inner) => { let inner_pat = self.next("inner"); println!( "AddrOf(BorrowKind::{:?}, Mutability::{:?}, ref {}) = {};", @@ -458,7 +458,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { }, ExprKind::Break(ref _destination, ref opt_value) => { let destination_pat = self.next("destination"); - if let Some(ref value) = *opt_value { + if let Some(value) = *opt_value { let value_pat = self.next("value"); println!("Break(ref {}, Some(ref {})) = {};", destination_pat, value_pat, current); self.current = value_pat; @@ -474,7 +474,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { // FIXME: implement label printing }, ExprKind::Ret(ref opt_value) => { - if let Some(ref value) = *opt_value { + if let Some(value) = *opt_value { let value_pat = self.next("value"); println!("Ret(Some(ref {})) = {};", value_pat, current); self.current = value_pat; @@ -491,10 +491,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!("LlvmInlineAsm(_) = {};", current); println!(" // unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment"); }, - ExprKind::Struct(ref path, ref fields, ref opt_base) => { + ExprKind::Struct(path, fields, ref opt_base) => { let path_pat = self.next("path"); let fields_pat = self.next("fields"); - if let Some(ref base) = *opt_base { + if let Some(base) = *opt_base { let base_pat = self.next("base"); println!( "Struct(ref {}, ref {}, Some(ref {})) = {};", @@ -516,7 +516,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = value_pat; }, // FIXME: compute length (needs type info) - ExprKind::Repeat(ref value, _) => { + ExprKind::Repeat(value, _) => { let value_pat = self.next("value"); println!("Repeat(ref {}, _) = {};", value_pat, current); println!("// unimplemented: repeat count check"); @@ -526,7 +526,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { ExprKind::Err => { println!("Err = {}", current); }, - ExprKind::DropTemps(ref expr) => { + ExprKind::DropTemps(expr) => { let expr_pat = self.next("expr"); println!("DropTemps(ref {}) = {};", expr_pat, current); self.current = expr_pat; @@ -560,7 +560,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { BindingAnnotation::RefMut => "BindingAnnotation::RefMut", }; let name_pat = self.next("name"); - if let Some(ref sub) = *sub { + if let Some(sub) = *sub { let sub_pat = self.next("sub"); println!( "Binding({}, _, {}, Some(ref {})) = {};", @@ -573,7 +573,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { } println!(" if {}.as_str() == \"{}\";", name_pat, ident.as_str()); }, - PatKind::Struct(ref path, ref fields, ignore) => { + PatKind::Struct(ref path, fields, ignore) => { let path_pat = self.next("path"); let fields_pat = self.next("fields"); println!( @@ -585,13 +585,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!(" if {}.len() == {};", fields_pat, fields.len()); println!(" // unimplemented: field checks"); }, - PatKind::Or(ref fields) => { + PatKind::Or(fields) => { let fields_pat = self.next("fields"); println!("Or(ref {}) = {};", fields_pat, current); println!(" if {}.len() == {};", fields_pat, fields.len()); println!(" // unimplemented: field checks"); }, - PatKind::TupleStruct(ref path, ref fields, skip_pos) => { + PatKind::TupleStruct(ref path, fields, skip_pos) => { let path_pat = self.next("path"); let fields_pat = self.next("fields"); println!( @@ -609,25 +609,25 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = path_pat; self.print_qpath(path); }, - PatKind::Tuple(ref fields, skip_pos) => { + PatKind::Tuple(fields, skip_pos) => { let fields_pat = self.next("fields"); println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current); println!(" if {}.len() == {};", fields_pat, fields.len()); println!(" // unimplemented: field checks"); }, - PatKind::Box(ref pat) => { + PatKind::Box(pat) => { let pat_pat = self.next("pat"); println!("Box(ref {}) = {};", pat_pat, current); self.current = pat_pat; self.visit_pat(pat); }, - PatKind::Ref(ref pat, muta) => { + PatKind::Ref(pat, muta) => { let pat_pat = self.next("pat"); println!("Ref(ref {}, Mutability::{:?}) = {};", pat_pat, muta, current); self.current = pat_pat; self.visit_pat(pat); }, - PatKind::Lit(ref lit_expr) => { + PatKind::Lit(lit_expr) => { let lit_expr_pat = self.next("lit_expr"); println!("Lit(ref {}) = {}", lit_expr_pat, current); self.current = lit_expr_pat; @@ -645,10 +645,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = end_pat; walk_list!(self, visit_expr, end); }, - PatKind::Slice(ref start, ref middle, ref end) => { + PatKind::Slice(start, ref middle, end) => { let start_pat = self.next("start"); let end_pat = self.next("end"); - if let Some(ref middle) = middle { + if let Some(middle) = middle { let middle_pat = self.next("middle"); println!( "Slice(ref {}, Some(ref {}), ref {}) = {};", @@ -678,17 +678,17 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { let current = format!("{}.kind", self.current); match s.kind { // A local (let) binding: - StmtKind::Local(ref local) => { + StmtKind::Local(local) => { let local_pat = self.next("local"); println!("Local(ref {}) = {};", local_pat, current); - if let Some(ref init) = local.init { + if let Some(init) = local.init { let init_pat = self.next("init"); println!(" if let Some(ref {}) = {}.init;", init_pat, local_pat); self.current = init_pat; self.visit_expr(init); } self.current = format!("{}.pat", local_pat); - self.visit_pat(&local.pat); + self.visit_pat(local.pat); }, // An item binding: StmtKind::Item(_) => { @@ -696,7 +696,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { }, // Expr without trailing semi-colon (must have unit type): - StmtKind::Expr(ref e) => { + StmtKind::Expr(e) => { let e_pat = self.next("e"); println!("Expr(ref {}, _) = {}", e_pat, current); self.current = e_pat; @@ -704,7 +704,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { }, // Expr with trailing semi-colon (may have any type): - StmtKind::Semi(ref e) => { + StmtKind::Semi(e) => { let e_pat = self.next("e"); println!("Semi(ref {}, _) = {}", e_pat, current); self.current = e_pat; @@ -752,7 +752,7 @@ fn loop_desugaring_name(des: hir::LoopSource) -> &'static str { fn print_path(path: &QPath<'_>, first: &mut bool) { match *path { - QPath::Resolved(_, ref path) => { + QPath::Resolved(_, path) => { for segment in path.segments { if *first { *first = false; @@ -762,7 +762,7 @@ fn print_path(path: &QPath<'_>, first: &mut bool) { print!("{:?}", segment.ident.as_str()); } }, - QPath::TypeRelative(ref ty, ref segment) => match ty.kind { + QPath::TypeRelative(ty, segment) => match ty.kind { hir::TyKind::Path(ref inner_path) => { print_path(inner_path, first); if *first { diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 6fd3c9d7dec..32d34e8d31e 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { match item.vis.node { hir::VisibilityKind::Public => println!("public"), hir::VisibilityKind::Crate(_) => println!("visible crate wide"), - hir::VisibilityKind::Restricted { ref path, .. } => println!( + hir::VisibilityKind::Restricted { path, .. } => println!( "visible in module `{}`", rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false)) ), @@ -99,13 +99,13 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { if !has_attr(cx.sess(), cx.tcx.hir().attrs(arm.hir_id)) { return; } - print_pat(cx, &arm.pat, 1); + print_pat(cx, arm.pat, 1); if let Some(ref guard) = arm.guard { println!("guard:"); print_guard(cx, guard, 1); } println!("body:"); - print_expr(cx, &arm.body, 1); + print_expr(cx, arm.body, 1); } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { @@ -113,17 +113,17 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { return; } match stmt.kind { - hir::StmtKind::Local(ref local) => { + hir::StmtKind::Local(local) => { println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id)); println!("pattern:"); - print_pat(cx, &local.pat, 0); - if let Some(ref e) = local.init { + print_pat(cx, local.pat, 0); + if let Some(e) = local.init { println!("init expression:"); print_expr(cx, e, 0); } }, hir::StmtKind::Item(_) => println!("item decl"), - hir::StmtKind::Expr(ref e) | hir::StmtKind::Semi(ref e) => print_expr(cx, e, 0), + hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) => print_expr(cx, e, 0), } } // fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx @@ -151,7 +151,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { cx.typeck_results().adjustments().get(expr.hir_id) ); match expr.kind { - hir::ExprKind::Box(ref e) => { + hir::ExprKind::Box(e) => { println!("{}Box", ind); print_expr(cx, e, indent + 1); }, @@ -161,7 +161,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, e, indent + 1); } }, - hir::ExprKind::Call(ref func, args) => { + hir::ExprKind::Call(func, args) => { println!("{}Call", ind); println!("{}function:", ind); print_expr(cx, func, indent + 1); @@ -170,7 +170,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, arg, indent + 1); } }, - hir::ExprKind::MethodCall(ref path, _, args, _) => { + hir::ExprKind::MethodCall(path, _, args, _) => { println!("{}MethodCall", ind); println!("{}method name: {}", ind, path.ident.name); for arg in args { @@ -183,7 +183,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, e, indent + 1); } }, - hir::ExprKind::Binary(op, ref lhs, ref rhs) => { + hir::ExprKind::Binary(op, lhs, rhs) => { println!("{}Binary", ind); println!("{}op: {:?}", ind, op.node); println!("{}lhs:", ind); @@ -191,7 +191,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}rhs:", ind); print_expr(cx, rhs, indent + 1); }, - hir::ExprKind::Unary(op, ref inner) => { + hir::ExprKind::Unary(op, inner) => { println!("{}Unary", ind); println!("{}op: {:?}", ind, op); print_expr(cx, inner, indent + 1); @@ -200,12 +200,12 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}Lit", ind); println!("{}{:?}", ind, lit); }, - hir::ExprKind::Cast(ref e, ref target) => { + hir::ExprKind::Cast(e, target) => { println!("{}Cast", ind); print_expr(cx, e, indent + 1); println!("{}target type: {:?}", ind, target); }, - hir::ExprKind::Type(ref e, ref target) => { + hir::ExprKind::Type(e, target) => { println!("{}Type", ind); print_expr(cx, e, indent + 1); println!("{}target type: {:?}", ind, target); @@ -213,16 +213,16 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { hir::ExprKind::Loop(..) => { println!("{}Loop", ind); }, - hir::ExprKind::If(ref cond, _, ref else_opt) => { + hir::ExprKind::If(cond, _, ref else_opt) => { println!("{}If", ind); println!("{}condition:", ind); print_expr(cx, cond, indent + 1); - if let Some(ref els) = *else_opt { + if let Some(els) = *else_opt { println!("{}else:", ind); print_expr(cx, els, indent + 1); } }, - hir::ExprKind::Match(ref cond, _, ref source) => { + hir::ExprKind::Match(cond, _, ref source) => { println!("{}Match", ind); println!("{}condition:", ind); print_expr(cx, cond, indent + 1); @@ -232,21 +232,21 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}Closure", ind); println!("{}clause: {:?}", ind, clause); }, - hir::ExprKind::Yield(ref sub, _) => { + hir::ExprKind::Yield(sub, _) => { println!("{}Yield", ind); print_expr(cx, sub, indent + 1); }, hir::ExprKind::Block(_, _) => { println!("{}Block", ind); }, - hir::ExprKind::Assign(ref lhs, ref rhs, _) => { + hir::ExprKind::Assign(lhs, rhs, _) => { println!("{}Assign", ind); println!("{}lhs:", ind); print_expr(cx, lhs, indent + 1); println!("{}rhs:", ind); print_expr(cx, rhs, indent + 1); }, - hir::ExprKind::AssignOp(ref binop, ref lhs, ref rhs) => { + hir::ExprKind::AssignOp(ref binop, lhs, rhs) => { println!("{}AssignOp", ind); println!("{}op: {:?}", ind, binop.node); println!("{}lhs:", ind); @@ -254,31 +254,31 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}rhs:", ind); print_expr(cx, rhs, indent + 1); }, - hir::ExprKind::Field(ref e, ident) => { + hir::ExprKind::Field(e, ident) => { println!("{}Field", ind); println!("{}field name: {}", ind, ident.name); println!("{}struct expr:", ind); print_expr(cx, e, indent + 1); }, - hir::ExprKind::Index(ref arr, ref idx) => { + hir::ExprKind::Index(arr, idx) => { println!("{}Index", ind); println!("{}array expr:", ind); print_expr(cx, arr, indent + 1); println!("{}index expr:", ind); print_expr(cx, idx, indent + 1); }, - hir::ExprKind::Path(hir::QPath::Resolved(ref ty, ref path)) => { + hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => { println!("{}Resolved Path, {:?}", ind, ty); println!("{}path: {:?}", ind, path); }, - hir::ExprKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => { + hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => { println!("{}Relative Path, {:?}", ind, ty); println!("{}seg: {:?}", ind, seg); }, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => { println!("{}Lang Item Path, {:?}", ind, lang_item.name()); }, - hir::ExprKind::AddrOf(kind, ref muta, ref e) => { + hir::ExprKind::AddrOf(kind, ref muta, e) => { println!("{}AddrOf", ind); println!("kind: {:?}", kind); println!("mutability: {:?}", muta); @@ -286,18 +286,18 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { }, hir::ExprKind::Break(_, ref e) => { println!("{}Break", ind); - if let Some(ref e) = *e { + if let Some(e) = *e { print_expr(cx, e, indent + 1); } }, hir::ExprKind::Continue(_) => println!("{}Again", ind), hir::ExprKind::Ret(ref e) => { println!("{}Ret", ind); - if let Some(ref e) = *e { + if let Some(e) = *e { print_expr(cx, e, indent + 1); } }, - hir::ExprKind::InlineAsm(ref asm) => { + hir::ExprKind::InlineAsm(asm) => { println!("{}InlineAsm", ind); println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template)); println!("{}options: {:?}", ind, asm.options); @@ -322,7 +322,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { } } }, - hir::ExprKind::LlvmInlineAsm(ref asm) => { + hir::ExprKind::LlvmInlineAsm(asm) => { let inputs = &asm.inputs_exprs; let outputs = &asm.outputs_exprs; println!("{}LlvmInlineAsm", ind); @@ -335,14 +335,14 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, e, indent + 1); } }, - hir::ExprKind::Struct(ref path, fields, ref base) => { + hir::ExprKind::Struct(path, fields, ref base) => { println!("{}Struct", ind); println!("{}path: {:?}", ind, path); for field in fields { println!("{}field \"{}\":", ind, field.ident.name); - print_expr(cx, &field.expr, indent + 1); + print_expr(cx, field.expr, indent + 1); } - if let Some(ref base) = *base { + if let Some(base) = *base { println!("{}base:", ind); print_expr(cx, base, indent + 1); } @@ -352,7 +352,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}anon_const:", ind); print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); }, - hir::ExprKind::Repeat(ref val, ref anon_const) => { + hir::ExprKind::Repeat(val, ref anon_const) => { println!("{}Repeat", ind); println!("{}value:", ind); print_expr(cx, val, indent + 1); @@ -362,7 +362,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { hir::ExprKind::Err => { println!("{}Err", ind); }, - hir::ExprKind::DropTemps(ref e) => { + hir::ExprKind::DropTemps(e) => { println!("{}DropTemps", ind); print_expr(cx, e, indent + 1); }, @@ -375,7 +375,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { match item.vis.node { hir::VisibilityKind::Public => println!("public"), hir::VisibilityKind::Crate(_) => println!("visible crate wide"), - hir::VisibilityKind::Restricted { ref path, .. } => println!( + hir::VisibilityKind::Restricted { path, .. } => println!( "visible in module `{}`", rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false)) ), @@ -395,7 +395,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { println!("weird extern crate without a crate id"); } }, - hir::ItemKind::Use(ref path, ref kind) => println!("{:?}, {:?}", path, kind), + hir::ItemKind::Use(path, ref kind) => println!("{:?}, {:?}", path, kind), hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)), hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)), hir::ItemKind::Fn(..) => { @@ -404,7 +404,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { }, hir::ItemKind::Mod(..) => println!("module"), hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi), - hir::ItemKind::GlobalAsm(ref asm) => println!("global asm: {:?}", asm), + hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm), hir::ItemKind::TyAlias(..) => { println!("type alias for {:?}", cx.tcx.type_of(did)); }, @@ -454,7 +454,7 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { println!("{}Binding", ind); println!("{}mode: {:?}", ind, mode); println!("{}name: {}", ind, ident.name); - if let Some(ref inner) = *inner { + if let Some(inner) = *inner { println!("{}inner:", ind); print_pat(cx, inner, indent + 1); } @@ -479,7 +479,7 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { if field.is_shorthand { println!("{} in shorthand notation", ind); } - print_pat(cx, &field.pat, indent + 1); + print_pat(cx, field.pat, indent + 1); } }, hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => { @@ -496,11 +496,11 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { print_pat(cx, field, indent + 1); } }, - hir::PatKind::Path(hir::QPath::Resolved(ref ty, ref path)) => { + hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => { println!("{}Resolved Path, {:?}", ind, ty); println!("{}path: {:?}", ind, path); }, - hir::PatKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => { + hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => { println!("{}Relative Path, {:?}", ind, ty); println!("{}seg: {:?}", ind, seg); }, @@ -516,16 +516,16 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { print_pat(cx, field, indent + 1); } }, - hir::PatKind::Box(ref inner) => { + hir::PatKind::Box(inner) => { println!("{}Box", ind); print_pat(cx, inner, indent + 1); }, - hir::PatKind::Ref(ref inner, ref muta) => { + hir::PatKind::Ref(inner, ref muta) => { println!("{}Ref", ind); println!("{}mutability: {:?}", ind, muta); print_pat(cx, inner, indent + 1); }, - hir::PatKind::Lit(ref e) => { + hir::PatKind::Lit(e) => { println!("{}Lit", ind); print_expr(cx, e, indent + 1); }, @@ -549,7 +549,7 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { print_pat(cx, pat, indent + 1); } println!("i:"); - if let Some(ref pat) = *range { + if let Some(pat) = *range { print_pat(cx, pat, indent + 1); } println!("[y, z]:"); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index d5a13c135b1..cf8039d6059 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -353,12 +353,12 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { return; } - if let hir::ItemKind::Static(ref ty, Mutability::Not, body_id) = item.kind { + if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind { if is_lint_ref_type(cx, ty) { let expr = &cx.tcx.hir().body(body_id).value; if_chain! { - if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind; - if let ExprKind::Struct(_, ref fields, _) = inner_exp.kind; + if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind; + if let ExprKind::Struct(_, fields, _) = inner_exp.kind; let field = fields .iter() .find(|f| f.ident.as_str() == "desc") @@ -385,7 +385,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { { if let hir::ItemKind::Impl(hir::Impl { of_trait: None, - items: ref impl_item_refs, + items: impl_item_refs, .. }) = item.kind { @@ -437,7 +437,7 @@ fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool { if let TyKind::Rptr( _, MutTy { - ty: ref inner, + ty: inner, mutbl: Mutability::Not, }, ) = ty.kind @@ -498,7 +498,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { } if_chain! { - if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, args, _) = expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(&*fn_name.as_str()); let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); @@ -577,7 +577,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { } if_chain! { - if let ExprKind::Call(ref func, ref and_then_args) = expr.kind; + if let ExprKind::Call(func, and_then_args) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if match_qpath(path, &["span_lint_and_then"]); if and_then_args.len() == 5; @@ -587,7 +587,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { let stmts = &block.stmts; if stmts.len() == 1 && block.expr.is_none(); if let StmtKind::Semi(only_expr) = &stmts[0].kind; - if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind; + if let ExprKind::MethodCall(ps, _, span_call_args, _) = &only_expr.kind; then { let and_then_snippets = get_and_then_snippets(cx, and_then_args); let mut sle = SpanlessEq::new(cx).deny_side_effects(); @@ -762,7 +762,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { // Check if this is a call to utils::match_type() if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; if let ExprKind::Path(fn_qpath) = &fn_path.kind; - if match_qpath(&fn_qpath, &["utils", "match_type"]); + if match_qpath(fn_qpath, &["utils", "match_type"]); // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, ty_path); let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index bc2eb88114e..febd4b6ff7b 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { if_chain! { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind(); if let ty::Slice(..) = ty.kind(); - if let ExprKind::AddrOf(BorrowKind::Ref, mutability, ref addressee) = expr.kind; + if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind; if let Some(vec_args) = higher::vec_macro(cx, addressee); then { self.check_vec_macro(cx, &vec_args, mutability, expr.span); diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index e035d3c5cad..5540e87405f 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -30,7 +30,7 @@ declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]); impl<'tcx> LateLintPass<'tcx> for VecResizeToZero { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let hir::ExprKind::MethodCall(path_segment, _, ref args, _) = expr.kind; + if let hir::ExprKind::MethodCall(path_segment, _, args, _) = expr.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3; if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 3b4890ad560..350b1cf25ff 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -31,7 +31,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // check for instances of 0.0/0.0 if_chain! { - if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind; + if let ExprKind::Binary(ref op, left, right) = expr.kind; if let BinOpKind::Div = op.node; // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 2abd033e2a0..f93f0047f51 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -50,7 +50,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues { if !in_trait_impl(cx, hir_ty.hir_id); let ty = ty_from_hir_ty(cx, hir_ty); if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || match_type(cx, ty, &paths::BTREEMAP); - if let Adt(_, ref substs) = ty.kind(); + if let Adt(_, substs) = ty.kind(); let ty = substs.type_at(1); // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`. if is_normalizable(cx, cx.param_env, ty); diff --git a/src/driver.rs b/src/driver.rs index b6aed862e89..fa0c5f01430 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -99,17 +99,17 @@ impl rustc_driver::Callbacks for ClippyCallbacks { config.parse_sess_created = Some(Box::new(move |parse_sess| { track_clippy_args(parse_sess, &clippy_args_var); })); - config.register_lints = Some(Box::new(move |sess, mut lint_store| { + config.register_lints = Some(Box::new(move |sess, lint_store| { // technically we're ~guaranteed that this is none but might as well call anything that // is there already. Certainly it can't hurt. if let Some(previous) = &previous { (previous)(sess, lint_store); } - let conf = clippy_lints::read_conf(&[], &sess); - clippy_lints::register_plugins(&mut lint_store, &sess, &conf); - clippy_lints::register_pre_expansion_lints(&mut lint_store); - clippy_lints::register_renamed(&mut lint_store); + let conf = clippy_lints::read_conf(&[], sess); + clippy_lints::register_plugins(lint_store, sess, &conf); + clippy_lints::register_pre_expansion_lints(lint_store); + clippy_lints::register_renamed(lint_store); })); // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be @@ -191,7 +191,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { ]; for note in &xs { - handler.note_without_error(¬e); + handler.note_without_error(note); } // If backtraces are enabled, also print the query stack diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 0594663786c..f4d354f0bf9 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -98,7 +98,7 @@ fn default_config() -> compiletest::Config { fn run_mode(cfg: &mut compiletest::Config) { cfg.mode = TestMode::Ui; cfg.src_base = Path::new("tests").join("ui"); - compiletest::run_tests(&cfg); + compiletest::run_tests(cfg); } fn run_internal_tests(cfg: &mut compiletest::Config) { @@ -108,7 +108,7 @@ fn run_internal_tests(cfg: &mut compiletest::Config) { } cfg.mode = TestMode::Ui; cfg.src_base = Path::new("tests").join("ui-internal"); - compiletest::run_tests(&cfg); + compiletest::run_tests(cfg); } fn run_ui_toml(config: &mut compiletest::Config) { @@ -136,7 +136,7 @@ fn run_ui_toml(config: &mut compiletest::Config) { base: config.src_base.clone(), relative_dir: dir_path.file_name().unwrap().into(), }; - let test_name = compiletest::make_test_name(&config, &paths); + let test_name = compiletest::make_test_name(config, &paths); let index = tests .iter() .position(|test| test.desc.name == test_name) @@ -150,10 +150,10 @@ fn run_ui_toml(config: &mut compiletest::Config) { config.mode = TestMode::Ui; config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap(); - let tests = compiletest::make_tests(&config); + let tests = compiletest::make_tests(config); let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default(); - let res = run_tests(&config, tests); + let res = run_tests(config, tests); set_var("CARGO_MANIFEST_DIR", &manifest_dir); match res { Ok(true) => {}, @@ -221,7 +221,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) { base: config.src_base.clone(), relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(), }; - let test_name = compiletest::make_test_name(&config, &paths); + let test_name = compiletest::make_test_name(config, &paths); let index = tests .iter() .position(|test| test.desc.name == test_name) @@ -240,11 +240,11 @@ fn run_ui_cargo(config: &mut compiletest::Config) { config.mode = TestMode::Ui; config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap(); - let tests = compiletest::make_tests(&config); + let tests = compiletest::make_tests(config); let current_dir = env::current_dir().unwrap(); let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default(); - let res = run_tests(&config, &config.filters, tests); + let res = run_tests(config, &config.filters, tests); env::set_current_dir(current_dir).unwrap(); set_var("CLIPPY_CONF_DIR", conf_dir); diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs index ea25729d11d..4327f12c37c 100644 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -1,5 +1,9 @@ #![warn(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)] +#![allow( + clippy::declare_interior_mutable_const, + clippy::ref_in_deref, + clippy::needless_borrow +)] #![allow(const_item_mutation)] use std::borrow::Cow; diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 9a908cf30e9..f146b97cf61 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:54:5 + --> $DIR/others.rs:58:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -8,7 +8,7 @@ LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:55:16 + --> $DIR/others.rs:59:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:58:22 + --> $DIR/others.rs:62:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:59:25 + --> $DIR/others.rs:63:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:60:27 + --> $DIR/others.rs:64:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:61:26 + --> $DIR/others.rs:65:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:72:14 + --> $DIR/others.rs:76:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:73:14 + --> $DIR/others.rs:77:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:74:19 + --> $DIR/others.rs:78:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:75:14 + --> $DIR/others.rs:79:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:76:13 + --> $DIR/others.rs:80:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:82:13 + --> $DIR/others.rs:86:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:87:5 + --> $DIR/others.rs:91:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +104,7 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/others.rs:88:16 + --> $DIR/others.rs:92:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ diff --git a/tests/ui/collapsible_match2.rs b/tests/ui/collapsible_match2.rs index 8372a212477..542e6948427 100644 --- a/tests/ui/collapsible_match2.rs +++ b/tests/ui/collapsible_match2.rs @@ -1,5 +1,10 @@ #![warn(clippy::collapsible_match)] -#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] +#![allow( + clippy::needless_return, + clippy::no_effect, + clippy::single_match, + clippy::needless_borrow +)] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { // if guards on outer match diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr index c8a445ef369..ffef32d1fde 100644 --- a/tests/ui/collapsible_match2.stderr +++ b/tests/ui/collapsible_match2.stderr @@ -1,5 +1,5 @@ error: unnecessary nested match - --> $DIR/collapsible_match2.rs:8:34 + --> $DIR/collapsible_match2.rs:13:34 | LL | Ok(val) if make() => match val { | __________________________________^ @@ -10,7 +10,7 @@ LL | | }, | = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match2.rs:8:16 + --> $DIR/collapsible_match2.rs:13:16 | LL | Ok(val) if make() => match val { | ^^^ replace this binding @@ -18,7 +18,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: unnecessary nested match - --> $DIR/collapsible_match2.rs:15:24 + --> $DIR/collapsible_match2.rs:20:24 | LL | Ok(val) => match val { | ________________________^ @@ -28,7 +28,7 @@ LL | | }, | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match2.rs:15:16 + --> $DIR/collapsible_match2.rs:20:16 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -36,7 +36,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: unnecessary nested match - --> $DIR/collapsible_match2.rs:29:29 + --> $DIR/collapsible_match2.rs:34:29 | LL | $pat => match $e { | _____________________________^ @@ -49,7 +49,7 @@ LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); | ------------------------------------------------- in this macro invocation | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match2.rs:41:28 + --> $DIR/collapsible_match2.rs:46:28 | LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); | ^^^ ^^^^^^^ with this pattern @@ -58,7 +58,7 @@ LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unnecessary nested match - --> $DIR/collapsible_match2.rs:46:20 + --> $DIR/collapsible_match2.rs:51:20 | LL | Some(s) => match *s { | ____________________^ @@ -68,7 +68,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match2.rs:46:14 + --> $DIR/collapsible_match2.rs:51:14 | LL | Some(s) => match *s { | ^ replace this binding @@ -76,7 +76,7 @@ LL | [n] => foo(n), | ^^^ with this pattern error: unnecessary nested match - --> $DIR/collapsible_match2.rs:55:24 + --> $DIR/collapsible_match2.rs:60:24 | LL | Some(ref s) => match &*s { | ________________________^ @@ -86,7 +86,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match2.rs:55:14 + --> $DIR/collapsible_match2.rs:60:14 | LL | Some(ref s) => match &*s { | ^^^^^ replace this binding diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index d26f48fc68f..13e2b6c7a2e 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -101,7 +101,7 @@ fn warn_match() { let x = box A; match &x { // not moved - ref y => (), + y => (), } } @@ -111,7 +111,7 @@ fn nowarn_large_array() { let x = box [1; 10000]; match &x { // not moved - ref y => (), + y => (), } } diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index 19101522163..cef71cf79d7 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -66,7 +66,7 @@ fn main() { let _ = vec.to_vec(); let vec_ref = &vec; - let _ = return_owned_from_slice(&vec_ref); + let _ = return_owned_from_slice(vec_ref); let _ = vec_ref.to_owned(); let _ = vec_ref.to_vec(); diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index 7f92d0dbdc9..b77f17944d8 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] struct X; diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 416056d3fdb..3854bb05af8 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] struct X; diff --git a/tests/ui/ref_option_ref.rs b/tests/ui/ref_option_ref.rs index b2c275d68af..2df45c927d7 100644 --- a/tests/ui/ref_option_ref.rs +++ b/tests/ui/ref_option_ref.rs @@ -9,7 +9,7 @@ static THRESHOLD: i32 = 10; static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD); const CONST_THRESHOLD: &i32 = &10; -const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD); +const REF_CONST: &Option<&i32> = &Some(CONST_THRESHOLD); type RefOptRefU32<'a> = &'a Option<&'a u32>; type RefOptRef<'a, T> = &'a Option<&'a T>; diff --git a/tests/ui/ref_option_ref.stderr b/tests/ui/ref_option_ref.stderr index 4e7fc800061..b61334758e8 100644 --- a/tests/ui/ref_option_ref.stderr +++ b/tests/ui/ref_option_ref.stderr @@ -9,7 +9,7 @@ LL | static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD); error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` --> $DIR/ref_option_ref.rs:12:18 | -LL | const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD); +LL | const REF_CONST: &Option<&i32> = &Some(CONST_THRESHOLD); | ^^^^^^^^^^^^^ help: try: `Option<&i32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` diff --git a/tests/ui/stable_sort_primitive.fixed b/tests/ui/stable_sort_primitive.fixed index 8f8f5665931..f5f18169df2 100644 --- a/tests/ui/stable_sort_primitive.fixed +++ b/tests/ui/stable_sort_primitive.fixed @@ -20,7 +20,7 @@ fn main() { // Negative examples: behavior changes if made unstable let mut vec = vec![1, 3, 2]; vec.sort_by_key(|i| i / 2); - vec.sort_by(|a, b| (a + b).cmp(&b)); + vec.sort_by(|&a, &b| (a + b).cmp(&b)); // negative examples - Not of a primitive type let mut vec_of_complex = vec![String::from("hello"), String::from("world!")]; vec_of_complex.sort(); diff --git a/tests/ui/stable_sort_primitive.rs b/tests/ui/stable_sort_primitive.rs index f9bd9779067..8149c5638e0 100644 --- a/tests/ui/stable_sort_primitive.rs +++ b/tests/ui/stable_sort_primitive.rs @@ -20,7 +20,7 @@ fn main() { // Negative examples: behavior changes if made unstable let mut vec = vec![1, 3, 2]; vec.sort_by_key(|i| i / 2); - vec.sort_by(|a, b| (a + b).cmp(&b)); + vec.sort_by(|&a, &b| (a + b).cmp(&b)); // negative examples - Not of a primitive type let mut vec_of_complex = vec![String::from("hello"), String::from("world!")]; vec_of_complex.sort(); -- cgit 1.4.1-3-g733a5 From 47f0c15f67e334338b82deef1e812f157a54dcf2 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 24 Mar 2021 09:31:43 -0500 Subject: Symbol optimizations --- clippy_lints/src/attrs.rs | 112 +++++++++++++++----------------- clippy_lints/src/excessive_bools.rs | 6 +- clippy_lints/src/functions/must_use.rs | 6 +- clippy_lints/src/macro_use.rs | 6 +- clippy_lints/src/methods/or_fun_call.rs | 6 +- clippy_lints/src/option_env_unwrap.rs | 4 +- clippy_utils/src/lib.rs | 9 +-- 7 files changed, 67 insertions(+), 82 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 382fb03d920..c5b01461c1c 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -250,12 +250,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { if let Some(items) = &attr.meta_item_list() { if let Some(ident) = attr.ident() { - let ident = &*ident.as_str(); - match ident { - "allow" | "warn" | "deny" | "forbid" => { - check_clippy_lint_names(cx, ident, items); - }, - _ => {}, + if is_lint_level(ident.name) { + check_clippy_lint_names(cx, ident.name, items); } if items.is_empty() || !attr.has_name(sym::deprecated) { return; @@ -288,60 +284,54 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { return; } if let Some(lint_list) = &attr.meta_item_list() { - if let Some(ident) = attr.ident() { - match &*ident.as_str() { - "allow" | "warn" | "deny" | "forbid" => { - // permit `unused_imports`, `deprecated`, `unreachable_pub`, - // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items - // and `unused_imports` for `extern crate` items with `macro_use` - for lint in lint_list { - match item.kind { - ItemKind::Use(..) => { - if is_word(lint, sym!(unused_imports)) - || is_word(lint, sym::deprecated) - || is_word(lint, sym!(unreachable_pub)) - || is_word(lint, sym!(unused)) - || extract_clippy_lint(lint) - .map_or(false, |s| s == "wildcard_imports") - || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use") - { - return; - } - }, - ItemKind::ExternCrate(..) => { - if is_word(lint, sym!(unused_imports)) && skip_unused_imports { - return; - } - if is_word(lint, sym!(unused_extern_crates)) { - return; - } - }, - _ => {}, + if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) { + // permit `unused_imports`, `deprecated`, `unreachable_pub`, + // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items + // and `unused_imports` for `extern crate` items with `macro_use` + for lint in lint_list { + match item.kind { + ItemKind::Use(..) => { + if is_word(lint, sym!(unused_imports)) + || is_word(lint, sym::deprecated) + || is_word(lint, sym!(unreachable_pub)) + || is_word(lint, sym!(unused)) + || extract_clippy_lint(lint).map_or(false, |s| s == "wildcard_imports") + || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use") + { + return; + } + }, + ItemKind::ExternCrate(..) => { + if is_word(lint, sym!(unused_imports)) && skip_unused_imports { + return; } - } - let line_span = first_line_of_span(cx, attr.span); - - if let Some(mut sugg) = snippet_opt(cx, line_span) { - if sugg.contains("#[") { - span_lint_and_then( - cx, - USELESS_ATTRIBUTE, + if is_word(lint, sym!(unused_extern_crates)) { + return; + } + }, + _ => {}, + } + } + let line_span = first_line_of_span(cx, attr.span); + + if let Some(mut sugg) = snippet_opt(cx, line_span) { + if sugg.contains("#[") { + span_lint_and_then( + cx, + USELESS_ATTRIBUTE, + line_span, + "useless lint attribute", + |diag| { + sugg = sugg.replacen("#[", "#![", 1); + diag.span_suggestion( line_span, - "useless lint attribute", - |diag| { - sugg = sugg.replacen("#[", "#![", 1); - diag.span_suggestion( - line_span, - "if you just forgot a `!`, use", - sugg, - Applicability::MaybeIncorrect, - ); - }, + "if you just forgot a `!`, use", + sugg, + Applicability::MaybeIncorrect, ); - } - } - }, - _ => {}, + }, + ); + } } } } @@ -379,10 +369,10 @@ fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { None } -fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { +fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { - if lint_name == "restriction" && ident != "allow" { + if lint_name == "restriction" && name != sym::allow { span_lint_and_help( cx, BLANKET_CLIPPY_RESTRICTION_LINTS, @@ -647,3 +637,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { } } } + +fn is_lint_level(symbol: Symbol) -> bool { + matches!(symbol, sym::allow | sym::warn | sym::deny | sym::forbid) +} diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 6c9652fd87d..249ee27330b 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{attr_by_name, in_macro, match_path_ast}; +use clippy_utils::{in_macro, match_path_ast}; use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use std::convert::TryInto; @@ -138,7 +138,7 @@ impl EarlyLintPass for ExcessiveBools { } match &item.kind { ItemKind::Struct(variant_data, _) => { - if attr_by_name(&item.attrs, "repr").is_some() { + if item.attrs.iter().any(|attr| attr.has_name(sym::repr)) { return; } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index db5fe90b663..9ea8e2eaa2a 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -8,13 +8,13 @@ use rustc_middle::{ lint::in_external_macro, ty::{self, Ty}, }; -use rustc_span::Span; +use rustc_span::{sym, Span}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; -use clippy_utils::{attr_by_name, match_def_path, must_use_attr, return_ty, trait_ref_of_method}; +use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method}; use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; @@ -27,7 +27,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); return; - } else if is_public && !is_proc_macro(cx.sess(), attrs) && attr_by_name(attrs, "no_mangle").is_none() { + } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, sig.decl, diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index d573c297838..c506d52e746 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{edition::Edition, Span}; +use rustc_span::{edition::Edition, sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for `#[macro_use] use...`. @@ -110,9 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { if cx.sess().opts.edition >= Edition::Edition2018; if let hir::ItemKind::Use(path, _kind) = &item.kind; let attrs = cx.tcx.hir().attrs(item.hir_id()); - if let Some(mac_attr) = attrs - .iter() - .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string())); + if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)); if let Res::Def(DefKind::Mod, id) = path.res; then { for kid in cx.tcx.item_children(id).iter() { diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index df89da5d3e0..800172f4cf3 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -10,7 +10,7 @@ use rustc_hir::{BlockCheckMode, UnsafeSource}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Span; -use rustc_span::symbol::sym; +use rustc_span::symbol::{kw, sym}; use std::borrow::Cow; use super::OR_FUN_CALL; @@ -38,8 +38,8 @@ pub(super) fn check<'tcx>( if !or_has_args; if name == "unwrap_or"; if let hir::ExprKind::Path(ref qpath) = fun.kind; - let path = &*last_path_segment(qpath).ident.as_str(); - if ["default", "new"].contains(&path); + let path = last_path_segment(qpath).ident.name; + if matches!(path, kw::Default | sym::new); let arg_ty = cx.typeck_results().expr_ty(arg); if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); if implements_trait(cx, arg_ty, default_trait_id, &[]); diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index a0bc324e026..b6f518661bd 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -4,6 +4,7 @@ use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `option_env!(...).unwrap()` and @@ -37,8 +38,7 @@ impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind; - let method_name = path_segment.ident.as_str(); - if method_name == "expect" || method_name == "unwrap"; + if matches!(path_segment.ident.name, sym::expect | sym::unwrap); if let ExprKind::Call(caller, _) = &args[0].kind; if is_direct_expn_of(caller.span, "option_env").is_some(); then { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 64f86f5f101..6088cd323c4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1203,16 +1203,9 @@ pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { ) } -// Finds the attribute with the given name, if any -pub fn attr_by_name<'a>(attrs: &'a [Attribute], name: &'_ str) -> Option<&'a Attribute> { - attrs - .iter() - .find(|attr| attr.ident().map_or(false, |ident| ident.as_str() == name)) -} - // Finds the `#[must_use]` attribute, if any pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { - attr_by_name(attrs, "must_use") + attrs.iter().find(|a| a.has_name(sym::must_use)) } // check if expr is calling method or function with #[must_use] attribute -- cgit 1.4.1-3-g733a5 From 7468542328caf3f0114ac4733fe2b76e2ed79954 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 2 Apr 2021 17:09:58 -0500 Subject: Introduce is_lang_ctor --- clippy_lints/src/collapsible_match.rs | 27 ++++------- clippy_lints/src/if_then_some_else_none.rs | 9 ++-- clippy_lints/src/loops/manual_flatten.rs | 11 +++-- clippy_lints/src/manual_map.rs | 35 ++++---------- clippy_lints/src/manual_ok_or.rs | 9 ++-- clippy_lints/src/manual_unwrap_or.rs | 25 +++++----- clippy_lints/src/matches.rs | 38 +++++++-------- clippy_lints/src/mem_replace.rs | 7 +-- clippy_lints/src/methods/option_map_or_none.rs | 7 +-- clippy_lints/src/methods/unnecessary_filter_map.rs | 7 +-- clippy_lints/src/needless_question_mark.rs | 8 ++-- clippy_lints/src/option_if_let_else.rs | 6 +-- clippy_lints/src/question_mark.rs | 17 ++----- clippy_lints/src/try_err.rs | 5 +- clippy_lints/src/unnecessary_wraps.rs | 11 +++-- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_utils/src/lib.rs | 54 +++++++++------------- 17 files changed, 121 insertions(+), 157 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index 04fff237bb4..ab22578abd6 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::visitors::LocalUsedVisitor; -use clippy_utils::{path_to_local, SpanlessEq}; +use clippy_utils::{is_lang_ctor, path_to_local, SpanlessEq}; use if_chain::if_chain; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp}; +use rustc_hir::LangItem::OptionNone; +use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{DefIdTree, TyCtxt, TypeckResults}; +use rustc_middle::ty::TypeckResults; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{MultiSpan, Span}; @@ -52,7 +52,7 @@ declare_lint_pass!(CollapsibleMatch => [COLLAPSIBLE_MATCH]); impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::Match(_expr, arms, _source) = expr.kind { - if let Some(wild_arm) = arms.iter().rfind(|arm| arm_is_wild_like(arm, cx.tcx)) { + if let Some(wild_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { for arm in arms { check_arm(arm, wild_arm, cx); } @@ -75,7 +75,7 @@ fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext // match { .. } if let Some(binding_id) = path_to_local(strip_ref_operators(expr_in, cx.typeck_results())); // one of the branches must be "wild-like" - if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx)); + if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(cx, arm_inner)); let (wild_inner_arm, non_wild_inner_arm) = (&arms_inner[wild_inner_arm_idx], &arms_inner[1 - wild_inner_arm_idx]); if !pat_contains_or(non_wild_inner_arm.pat); @@ -126,13 +126,13 @@ fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> /// A "wild-like" pattern is wild ("_") or `None`. /// For this lint to apply, both the outer and inner match expressions /// must have "wild-like" branches that can be combined. -fn arm_is_wild_like(arm: &Arm<'_>, tcx: TyCtxt<'_>) -> bool { +fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if arm.guard.is_some() { return false; } match arm.pat.kind { PatKind::Binding(..) | PatKind::Wild => true, - PatKind::Path(QPath::Resolved(None, path)) if is_none_ctor(path.res, tcx) => true, + PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), _ => false, } } @@ -164,17 +164,6 @@ fn pat_contains_or(pat: &Pat<'_>) -> bool { result } -fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool { - if let Some(none_id) = tcx.lang_items().option_none_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = res { - if let Some(variant_id) = tcx.parent(id) { - return variant_id == none_id; - } - } - } - false -} - /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. fn strip_ref_operators<'hir>(mut expr: &'hir Expr<'hir>, typeck_results: &TypeckResults<'_>) -> &'hir Expr<'hir> { diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index ee16519692f..f73b3a1fe67 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{match_qpath, meets_msrv, parent_node_is_if_expr}; +use clippy_utils::{is_lang_ctor, meets_msrv, parent_node_is_if_expr}; use if_chain::if_chain; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -77,12 +78,12 @@ impl LateLintPass<'_> for IfThenSomeElseNone { if let Some(then_expr) = then_block.expr; if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind; if let ExprKind::Path(ref then_call_qpath) = then_call.kind; - if match_qpath(then_call_qpath, &clippy_utils::paths::OPTION_SOME); + if is_lang_ctor(cx, then_call_qpath, OptionSome); if let ExprKind::Block(els_block, _) = els.kind; if els_block.stmts.is_empty(); if let Some(els_expr) = els_block.expr; - if let ExprKind::Path(ref els_call_qpath) = els_expr.kind; - if match_qpath(els_call_qpath, &clippy_utils::paths::OPTION_NONE); + if let ExprKind::Path(ref qpath) = els_expr.kind; + if is_lang_ctor(cx, qpath, OptionNone); then { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 94743cfcf46..64ff7574f86 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -1,10 +1,11 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{is_ok_ctor, is_some_ctor, path_to_local_id}; +use clippy_utils::{is_lang_ctor, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, StmtKind}; +use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, StmtKind}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Span; @@ -42,9 +43,9 @@ pub(super) fn check<'tcx>( if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; if path_to_local_id(match_expr, pat_hir_id); // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` - if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; - let some_ctor = is_some_ctor(cx, path.res); - let ok_ctor = is_ok_ctor(cx, path.res); + if let PatKind::TupleStruct(ref qpath, _, _) = match_arms[0].pat.kind; + let some_ctor = is_lang_ctor(cx, qpath, OptionSome); + let ok_ctor = is_lang_ctor(cx, qpath, ResultOk); if some_ctor || ok_ctor; then { let if_let_type = if some_ctor { "Some" } else { "Ok" }; diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 8c9e3af62f4..29be0739977 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -2,9 +2,10 @@ use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{can_partially_move_ty, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{in_constant, is_allowed, is_else_clause, match_def_path, match_var, paths, peel_hir_expr_refs}; +use clippy_utils::{in_constant, is_allowed, is_else_clause, is_lang_ctor, match_var, peel_hir_expr_refs}; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{ def::Res, intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}, @@ -269,20 +270,9 @@ fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxCon match pat.kind { PatKind::Wild => Some(OptionPat::Wild), PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt), - PatKind::Path(QPath::Resolved(None, path)) - if path - .res - .opt_def_id() - .map_or(false, |id| match_def_path(cx, id, &paths::OPTION_NONE)) => - { - Some(OptionPat::None) - }, - PatKind::TupleStruct(QPath::Resolved(None, path), [pattern], _) - if path - .res - .opt_def_id() - .map_or(false, |id| match_def_path(cx, id, &paths::OPTION_SOME)) - && pat.span.ctxt() == ctxt => + PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None), + PatKind::TupleStruct(ref qpath, [pattern], _) + if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt => { Some(OptionPat::Some { pattern, ref_count }) }, @@ -298,17 +288,11 @@ fn get_some_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ctxt: SyntaxConte match expr.kind { ExprKind::Call( Expr { - kind: ExprKind::Path(QPath::Resolved(None, path)), + kind: ExprKind::Path(ref qpath), .. }, [arg], - ) if ctxt == expr.span.ctxt() => { - if match_def_path(cx, path.res.opt_def_id()?, &paths::OPTION_SOME) { - Some(arg) - } else { - None - } - }, + ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(arg), ExprKind::Block( Block { stmts: [], @@ -324,10 +308,7 @@ fn get_some_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ctxt: SyntaxConte // Checks for the `None` value. fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { match expr.kind { - ExprKind::Path(QPath::Resolved(None, path)) => path - .res - .opt_def_id() - .map_or(false, |id| match_def_path(cx, id, &paths::OPTION_NONE)), + ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), ExprKind::Block( Block { stmts: [], diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 9bfae602c40..847c8c648b0 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_qpath, path_to_local_id, paths}; +use clippy_utils::{is_lang_ctor, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; @@ -54,7 +55,7 @@ impl LateLintPass<'_> for ManualOkOr { let or_expr = &args[1]; if is_ok_wrapping(cx, &args[2]); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; - if match_qpath(err_path, &paths::RESULT_ERR); + if is_lang_ctor(cx, err_path, ResultErr); if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); if let Some(indent) = indent_of(cx, scrutinee.span); @@ -81,7 +82,7 @@ impl LateLintPass<'_> for ManualOkOr { fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { if let ExprKind::Path(ref qpath) = map_expr.kind { - if match_qpath(qpath, &paths::RESULT_OK) { + if is_lang_ctor(cx, qpath, ResultOk) { return true; } } @@ -90,7 +91,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { let body = cx.tcx.hir().body(body_id); if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; - if match_qpath(ok_path, &paths::RESULT_OK); + if is_lang_ctor(cx, ok_path, ResultOk); then { path_to_local_id(ok_arg, param_id) } else { false } } } diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index f296d6a1a15..65baa2552cc 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -3,10 +3,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{in_constant, match_qpath, path_to_local_id, paths, sugg}; +use clippy_utils::{in_constant, is_lang_ctor, path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::{Arm, Expr, ExprKind, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -68,23 +69,21 @@ impl Case { } fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - fn applicable_or_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { + fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if_chain! { if arms.len() == 2; if arms.iter().all(|arm| arm.guard.is_none()); - if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| + if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| { match arm.pat.kind { - PatKind::Path(ref some_qpath) => - match_qpath(some_qpath, &paths::OPTION_NONE), - PatKind::TupleStruct(ref err_qpath, &[Pat { kind: PatKind::Wild, .. }], _) => - match_qpath(err_qpath, &paths::RESULT_ERR), + PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::TupleStruct(ref qpath, &[pat], _) => + matches!(pat.kind, PatKind::Wild) && is_lang_ctor(cx, qpath, ResultErr), _ => false, } - ); + }); let unwrap_arm = &arms[1 - idx]; - if let PatKind::TupleStruct(ref unwrap_qpath, &[unwrap_pat], _) = unwrap_arm.pat.kind; - if match_qpath(unwrap_qpath, &paths::OPTION_SOME) - || match_qpath(unwrap_qpath, &paths::RESULT_OK); + if let PatKind::TupleStruct(ref qpath, &[unwrap_pat], _) = unwrap_arm.pat.kind; + if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); if !contains_return_break_continue_macro(or_arm.body); @@ -106,7 +105,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { } else { None }; - if let Some(or_arm) = applicable_or_arm(match_arms); + if let Some(or_arm) = applicable_or_arm(cx, match_arms); if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span); if let Some(indent) = indent_of(cx, expr.span); if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some(); diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index a892e24482b..72f5eed6531 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -7,7 +7,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use clippy_utils::visitors::LocalUsedVisitor; use clippy_utils::{ - get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local, + get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs, }; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; @@ -15,6 +15,7 @@ use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{ self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource, Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind, @@ -1188,10 +1189,10 @@ fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], e fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() { - let arm_ref: Option = if is_none_arm(&arms[0]) { - is_ref_some_arm(&arms[1]) - } else if is_none_arm(&arms[1]) { - is_ref_some_arm(&arms[0]) + let arm_ref: Option = if is_none_arm(cx, &arms[0]) { + is_ref_some_arm(cx, &arms[1]) + } else if is_none_arm(cx, &arms[1]) { + is_ref_some_arm(cx, &arms[0]) } else { None }; @@ -1574,20 +1575,20 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool { } // Checks if arm has the form `None => None` -fn is_none_arm(arm: &Arm<'_>) -> bool { - matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE)) +fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { + matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) -fn is_ref_some_arm(arm: &Arm<'_>) -> Option { +fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if_chain! { - if let PatKind::TupleStruct(ref path, pats, _) = arm.pat.kind; - if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME); + if let PatKind::TupleStruct(ref qpath, pats, _) = arm.pat.kind; + if is_lang_ctor(cx, qpath, OptionSome); if let PatKind::Binding(rb, .., ident, _) = pats[0].kind; if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut; if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; - if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1; + if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1; if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { @@ -1699,10 +1700,11 @@ mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; - use clippy_utils::{is_trait_method, match_qpath, paths}; + use clippy_utils::{is_lang_ctor, is_trait_method, match_qpath, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; + use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -1734,13 +1736,13 @@ mod redundant_pattern_match { let good_method = match kind { PatKind::TupleStruct(ref path, patterns, _) if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { - if match_qpath(path, &paths::RESULT_OK) { + if is_lang_ctor(cx, path, ResultOk) { "is_ok()" - } else if match_qpath(path, &paths::RESULT_ERR) { + } else if is_lang_ctor(cx, path, ResultErr) { "is_err()" - } else if match_qpath(path, &paths::OPTION_SOME) { + } else if is_lang_ctor(cx, path, OptionSome) { "is_some()" - } else if match_qpath(path, &paths::POLL_READY) { + } else if is_lang_ctor(cx, path, PollReady) { "is_ready()" } else if match_qpath(path, &paths::IPADDR_V4) { "is_ipv4()" @@ -1754,9 +1756,9 @@ mod redundant_pattern_match { } }, PatKind::Path(ref path) => { - if match_qpath(path, &paths::OPTION_NONE) { + if is_lang_ctor(cx, path, OptionNone) { "is_none()" - } else if match_qpath(path, &paths::POLL_PENDING) { + } else if is_lang_ctor(cx, path, PollPending) { "is_pending()" } else { return; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index e1d351aee45..1f521ec6090 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::is_diagnostic_assoc_item; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, match_def_path, match_qpath, meets_msrv, paths}; +use clippy_utils::{in_macro, match_def_path, meets_msrv, paths}; +use clippy_utils::{is_diagnostic_assoc_item, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem::OptionNone; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -102,7 +103,7 @@ impl_lint_pass!(MemReplace => fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if let ExprKind::Path(ref replacement_qpath) = src.kind { // Check that second argument is `Option::None` - if match_qpath(replacement_qpath, &paths::OPTION_NONE) { + if is_lang_ctor(cx, replacement_qpath, OptionNone) { // Since this is a late pass (already type-checked), // and we already know that the second argument is an // `Option`, we do not need to check the first diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 013a6f90ac9..36a1c13d5be 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_qpath, paths}; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -32,7 +33,7 @@ pub(super) fn check<'tcx>( let (lint_name, msg, instead, hint) = { let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { - match_qpath(qpath, &paths::OPTION_NONE) + is_lang_ctor(cx, qpath, OptionNone) } else { return; }; @@ -43,7 +44,7 @@ pub(super) fn check<'tcx>( } let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { - match_qpath(qpath, &paths::OPTION_SOME) + is_lang_ctor(cx, qpath, OptionSome) } else { false }; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 0f28bfdf09e..66255b77331 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::usage::mutated_variables; -use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use clippy_utils::{is_lang_ctor, is_trait_method, path_to_local_id}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_span::sym; @@ -54,7 +55,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc match &expr.kind { hir::ExprKind::Call(func, args) => { if let hir::ExprKind::Path(ref path) = func.kind { - if match_qpath(path, &paths::OPTION_SOME) { + if is_lang_ctor(cx, path, OptionSome) { if path_to_local_id(&args[0], arg_id) { return (false, false); } @@ -85,7 +86,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc let else_check = check_expression(cx, arg_id, else_arm); (if_check.0 | else_check.0, if_check.1 | else_check.1) }, - hir::ExprKind::Path(path) if match_qpath(path, &paths::OPTION_NONE) => (false, true), + hir::ExprKind::Path(path) if is_lang_ctor(cx, path, OptionNone) => (false, true), _ => (true, true), } } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 9852633b734..cfe7ae6630e 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, is_ok_ctor, is_some_ctor, meets_msrv}; +use clippy_utils::{differing_macro_contexts, meets_msrv}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_semver::RustcVersion; @@ -159,8 +161,8 @@ fn is_some_or_ok_call<'a>( if_chain! { // Check outer expression matches CALL_IDENT(ARGUMENT) format if let ExprKind::Call(path, args) = &expr.kind; - if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind; - if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); + if let ExprKind::Path(ref qpath) = &path.kind; + if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); // Extract inner expression from ARGUMENT if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 1b9120ae45f..e527adbb892 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, match_qpath}; +use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::LangItem::OptionSome; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -164,7 +164,7 @@ fn detect_option_if_let_else<'tcx>( if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; - if match_qpath(struct_qpath, &paths::OPTION_SOME); + if is_lang_ctor(cx, struct_qpath, OptionSome); if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; if !contains_return_break_continue_macro(arms[0].body); if !contains_return_break_continue_macro(arms[1].body); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 6d720f43851..ea9ff37e13f 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eq_expr_value, match_def_path, match_qpath, paths}; +use clippy_utils::{eq_expr_value, match_qpath}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind}; +use rustc_hir::LangItem::OptionNone; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -156,15 +157,7 @@ impl QuestionMark { false }, ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr), - ExprKind::Path(ref qp) => { - if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) = - cx.qpath_res(qp, expression.hir_id) - { - return match_def_path(cx, def_id, &paths::OPTION_NONE); - } - - false - }, + ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), _ => false, } } diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 23a1953ffac..0b8c03c6865 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths}; +use clippy_utils::{differing_macro_contexts, in_macro, is_lang_ctor, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::LangItem::ResultErr; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { if let ExprKind::Call(err_fun, err_args) = try_arg.kind; if let Some(err_arg) = err_args.get(0); if let ExprKind::Path(ref err_fun_path) = err_fun.kind; - if match_qpath(err_fun_path, &paths::RESULT_ERR); + if is_lang_ctor(cx, err_fun_path, ResultErr); if let Some(return_ty) = find_return_type(cx, &expr.kind); then { let prefix; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 5bb417cb1be..d2c0f60d296 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{contains_return, in_macro, match_qpath, paths, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::{contains_return, in_macro, is_lang_ctor, return_ty, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; +use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -85,11 +86,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } // Get the wrapper and inner types, if can't, abort. - let (return_type_label, path, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() { + let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() { if cx.tcx.is_diagnostic_item(sym::option_type, adt_def.did) { - ("Option", &paths::OPTION_SOME, subst.type_at(0)) + ("Option", OptionSome, subst.type_at(0)) } else if cx.tcx.is_diagnostic_item(sym::result_type, adt_def.did) { - ("Result", &paths::RESULT_OK, subst.type_at(0)) + ("Result", ResultOk, subst.type_at(0)) } else { return; } @@ -107,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Get the Path of the function call. if let ExprKind::Path(ref qpath) = func.kind; // Check if OPTION_SOME or RESULT_OK, depending on return type. - if match_qpath(qpath, path); + if is_lang_ctor(cx, qpath, lang_item); if args.len() == 1; // Make sure the function argument does not contain a return expression. if !contains_return(&args[0]); diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 024ab03fd41..5e8e530f480 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { }; match expr.kind { - hir::ExprKind::Match(res, _, _) if is_try(expr).is_some() => { + hir::ExprKind::Match(res, _, _) if is_try(cx, expr).is_some() => { if let hir::ExprKind::Call(func, args) = res.kind { if matches!( func.kind, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 64f86f5f101..1d61b7dd412 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -56,9 +56,10 @@ use if_chain::if_chain; use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::LangItem::{ResultErr, ResultOk}; use rustc_hir::{ def, Arm, BindingAnnotation, Block, Body, Constness, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, MatchSource, Node, Param, Pat, PatKind, Path, PathSegment, QPath, @@ -221,6 +222,19 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { } } +/// Checks if a `QPath` resolves to a constructor of a `LangItem`. +/// For example, use this to check whether a function call or a pattern is `Some(..)`. +pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool { + if let QPath::Resolved(_, path) = qpath { + if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res { + if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) { + return cx.tcx.parent(ctor_id) == Some(item_id); + } + } + } + false +} + /// Returns `true` if this `span` was expanded by any macro. #[must_use] pub fn in_macro(span: Span) -> bool { @@ -1010,11 +1024,11 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It /// Checks if a given expression is a match expression expanded from the `?` /// operator or the `try` macro. -pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { - fn is_ok(arm: &Arm<'_>) -> bool { +pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if_chain! { if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind; - if match_qpath(path, &paths::RESULT_OK[1..]); + if is_lang_ctor(cx, path, ResultOk); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; if path_to_local_id(arm.body, hir_id); then { @@ -1024,9 +1038,9 @@ pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { false } - fn is_err(arm: &Arm<'_>) -> bool { + fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind { - match_qpath(path, &paths::RESULT_ERR[1..]) + is_lang_ctor(cx, path, ResultErr) } else { false } @@ -1042,8 +1056,8 @@ pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if arms.len() == 2; if arms[0].guard.is_none(); if arms[1].guard.is_none(); - if (is_ok(&arms[0]) && is_err(&arms[1])) || - (is_ok(&arms[1]) && is_err(&arms[0])); + if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || + (is_ok(cx, &arms[1]) && is_err(cx, &arms[0])); then { return Some(expr); } @@ -1456,27 +1470,3 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { } } } - -/// Check if the resolution of a given path is an `Ok` variant of `Result`. -pub fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool { - if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.parent(id) { - return variant_id == ok_id; - } - } - } - false -} - -/// Check if the resolution of a given path is a `Some` variant of `Option`. -pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { - if let Some(some_id) = cx.tcx.lang_items().option_some_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.parent(id) { - return variant_id == some_id; - } - } - } - false -} -- cgit 1.4.1-3-g733a5 From a45faf66f3f35f644be2e121a1cd478bb2b908e0 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 9 Apr 2021 16:25:39 -0500 Subject: Deprecate filter_map --- clippy_lints/src/deprecated_lints.rs | 9 ++++++ clippy_lints/src/lib.rs | 6 ++-- clippy_lints/src/methods/filter_flat_map.rs | 18 ----------- clippy_lints/src/methods/filter_map_flat_map.rs | 18 ----------- clippy_lints/src/methods/filter_map_map.rs | 17 ----------- clippy_lints/src/methods/mod.rs | 40 +------------------------ clippy_utils/src/attrs.rs | 1 - lintcheck/src/main.rs | 2 +- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 ++++- tests/ui/filter_methods.rs | 25 ---------------- tests/ui/filter_methods.stderr | 39 ------------------------ 12 files changed, 23 insertions(+), 161 deletions(-) delete mode 100644 clippy_lints/src/methods/filter_flat_map.rs delete mode 100644 clippy_lints/src/methods/filter_map_flat_map.rs delete mode 100644 clippy_lints/src/methods/filter_map_map.rs delete mode 100644 tests/ui/filter_methods.rs delete mode 100644 tests/ui/filter_methods.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 89088c533ed..6f61229e133 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -188,3 +188,12 @@ declare_deprecated_lint! { pub FIND_MAP, "this lint has been replaced by `manual_find_map`, a more specific lint" } + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** This lint has been replaced by `manual_filter_map`, a + /// more specific lint. + pub FILTER_MAP, + "this lint has been replaced by `manual_filter_map`, a more specific lint" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b066643b568..03454271da5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -537,6 +537,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::find_map", "this lint has been replaced by `manual_find_map`, a more specific lint", ); + store.register_removed( + "clippy::filter_map", + "this lint has been replaced by `manual_filter_map`, a more specific lint", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -788,7 +792,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::EXPECT_FUN_CALL, methods::EXPECT_USED, methods::FILETYPE_IS_FILE, - methods::FILTER_MAP, methods::FILTER_MAP_IDENTITY, methods::FILTER_MAP_NEXT, methods::FILTER_NEXT, @@ -1404,7 +1407,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(matches::MATCH_WILD_ERR_ARM), LintId::of(matches::SINGLE_MATCH_ELSE), - LintId::of(methods::FILTER_MAP), LintId::of(methods::FILTER_MAP_NEXT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), diff --git a/clippy_lints/src/methods/filter_flat_map.rs b/clippy_lints/src/methods/filter_flat_map.rs deleted file mode 100644 index 1588eec8882..00000000000 --- a/clippy_lints/src/methods/filter_flat_map.rs +++ /dev/null @@ -1,18 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_trait_method; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_span::sym; - -use super::FILTER_MAP; - -/// lint use of `filter().flat_map()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - // lint if caller of `.filter().flat_map()` is an Iterator - if is_trait_method(cx, expr, sym::Iterator) { - let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ - and filtering by returning `iter::empty()`"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); - } -} diff --git a/clippy_lints/src/methods/filter_map_flat_map.rs b/clippy_lints/src/methods/filter_map_flat_map.rs deleted file mode 100644 index 741b1e7e361..00000000000 --- a/clippy_lints/src/methods/filter_map_flat_map.rs +++ /dev/null @@ -1,18 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_trait_method; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_span::sym; - -use super::FILTER_MAP; - -/// lint use of `filter_map().flat_map()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - // lint if caller of `.filter_map().flat_map()` is an Iterator - if is_trait_method(cx, expr, sym::Iterator) { - let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ - and filtering by returning `iter::empty()`"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); - } -} diff --git a/clippy_lints/src/methods/filter_map_map.rs b/clippy_lints/src/methods/filter_map_map.rs deleted file mode 100644 index 713bbf25837..00000000000 --- a/clippy_lints/src/methods/filter_map_map.rs +++ /dev/null @@ -1,17 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_trait_method; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_span::sym; - -use super::FILTER_MAP; - -/// lint use of `filter_map().map()` for `Iterators` -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - // lint if caller of `.filter_map().map()` is an Iterator - if is_trait_method(cx, expr, sym::Iterator) { - let msg = "called `filter_map(..).map(..)` on an `Iterator`"; - let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; - span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); - } -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b1ade5addd6..fc18849b07c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -11,11 +11,8 @@ mod clone_on_ref_ptr; mod expect_fun_call; mod expect_used; mod filetype_is_file; -mod filter_flat_map; mod filter_map; -mod filter_map_flat_map; mod filter_map_identity; -mod filter_map_map; mod filter_map_next; mod filter_next; mod flat_map_identity; @@ -472,35 +469,6 @@ declare_clippy_lint! { "using combinations of `flatten` and `map` which can usually be written as a single method call" } -declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.filter(_).map(_)`, - /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar. - /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.filter_map(_)`. - /// - /// **Known problems:** Often requires a condition + Option/Iterator creation - /// inside the closure. - /// - /// **Example:** - /// ```rust - /// let vec = vec![1]; - /// - /// // Bad - /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2); - /// - /// // Good - /// vec.iter().filter_map(|x| if *x == 0 { - /// Some(*x * 2) - /// } else { - /// None - /// }); - /// ``` - pub FILTER_MAP, - pedantic, - "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call" -} - declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter(_).map(_)` that can be written more simply /// as `filter_map(_)`. @@ -1677,7 +1645,6 @@ impl_lint_pass!(Methods => [ SEARCH_IS_SOME, FILTER_NEXT, SKIP_WHILE_NEXT, - FILTER_MAP, FILTER_MAP_IDENTITY, MANUAL_FILTER_MAP, MANUAL_FIND_MAP, @@ -1965,11 +1932,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_filter_map::check(cx, expr, arg); filter_map_identity::check(cx, expr, arg, span); }, - ("flat_map", [flm_arg]) => match method_call!(recv) { - Some(("filter", [_, _], _)) => filter_flat_map::check(cx, expr), - Some(("filter_map", [_, _], _)) => filter_map_flat_map::check(cx, expr), - _ => flat_map_identity::check(cx, expr, flm_arg, span), - }, + ("flat_map", [flm_arg]) => flat_map_identity::check(cx, expr, flm_arg, span), ("flatten", []) => { if let Some(("map", [recv, map_arg], _)) = method_call!(recv) { map_flatten::check(cx, expr, recv, map_arg); @@ -1993,7 +1956,6 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("filter", [f_arg]) => { filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false) }, - ("filter_map", [_]) => filter_map_map::check(cx, expr), ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true), _ => {}, } diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 7ec8452bf4c..5e44c7b3ee0 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -151,7 +151,6 @@ pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { /// Return true if the attributes contain `#[doc(hidden)]` pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { - #[allow(clippy::filter_map)] attrs .iter() .filter(|attr| attr.has_name(sym::doc)) diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 2041aed2b97..bfb0c3b3f74 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -5,7 +5,7 @@ // When a new lint is introduced, we can search the results for new warnings and check for false // positives. -#![allow(clippy::filter_map, clippy::collapsible_else_if)] +#![allow(clippy::collapsible_else_if)] use std::ffi::OsStr; use std::process::Command; diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index fc444c0bea7..dbf0b03af76 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -11,5 +11,6 @@ #[warn(clippy::panic_params)] #[warn(clippy::unknown_clippy_lints)] #[warn(clippy::find_map)] +#[warn(clippy::filter_map)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 64efcd18f88..aa3ed28d40b 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -78,11 +78,17 @@ error: lint `clippy::find_map` has been removed: this lint has been replaced by LL | #[warn(clippy::find_map)] | ^^^^^^^^^^^^^^^^ +error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint + --> $DIR/deprecated.rs:14:8 + | +LL | #[warn(clippy::filter_map)] + | ^^^^^^^^^^^^^^^^^^ + error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::unstable_as_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs deleted file mode 100644 index 51450241619..00000000000 --- a/tests/ui/filter_methods.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] - -fn main() { - let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); - - let _: Vec<_> = vec![5_i8; 6] - .into_iter() - .filter(|&x| x == 0) - .flat_map(|x| x.checked_mul(2)) - .collect(); - - let _: Vec<_> = vec![5_i8; 6] - .into_iter() - .filter_map(|x| x.checked_mul(2)) - .flat_map(|x| x.checked_mul(2)) - .collect(); - - let _: Vec<_> = vec![5_i8; 6] - .into_iter() - .filter_map(|x| x.checked_mul(2)) - .map(|x| x.checked_mul(2)) - .collect(); -} diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr deleted file mode 100644 index c7b4f28be3a..00000000000 --- a/tests/ui/filter_methods.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: called `filter(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:8:21 - | -LL | let _: Vec<_> = vec![5_i8; 6] - | _____________________^ -LL | | .into_iter() -LL | | .filter(|&x| x == 0) -LL | | .flat_map(|x| x.checked_mul(2)) - | |_______________________________________^ - | - = note: `-D clippy::filter-map` implied by `-D warnings` - = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` - -error: called `filter_map(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:14:21 - | -LL | let _: Vec<_> = vec![5_i8; 6] - | _____________________^ -LL | | .into_iter() -LL | | .filter_map(|x| x.checked_mul(2)) -LL | | .flat_map(|x| x.checked_mul(2)) - | |_______________________________________^ - | - = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` - -error: called `filter_map(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:20:21 - | -LL | let _: Vec<_> = vec![5_i8; 6] - | _____________________^ -LL | | .into_iter() -LL | | .filter_map(|x| x.checked_mul(2)) -LL | | .map(|x| x.checked_mul(2)) - | |__________________________________^ - | - = help: this is more succinctly expressed by only calling `.filter_map(..)` instead - -error: aborting due to 3 previous errors - -- cgit 1.4.1-3-g733a5 From 3ce6f0d022014ba13ed328a372c1ac1f37d9045e Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 11 Apr 2021 13:29:08 +0200 Subject: Fix FP in `wrong_self_convention` lint --- clippy_lints/src/methods/wrong_self_convention.rs | 8 ++++++++ tests/ui/wrong_self_convention2.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 1e0de249a91..6e2bcb113c2 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -102,6 +102,14 @@ pub(super) fn check<'tcx>( .iter() .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item)) }) { + // don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032) + if implements_trait + && !conventions + .iter() + .any(|conv| matches!(conv, Convention::IsSelfTypeCopy(_))) + { + return; + } if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) { let suggestion = { if conventions.len() > 1 { diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index 8b42aa59e13..ae3a740d405 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -30,3 +30,15 @@ mod issue6983 { } } } + +mod issue7032 { + trait Foo { + fn from_usize(x: usize) -> Self; + } + // don't trigger + impl Foo for usize { + fn from_usize(x: usize) -> Self { + x + } + } +} -- cgit 1.4.1-3-g733a5 From 76bd5d232c767dbdab63005eca07a9563982e9dd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 12 Apr 2021 18:01:32 -0500 Subject: Refactor diagnostic item methods --- clippy_lints/src/mem_replace.rs | 21 ++++++++++---------- clippy_lints/src/methods/implicit_clone.rs | 28 ++++++++++++++++---------- clippy_lints/src/methods/mod.rs | 7 +++---- clippy_lints/src/misc.rs | 6 +++--- clippy_lints/src/to_string_in_display.rs | 4 ++-- clippy_utils/src/lib.rs | 32 ++++++++++++++++-------------- 6 files changed, 53 insertions(+), 45 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 1f521ec6090..ec60bffe955 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, match_def_path, meets_msrv, paths}; -use clippy_utils::{is_diagnostic_assoc_item, is_lang_ctor}; +use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -211,17 +210,17 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< sym::BinaryHeap, ]; - if std_types_symbols - .iter() - .any(|symbol| is_diagnostic_assoc_item(cx, def_id, *symbol)) - { - if let QPath::TypeRelative(_, method) = path { - if method.ident.name == sym::new { - return true; + if let QPath::TypeRelative(_, method) = path { + if method.ident.name == sym::new { + if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { + if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { + return std_types_symbols + .iter() + .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did)); + } } } } - false } @@ -231,7 +230,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< if !in_external_macro(cx.tcx.sess, expr_span); if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default) + if is_diag_trait_item(cx, repl_def_id, sym::Default) || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); then { diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 1211e2f2bf7..81c42de145f 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,28 +1,36 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_diag_item_method, is_diag_trait_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::ExprKind; use rustc_lint::LateContext; use rustc_middle::ty::TyS; -use rustc_span::symbol::Symbol; +use rustc_span::{sym, Span}; use super::IMPLICIT_CLONE; -use clippy_utils::is_diagnostic_assoc_item; -pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, trait_diagnostic: Symbol) { +pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) { if_chain! { - if let ExprKind::MethodCall(method_path, _, [arg], _) = &expr.kind; + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if match method_name { + "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), + "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), + "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), + "to_vec" => cx.tcx.impl_of_method(method_def_id) + .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl()) + == Some(true), + _ => false, + }; let return_type = cx.typeck_results().expr_ty(expr); - let input_type = cx.typeck_results().expr_ty(arg).peel_refs(); - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + let input_type = cx.typeck_results().expr_ty(recv).peel_refs(); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); if TyS::same_type(return_type, input_type); - if is_diagnostic_assoc_item(cx, expr_def_id, trait_diagnostic); then { span_lint_and_sugg( - cx,IMPLICIT_CLONE,method_path.ident.span, - &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_path.ident.name), + cx, + IMPLICIT_CLONE, + span, + &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name), "consider using", "clone".to_string(), Applicability::MachineApplicable diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fc18849b07c..b2faaef0786 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1987,10 +1987,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("to_os_string", []) => implicit_clone::check(cx, expr, sym::OsStr), - ("to_owned", []) => implicit_clone::check(cx, expr, sym::ToOwned), - ("to_path_buf", []) => implicit_clone::check(cx, expr, sym::Path), - ("to_vec", []) => implicit_clone::check(cx, expr, sym::slice), + ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { + implicit_clone::check(cx, name, expr, recv, span); + }, ("unwrap", []) => match method_call!(recv) { Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index afced5a5ce5..d156c1d5bf4 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -20,7 +20,7 @@ use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, + get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, last_path_segment, match_qpath, unsext, SpanlessEq, }; @@ -555,8 +555,8 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: ExprKind::MethodCall(.., args, _) if args.len() == 1 => { if_chain!( if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString) - || is_diagnostic_assoc_item(cx, expr_def_id, sym::ToOwned); + if is_diag_trait_item(cx, expr_def_id, sym::ToString) + || is_diag_trait_item(cx, expr_def_id, sym::ToOwned); then { (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index ae05a8da37b..4fb297ac6c6 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths}; +use clippy_utils::{is_diag_trait_item, match_def_path, path_to_local_id, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -95,7 +95,7 @@ impl LateLintPass<'_> for ToStringInDisplay { if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString); + if is_diag_trait_item(cx, expr_def_id, sym::ToString); if path_to_local_id(&args[0], self_hir_id); then { span_lint( diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e99ffbe269b..ec140463a8a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -293,27 +293,29 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } -/// Checks if the method call given in `def_id` belongs to a trait or other container with a given -/// diagnostic item -pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { - cx.tcx - .opt_associated_item(def_id) - .and_then(|associated_item| match associated_item.container { - rustc_ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), - rustc_ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { - rustc_ty::Adt(adt, _) => Some(adt.did), - rustc_ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works - _ => None, - }, - }) - .map_or(false, |assoc_def_id| cx.tcx.is_diagnostic_item(diag_item, assoc_def_id)) +/// Checks if a method is defined in an impl of a diagnostic item +pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { + if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { + if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { + return cx.tcx.is_diagnostic_item(diag_item, adt.did); + } + } + false +} + +/// Checks if a method is in a diagnostic item trait +pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { + if let Some(trait_did) = cx.tcx.trait_of_item(def_id) { + return cx.tcx.is_diagnostic_item(diag_item, trait_did); + } + false } /// Checks if the method call given in `expr` belongs to the given trait. pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { cx.typeck_results() .type_dependent_def_id(expr.hir_id) - .map_or(false, |did| is_diagnostic_assoc_item(cx, did, diag_item)) + .map_or(false, |did| is_diag_trait_item(cx, did, diag_item)) } /// Checks if an expression references a variable of the given name. -- cgit 1.4.1-3-g733a5 From f6c5d8d599070bacad800ac7014fa3a6f140eadc Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 7 Apr 2021 16:19:25 -0400 Subject: Remove all usages of `match_path`, `match_qpath` and `match_path_ast` except the `author` lint. Add note to fix `MATCH_TYPE_ON_DIAG_ITEM` Add false negative test for `uninit_assumed_init` --- clippy_lints/src/assertions_on_constants.rs | 5 +- clippy_lints/src/excessive_bools.rs | 6 +- clippy_lints/src/implicit_hasher.rs | 7 +- clippy_lints/src/implicit_saturating_sub.rs | 43 ++++++++--- clippy_lints/src/infinite_iter.rs | 4 +- clippy_lints/src/map_identity.rs | 4 +- clippy_lints/src/matches.rs | 24 ++++-- clippy_lints/src/methods/filter_map_identity.rs | 12 +-- clippy_lints/src/methods/flat_map_identity.rs | 18 ++--- .../src/methods/from_iter_instead_of_collect.rs | 11 +-- .../src/methods/manual_saturating_arithmetic.rs | 6 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/uninit_assumed_init.rs | 5 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 - clippy_lints/src/misc.rs | 18 ++--- clippy_lints/src/ptr.rs | 17 ++--- clippy_lints/src/question_mark.rs | 11 ++- clippy_lints/src/returns.rs | 7 +- clippy_lints/src/slow_vector_initialization.rs | 69 ++++++++--------- clippy_lints/src/transmuting_null.rs | 23 +++--- clippy_lints/src/types/borrowed_box.rs | 9 ++- clippy_lints/src/unnecessary_wraps.rs | 10 +-- clippy_lints/src/utils/internal_lints.rs | 14 ++-- clippy_utils/src/lib.rs | 89 ++++++++++++++-------- clippy_utils/src/paths.rs | 12 +-- doc/adding_lints.md | 2 +- .../ui-internal/collapsible_span_lint_calls.fixed | 48 +----------- tests/ui-internal/collapsible_span_lint_calls.rs | 48 +----------- .../ui-internal/collapsible_span_lint_calls.stderr | 10 +-- tests/ui-internal/match_type_on_diag_item.rs | 21 ++--- tests/ui-internal/match_type_on_diag_item.stderr | 30 +++----- tests/ui/repl_uninit.rs | 4 +- tests/ui/uninit.rs | 5 +- tests/ui/uninit.stderr | 8 +- 34 files changed, 269 insertions(+), 335 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index a0993bb6913..c565e29d078 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -127,10 +127,9 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) _ => &block.expr, }; // function call - if let Some(args) = match_panic_call(cx, begin_panic_call); - if args.len() == 1; + if let Some(arg) = match_panic_call(cx, begin_panic_call); // bind the second argument of the `assert!` macro if it exists - if let panic_message = snippet_opt(cx, args[0].span); + if let panic_message = snippet_opt(cx, arg.span); // second argument of begin_panic is irrelevant // as is the second match arm then { diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 249ee27330b..4e2dbf005d5 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{in_macro, match_path_ast}; +use clippy_utils::in_macro; use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -126,7 +126,9 @@ impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_B fn is_bool_ty(ty: &Ty) -> bool { if let TyKind::Path(None, path) = &ty.kind { - return match_path_ast(path, &["bool"]); + if let [name] = path.segments.as_slice() { + return name.ident.name == sym::bool; + } } false } diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 77a38544edc..03fe0d16d48 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -22,7 +22,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::paths; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, match_path}; +use clippy_utils::{differing_macro_contexts, match_def_path}; declare_clippy_lint! { /// **What it does:** Checks for public `impl` or `fn` missing generalization @@ -333,12 +333,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't if let ExprKind::Call(fun, args) = e.kind; if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind; if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; + if let Some(ty_did) = ty_path.res.opt_def_id(); then { if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) { return; } - if match_path(ty_path, &paths::HASHMAP) { + if match_def_path(self.cx, ty_did, &paths::HASHMAP) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashMap::default()".to_string()); @@ -351,7 +352,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't ), ); } - } else if match_path(ty_path, &paths::HASHSET) { + } else if match_def_path(self.cx, ty_did, &paths::HASHSET) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashSet::default()".to_string()); diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index cba3183e869..4069a685ea0 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{in_macro, match_qpath, SpanlessEq}; +use clippy_utils::{in_macro, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, StmtKind}; +use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -87,7 +87,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Get the variable name let var_name = ares_path.segments[0].ident.name.as_str(); - const INT_TYPES: [&str; 5] = ["i8", "i16", "i32", "i64", "i128"]; + const INT_TYPES: [LangItem; 5] = [ + LangItem::I8, + LangItem::I16, + LangItem::I32, + LangItem::I64, + LangItem::Isize + ]; match cond_num_val.kind { ExprKind::Lit(ref cond_lit) => { @@ -99,17 +105,30 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { }; } }, - ExprKind::Path(ref cond_num_path) => { - if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "MIN"])) { - print_lint_and_sugg(cx, &var_name, expr); - }; + ExprKind::Path(QPath::TypeRelative(_, name)) => { + if_chain! { + if name.ident.as_str() == "MIN"; + if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(const_id); + let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok()); + if int_ids.any(|int_id| int_id == impl_id); + then { + print_lint_and_sugg(cx, &var_name, expr) + } + } }, - ExprKind::Call(func, _) => { - if let ExprKind::Path(ref cond_num_path) = func.kind { - if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) { - print_lint_and_sugg(cx, &var_name, expr); + ExprKind::Call(func, []) => { + if_chain! { + if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind; + if name.ident.as_str() == "min_value"; + if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(func_id); + let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok()); + if int_ids.any(|int_id| int_id == impl_id); + then { + print_lint_and_sugg(cx, &var_name, expr) } - }; + } }, _ => (), } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index bbb4ddc613a..afee20ce43e 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, match_type}; -use clippy_utils::{get_trait_def_id, higher, match_qpath, paths}; +use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -163,7 +163,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind { - match_qpath(qpath, &paths::REPEAT).into() + is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into() } else { Finite } diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index e7719e7663d..41cda23510e 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; +use clippy_utils::{is_adjusted, is_qpath_def_path, is_trait_method, match_var, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; @@ -80,7 +80,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), - ExprKind::Path(QPath::Resolved(_, path)) => match_path(path, &paths::STD_CONVERT_IDENTITY), + ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY), _ => false, } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 30091e0e2d7..8f1112cff7b 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1701,7 +1701,7 @@ mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; - use clippy_utils::{is_lang_ctor, is_trait_method, match_qpath, paths}; + use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -1735,8 +1735,8 @@ mod redundant_pattern_match { kind = &inner.kind; } let good_method = match kind { - PatKind::TupleStruct(ref path, patterns, _) if patterns.len() == 1 => { - if let PatKind::Wild = patterns[0].kind { + PatKind::TupleStruct(ref path, [sub_pat], _) => { + if let PatKind::Wild = sub_pat.kind { if is_lang_ctor(cx, path, ResultOk) { "is_ok()" } else if is_lang_ctor(cx, path, ResultErr) { @@ -1745,9 +1745,9 @@ mod redundant_pattern_match { "is_some()" } else if is_lang_ctor(cx, path, PollReady) { "is_ready()" - } else if match_qpath(path, &paths::IPADDR_V4) { + } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) { "is_ipv4()" - } else if match_qpath(path, &paths::IPADDR_V6) { + } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) { "is_ipv6()" } else { return; @@ -1821,6 +1821,7 @@ mod redundant_pattern_match { ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1831,6 +1832,7 @@ mod redundant_pattern_match { ) .or_else(|| { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1850,6 +1852,7 @@ mod redundant_pattern_match { { if let PatKind::Wild = patterns[0].kind { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1860,6 +1863,7 @@ mod redundant_pattern_match { ) .or_else(|| { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1900,7 +1904,9 @@ mod redundant_pattern_match { } } + #[allow(clippy::too_many_arguments)] fn find_good_method_for_match<'a>( + cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>, path_right: &QPath<'_>, @@ -1909,9 +1915,13 @@ mod redundant_pattern_match { should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { + let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left) + && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right) + { (&(*arms[0].body).kind, &(*arms[1].body).kind) - } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) { + } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left) + && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right) + { (&(*arms[1].body).kind, &(*arms[0].body).kind) } else { return None; diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 3a61f4ccad7..403fe8d3546 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use clippy_utils::{is_expr_path_def_path, is_trait_method, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -33,14 +33,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: } } - if_chain! { - if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind; - - if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); - - then { - apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); - } + if is_expr_path_def_path(cx, filter_map_arg, &paths::CONVERT_IDENTITY) { + apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); } } } diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index dd613d0cd63..25f8434cb94 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_trait_method, match_qpath, paths}; +use clippy_utils::{is_expr_path_def_path, is_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -16,8 +16,6 @@ pub(super) fn check<'tcx>( flat_map_span: Span, ) { if is_trait_method(cx, expr, sym::Iterator) { - let arg_node = &flat_map_arg.kind; - let apply_lint = |message: &str| { span_lint_and_sugg( cx, @@ -31,8 +29,8 @@ pub(super) fn check<'tcx>( }; if_chain! { - if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; - let body = cx.tcx.hir().body(*body_id); + if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind; + let body = cx.tcx.hir().body(body_id); if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind; @@ -45,14 +43,8 @@ pub(super) fn check<'tcx>( } } - if_chain! { - if let hir::ExprKind::Path(ref qpath) = arg_node; - - if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); - - then { - apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); - } + if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) { + apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); } } } diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 707c54f7a3c..28d0e8cd4ae 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,26 +1,23 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_qpath, paths, sugg}; +use clippy_utils::{is_expr_path_def_path, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Ty; use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func_kind: &ExprKind<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::Path(path) = func_kind; - if match_qpath(path, &["from_iter"]); + if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD); let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); - if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + if implements_trait(cx, arg_ty, iter_id, &[]); then { // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index ecb8b72ef46..2fddea7068d 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_qpath; +use clippy_utils::is_qpath_def_path; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; @@ -94,11 +94,11 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(func, args) => { - from_iter_instead_of_collect::check(cx, expr, args, &func.kind); + from_iter_instead_of_collect::check(cx, expr, args, func); }, hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 0ae65c0c01d..1a5894e48d1 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_def_path, match_qpath, paths}; +use clippy_utils::{is_expr_path_def_path, match_def_path, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,8 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if_chain! { if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); - if let hir::ExprKind::Path(ref path) = callee.kind; - if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); + if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 66255b77331..b61c4ffe9b3 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -61,8 +61,6 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } return (true, false); } - // We don't know. It might do anything. - return (true, true); } (true, true) }, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index d156c1d5bf4..0b0cd9be46c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -20,8 +20,8 @@ use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, - last_path_segment, match_qpath, unsext, SpanlessEq, + expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, + iter_input_pats, last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq, }; declare_clippy_lint! { @@ -564,13 +564,13 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: } ) }, - ExprKind::Call(path, v) if v.len() == 1 => { - if let ExprKind::Path(ref path) = path.kind { - if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { - (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) - } else { - return; - } + ExprKind::Call(path, [arg]) => { + if expr_path_res(cx, path) + .opt_def_id() + .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM])) + .is_some() + { + (cx.typeck_results().expr_ty(arg), snippet(cx, arg.span, "..")) } else { return; } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 2ab1e958ec8..b0674f90678 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; -use clippy_utils::{is_allowed, match_def_path, paths}; +use clippy_utils::{expr_path_res, is_allowed, match_any_def_paths, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ @@ -417,14 +417,11 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, } fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if_chain! { - if let ExprKind::Call(path, []) = expr.kind; - if let ExprKind::Path(ref qpath) = path.kind; - if let Some(fn_def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - then { - match_def_path(cx, fn_def_id, &paths::PTR_NULL) || match_def_path(cx, fn_def_id, &paths::PTR_NULL_MUT) - } else { - false - } + if let ExprKind::Call(pathexp, []) = expr.kind { + expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| { + match_any_def_paths(cx, id, &[&paths::PTR_NULL, &paths::PTR_NULL_MUT]).is_some() + }) + } else { + false } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index ea9ff37e13f..30bee213900 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -3,10 +3,10 @@ use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eq_expr_value, match_qpath}; +use clippy_utils::{eq_expr_value, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::OptionNone; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -101,15 +101,14 @@ impl QuestionMark { if Self::is_option(cx, subject); if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind; - if match_qpath(path1, &["Some"]); - if let PatKind::Binding(annot, _, bind, _) = &fields[0].kind; + if is_lang_ctor(cx, path1, OptionSome); + if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind; let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); if let ExprKind::Block(block, None) = &arms[0].body.kind; if block.stmts.is_empty(); if let Some(trailing_expr) = &block.expr; - if let ExprKind::Path(path) = &trailing_expr.kind; - if match_qpath(path, &[&bind.as_str()]); + if path_to_local_id(trailing_expr, bind_id); if let PatKind::Wild = arms[1].pat.kind; if Self::expression_returns_none(cx, arms[1].body); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 3a6151dce71..b565c77aaec 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; -use clippy_utils::{fn_def_id, in_macro, match_qpath}; +use clippy_utils::{fn_def_id, in_macro, path_to_local_id}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; @@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Return { if local.ty.is_none(); if cx.tcx.hir().attrs(local.hir_id).is_empty(); if let Some(initexpr) = &local.init; - if let PatKind::Binding(.., ident, _) = local.pat.kind; - if let ExprKind::Path(qpath) = &retexpr.kind; - if match_qpath(qpath, &[&*ident.name.as_str()]); + if let PatKind::Binding(_, local_id, _, _) = local.pat.kind; + if path_to_local_id(retexpr, local_id); if !last_statement_borrows(cx, initexpr); if !in_external_macro(cx.sess(), initexpr.span); if !in_external_macro(cx.sess(), retexpr.span); diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 8cf89ae456e..191781be000 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_enclosing_block, match_qpath, SpanlessEq}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_enclosing_block, is_expr_path_def_path, path_to_local, path_to_local_id, paths, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -9,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::sym; declare_clippy_lint! { /// **What it does:** Checks slow zero-filled vector initialization @@ -46,8 +47,8 @@ declare_lint_pass!(SlowVectorInit => [SLOW_VECTOR_INITIALIZATION]); /// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or /// `vec = Vec::with_capacity(0)` struct VecAllocation<'tcx> { - /// Symbol of the local variable name - variable_name: Symbol, + /// HirId of the variable + local_id: HirId, /// Reference to the expression which allocates the vector allocation_expr: &'tcx Expr<'tcx>, @@ -72,16 +73,15 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { if_chain! { if let ExprKind::Assign(left, right, _) = expr.kind; - // Extract variable name - if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind; - if let Some(variable_name) = path.segments.get(0); + // Extract variable + if let Some(local_id) = path_to_local(left); // Extract len argument - if let Some(len_arg) = Self::is_vec_with_capacity(right); + if let Some(len_arg) = Self::is_vec_with_capacity(cx, right); then { let vi = VecAllocation { - variable_name: variable_name.ident.name, + local_id, allocation_expr: right, len_expr: len_arg, }; @@ -95,13 +95,13 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(BindingAnnotation::Mutable, .., variable_name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind; if let Some(init) = local.init; - if let Some(len_arg) = Self::is_vec_with_capacity(init); + if let Some(len_arg) = Self::is_vec_with_capacity(cx, init); then { let vi = VecAllocation { - variable_name: variable_name.name, + local_id, allocation_expr: init, len_expr: len_arg, }; @@ -115,19 +115,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { impl SlowVectorInit { /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression /// of the first argument of `with_capacity` call if it matches or `None` if it does not. - fn is_vec_with_capacity<'tcx>(expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::Call(func, args) = expr.kind; - if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &["Vec", "with_capacity"]); - if args.len() == 1; - + if let ExprKind::Call(func, [arg]) = expr.kind; + if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind; + if name.ident.as_str() == "with_capacity"; + if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type); then { - return Some(&args[0]); + Some(arg) + } else { + None } } - - None } /// Search initialization for the given vector @@ -208,11 +207,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; - if let ExprKind::Path(ref qpath_subj) = args[0].kind; - if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); + if let ExprKind::MethodCall(path, _, [self_arg, extend_arg], _) = expr.kind; + if path_to_local_id(self_arg, self.vec_alloc.local_id); if path.ident.name == sym!(extend); - if let Some(extend_arg) = args.get(1); if self.is_repeat_take(extend_arg); then { @@ -225,11 +222,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; - if let ExprKind::Path(ref qpath_subj) = args[0].kind; - if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); + if let ExprKind::MethodCall(path, _, [self_arg, len_arg, fill_arg], _) = expr.kind; + if path_to_local_id(self_arg, self.vec_alloc.local_id); if path.ident.name == sym!(resize); - if let (Some(len_arg), Some(fill_arg)) = (args.get(1), args.get(2)); // Check that is filled with 0 if let ExprKind::Lit(ref lit) = fill_arg.kind; @@ -252,7 +247,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that take is applied to `repeat(0)` if let Some(repeat_expr) = take_args.get(0); - if Self::is_repeat_zero(repeat_expr); + if self.is_repeat_zero(repeat_expr); // Check that len expression is equals to `with_capacity` expression if let Some(len_arg) = take_args.get(1); @@ -267,21 +262,19 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { } /// Returns `true` if given expression is `repeat(0)` - fn is_repeat_zero(expr: &Expr<'_>) -> bool { + fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::Call(fn_expr, repeat_args) = expr.kind; - if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind; - if match_qpath(qpath_repeat, &["repeat"]); - if let Some(repeat_arg) = repeat_args.get(0); + if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; + if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT); if let ExprKind::Lit(ref lit) = repeat_arg.kind; if let LitKind::Int(0, _) = lit.node; then { - return true + true + } else { + false } } - - false } } diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 755132da591..888ecab1046 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,6 +1,6 @@ use crate::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_def_path, paths}; +use clippy_utils::{is_expr_path_def_path, paths}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -37,18 +37,15 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { } if_chain! { - if let ExprKind::Call(func, args) = expr.kind; - if args.len() == 1; - if let ExprKind::Path(ref path) = func.kind; - if let Some(func_def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if match_def_path(cx, func_def_id, &paths::TRANSMUTE); - then { + if let ExprKind::Call(func, [arg]) = expr.kind; + if is_expr_path_def_path(cx, func, &paths::TRANSMUTE); + then { // Catching transmute over constants that resolve to `null`. let mut const_eval_context = constant_context(cx, cx.typeck_results()); if_chain! { - if let ExprKind::Path(ref _qpath) = args[0].kind; - let x = const_eval_context.expr(&args[0]); + if let ExprKind::Path(ref _qpath) = arg.kind; + let x = const_eval_context.expr(arg); if let Some(Constant::RawPtr(0)) = x; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) @@ -58,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // Catching: // `std::mem::transmute(0 as *const i32)` if_chain! { - if let ExprKind::Cast(inner_expr, _cast_ty) = args[0].kind; + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind; if let ExprKind::Lit(ref lit) = inner_expr.kind; if let LitKind::Int(0, _) = lit.node; then { @@ -69,10 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // Catching: // `std::mem::transmute(std::ptr::null::())` if_chain! { - if let ExprKind::Call(func1, []) = args[0].kind; - if let ExprKind::Path(ref path1) = func1.kind; - if let Some(func1_def_id) = cx.qpath_res(path1, func1.hir_id).opt_def_id(); - if match_def_path(cx, func1_def_id, &paths::PTR_NULL); + if let ExprKind::Call(func1, []) = arg.kind; + if is_expr_path_def_path(cx, func1, &paths::PTR_NULL); then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 1425d8f3f37..bdeff035e5e 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{match_path, paths}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m _ => None, }); then { - if is_any_trait(inner) { + if is_any_trait(cx, inner) { // Ignore `Box` types; see issue #1884 for details. return false; } @@ -84,13 +84,14 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m } // Returns true if given type is `Any` trait. -fn is_any_trait(t: &hir::Ty<'_>) -> bool { +fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { if_chain! { if let TyKind::TraitObject(traits, ..) = t.kind; if !traits.is_empty(); + if let Some(trait_did) = traits[0].trait_ref.trait_def_id(); // Only Send/Sync can be used as additional traits, so it is enough to // check only the first trait. - if match_path(traits[0].trait_ref.path, &paths::ANY_TRAIT); + if match_def_path(cx, trait_did, &paths::ANY_TRAIT); then { return true; } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index d2c0f60d296..f2f1410aed7 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -104,14 +104,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if_chain! { if !in_macro(ret_expr.span); // Check if a function call. - if let ExprKind::Call(func, args) = ret_expr.kind; - // Get the Path of the function call. - if let ExprKind::Path(ref qpath) = func.kind; + if let ExprKind::Call(func, [arg]) = ret_expr.kind; // Check if OPTION_SOME or RESULT_OK, depending on return type. + if let ExprKind::Path(qpath) = &func.kind; if is_lang_ctor(cx, qpath, lang_item); - if args.len() == 1; // Make sure the function argument does not contain a return expression. - if !contains_return(&args[0]); + if !contains_return(arg); then { suggs.push( ( @@ -119,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if inner_type.is_unit() { "".to_string() } else { - snippet(cx, args[0].span.source_callsite(), "..").to_string() + snippet(cx, arg.span.source_callsite(), "..").to_string() } ) ); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index cf8039d6059..3d3d0e19d26 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -3,7 +3,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{ - is_else_clause, is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq, + is_else_clause, is_expn_of, is_expr_path_def_path, match_def_path, method_calls, path_to_res, paths, run_lints, + SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; @@ -578,8 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { if_chain! { if let ExprKind::Call(func, and_then_args) = expr.kind; - if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &["span_lint_and_then"]); + if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]); if and_then_args.len() == 5; if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind; let body = cx.tcx.hir().body(*body_id); @@ -761,8 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { if_chain! { // Check if this is a call to utils::match_type() if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; - if let ExprKind::Path(fn_qpath) = &fn_path.kind; - if match_qpath(fn_qpath, &["utils", "match_type"]); + if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]); // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, ty_path); let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); @@ -771,6 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { let diag_items = cx.tcx.diagnostic_items(ty_did.krate); if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None }); then { + // TODO: check paths constants from external crates. let cx_snippet = snippet(cx, context.span, "_"); let ty_snippet = snippet(cx, ty.span, "_"); @@ -778,9 +778,9 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.span, - "usage of `utils::match_type()` on a type diagnostic item", + "usage of `clippy_utils::ty::match_type()` on a type diagnostic item", "try", - format!("utils::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), + format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), Applicability::MaybeIncorrect, ); } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8e1a2105b96..4a523520a43 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -397,6 +397,29 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { } } +/// If the expression is a path, resolve it. Otherwise, return `Res::Err`. +pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res { + if let ExprKind::Path(p) = &expr.kind { + cx.qpath_res(p, expr.hir_id) + } else { + Res::Err + } +} + +/// Resolves the path to a `DefId` and checks if it matches the given path. +pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool { + cx.qpath_res(path, hir_id) + .opt_def_id() + .map_or(false, |id| match_def_path(cx, id, segments)) +} + +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. +pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { + expr_path_res(cx, expr) + .opt_def_id() + .map_or(false, |id| match_def_path(cx, id, segments)) +} + /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. @@ -425,20 +448,6 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { .all(|(a, b)| a.ident.name.as_str() == *b) } -/// Matches a `Path` against a slice of segment string literals, e.g. -/// -/// # Examples -/// ```rust,ignore -/// match_path_ast(path, &["std", "rt", "begin_unwind"]) -/// ``` -pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { - path.segments - .iter() - .rev() - .zip(segments.iter().rev()) - .all(|(a, b)| a.ident.name.as_str() == *b) -} - /// If the expression is a path to a local, returns the canonical `HirId` of the local. pub fn path_to_local(expr: &Expr<'_>) -> Option { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { @@ -1148,29 +1157,47 @@ pub fn match_function_call<'tcx>( None } +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if +/// any. +pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option { + let search_path = cx.get_def_path(did); + paths + .iter() + .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().cloned())) +} + +/// Checks if the given `DefId` matches the path. pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { - // We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path` - // accepts only that. We should probably move to Symbols in Clippy as well. - let syms = syms.iter().map(|p| Symbol::intern(p)).collect::>(); - cx.match_def_path(did, &syms) + // We should probably move to Symbols in Clippy as well rather than interning every time. + let path = cx.get_def_path(did); + syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().cloned()) } -pub fn match_panic_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx [Expr<'tcx>]> { - match_function_call(cx, expr, &paths::BEGIN_PANIC) - .or_else(|| match_function_call(cx, expr, &paths::BEGIN_PANIC_FMT)) - .or_else(|| match_function_call(cx, expr, &paths::PANIC_ANY)) - .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC)) - .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_FMT)) - .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_STR)) +pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Call(func, [arg]) = expr.kind { + expr_path_res(cx, func) + .opt_def_id() + .map_or(false, |id| match_panic_def_id(cx, id)) + .then(|| arg) + } else { + None + } } pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { - match_def_path(cx, did, &paths::BEGIN_PANIC) - || match_def_path(cx, did, &paths::BEGIN_PANIC_FMT) - || match_def_path(cx, did, &paths::PANIC_ANY) - || match_def_path(cx, did, &paths::PANICKING_PANIC) - || match_def_path(cx, did, &paths::PANICKING_PANIC_FMT) - || match_def_path(cx, did, &paths::PANICKING_PANIC_STR) + match_any_def_paths( + cx, + did, + &[ + &paths::BEGIN_PANIC, + &paths::BEGIN_PANIC_FMT, + &paths::PANIC_ANY, + &paths::PANICKING_PANIC, + &paths::PANICKING_PANIC_FMT, + &paths::PANICKING_PANIC_STR, + ], + ) + .is_some() } /// Returns the list of condition expressions and the list of blocks in a diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index ed8915f59e1..21011dbded6 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -4,7 +4,7 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See for more information. -pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"]; +pub const ANY_TRAIT: [&str; 3] = ["core", "any", "Any"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; @@ -42,6 +42,8 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; +pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; +pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; @@ -58,8 +60,9 @@ pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; -pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; -pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; +pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; +pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; +pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; #[cfg(feature = "internal-lints")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; #[cfg(feature = "internal-lints")] @@ -126,7 +129,6 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; -pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"]; pub const RESULT: [&str; 3] = ["core", "result", "Result"]; pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"]; pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"]; @@ -140,7 +142,7 @@ pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; -pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; +pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 99b86953d51..50f0d724016 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -625,7 +625,7 @@ in the following steps: Here are some pointers to things you are likely going to need for every lint: * [Clippy utils][utils] - Various helper functions. Maybe the function you need - is already in here (`implements_trait`, `match_path`, `snippet`, etc) + is already in here (`implements_trait`, `match_def_path`, `snippet`, etc) * [Clippy diagnostics][diagnostics] * [The `if_chain` macro][if_chain] * [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro] diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index e588c23345e..7764cc8da78 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -2,58 +2,18 @@ #![deny(clippy::internal)] #![feature(rustc_private)] +extern crate clippy_utils; extern crate rustc_ast; extern crate rustc_errors; extern crate rustc_lint; extern crate rustc_session; extern crate rustc_span; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use rustc_ast::ast::Expr; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; - -#[allow(unused_variables)] -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) -where - F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), -{ -} - -#[allow(unused_variables)] -fn span_lint_and_help<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - option_span: Option, - help: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_note<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - note_span: Option, - note: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_sugg<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - sp: Span, - msg: &str, - help: &str, - sugg: String, - applicability: Applicability, -) { -} declare_tool_lint! { pub clippy::TEST_LINT, diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index d5dd3bb562b..bdd296db832 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -2,58 +2,18 @@ #![deny(clippy::internal)] #![feature(rustc_private)] +extern crate clippy_utils; extern crate rustc_ast; extern crate rustc_errors; extern crate rustc_lint; extern crate rustc_session; extern crate rustc_span; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use rustc_ast::ast::Expr; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; - -#[allow(unused_variables)] -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) -where - F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), -{ -} - -#[allow(unused_variables)] -fn span_lint_and_help<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - option_span: Option, - help: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_note<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - note_span: Option, - note: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_sugg<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - sp: Span, - msg: &str, - help: &str, - sugg: String, - applicability: Applicability, -) { -} declare_tool_lint! { pub clippy::TEST_LINT, diff --git a/tests/ui-internal/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr index 874d4a9f255..0632b038577 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.stderr +++ b/tests/ui-internal/collapsible_span_lint_calls.stderr @@ -1,5 +1,5 @@ error: this call is collapsible - --> $DIR/collapsible_span_lint_calls.rs:75:9 + --> $DIR/collapsible_span_lint_calls.rs:35:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable); @@ -14,7 +14,7 @@ LL | #![deny(clippy::internal)] = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]` error: this call is collapsible - --> $DIR/collapsible_span_lint_calls.rs:78:9 + --> $DIR/collapsible_span_lint_calls.rs:38:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.span_help(expr.span, help_msg); @@ -22,7 +22,7 @@ LL | | }); | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)` error: this call is collapsible - --> $DIR/collapsible_span_lint_calls.rs:81:9 + --> $DIR/collapsible_span_lint_calls.rs:41:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.help(help_msg); @@ -30,7 +30,7 @@ LL | | }); | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)` error: this call is collspible - --> $DIR/collapsible_span_lint_calls.rs:84:9 + --> $DIR/collapsible_span_lint_calls.rs:44:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.span_note(expr.span, note_msg); @@ -38,7 +38,7 @@ LL | | }); | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)` error: this call is collspible - --> $DIR/collapsible_span_lint_calls.rs:87:9 + --> $DIR/collapsible_span_lint_calls.rs:47:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.note(note_msg); diff --git a/tests/ui-internal/match_type_on_diag_item.rs b/tests/ui-internal/match_type_on_diag_item.rs index fe950b0aa7c..063f0c6460c 100644 --- a/tests/ui-internal/match_type_on_diag_item.rs +++ b/tests/ui-internal/match_type_on_diag_item.rs @@ -1,29 +1,18 @@ #![deny(clippy::internal)] #![feature(rustc_private)] +extern crate clippy_utils; extern crate rustc_hir; extern crate rustc_lint; extern crate rustc_middle; + #[macro_use] extern crate rustc_session; +use clippy_utils::{paths, ty::match_type}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -mod paths { - pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; -} - -mod utils { - use super::*; - - pub fn match_type(_cx: &LateContext<'_>, _ty: Ty<'_>, _path: &[&str]) -> bool { - false - } -} - -use utils::match_type; - declare_lint! { pub TEST_LINT, Warn, @@ -38,12 +27,12 @@ impl<'tcx> LateLintPass<'tcx> for Pass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) { let ty = cx.typeck_results().expr_ty(expr); - let _ = match_type(cx, ty, &paths::VEC); + let _ = match_type(cx, ty, &paths::VEC); // FIXME: Doesn't lint external paths let _ = match_type(cx, ty, &OPTION); let _ = match_type(cx, ty, &["core", "result", "Result"]); let rc_path = &["alloc", "rc", "Rc"]; - let _ = utils::match_type(cx, ty, rc_path); + let _ = clippy_utils::ty::match_type(cx, ty, rc_path); } } diff --git a/tests/ui-internal/match_type_on_diag_item.stderr b/tests/ui-internal/match_type_on_diag_item.stderr index 82465dbaf6e..71472960565 100644 --- a/tests/ui-internal/match_type_on_diag_item.stderr +++ b/tests/ui-internal/match_type_on_diag_item.stderr @@ -1,8 +1,8 @@ -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:41:17 +error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item + --> $DIR/match_type_on_diag_item.rs:31:17 | -LL | let _ = match_type(cx, ty, &paths::VEC); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::vec_type)` +LL | let _ = match_type(cx, ty, &OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::option_type)` | note: the lint level is defined here --> $DIR/match_type_on_diag_item.rs:1:9 @@ -11,23 +11,17 @@ LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:42:17 - | -LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::option_type)` - -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:43:17 +error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item + --> $DIR/match_type_on_diag_item.rs:32:17 | LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::result_type)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::result_type)` -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:46:17 +error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item + --> $DIR/match_type_on_diag_item.rs:35:17 | -LL | let _ = utils::match_type(cx, ty, rc_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::Rc)` +LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/repl_uninit.rs b/tests/ui/repl_uninit.rs index ad5b8e4857d..6c7e2b854dc 100644 --- a/tests/ui/repl_uninit.rs +++ b/tests/ui/repl_uninit.rs @@ -1,5 +1,5 @@ -#![allow(deprecated, invalid_value)] -#![warn(clippy::all)] +#![allow(deprecated, invalid_value, clippy::uninit_assumed_init)] +#![warn(clippy::mem_replace_with_uninit)] use std::mem; diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index f42b884e0f0..1ed3883c1f0 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -1,6 +1,6 @@ #![feature(stmt_expr_attributes)] -use std::mem::MaybeUninit; +use std::mem::{self, MaybeUninit}; fn main() { let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; @@ -19,4 +19,7 @@ fn main() { // This is OK, because all constitutent types are uninit-compatible. let _: (MaybeUninit, [MaybeUninit; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; + + // Was a false negative. + let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; } diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr index a37233ecdda..85b64a8419a 100644 --- a/tests/ui/uninit.stderr +++ b/tests/ui/uninit.stderr @@ -12,5 +12,11 @@ error: this call for this type may be undefined behavior LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: this call for this type may be undefined behavior + --> $DIR/uninit.rs:24:29 + | +LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 0462666c7067d8992501aa8997d16e18da021ee5 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 16 Apr 2021 11:00:08 -0500 Subject: Add cloned_instead_of_copied lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 ++ .../src/methods/cloned_instead_of_copied.rs | 38 ++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 26 +++++++++++++++ clippy_utils/src/ty.rs | 21 +++++++++++- tests/ui/cloned_instead_of_copied.fixed | 15 +++++++++ tests/ui/cloned_instead_of_copied.rs | 15 +++++++++ tests/ui/cloned_instead_of_copied.stderr | 34 +++++++++++++++++++ 8 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/cloned_instead_of_copied.rs create mode 100644 tests/ui/cloned_instead_of_copied.fixed create mode 100644 tests/ui/cloned_instead_of_copied.rs create mode 100644 tests/ui/cloned_instead_of_copied.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7885bdfb12c..483365b5e91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2148,6 +2148,7 @@ Released 2018-09-13 [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr +[`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 93631c5669b..0f48799d339 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -759,6 +759,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::BYTES_NTH, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, + methods::CLONED_INSTEAD_OF_COPIED, methods::CLONE_DOUBLE_REF, methods::CLONE_ON_COPY, methods::CLONE_ON_REF_PTR, @@ -1380,6 +1381,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(matches::MATCH_WILD_ERR_ARM), LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::CLONED_INSTEAD_OF_COPIED), LintId::of(methods::FILTER_MAP_NEXT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs new file mode 100644 index 00000000000..ba97ab3900c --- /dev/null +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::{get_iterator_item_ty, is_copy}; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::CLONED_INSTEAD_OF_COPIED; + +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { + let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); + let inner_ty = match recv_ty.kind() { + // `Option` -> `T` + ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) => subst.type_at(0), + _ if is_trait_method(cx, expr, sym::Iterator) => match get_iterator_item_ty(cx, recv_ty) { + // ::Item + Some(ty) => ty, + _ => return, + }, + _ => return, + }; + match inner_ty.kind() { + // &T where T: Copy + ty::Ref(_, ty, _) if is_copy(cx, ty) => {}, + _ => return, + }; + span_lint_and_sugg( + cx, + CLONED_INSTEAD_OF_COPIED, + span, + "used `cloned` where `copied` could be used instead", + "try", + "copied".into(), + Applicability::MachineApplicable, + ) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6c21ff0f6c2..49a9af2a465 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -8,6 +8,7 @@ mod chars_next_cmp; mod chars_next_cmp_with_unwrap; mod clone_on_copy; mod clone_on_ref_ptr; +mod cloned_instead_of_copied; mod expect_fun_call; mod expect_used; mod filetype_is_file; @@ -73,6 +74,29 @@ use rustc_span::symbol::SymbolStr; use rustc_span::{sym, Span}; use rustc_typeck::hir_ty_to_ty; +declare_clippy_lint! { + /// **What it does:** Checks for usages of `cloned()` on an `Iterator` or `Option` where + /// `copied()` could be used instead. + /// + /// **Why is this bad?** `copied()` is better because it guarantees that the type being cloned + /// implements `Copy`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// [1, 2, 3].iter().cloned(); + /// ``` + /// Use instead: + /// ```rust + /// [1, 2, 3].iter().copied(); + /// ``` + pub CLONED_INSTEAD_OF_COPIED, + pedantic, + "used `cloned` where `copied` could be used instead" +} + declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. /// @@ -1638,6 +1662,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_COPY, CLONE_ON_REF_PTR, CLONE_DOUBLE_REF, + CLONED_INSTEAD_OF_COPIED, INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, @@ -1909,6 +1934,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("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), ("collect", []) => match method_call!(recv) { Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2), Some(("map", [m_recv, m_arg], _)) => { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 807cfbc4c7f..64a80f2554f 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -13,7 +13,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TypeFoldable, UintTy}; use rustc_span::sym; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::normalize::AtExt; @@ -52,6 +52,25 @@ pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool { }) } +/// Resolves `::Item` for `T` +/// Do not invoke without first verifying that the type implements `Iterator` +pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { + cx.tcx + .get_diagnostic_item(sym::Iterator) + .and_then(|iter_did| { + cx.tcx.associated_items(iter_did).find_by_name_and_kind( + cx.tcx, + Ident::from_str("Item"), + ty::AssocKind::Type, + iter_did, + ) + }) + .map(|assoc| { + let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[])); + cx.tcx.normalize_erasing_regions(cx.param_env, proj) + }) +} + /// Returns true if ty has `iter` or `iter_mut` methods pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option { // FIXME: instead of this hard-coded list, we should check if `::iter` diff --git a/tests/ui/cloned_instead_of_copied.fixed b/tests/ui/cloned_instead_of_copied.fixed new file mode 100644 index 00000000000..4eb999e18e6 --- /dev/null +++ b/tests/ui/cloned_instead_of_copied.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![warn(clippy::cloned_instead_of_copied)] + +fn main() { + // yay + let _ = [1].iter().copied(); + let _ = vec!["hi"].iter().copied(); + let _ = Some(&1).copied(); + let _ = Box::new([1].iter()).copied(); + let _ = Box::new(Some(&1)).copied(); + + // nay + let _ = [String::new()].iter().cloned(); + let _ = Some(&String::new()).cloned(); +} diff --git a/tests/ui/cloned_instead_of_copied.rs b/tests/ui/cloned_instead_of_copied.rs new file mode 100644 index 00000000000..894496c0ebb --- /dev/null +++ b/tests/ui/cloned_instead_of_copied.rs @@ -0,0 +1,15 @@ +// run-rustfix +#![warn(clippy::cloned_instead_of_copied)] + +fn main() { + // yay + let _ = [1].iter().cloned(); + let _ = vec!["hi"].iter().cloned(); + let _ = Some(&1).cloned(); + let _ = Box::new([1].iter()).cloned(); + let _ = Box::new(Some(&1)).cloned(); + + // nay + let _ = [String::new()].iter().cloned(); + let _ = Some(&String::new()).cloned(); +} diff --git a/tests/ui/cloned_instead_of_copied.stderr b/tests/ui/cloned_instead_of_copied.stderr new file mode 100644 index 00000000000..e0707d32146 --- /dev/null +++ b/tests/ui/cloned_instead_of_copied.stderr @@ -0,0 +1,34 @@ +error: used `cloned` where `copied` could be used instead + --> $DIR/cloned_instead_of_copied.rs:6:24 + | +LL | let _ = [1].iter().cloned(); + | ^^^^^^ help: try: `copied` + | + = note: `-D clippy::cloned-instead-of-copied` implied by `-D warnings` + +error: used `cloned` where `copied` could be used instead + --> $DIR/cloned_instead_of_copied.rs:7:31 + | +LL | let _ = vec!["hi"].iter().cloned(); + | ^^^^^^ help: try: `copied` + +error: used `cloned` where `copied` could be used instead + --> $DIR/cloned_instead_of_copied.rs:8:22 + | +LL | let _ = Some(&1).cloned(); + | ^^^^^^ help: try: `copied` + +error: used `cloned` where `copied` could be used instead + --> $DIR/cloned_instead_of_copied.rs:9:34 + | +LL | let _ = Box::new([1].iter()).cloned(); + | ^^^^^^ help: try: `copied` + +error: used `cloned` where `copied` could be used instead + --> $DIR/cloned_instead_of_copied.rs:10:32 + | +LL | let _ = Box::new(Some(&1)).cloned(); + | ^^^^^^ help: try: `copied` + +error: aborting due to 5 previous errors + -- cgit 1.4.1-3-g733a5 From 5af078ac1b705abde41cc2e7c71be38701943cdb Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 16 Apr 2021 15:06:21 -0500 Subject: Add flat_map_option lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/matches.rs | 2 +- clippy_lints/src/methods/flat_map_option.rs | 34 +++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 30 ++++++++++++++++++++++++- clippy_utils/src/attrs.rs | 2 +- tests/ui/flat_map_option.fixed | 13 +++++++++++ tests/ui/flat_map_option.rs | 13 +++++++++++ tests/ui/flat_map_option.stderr | 16 ++++++++++++++ 9 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/methods/flat_map_option.rs create mode 100644 tests/ui/flat_map_option.fixed create mode 100644 tests/ui/flat_map_option.rs create mode 100644 tests/ui/flat_map_option.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 483365b5e91..56cdd356469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2216,6 +2216,7 @@ Released 2018-09-13 [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map [`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity +[`flat_map_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0f48799d339..a7871b7aba7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -770,6 +770,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::FILTER_MAP_NEXT, methods::FILTER_NEXT, methods::FLAT_MAP_IDENTITY, + methods::FLAT_MAP_OPTION, methods::FROM_ITER_INSTEAD_OF_COLLECT, methods::GET_UNWRAP, methods::IMPLICIT_CLONE, @@ -1383,6 +1384,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(matches::SINGLE_MATCH_ELSE), LintId::of(methods::CLONED_INSTEAD_OF_COPIED), LintId::of(methods::FILTER_MAP_NEXT), + LintId::of(methods::FLAT_MAP_OPTION), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), LintId::of(methods::MAP_FLATTEN), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 2c8d8a0f132..44b4eb29035 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1509,7 +1509,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<' /// Gets all arms that are unbounded `PatRange`s. fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec> { arms.iter() - .flat_map(|arm| { + .filter_map(|arm| { if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs = match lhs { diff --git a/clippy_lints/src/methods/flat_map_option.rs b/clippy_lints/src/methods/flat_map_option.rs new file mode 100644 index 00000000000..12d560653ed --- /dev/null +++ b/clippy_lints/src/methods/flat_map_option.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{source_map::Span, sym}; + +use super::FLAT_MAP_OPTION; +use clippy_utils::ty::is_type_diagnostic_item; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) { + if !is_trait_method(cx, expr, sym::Iterator) { + return; + } + let arg_ty = cx.typeck_results().expr_ty_adjusted(arg); + let sig = match arg_ty.kind() { + ty::Closure(_, substs) => substs.as_closure().sig(), + _ if arg_ty.is_fn() => arg_ty.fn_sig(cx.tcx), + _ => return, + }; + if !is_type_diagnostic_item(cx, sig.output().skip_binder(), sym::option_type) { + return; + } + span_lint_and_sugg( + cx, + FLAT_MAP_OPTION, + span, + "used `flat_map` where `filter_map` could be used instead", + "try", + "filter_map".into(), + Applicability::MachineApplicable, + ) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 49a9af2a465..c2cd3011d14 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -17,6 +17,7 @@ mod filter_map_identity; mod filter_map_next; mod filter_next; mod flat_map_identity; +mod flat_map_option; mod from_iter_instead_of_collect; mod get_unwrap; mod implicit_clone; @@ -97,6 +98,29 @@ declare_clippy_lint! { "used `cloned` where `copied` could be used instead" } +declare_clippy_lint! { + /// **What it does:** Checks for usages of `Iterator::flat_map()` where `filter_map()` could be + /// used instead. + /// + /// **Why is this bad?** When applicable, `filter_map()` is more clear since it shows that + /// `Option` is used to produce 0 or 1 items. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let nums: Vec = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); + /// ``` + /// Use instead: + /// ```rust + /// let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); + /// ``` + pub FLAT_MAP_OPTION, + pedantic, + "used `flat_map` where `filter_map` could be used instead" +} + declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. /// @@ -1663,6 +1687,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_REF_PTR, CLONE_DOUBLE_REF, CLONED_INSTEAD_OF_COPIED, + FLAT_MAP_OPTION, INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, @@ -1958,7 +1983,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_filter_map::check(cx, expr, arg); filter_map_identity::check(cx, expr, arg, span); }, - ("flat_map", [flm_arg]) => flat_map_identity::check(cx, expr, flm_arg, span), + ("flat_map", [arg]) => { + flat_map_identity::check(cx, expr, arg, span); + flat_map_option::check(cx, expr, arg, span); + }, ("flatten", []) => { if let Some(("map", [recv, map_arg], _)) = method_call!(recv) { map_flatten::check(cx, expr, recv, map_arg); diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 5e44c7b3ee0..c0584e1e226 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -154,6 +154,6 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { attrs .iter() .filter(|attr| attr.has_name(sym::doc)) - .flat_map(ast::Attribute::meta_item_list) + .filter_map(ast::Attribute::meta_item_list) .any(|l| attr::list_contains_name(&l, sym::hidden)) } diff --git a/tests/ui/flat_map_option.fixed b/tests/ui/flat_map_option.fixed new file mode 100644 index 00000000000..6a34f008995 --- /dev/null +++ b/tests/ui/flat_map_option.fixed @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::flat_map_option)] +#![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] + +fn main() { + // yay + let c = |x| Some(x); + let _ = [1].iter().filter_map(c); + let _ = [1].iter().filter_map(Some); + + // nay + let _ = [1].iter().flat_map(|_| &Some(1)); +} diff --git a/tests/ui/flat_map_option.rs b/tests/ui/flat_map_option.rs new file mode 100644 index 00000000000..2479abddbf0 --- /dev/null +++ b/tests/ui/flat_map_option.rs @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::flat_map_option)] +#![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] + +fn main() { + // yay + let c = |x| Some(x); + let _ = [1].iter().flat_map(c); + let _ = [1].iter().flat_map(Some); + + // nay + let _ = [1].iter().flat_map(|_| &Some(1)); +} diff --git a/tests/ui/flat_map_option.stderr b/tests/ui/flat_map_option.stderr new file mode 100644 index 00000000000..a9d8056dee9 --- /dev/null +++ b/tests/ui/flat_map_option.stderr @@ -0,0 +1,16 @@ +error: used `flat_map` where `filter_map` could be used instead + --> $DIR/flat_map_option.rs:8:24 + | +LL | let _ = [1].iter().flat_map(c); + | ^^^^^^^^ help: try: `filter_map` + | + = note: `-D clippy::flat-map-option` implied by `-D warnings` + +error: used `flat_map` where `filter_map` could be used instead + --> $DIR/flat_map_option.rs:9:24 + | +LL | let _ = [1].iter().flat_map(Some); + | ^^^^^^^^ help: try: `filter_map` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 3f5be5e2357d11ed3273d4e286e2cb9efe46cd28 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 25 Apr 2021 09:51:44 -0500 Subject: Fix cloned_instead_of_copied MSRV --- .../src/methods/cloned_instead_of_copied.rs | 24 +++++++++++++++------- clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index ba97ab3900c..9c1b6f55c88 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,23 +1,33 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; +use clippy_utils::{is_trait_method, meets_msrv}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_semver::RustcVersion; use rustc_span::{sym, Span}; use super::CLONED_INSTEAD_OF_COPIED; -pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { +const ITERATOR_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 36, 0); +const OPTION_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); + +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` - ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) => subst.type_at(0), - _ if is_trait_method(cx, expr, sym::Iterator) => match get_iterator_item_ty(cx, recv_ty) { - // ::Item - Some(ty) => ty, - _ => return, + ty::Adt(adt, subst) + if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &OPTION_COPIED_MSRV) => + { + subst.type_at(0) + }, + _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &ITERATOR_COPIED_MSRV) => { + match get_iterator_item_ty(cx, recv_ty) { + // ::Item + Some(ty) => ty, + _ => return, + } }, _ => return, }; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c2cd3011d14..e15dbb899b3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1959,7 +1959,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("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), + ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv), ("collect", []) => match method_call!(recv) { Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2), Some(("map", [m_recv, m_arg], _)) => { -- cgit 1.4.1-3-g733a5 From d7627dcfc8a60aaedccf002738dc44a2576fa8fd Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Mon, 26 Apr 2021 13:03:51 -0700 Subject: Fix FN in `iter_cloned_collect` with a large array --- clippy_lints/src/methods/utils.rs | 4 +--- tests/ui/iter_cloned_collect.fixed | 4 ++++ tests/ui/iter_cloned_collect.rs | 4 ++++ tests/ui/iter_cloned_collect.stderr | 8 +++++++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index f6bf37e08b9..0daea47816a 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -18,9 +18,7 @@ pub(super) fn derefs_to_slice<'tcx>( ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), - ty::Array(_, size) => size - .try_eval_usize(cx.tcx, cx.param_env) - .map_or(false, |size| size < 32), + ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(), ty::Ref(_, inner, _) => may_slice(cx, inner), _ => false, } diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 2773227e26b..39cc58cd298 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -19,4 +19,8 @@ fn main() { let _: Vec = std::ffi::CStr::from_ptr(std::ptr::null()) .to_bytes().to_vec(); } + + // Issue #6808 + let arr: [u8; 64] = [0; 64]; + let _: Vec<_> = arr.to_vec(); } diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index 60a4eac23c7..c2a036ec09f 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -22,4 +22,8 @@ fn main() { .cloned() .collect(); } + + // Issue #6808 + let arr: [u8; 64] = [0; 64]; + let _: Vec<_> = arr.iter().cloned().collect(); } diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index b90a1e6c919..e1df61794ce 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -22,5 +22,11 @@ LL | | .cloned() LL | | .collect(); | |______________________^ help: try: `.to_vec()` -error: aborting due to 3 previous errors +error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable + --> $DIR/iter_cloned_collect.rs:28:24 + | +LL | let _: Vec<_> = arr.iter().cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 340b570ea0479dc3a9f9bbe1031f8686c9f660e1 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 26 Apr 2021 14:10:32 -0500 Subject: Refactor MSRV aliases --- clippy_lints/src/casts/ptr_as_ptr.rs | 6 ++--- clippy_lints/src/checked_conversions.rs | 6 ++--- clippy_lints/src/from_over_into.rs | 6 ++--- clippy_lints/src/if_then_some_else_none.rs | 6 ++--- clippy_lints/src/manual_non_exhaustive.rs | 6 ++--- clippy_lints/src/manual_strip.rs | 6 ++--- clippy_lints/src/matches.rs | 9 +++---- clippy_lints/src/mem_replace.rs | 6 ++--- .../src/methods/cloned_instead_of_copied.rs | 9 +++---- clippy_lints/src/methods/filter_map_next.rs | 6 ++--- clippy_lints/src/methods/map_unwrap_or.rs | 11 ++++---- clippy_lints/src/methods/option_as_ref_deref.rs | 6 ++--- clippy_lints/src/missing_const_for_fn.rs | 6 ++--- clippy_lints/src/ranges.rs | 6 ++--- clippy_lints/src/redundant_field_names.rs | 6 ++--- clippy_lints/src/redundant_static_lifetimes.rs | 6 ++--- clippy_lints/src/unnested_or_patterns.rs | 17 +++++-------- clippy_lints/src/use_self.rs | 11 ++++---- clippy_utils/src/lib.rs | 1 + clippy_utils/src/msrvs.rs | 29 ++++++++++++++++++++++ 20 files changed, 80 insertions(+), 85 deletions(-) create mode 100644 clippy_utils/src/msrvs.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 9113e5a0920..3132d3a5cf0 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::meets_msrv; use clippy_utils::sugg::Sugg; +use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; @@ -12,10 +12,8 @@ use rustc_semver::RustcVersion; use super::PTR_AS_PTR; -const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0); - pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option) { - if !meets_msrv(msrv.as_ref(), &PTR_AS_PTR_MSRV) { + if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) { return; } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 6a2666bc6c0..8d3123e1ec8 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{meets_msrv, SpanlessEq}; +use clippy_utils::{meets_msrv, msrvs, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -12,8 +12,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const CHECKED_CONVERSIONS_MSRV: RustcVersion = RustcVersion::new(1, 34, 0); - declare_clippy_lint! { /// **What it does:** Checks for explicit bounds checking when casting. /// @@ -58,7 +56,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &CHECKED_CONVERSIONS_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) { return; } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 5e2baba8943..3560672a748 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,14 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::paths::INTO; -use clippy_utils::{match_def_path, meets_msrv}; +use clippy_utils::{match_def_path, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const FROM_OVER_INTO_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); - declare_clippy_lint! { /// **What it does:** Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. /// @@ -57,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); impl LateLintPass<'_> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !meets_msrv(self.msrv.as_ref(), &FROM_OVER_INTO_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) { return; } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 85c95f1151f..eadcd0867a8 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv}; +use clippy_utils::{is_else_clause, is_lang_ctor, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; @@ -9,8 +9,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const IF_THEN_SOME_ELSE_NONE_MSRV: RustcVersion = RustcVersion::new(1, 50, 0); - declare_clippy_lint! { /// **What it does:** Checks for if-else that could be written to `bool::then`. /// @@ -59,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl LateLintPass<'_> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &IF_THEN_SOME_ELSE_NONE_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) { return; } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index dc19805b50a..54f714b54b6 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,7 +1,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::meets_msrv; use clippy_utils::source::snippet_opt; +use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind}; use rustc_errors::Applicability; @@ -10,8 +10,6 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -const MANUAL_NON_EXHAUSTIVE_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. /// @@ -76,7 +74,7 @@ impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustive { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { return; } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index dfa464ddb81..23428524dee 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; -use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, paths}; +use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; @@ -17,8 +17,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; -const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); - declare_clippy_lint! { /// **What it does:** /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using @@ -74,7 +72,7 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { return; } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 44b4eb29035..13b2a834b0a 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -7,8 +7,9 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use clippy_utils::visitors::LocalUsedVisitor; use clippy_utils::{ - get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, path_to_local, - path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs, + get_parent_expr, in_macro, is_allowed, is_expn_of, is_lang_ctor, is_refutable, is_wild, meets_msrv, msrvs, + path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, + strip_pat_refs, }; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -578,8 +579,6 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); -const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0); - impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { @@ -588,7 +587,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { redundant_pattern_match::check(cx, expr); - if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { if !check_match_like_matches(cx, expr) { lint_match_arms(cx, expr); } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index ec60bffe955..183daee3617 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, paths}; +use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -256,8 +256,6 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< } } -const MEM_REPLACE_WITH_DEFAULT_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - pub struct MemReplace { msrv: Option, } @@ -281,7 +279,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); - if meets_msrv(self.msrv.as_ref(), &MEM_REPLACE_WITH_DEFAULT_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) { check_replace_with_default(cx, src, dest, expr.span); } } diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index 9c1b6f55c88..ecec6da3aa0 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; -use clippy_utils::{is_trait_method, meets_msrv}; +use clippy_utils::{is_trait_method, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -10,19 +10,16 @@ use rustc_span::{sym, Span}; use super::CLONED_INSTEAD_OF_COPIED; -const ITERATOR_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 36, 0); -const OPTION_COPIED_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); - pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &OPTION_COPIED_MSRV) => + if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => { subst.type_at(0) }, - _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &ITERATOR_COPIED_MSRV) => { + _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => { match get_iterator_item_ty(cx, recv_ty) { // ::Item Some(ty) => ty, diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 2b19e4ee8c0..f0d69a1f42e 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet; -use clippy_utils::{is_trait_method, meets_msrv}; +use clippy_utils::{is_trait_method, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,8 +9,6 @@ use rustc_span::sym; use super::FILTER_MAP_NEXT; -const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0); - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -19,7 +17,7 @@ pub(super) fn check<'tcx>( msrv: Option<&RustcVersion>, ) { if is_trait_method(cx, expr, sym::Iterator) { - if !meets_msrv(msrv, &FILTER_MAP_NEXT_MSRV) { + if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) { return; } diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 4330fea727b..4d8365fcda1 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::meets_msrv; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::mutated_variables; +use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -11,8 +11,6 @@ use rustc_span::symbol::sym; use super::MAP_UNWRAP_OR; -const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0); - /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s /// Return true if lint triggered pub(super) fn check<'tcx>( @@ -23,13 +21,14 @@ pub(super) fn check<'tcx>( unwrap_arg: &'tcx hir::Expr<'_>, msrv: Option<&RustcVersion>, ) -> bool { - if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) { - return false; - } // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type); + if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) { + return false; + } + if is_option || is_result { // Don't make a suggestion that may fail to compile due to mutably borrowing // the same variable twice. diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 7e9c8fa829d..5a57135038f 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks}; +use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -12,8 +12,6 @@ use rustc_span::sym; use super::OPTION_AS_REF_DEREF; -const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); - /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -23,7 +21,7 @@ pub(super) fn check<'tcx>( is_mut: bool, msrv: Option<&RustcVersion>, ) { - if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { + if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) { return; } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 93b7a897405..27b5a07c1bc 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; -use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, trait_ref_of_method}; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; @@ -12,8 +12,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; -const MISSING_CONST_FOR_FN_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); - declare_clippy_lint! { /// **What it does:** /// @@ -97,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, hir_id: HirId, ) { - if !meets_msrv(self.msrv.as_ref(), &MISSING_CONST_FOR_FN_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) { return; } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 1c3c125e579..7169f96eaf1 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, single_segment_path}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path}; use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; @@ -159,8 +159,6 @@ declare_clippy_lint! { "manually reimplementing {`Range`, `RangeInclusive`}`::contains`" } -const MANUAL_RANGE_CONTAINS_MSRV: RustcVersion = RustcVersion::new(1, 35, 0); - pub struct Ranges { msrv: Option, } @@ -187,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_range_zip_with_len(cx, path, args, expr.span); }, ExprKind::Binary(ref op, l, r) => { - if meets_msrv(self.msrv.as_ref(), &MANUAL_RANGE_CONTAINS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) { check_possible_range_contains(cx, op.node, l, r, expr); } }, diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index abebd422797..d5ee8d3468d 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::meets_msrv; +use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -7,8 +7,6 @@ use rustc_middle::lint::in_external_macro; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const REDUNDANT_FIELD_NAMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); - declare_clippy_lint! { /// **What it does:** Checks for fields in struct literals where shorthands /// could be used. @@ -52,7 +50,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_FIELD_NAMES_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) { return; } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 32b57698ec5..48107d9c037 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,14 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::meets_msrv; use clippy_utils::source::snippet; +use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -const REDUNDANT_STATIC_LIFETIMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0); - declare_clippy_lint! { /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime. /// @@ -100,7 +98,7 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_STATIC_LIFETIMES_MSRV) { + if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) { return; } diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 9376a2cf66a..3e985fa72b8 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,11 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] +use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::over; -use clippy_utils::{ - ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}, - meets_msrv, -}; +use clippy_utils::{meets_msrv, msrvs, over}; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; @@ -54,8 +51,6 @@ declare_clippy_lint! { "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`" } -const UNNESTED_OR_PATTERNS_MSRV: RustcVersion = RustcVersion::new(1, 53, 0); - #[derive(Clone, Copy)] pub struct UnnestedOrPatterns { msrv: Option, @@ -72,13 +67,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]); impl EarlyLintPass for UnnestedOrPatterns { fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &a.pat); } } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { if let ast::ExprKind::Let(pat, _) = &e.kind { lint_unnested_or_patterns(cx, pat); } @@ -86,13 +81,13 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &p.pat); } } fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { - if meets_msrv(self.msrv.as_ref(), &UNNESTED_OR_PATTERNS_MSRV) { + if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &l.pat); } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index c6a3c58a9a2..aa4d16633ff 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::{in_macro, meets_msrv}; +use clippy_utils::{in_macro, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -62,8 +62,6 @@ pub struct UseSelf { stack: Vec, } -const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); - impl UseSelf { #[must_use] pub fn new(msrv: Option) -> Self { @@ -236,7 +234,10 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { - if in_macro(hir_ty.span) | in_impl(cx, hir_ty) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + if in_macro(hir_ty.span) + || in_impl(cx, hir_ty) + || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) + { return; } @@ -288,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } - if in_macro(expr.span) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + if in_macro(expr.span) || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) { return; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b7017411927..9b60c92bca1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -38,6 +38,7 @@ pub mod diagnostics; pub mod eager_or_lazy; pub mod higher; mod hir_utils; +pub mod msrvs; pub mod numeric_literal; pub mod paths; pub mod ptr; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs new file mode 100644 index 00000000000..00df04c0144 --- /dev/null +++ b/clippy_utils/src/msrvs.rs @@ -0,0 +1,29 @@ +use rustc_semver::RustcVersion; + +macro_rules! msrv_aliases { + ($($major:literal,$minor:literal,$patch:literal { + $($name:ident),* $(,)? + })*) => { + $($( + pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch); + )*)* + }; +} + +// names may refer to stabilized feature flags or library items +msrv_aliases! { + 1,53,0 { OR_PATTERNS } + 1,50,0 { BOOL_THEN } + 1,46,0 { CONST_IF_MATCH } + 1,45,0 { STR_STRIP_PREFIX } + 1,42,0 { MATCHES_MACRO } + 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } + 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } + 1,38,0 { POINTER_CAST } + 1,37,0 { TYPE_ALIAS_ENUM_VARIANTS } + 1,36,0 { ITERATOR_COPIED } + 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } + 1,34,0 { TRY_FROM } + 1,30,0 { ITERATOR_FIND_MAP } + 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST } +} -- cgit 1.4.1-3-g733a5 From c0808998481402cb1cd502ad6aa54e253840efc6 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Mon, 3 May 2021 16:18:41 +0200 Subject: add strip_{prefix,suffix} to PATTERN_METHODS this will warn, if a single_char_pattern is used in one of the above methods --- clippy_lints/src/methods/mod.rs | 4 +++- tests/ui/single_char_pattern.fixed | 2 ++ tests/ui/single_char_pattern.rs | 2 ++ tests/ui/single_char_pattern.stderr | 34 +++++++++++++++++++++++----------- 4 files changed, 30 insertions(+), 12 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e15dbb899b3..5ea989aa684 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2190,7 +2190,7 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ]; #[rustfmt::skip] -const PATTERN_METHODS: [(&str, usize); 17] = [ +const PATTERN_METHODS: [(&str, usize); 19] = [ ("contains", 1), ("starts_with", 1), ("ends_with", 1), @@ -2206,6 +2206,8 @@ const PATTERN_METHODS: [(&str, usize); 17] = [ ("rmatches", 1), ("match_indices", 1), ("rmatch_indices", 1), + ("strip_prefix", 1), + ("strip_suffix", 1), ("trim_start_matches", 1), ("trim_end_matches", 1), ]; diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index d8b5f19e144..fcbe9af9f56 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -33,6 +33,8 @@ fn main() { x.rmatch_indices('x'); x.trim_start_matches('x'); x.trim_end_matches('x'); + x.strip_prefix('x'); + x.strip_suffix('x'); // Make sure we escape characters correctly. x.split('\n'); x.split('\''); diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index a7bc73e3756..b8bc20f4070 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -33,6 +33,8 @@ fn main() { x.rmatch_indices("x"); x.trim_start_matches("x"); x.trim_end_matches("x"); + x.strip_prefix("x"); + x.strip_suffix("x"); // Make sure we escape characters correctly. x.split("\n"); x.split("'"); diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index ee4e7e50efd..6d94d8a34e3 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -121,64 +121,76 @@ LL | x.trim_end_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:37:13 + --> $DIR/single_char_pattern.rs:36:20 + | +LL | x.strip_prefix("x"); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:37:20 + | +LL | x.strip_suffix("x"); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:39:13 | LL | x.split("/n"); | ^^^^ help: try using a `char` instead: `'/n'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:38:13 + --> $DIR/single_char_pattern.rs:40:13 | LL | x.split("'"); | ^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:39:13 + --> $DIR/single_char_pattern.rs:41:13 | LL | x.split("/'"); | ^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:44:31 + --> $DIR/single_char_pattern.rs:46:31 | LL | x.replace(";", ",").split(","); // issue #2978 | ^^^ help: try using a `char` instead: `','` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:45:19 + --> $DIR/single_char_pattern.rs:47:19 | LL | x.starts_with("/x03"); // issue #2996 | ^^^^^^ help: try using a `char` instead: `'/x03'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:52:13 + --> $DIR/single_char_pattern.rs:54:13 | LL | x.split(r"a"); | ^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:53:13 + --> $DIR/single_char_pattern.rs:55:13 | LL | x.split(r#"a"#); | ^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:54:13 + --> $DIR/single_char_pattern.rs:56:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:55:13 + --> $DIR/single_char_pattern.rs:57:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:56:13 + --> $DIR/single_char_pattern.rs:58:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` -error: aborting due to 30 previous errors +error: aborting due to 32 previous errors -- cgit 1.4.1-3-g733a5 From 19e7448c7f6a4e3a07507c2742bef07d56f1a4a3 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Mon, 3 May 2021 16:21:27 +0200 Subject: move PATTERN_METHODS table directly into file also removed rustfmt::skip --- clippy_lints/src/methods/mod.rs | 23 ----------------------- clippy_lints/src/methods/single_char_pattern.rs | 24 +++++++++++++++++++++++- 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ea989aa684..0b1b6304def 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2189,29 +2189,6 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ]; -#[rustfmt::skip] -const PATTERN_METHODS: [(&str, usize); 19] = [ - ("contains", 1), - ("starts_with", 1), - ("ends_with", 1), - ("find", 1), - ("rfind", 1), - ("split", 1), - ("rsplit", 1), - ("split_terminator", 1), - ("rsplit_terminator", 1), - ("splitn", 2), - ("rsplitn", 2), - ("matches", 1), - ("rmatches", 1), - ("match_indices", 1), - ("rmatch_indices", 1), - ("strip_prefix", 1), - ("strip_suffix", 1), - ("trim_start_matches", 1), - ("trim_end_matches", 1), -]; - #[derive(Clone, Copy, PartialEq, Debug)] enum SelfKind { Value, diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index f4090c7c617..d313a3db479 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -9,9 +9,31 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; +const PATTERN_METHODS: [(&str, usize); 19] = [ + ("contains", 1), + ("starts_with", 1), + ("ends_with", 1), + ("find", 1), + ("rfind", 1), + ("split", 1), + ("rsplit", 1), + ("split_terminator", 1), + ("rsplit_terminator", 1), + ("splitn", 2), + ("rsplitn", 2), + ("matches", 1), + ("rmatches", 1), + ("match_indices", 1), + ("rmatch_indices", 1), + ("strip_prefix", 1), + ("strip_suffix", 1), + ("trim_start_matches", 1), + ("trim_end_matches", 1), +]; + /// lint for length-1 `str`s for methods in `PATTERN_METHODS` pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { - for &(method, pos) in &crate::methods::PATTERN_METHODS { + for &(method, pos) in &PATTERN_METHODS { if_chain! { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind(); if *ty.kind() == ty::Str; -- cgit 1.4.1-3-g733a5 From d66d37303c7074e8e26a0f67bba5a36cd6b12e29 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 5 May 2021 16:05:16 -0500 Subject: Fix unnecessary_filter_map false positive --- clippy_lints/src/methods/unnecessary_filter_map.rs | 40 ++++++++++++---------- tests/ui/unnecessary_filter_map.rs | 4 +++ 2 files changed, 26 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index b61c4ffe9b3..8b66587bfd1 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -6,6 +6,7 @@ use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; +use rustc_middle::ty::{self, TyS}; use rustc_span::sym; use super::UNNECESSARY_FILTER_MAP; @@ -28,25 +29,28 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< found_mapping |= return_visitor.found_mapping; found_filtering |= return_visitor.found_filtering; - if !found_filtering { - span_lint( - cx, - UNNECESSARY_FILTER_MAP, - expr.span, - "this `.filter_map` can be written more simply using `.map`", - ); - return; - } - - if !found_mapping && !mutates_arg { - span_lint( - cx, - UNNECESSARY_FILTER_MAP, - expr.span, - "this `.filter_map` can be written more simply using `.filter`", - ); + let sugg = if !found_filtering { + "map" + } else if !found_mapping && !mutates_arg { + let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); + match cx.typeck_results().expr_ty(&body.value).kind() { + ty::Adt(adt, subst) + if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) + && TyS::same_type(in_ty, subst.type_at(0)) => + { + "filter" + }, + _ => return, + } + } else { return; - } + }; + span_lint( + cx, + UNNECESSARY_FILTER_MAP, + expr.span, + &format!("this `.filter_map` can be written more simply using `.{}`", sugg), + ); } } diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs index af858e4abcf..c58181f518d 100644 --- a/tests/ui/unnecessary_filter_map.rs +++ b/tests/ui/unnecessary_filter_map.rs @@ -15,3 +15,7 @@ fn main() { let _ = (0..4).filter_map(i32::checked_abs); } + +fn filter_map_none_changes_item_type() -> impl Iterator { + "".chars().filter_map(|_| None) +} -- cgit 1.4.1-3-g733a5 From ab3094b3dbf0bf6423a9cf0509a170eee89f106e Mon Sep 17 00:00:00 2001 From: Mateusz Gacek <96mateusz.gacek@gmail.com> Date: Thu, 6 May 2021 10:49:31 -0700 Subject: wrong_self_convention: For `to_*` variant don't lint in trait impl taking `self` when non-`Copy` type It relaxes rules for `to_*` variant, so it doesn't lint in trait definitions and implementations anymore. Although, non-`Copy` type implementing trait's `to_*` method taking `self` feels not good (consumes ownership, so should be rather named `into_`), it would be better if this case was a pedantic lint (allow-by-default) instead. --- clippy_lints/src/methods/wrong_self_convention.rs | 2 +- tests/ui/wrong_self_convention2.rs | 2 +- tests/ui/wrong_self_convention2.stderr | 11 ----------- 3 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 tests/ui/wrong_self_convention2.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 6e2bcb113c2..1773c26c251 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -22,7 +22,7 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types). // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), - Convention::IsTraitItem(false)], &[SelfKind::Ref]), + Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]), (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index ae3a740d405..18202ef2989 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -23,7 +23,7 @@ mod issue6983 { } struct FooNoCopy; - // trigger lint + // don't trigger impl ToU64 for FooNoCopy { fn to_u64(self) -> u64 { 2 diff --git a/tests/ui/wrong_self_convention2.stderr b/tests/ui/wrong_self_convention2.stderr deleted file mode 100644 index 0ca1a390974..00000000000 --- a/tests/ui/wrong_self_convention2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention2.rs:28:19 - | -LL | fn to_u64(self) -> u64 { - | ^^^^ - | - = note: `-D clippy::wrong-self-convention` implied by `-D warnings` - = help: consider choosing a less ambiguous name - -error: aborting due to previous error - -- cgit 1.4.1-3-g733a5 From cd241b33cb8379311286f53c4afc6e671ddfded1 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 13 May 2021 10:24:29 +0200 Subject: Trigger `wrong_self_convention` only if it has implicit self --- clippy_lints/src/methods/mod.rs | 24 ++++++++++++++---------- tests/ui/wrong_self_convention2.rs | 23 +++++++++++++++++++++++ tests/ui/wrong_self_convention2.stderr | 19 +++++++++++++++++++ 3 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 tests/ui/wrong_self_convention2.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0b1b6304def..e0d29682146 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1838,16 +1838,18 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - wrong_self_convention::check( - cx, - &name, - item.vis.node.is_pub(), - self_ty, - first_arg_ty, - first_arg.pat.span, - implements_trait, - false - ); + if sig.decl.implicit_self.has_implicit_self() { + wrong_self_convention::check( + cx, + &name, + item.vis.node.is_pub(), + self_ty, + first_arg_ty, + first_arg.pat.span, + implements_trait, + false + ); + } } } @@ -1903,7 +1905,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if_chain! { if let TraitItemKind::Fn(ref sig, _) = item.kind; + if sig.decl.implicit_self.has_implicit_self(); if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); + then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index 18202ef2989..b2c6503de49 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -42,3 +42,26 @@ mod issue7032 { } } } + +mod issue7179 { + pub struct S(i32); + + impl S { + // don't trigger (`s` is not `self`) + pub fn from_be(s: Self) -> Self { + S(i32::from_be(s.0)) + } + + // lint + pub fn from_be_self(self) -> Self { + S(i32::from_be(self.0)) + } + } + + trait T { + // don't trigger (`s` is not `self`) + fn from_be(s: Self) -> Self; + // lint + fn from_be_self(self) -> Self; + } +} diff --git a/tests/ui/wrong_self_convention2.stderr b/tests/ui/wrong_self_convention2.stderr new file mode 100644 index 00000000000..d2d74ce099e --- /dev/null +++ b/tests/ui/wrong_self_convention2.stderr @@ -0,0 +1,19 @@ +error: methods called `from_*` usually take no `self` + --> $DIR/wrong_self_convention2.rs:56:29 + | +LL | pub fn from_be_self(self) -> Self { + | ^^^^ + | + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name + +error: methods called `from_*` usually take no `self` + --> $DIR/wrong_self_convention2.rs:65:25 + | +LL | fn from_be_self(self) -> Self; + | ^^^^ + | + = help: consider choosing a less ambiguous name + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From ae0d4da764fd751494fb270fd04c2c686eac1302 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 22 May 2021 21:47:11 +0300 Subject: Fix invalid syntax in `from_iter_instead_of_collect` suggestion with "as Trait" --- .../src/methods/from_iter_instead_of_collect.rs | 47 ++++++++++++++-------- tests/ui/from_iter_instead_of_collect.fixed | 14 +++++++ tests/ui/from_iter_instead_of_collect.rs | 14 +++++++ tests/ui/from_iter_instead_of_collect.stderr | 40 ++++++++++-------- 4 files changed, 81 insertions(+), 34 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 28d0e8cd4ae..b4188d9ed30 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -37,6 +37,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp } fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + fn strip_angle_brackets(s: &str) -> Option<&str> { + s.strip_prefix('<')?.strip_suffix('>') + } + let call_site = expr.span.source_callsite(); if_chain! { if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); @@ -44,23 +48,32 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) - if let Some((_, elements)) = snippet_split.split_last(); then { - // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) - if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { - // remove the type specifier from the path elements - let without_ts = elements.iter().filter_map(|e| { - if e == type_specifier { None } else { Some((*e).to_string()) } - }).collect::>(); - // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) - format!("{}{}", without_ts.join("::"), type_specifier) - } else { - // type is not explicitly specified so wildcards are needed - // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` - let ty_str = ty.to_string(); - let start = ty_str.find('<').unwrap_or(0); - let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); - let nb_wildcard = ty_str[start..end].split(',').count(); - let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{}>", elements.join("::"), wildcards) + if_chain! { + if let [type_specifier, _] = snippet_split.as_slice(); + if let Some(type_specifier) = strip_angle_brackets(type_specifier); + if let Some((type_specifier, ..)) = type_specifier.split_once(" as "); + then { + type_specifier.to_string() + } else { + // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) + format!("{}{}", without_ts.join("::"), type_specifier) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{}>", elements.join("::"), wildcards) + } + } } } else { ty.to_string() diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index b5f548810e6..12db43b5343 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -6,6 +6,20 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; +struct Foo(Vec); + +impl FromIterator for Foo { + fn from_iter>(_: T) -> Self { + todo!() + } +} + +impl<'a> FromIterator<&'a bool> for Foo { + fn from_iter>(iter: T) -> Self { + iter.into_iter().copied().collect::() + } +} + fn main() { let iter_expr = std::iter::repeat(5).take(5); let _ = iter_expr.collect::>(); diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index b842b5451d1..f5ec190e0cd 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -6,6 +6,20 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; +struct Foo(Vec); + +impl FromIterator for Foo { + fn from_iter>(_: T) -> Self { + todo!() + } +} + +impl<'a> FromIterator<&'a bool> for Foo { + fn from_iter>(iter: T) -> Self { + >::from_iter(iter.into_iter().copied()) + } +} + fn main() { let iter_expr = std::iter::repeat(5).take(5); let _ = Vec::from_iter(iter_expr); diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 434734c9a21..8f08ac8c3ff 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,88 +1,94 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:11:13 + --> $DIR/from_iter_instead_of_collect.rs:19:9 | -LL | let _ = Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` +LL | >::from_iter(iter.into_iter().copied()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:13:13 + --> $DIR/from_iter_instead_of_collect.rs:25:13 + | +LL | let _ = Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:27:13 | LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:18:19 + --> $DIR/from_iter_instead_of_collect.rs:32:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:19:19 + --> $DIR/from_iter_instead_of_collect.rs:33:19 | LL | assert_eq!(a, Vec::::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:21:17 + --> $DIR/from_iter_instead_of_collect.rs:35:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:24:17 + --> $DIR/from_iter_instead_of_collect.rs:38:17 | LL | let mut b = VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:29:21 + --> $DIR/from_iter_instead_of_collect.rs:43:21 | LL | let mut b = collections::VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:34:14 + --> $DIR/from_iter_instead_of_collect.rs:48:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:35:19 + --> $DIR/from_iter_instead_of_collect.rs:49:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:38:19 + --> $DIR/from_iter_instead_of_collect.rs:52:19 | LL | let mut bts = BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:42:17 + --> $DIR/from_iter_instead_of_collect.rs:56:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:43:17 + --> $DIR/from_iter_instead_of_collect.rs:57:17 | LL | let _ = collections::BTreeSet::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:46:15 + --> $DIR/from_iter_instead_of_collect.rs:60:15 | LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:47:15 + --> $DIR/from_iter_instead_of_collect.rs:61:15 | LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From cadad20da1e970e62ea28f32a2f4a9177e8ca859 Mon Sep 17 00:00:00 2001 From: mbartlett21 <29034492+mbartlett21@users.noreply.github.com> Date: Tue, 25 May 2021 00:54:50 +0000 Subject: Add semicolons up to `needless_for_each.rs` --- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/attrs.rs | 6 +++--- clippy_lints/src/bit_mask.rs | 6 +++--- clippy_lints/src/booleans.rs | 6 +++--- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 4 ++-- clippy_lints/src/double_comparison.rs | 8 ++++---- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/eq_op.rs | 12 ++++++------ clippy_lints/src/eta_reduction.rs | 7 ++++--- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- clippy_lints/src/functions/too_many_lines.rs | 2 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/implicit_return.rs | 2 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/invalid_upcast_comparisons.rs | 4 ++-- clippy_lints/src/len_zero.rs | 4 ++-- clippy_lints/src/let_underscore.rs | 8 ++++---- clippy_lints/src/lifetimes.rs | 4 ++-- clippy_lints/src/literal_representation.rs | 8 ++++---- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 8 ++++---- clippy_lints/src/loops/same_item_push.rs | 4 ++-- clippy_lints/src/loops/utils.rs | 8 ++++---- clippy_lints/src/macro_use.rs | 6 +++--- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_clone.rs | 6 +++--- clippy_lints/src/matches.rs | 10 +++++----- clippy_lints/src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/cloned_instead_of_copied.rs | 2 +- clippy_lints/src/methods/flat_map_option.rs | 2 +- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/methods/unnecessary_fold.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 10 +++++----- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/needless_arbitrary_self_type.rs | 4 ++-- clippy_lints/src/needless_bool.rs | 18 +++++++++--------- clippy_lints/src/needless_borrow.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 4 ++-- .../src/utils/internal_lints/metadata_collector.rs | 2 +- 46 files changed, 105 insertions(+), 104 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index c565e29d078..6c9ceaa45c2 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { &format!("`assert!(false, {})` should probably be replaced", panic_message), None, &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message), - ) + ); }; if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index c5b01461c1c..932cd58bf62 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); if is_relevant_item(cx, item) { - check_attrs(cx, item.span, item.ident.name, attrs) + check_attrs(cx, item.span, item.ident.name, attrs); } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { @@ -343,13 +343,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if is_relevant_impl(cx, item) { - check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())) + check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if is_relevant_trait(cx, item) { - check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())) + check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); } } } diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index f7daf3dab49..0ac6dc28e73 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask { if let ExprKind::Binary(cmp, left, right) = &e.kind { if cmp.node.is_comparison() { if let Some(cmp_opt) = fetch_int_literal(cx, right) { - check_compare(cx, left, cmp.node, cmp_opt, e.span) + check_compare(cx, left, cmp.node, cmp_opt, e.span); } else if let Some(cmp_val) = fetch_int_literal(cx, left) { - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span) + check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span); } } } @@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp } fetch_int_literal(cx, right) .or_else(|| fetch_int_literal(cx, left)) - .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) + .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)); } } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 67f0e0c7870..e72399af232 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: HirId, ) { - NonminimalBoolVisitor { cx }.visit_body(body) + NonminimalBoolVisitor { cx }.visit_body(body); } } @@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { Term(n) => { let terminal = self.terminals[n as usize]; if let Some(str) = simplify_not(self.cx, terminal) { - self.output.push_str(&str) + self.output.push_str(&str); } else { self.output.push('!'); let snip = snippet_opt(self.cx, terminal.span)?; @@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } match &e.kind { ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { - self.bool_expr(e) + self.bool_expr(e); }, ExprKind::Unary(UnOp::Not, inner) => { if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index dae5c86bd44..6e950738239 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if !expr.span.from_expansion() { - check_if(cx, expr) + check_if(cx, expr); } } } diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 2a61d58e653..b6999bef6e7 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { "`if` chain can be rewritten with `match`", None, "consider rewriting the `if` chain to use `cmp` and `match`", - ) + ); } } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f956d171bfb..376a14b8181 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -476,7 +476,7 @@ fn emit_branches_sharing_code_lint( } suggestions.push(("end", span, suggestion.to_string())); - add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit() + add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit(); } let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 6e883942680..759f7d4062d 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -181,9 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { match stmt.kind { StmtKind::Local(local) => { if local.ty.is_some() { - self.ty_bounds.push(TyBound::Any) + self.ty_bounds.push(TyBound::Any); } else { - self.ty_bounds.push(TyBound::Nothing) + self.ty_bounds.push(TyBound::Nothing); } }, diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 58543ae6e4e..4966638cb1b 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -70,16 +70,16 @@ impl<'tcx> DoubleComparisons { #[rustfmt::skip] match (op, lkind, rkind) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => { - lint_double_comparison!(<=) + lint_double_comparison!(<=); }, (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => { - lint_double_comparison!(>=) + lint_double_comparison!(>=); }, (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => { - lint_double_comparison!(!=) + lint_double_comparison!(!=); }, (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => { - lint_double_comparison!(==) + lint_double_comparison!(==); }, _ => (), }; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 8db5050a5ac..2eb8b1422ed 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -469,7 +469,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { let mut is_map_used = self.is_map_used; for arm in arms { if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard { - self.visit_non_tail_expr(guard) + self.visit_non_tail_expr(guard); } is_map_used |= self.visit_cond_arm(arm.body); } diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 90f391b5f5c..47fe4e0de0d 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { vec![(left.span, lsnip), (right.span, rsnip)], ); }, - ) + ); } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } else if !lcpy && rcpy && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // &foo == bar @@ -218,9 +218,9 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } - }, + }, // foo == &bar (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { let rty = cx.typeck_results().expr_ty(r); @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { rsnip, Applicability::MaybeIncorrect, // FIXME #2597 ); - }) + }); } }, _ => {}, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index afc5d546474..8d066f305ee 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { for arg in args { // skip `foo(macro!())` if arg.span.ctxt() == expr.span.ctxt() { - check_closure(cx, arg) + check_closure(cx, arg); } } }, @@ -190,9 +190,10 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a cx.tcx.impl_of_method(method_def_id).and_then(|_| { //a type may implicitly implement other type's methods (e.g. Deref) if match_types(expected_type_of_self, actual_type_of_self) { - return Some(get_type_name(cx, actual_type_of_self)); + Some(get_type_name(cx, actual_type_of_self)) + } else { + None } - None }) } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 41acf55dd7d..5fdf5bc9e9d 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { self.visit_expr(e); for arm in arms { if let Some(Guard::If(if_expr)) = arm.guard { - self.visit_expr(if_expr) + self.visit_expr(if_expr); } // make sure top level arm expressions aren't linted self.maybe_walk_expr(&*arm.body); diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 20288427b4a..7f4fb68cf2f 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -240,7 +240,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { - self.mutates_static |= is_mutated_static(target) + self.mutates_static |= is_mutated_static(target); }, _ => {}, } diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index aa5494d5a7d..c02c343dc58 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -63,6 +63,6 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<' "this function has too many lines ({}/{})", line_count, too_many_lines_threshold ), - ) + ); } } diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 04730ace887..515b8887453 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { )); } } - }) + }); }, ); } diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 260a8f50157..f2f830ca5c0 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -67,7 +67,7 @@ fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) { "change `break` to `return` as shown", format!("return {}", snip), app, - ) + ); } #[derive(Clone, Copy, PartialEq, Eq)] diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index afee20ce43e..6b887da2630 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { return; }, }; - span_lint(cx, lint, expr.span, msg) + span_lint(cx, lint, expr.span, msg); } } diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index c67c02eefa5..aafdebef248 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -177,7 +177,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, true) + err_upcast_comparison(cx, span, lhs, true); } else if match rel { Rel::Lt => { if invert { @@ -195,7 +195,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, false) + err_upcast_comparison(cx, span, lhs, false); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index bb57adff7be..583514b22f9 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -380,9 +380,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to) + check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to); } else { - check_empty_expr(cx, span, method, lit, op) + check_empty_expr(cx, span, method, lit, op); } } diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 17e23781db7..e627b1385bc 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ) + ); } else if init_ty.needs_drop(cx.tcx, cx.param_env) { span_lint_and_help( cx, @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ) + ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on an expression with `#[must_use]` type", None, "consider explicitly using expression value" - ) + ); } else if is_must_use_func_call(cx, init) { span_lint_and_help( cx, @@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a result of a `#[must_use]` function", None, "consider explicitly using function result" - ) + ); } } } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 116ad072837..5ae68ba5b2f 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -205,7 +205,7 @@ fn could_use_elision<'tcx>( output_visitor.visit_ty(ty); } for lt in named_generics { - input_visitor.visit_generic_param(lt) + input_visitor.visit_generic_param(lt); } if input_visitor.abort() || output_visitor.abort() { @@ -463,7 +463,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker { // `'b` in `'a: 'b` is useless unless used elsewhere in // a non-lifetime bound if let GenericParamKind::Type { .. } = param.kind { - walk_generic_param(self, param) + walk_generic_param(self, param); } } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index e93b2e36b86..e0c5578bd60 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -231,7 +231,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -294,7 +294,7 @@ impl LiteralDigitGrouping { } }; if should_warn { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); } } } @@ -424,7 +424,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -446,7 +446,7 @@ impl DecimalLiteralRepresentation { let hex = format!("{:#X}", val); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); }); } } diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index ce02ad013be..f0327b5d777 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -43,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m "to write this more concisely, try", format!("&{}{}", muta, object), applicability, - ) + ); } /// Returns `true` if the type of expr is one that provides `IntoIterator` impls diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 1425d50f560..d07b5a93b67 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -88,10 +88,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { if let ty::BorrowKind::MutBorrow = bk { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } } @@ -100,10 +100,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index cb2c83e9029..f2e0a0f7003 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -32,10 +32,10 @@ pub(super) fn check<'tcx>( "it looks like the same item is being pushed into this Vec", None, &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + "try using vec![{}; SIZE] or {}.resize(NEW_SIZE, {})", item_str, vec_str, item_str ), - ) + ); } if !matches!(pat.kind, PatKind::Wild) { diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 4db6644b9d7..2f7360210ba 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -80,10 +80,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } }, ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => { - *state = IncrementVisitorVarState::DontWarn + *state = IncrementVisitorVarState::DontWarn; }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - *state = IncrementVisitorVarState::DontWarn + *state = IncrementVisitorVarState::DontWarn; }, _ => (), } @@ -207,7 +207,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - self.state = InitializeVisitorState::DontWarn + self.state = InitializeVisitorState::DontWarn; }, _ => (), } @@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } } - walk_pat(self, pat) + walk_pat(self, pat); } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 914b583186c..66479ae264e 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -212,9 +212,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let mut suggestions = vec![]; for ((root, span), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]))) + suggestions.push((span, format!("{}::{}", root, path[0]))); } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))) + suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))); } } @@ -231,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { "remove the attribute and import the macro directly, try", help, Applicability::MaybeIncorrect, - ) + ); } } } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 23428524dee..6a06090f6e2 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), - ) + ); }); } } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 99c35ae3bbf..e1f80ab025c 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -125,7 +125,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { "remove the `map` call", String::new(), Applicability::MachineApplicable, - ) + ); } fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { @@ -142,7 +142,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } else { span_lint_and_sugg( cx, @@ -155,6 +155,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index fcd37687010..e07d8ea56e4 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1144,7 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestions.join(" | "), Applicability::MaybeIncorrect, - ) + ); }, }; } @@ -1242,7 +1242,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp cast, ), applicability, - ) + ); } } } @@ -1494,7 +1494,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A "consider using the scrutinee and body instead", sugg, applicability, - ) + ); } else { span_lint_and_sugg( cx, @@ -1747,7 +1747,7 @@ mod redundant_pattern_match { match match_source { MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), MatchSource::IfLetDesugar { contains_else_clause } => { - find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause) + find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause); }, MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false), _ => {}, @@ -1876,7 +1876,7 @@ mod redundant_pattern_match { { self.res = true; } else { - self.visit_expr(self_arg) + self.visit_expr(self_arg); } } args.iter().for_each(|arg| self.visit_expr(arg)); diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 287bff886bf..da428a7b487 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -135,7 +135,7 @@ pub(crate) trait BindInsteadOfMap { .into_iter() .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), ), - ) + ); }); true } diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index ecec6da3aa0..f5b4b6bf8ea 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -41,5 +41,5 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, "try", "copied".into(), Applicability::MachineApplicable, - ) + ); } diff --git a/clippy_lints/src/methods/flat_map_option.rs b/clippy_lints/src/methods/flat_map_option.rs index 12d560653ed..32d40d97bf4 100644 --- a/clippy_lints/src/methods/flat_map_option.rs +++ b/clippy_lints/src/methods/flat_map_option.rs @@ -30,5 +30,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg "try", "filter_map".into(), Applicability::MachineApplicable, - ) + ); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e0d29682146..cabfe8023ef 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1951,7 +1951,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio if let Some((name, [recv, args @ ..], span)) = method_call!(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => { - zst_offset::check(cx, expr, recv) + zst_offset::check(cx, expr, recv); }, ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); @@ -2012,7 +2012,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv), ("filter", [f_arg]) => { - filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false) + filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); }, ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true), _ => {}, @@ -2058,7 +2058,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, Some(("map", [m_recv, m_arg], span)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span) + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, _ => {}, }, @@ -2073,7 +2073,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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) { - search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span) + search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); } } diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 75517c48a21..4c4034437da 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -87,7 +87,7 @@ pub(super) fn check( ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true), ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false), ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false) + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false); }, _ => (), } diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index dd38316fa25..050b6805b7c 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -310,7 +310,7 @@ impl EarlyLintPass for MiscEarlyLints { if in_external_macro(cx.sess(), expr.span) { return; } - double_neg::check(cx, expr) + double_neg::check(cx, expr); } } @@ -334,15 +334,15 @@ impl MiscEarlyLints { }; unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); if lit_snip.starts_with("0x") { - mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip) + mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip); } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { - /* nothing to do */ + // nothing to do } else if value != 0 && lit_snip.starts_with('0') { - zero_prefixed_literal::check(cx, lit, &lit_snip) + zero_prefixed_literal::check(cx, lit, &lit_snip); } } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind { let suffix = float_ty.name_str(); - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float") + unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); } } } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index cea6fce1195..6efe8ffcde0 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method") + check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method"); }, _ => (), } diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 533c5a22db0..81bf853300f 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -103,7 +103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { _ if !self.found => self.expr_span = Some(expr.span), _ => return, } - walk_expr(self, expr) + walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 3e2b2782ed5..fe3c4455be5 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -121,7 +121,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl) + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, TyKind::Rptr(lifetime, mut_ty) => { @@ -129,7 +129,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { if let TyKind::Path(None, path) = &mut_ty.ty.kind; if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind; then { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl) + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } } }, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index dd458198637..3b3736fd3a1 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if is_else_clause(cx.tcx, e) { - snip = snip.blockify() + snip = snip.blockify(); } span_lint_and_sugg( @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { |h: Sugg<'_>| !h, "equality checks against false can be replaced by a negation", )); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Ne => { let true_case = Some(( @@ -152,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { "inequality checks against true can be replaced by a negation", )); let false_case = Some((|h| h, "inequality checks against false are unnecessary")); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Lt => check_comparison( cx, @@ -251,22 +251,22 @@ fn check_comparison<'a, 'tcx>( snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability) ), applicability, - ) + ); } } match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { (Bool(true), Other) => left_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h) + suggest_bool_comparison(cx, e, right_side, applicability, m, h); }), (Other, Bool(true)) => right_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h) + suggest_bool_comparison(cx, e, left_side, applicability, m, h); }), (Bool(false), Other) => left_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h) + suggest_bool_comparison(cx, e, right_side, applicability, m, h); }), (Other, Bool(false)) => right_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h) + suggest_bool_comparison(cx, e, left_side, applicability, m, h); }), (Other, Other) => no_literal.map_or((), |(h, m)| { let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability); @@ -279,7 +279,7 @@ fn check_comparison<'a, 'tcx>( "try simplifying it as shown", h(left_side, right_side).to_string(), applicability, - ) + ); }), _ => (), } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index bcedebfccc7..dd1dfa2bdfb 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { |diag| { diag.multipart_suggestion("try this", replacements, app); }, - ) + ); } self.current_body = None; } diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 079b6642d58..3b936e6aaef 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -145,7 +145,7 @@ impl<'tcx> Visitor<'tcx> for RetCollector { self.ret_in_loop = true } - self.spans.push(expr.span) + self.spans.push(expr.span); }, ExprKind::Loop(..) => { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index e70f8a09ebe..39ef170ae36 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { LitKind::Str(ref text, _) => { let str_pat = self.next("s"); println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat); - println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()) + println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()); }, } }, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index ee7be24eae8..2c73c3d929b 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1100,7 +1100,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { IF_CHAIN_STYLE, if_chain_local_span(cx, local, if_chain_span), "`let` expression should be inside `then { .. }`", - ) + ); } } @@ -1141,7 +1141,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span) && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span) { - span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`") + span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`"); } } } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index a672af88271..46af03663b8 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -818,7 +818,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some()); if found_function { // These functions are all multi part suggestions - self.add_single_span_suggestion() + self.add_single_span_suggestion(); } }, ExprKind::MethodCall(path, _path_span, arg, _arg_span) => { -- cgit 1.4.1-3-g733a5 From d7f47f280ec267c0583f7d38fc149a2351b923e6 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 26 May 2021 16:39:39 -0500 Subject: Use break api config for wrong_pub_self_convention --- clippy_lints/src/deprecated_lints.rs | 9 +++++ clippy_lints/src/lib.rs | 9 +++-- clippy_lints/src/methods/mod.rs | 40 +++++-------------- clippy_lints/src/methods/wrong_self_convention.rs | 13 ++---- tests/ui/def_id_nocore.rs | 2 +- tests/ui/module_name_repetitions.rs | 8 ---- tests/ui/wrong_self_convention.rs | 1 - tests/ui/wrong_self_convention.stderr | 48 +++++++++++------------ tests/ui/wrong_self_convention2.rs | 1 - tests/ui/wrong_self_convention2.stderr | 4 +- 10 files changed, 55 insertions(+), 80 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 50ffc2e3f19..dd780ff87fe 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -141,3 +141,12 @@ declare_deprecated_lint! { pub FILTER_MAP, "this lint has been replaced by `manual_filter_map`, a more specific lint" } + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which + /// enables the `wrong_self_conversion` lint for public items. + pub WRONG_PUB_SELF_CONVENTION, + "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cf54021202f..6dd2486afae 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -505,6 +505,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::filter_map", "this lint has been replaced by `manual_filter_map`, a more specific lint", ); + store.register_removed( + "clippy::wrong_pub_self_convention", + "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -802,7 +806,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::UNNECESSARY_LAZY_EVALUATIONS, methods::UNWRAP_USED, methods::USELESS_ASREF, - methods::WRONG_PUB_SELF_CONVENTION, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -1026,7 +1029,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::FILETYPE_IS_FILE), LintId::of(methods::GET_UNWRAP), LintId::of(methods::UNWRAP_USED), - LintId::of(methods::WRONG_PUB_SELF_CONVENTION), LintId::of(misc::FLOAT_CMP_CONST), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), @@ -1862,7 +1864,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }) }); - store.register_late_pass(move || box methods::Methods::new(msrv)); + let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; + store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv)); store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cabfe8023ef..0b998dbf86c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -282,30 +282,6 @@ declare_clippy_lint! { "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention" } -declare_clippy_lint! { - /// **What it does:** This is the same as - /// [`wrong_self_convention`](#wrong_self_convention), but for public items. - /// - /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). - /// - /// **Known problems:** Actually *renaming* the function may break clients if - /// the function is part of the public interface. In that case, be mindful of - /// the stability guarantees you've given your users. - /// - /// **Example:** - /// ```rust - /// # struct X; - /// impl<'a> X { - /// pub fn as_str(self) -> &'a str { - /// "foo" - /// } - /// } - /// ``` - pub WRONG_PUB_SELF_CONVENTION, - restriction, - "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention" -} - declare_clippy_lint! { /// **What it does:** Checks for usage of `ok().expect(..)`. /// @@ -1658,13 +1634,17 @@ declare_clippy_lint! { } pub struct Methods { + avoid_breaking_exported_api: bool, msrv: Option, } impl Methods { #[must_use] - pub fn new(msrv: Option) -> Self { - Self { msrv } + pub fn new(avoid_breaking_exported_api: bool, msrv: Option) -> Self { + Self { + avoid_breaking_exported_api, + msrv, + } } } @@ -1673,7 +1653,6 @@ impl_lint_pass!(Methods => [ EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, - WRONG_PUB_SELF_CONVENTION, OK_EXPECT, MAP_UNWRAP_OR, RESULT_MAP_OR_INTO_OPTION, @@ -1838,11 +1817,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - if sig.decl.implicit_self.has_implicit_self() { + if sig.decl.implicit_self.has_implicit_self() + && !(self.avoid_breaking_exported_api + && cx.access_levels.is_exported(impl_item.hir_id())) + { wrong_self_convention::check( cx, &name, - item.vis.node.is_pub(), self_ty, first_arg_ty, first_arg.pat.span, @@ -1915,7 +1896,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { wrong_self_convention::check( cx, &item.ident.name.as_str(), - false, self_ty, first_arg_ty, first_arg_span, diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 1773c26c251..a2e09e5ecec 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -6,7 +6,6 @@ use rustc_middle::ty::TyS; use rustc_span::source_map::Span; use std::fmt; -use super::WRONG_PUB_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION; #[rustfmt::skip] @@ -21,9 +20,9 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types). // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]), - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; @@ -85,18 +84,12 @@ impl fmt::Display for Convention { pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, item_name: &str, - is_pub: bool, self_ty: &'tcx TyS<'tcx>, first_arg_ty: &'tcx TyS<'tcx>, first_arg_span: Span, implements_trait: bool, is_trait_item: bool, ) { - let lint = if is_pub { - WRONG_PUB_SELF_CONVENTION - } else { - WRONG_SELF_CONVENTION - }; if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { convs .iter() @@ -142,7 +135,7 @@ pub(super) fn check<'tcx>( span_lint_and_help( cx, - lint, + WRONG_SELF_CONVENTION, first_arg_span, &format!( "{} usually take {}", diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 2a948d60b10..cba7666c2d8 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -20,7 +20,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } -pub struct A; +struct A; impl A { pub fn as_ref(self) -> &'static str { diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index 669bf01a84c..f5908cb5701 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -15,12 +15,4 @@ mod foo { pub struct Foobar; } -#[cfg(test)] -mod test { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} - fn main() {} diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index cdfbdb8b0db..151dd0c27d5 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,6 +1,5 @@ // edition:2018 #![warn(clippy::wrong_self_convention)] -#![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] fn main() {} diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 29f5ba82695..ce23317abf6 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:18:17 + --> $DIR/wrong_self_convention.rs:17:17 | LL | fn from_i32(self) {} | ^^^^ @@ -8,7 +8,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:24:21 + --> $DIR/wrong_self_convention.rs:23:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -16,7 +16,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:36:15 + --> $DIR/wrong_self_convention.rs:35:15 | LL | fn as_i32(self) {} | ^^^^ @@ -24,7 +24,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:38:17 + --> $DIR/wrong_self_convention.rs:37:17 | LL | fn into_i32(&self) {} | ^^^^^ @@ -32,7 +32,7 @@ LL | fn into_i32(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:40:15 + --> $DIR/wrong_self_convention.rs:39:15 | LL | fn is_i32(self) {} | ^^^^ @@ -40,7 +40,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:42:15 + --> $DIR/wrong_self_convention.rs:41:15 | LL | fn to_i32(self) {} | ^^^^ @@ -48,7 +48,7 @@ LL | fn to_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:44:17 + --> $DIR/wrong_self_convention.rs:43:17 | LL | fn from_i32(self) {} | ^^^^ @@ -56,7 +56,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:46:19 + --> $DIR/wrong_self_convention.rs:45:19 | LL | pub fn as_i64(self) {} | ^^^^ @@ -64,7 +64,7 @@ LL | pub fn as_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:47:21 + --> $DIR/wrong_self_convention.rs:46:21 | LL | pub fn into_i64(&self) {} | ^^^^^ @@ -72,7 +72,7 @@ LL | pub fn into_i64(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:48:19 + --> $DIR/wrong_self_convention.rs:47:19 | LL | pub fn is_i64(self) {} | ^^^^ @@ -80,7 +80,7 @@ LL | pub fn is_i64(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:49:19 + --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn to_i64(self) {} | ^^^^ @@ -88,7 +88,7 @@ LL | pub fn to_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:50:21 + --> $DIR/wrong_self_convention.rs:49:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -96,7 +96,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:95:19 + --> $DIR/wrong_self_convention.rs:94:19 | LL | fn as_i32(self) {} | ^^^^ @@ -104,7 +104,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:98:25 + --> $DIR/wrong_self_convention.rs:97:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ @@ -112,7 +112,7 @@ LL | fn into_i32_ref(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:100:19 + --> $DIR/wrong_self_convention.rs:99:19 | LL | fn is_i32(self) {} | ^^^^ @@ -120,7 +120,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:104:21 + --> $DIR/wrong_self_convention.rs:103:21 | LL | fn from_i32(self) {} | ^^^^ @@ -128,7 +128,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:119:19 + --> $DIR/wrong_self_convention.rs:118:19 | LL | fn as_i32(self); | ^^^^ @@ -136,7 +136,7 @@ LL | fn as_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:122:25 + --> $DIR/wrong_self_convention.rs:121:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -144,7 +144,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:124:19 + --> $DIR/wrong_self_convention.rs:123:19 | LL | fn is_i32(self); | ^^^^ @@ -152,7 +152,7 @@ LL | fn is_i32(self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:128:21 + --> $DIR/wrong_self_convention.rs:127:21 | LL | fn from_i32(self); | ^^^^ @@ -160,7 +160,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:146:25 + --> $DIR/wrong_self_convention.rs:145:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -168,7 +168,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:152:21 + --> $DIR/wrong_self_convention.rs:151:21 | LL | fn from_i32(self); | ^^^^ @@ -176,7 +176,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value - --> $DIR/wrong_self_convention.rs:176:22 + --> $DIR/wrong_self_convention.rs:175:22 | LL | fn to_u64_v2(&self) -> u64 { | ^^^^^ @@ -184,7 +184,7 @@ LL | fn to_u64_v2(&self) -> u64 { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:185:19 + --> $DIR/wrong_self_convention.rs:184:19 | LL | fn to_u64(self) -> u64 { | ^^^^ diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index 3a72174d03d..501bc1e6a85 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -1,6 +1,5 @@ // edition:2018 #![warn(clippy::wrong_self_convention)] -#![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] fn main() {} diff --git a/tests/ui/wrong_self_convention2.stderr b/tests/ui/wrong_self_convention2.stderr index d2d74ce099e..0e0d066d656 100644 --- a/tests/ui/wrong_self_convention2.stderr +++ b/tests/ui/wrong_self_convention2.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention2.rs:56:29 + --> $DIR/wrong_self_convention2.rs:55:29 | LL | pub fn from_be_self(self) -> Self { | ^^^^ @@ -8,7 +8,7 @@ LL | pub fn from_be_self(self) -> Self { = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention2.rs:65:25 + --> $DIR/wrong_self_convention2.rs:64:25 | LL | fn from_be_self(self) -> Self; | ^^^^ -- cgit 1.4.1-3-g733a5 From d39a11cbe151d9578432e0c7c64364b7eaffe89c Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 27 May 2021 08:49:37 -0500 Subject: Remove clippy_utils::consts re-export --- clippy_lints/src/absurd_extreme_comparisons.rs | 3 +-- clippy_lints/src/arithmetic.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 2 +- clippy_lints/src/consts.rs | 1 - clippy_lints/src/duration_subsec.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/erasing_op.rs | 3 +-- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/invalid_upcast_comparisons.rs | 3 +-- clippy_lints/src/lib.rs | 1 - clippy_lints/src/loops/while_immutable_condition.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/manual_unwrap_or.rs | 2 +- clippy_lints/src/matches.rs | 2 +- clippy_lints/src/methods/iter_nth_zero.rs | 2 +- clippy_lints/src/methods/iterator_step_by_zero.rs | 2 +- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/neg_multiply.rs | 3 +-- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/repeat_once.rs | 2 +- clippy_lints/src/transmuting_null.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/vec.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 2 +- 31 files changed, 29 insertions(+), 35 deletions(-) delete mode 100644 clippy_lints/src/consts.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/absurd_extreme_comparisons.rs b/clippy_lints/src/absurd_extreme_comparisons.rs index 5fbf4bdbd18..49d4350123f 100644 --- a/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/absurd_extreme_comparisons.rs @@ -3,9 +3,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::consts::{constant, Constant}; - use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use clippy_utils::ty::is_isize_or_usize; diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index c560f545d6a..24c2a972811 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::constant_simple; +use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 6c9ceaa45c2..5235b2642d1 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call}; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 0ac6dc28e73..991ed94572c 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 040e0ca8864..c9c111a2847 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{method_chain_args, sext}; use if_chain::if_chain; diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs deleted file mode 100644 index 7e87f53e3fb..00000000000 --- a/clippy_lints/src/consts.rs +++ /dev/null @@ -1 +0,0 @@ -pub use clippy_utils::consts::*; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 529807770f3..94b09bf7173 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 7a98ae39d3a..021136ac5e0 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,7 +1,7 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use crate::consts::{miri_to_const, Constant}; +use clippy_utils::consts::{miri_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index f95ca86a2d0..4aa9c25b1b0 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,11 +1,10 @@ +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::consts::{constant_simple, Constant}; - declare_clippy_lint! { /// **What it does:** Checks for erasing operations, e.g., `x * 0`. /// diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 08f28cd54c5..e38384b01d4 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::{ +use clippy_utils::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 366b3b46a8a..99c461930e4 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{clip, unsext}; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 1c54599abc4..bfa284f333a 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -1,6 +1,6 @@ //! lint on indexing and slicing operations -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::higher; use rustc_ast::ast::RangeLimits; diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index aafdebef248..37011f5578d 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -7,9 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use rustc_target::abi::LayoutOf; -use crate::consts::{constant, Constant}; - use clippy_utils::comparisons::Rel; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; use clippy_utils::{comparisons, sext}; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fb91fac659e..4c9c44f55d1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -148,7 +148,6 @@ macro_rules! declare_clippy_lint { }; } -mod consts; #[cfg(feature = "metadata-collector-lint")] mod deprecated_lints; mod utils; diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index 55404b87ec9..5f9ebad25e8 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -1,5 +1,5 @@ use super::WHILE_IMMUTABLE_CONDITION; -use crate::consts::constant; +use clippy_utils::consts::constant; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; use if_chain::if_chain; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 6a06090f6e2..61b5fe81fa9 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 2f579edd6ad..18038dd7819 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -1,4 +1,4 @@ -use crate::consts::constant_simple; +use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index e07d8ea56e4..cd3e3b97928 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, miri_to_const, Constant}; +use clippy_utils::consts::{constant, miri_to_const, Constant}; use clippy_utils::diagnostics::{ multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index 52d7c15332e..68d906c3ea3 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 06b12998b1a..64c09214a76 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_trait_method; use rustc_hir as hir; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 45948f4d926..ff3473b744e 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{match_def_path, match_trait_method, paths}; use if_chain::if_chain; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 5976b060ad2..804c04fe1b8 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -17,7 +17,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; use rustc_span::symbol::sym; -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 64e9dc85466..1414fdc1b11 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sext; use if_chain::if_chain; diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 34fd012572f..d5e1ea6d242 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,3 +1,4 @@ +use clippy_utils::consts::{self, Constant}; use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -5,8 +6,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::consts::{self, Constant}; - declare_clippy_lint! { /// **What it does:** Checks for multiplication by -1 as a form of negation. /// diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 7169f96eaf1..ae5f0627fd6 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 4b5306de58e..75151167454 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 560a5e7c920..b479c40bca6 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_macro; use clippy_utils::source::snippet; diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 888ecab1046..b57d158293d 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{is_expr_path_def_path, paths}; use if_chain::if_chain; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 2c73c3d929b..b1523e032af 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index febd4b6ff7b..1d5b7c98d31 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,5 +1,5 @@ -use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 350b1cf25ff..a1ea743ba80 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; -- cgit 1.4.1-3-g733a5 From 898b6a0e072c4f8ba741e83bd7fd12a4c2ccb1a2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 30 May 2021 09:35:06 -0400 Subject: Add lint `suspicious_splitn` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/mod.rs | 36 +++++++++++++++- clippy_lints/src/methods/suspicious_splitn.rs | 52 +++++++++++++++++++++++ tests/ui/single_char_pattern.fixed | 4 +- tests/ui/single_char_pattern.rs | 4 +- tests/ui/single_char_pattern.stderr | 4 +- tests/ui/suspicious_splitn.rs | 16 ++++++++ tests/ui/suspicious_splitn.stderr | 59 +++++++++++++++++++++++++++ 9 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 clippy_lints/src/methods/suspicious_splitn.rs create mode 100644 tests/ui/suspicious_splitn.rs create mode 100644 tests/ui/suspicious_splitn.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index abfe7f91f4b..59daa074282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2671,6 +2671,7 @@ Released 2018-09-13 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings +[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4c9c44f55d1..0e815be9bd5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -779,6 +779,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::SKIP_WHILE_NEXT, methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, + methods::SUSPICIOUS_SPLITN, methods::UNINIT_ASSUMED_INIT, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FOLD, @@ -1312,6 +1313,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::STRING_EXTEND_CHARS), LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FOLD), @@ -1688,6 +1690,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0b998dbf86c..3904572c627 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -48,6 +48,7 @@ mod single_char_push_string; mod skip_while_next; mod string_extend_chars; mod suspicious_map; +mod suspicious_splitn; mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_fold; @@ -1633,6 +1634,35 @@ declare_clippy_lint! { "replace `.iter().count()` with `.len()`" } +declare_clippy_lint! { + /// **What it does:** Checks for calls to `splitn` and related functions with + /// either zero or one splits. + /// + /// **Why is this bad?** These calls don't actually split the value and are + /// likely to be intended as a different number. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let s = ""; + /// for x in s.splitn(1, ":") { + /// // use x + /// } + /// + /// // Good + /// let s = ""; + /// for x in s.splitn(2, ":") { + /// // use x + /// } + /// ``` + pub SUSPICIOUS_SPLITN, + correctness, + "checks for `.splitn(0, ..)` and `.splitn(1, ..)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -1705,7 +1735,8 @@ impl_lint_pass!(Methods => [ MAP_COLLECT_RESULT_UNIT, FROM_ITER_INSTEAD_OF_COLLECT, INSPECT_FOR_EACH, - IMPLICIT_CLONE + IMPLICIT_CLONE, + SUSPICIOUS_SPLITN ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2024,6 +2055,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => { + suspicious_splitn::check(cx, name, expr, recv, count_arg); + }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv, span); diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs new file mode 100644 index 00000000000..43affe20dc5 --- /dev/null +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_note; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::SUSPICIOUS_SPLITN; + +pub(super) fn check( + cx: &LateContext<'_>, + method_name: &str, + expr: &Expr<'_>, + self_arg: &Expr<'_>, + count_arg: &Expr<'_>, +) { + if_chain! { + // Ignore empty slice literal + if !matches!(self_arg.kind, ExprKind::Array([])); + // Ignore empty string literal + if !matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()); + if let ExprKind::Lit(count_lit) = &count_arg.kind; + if let LitKind::Int(count, _) = count_lit.node; + if count <= 1; + if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(call_id); + let lang_items = cx.tcx.lang_items(); + if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id); + then { + let (msg, note_msg) = if count == 0 { + (format!("`{}` called with `0` splits", method_name), + "the resulting iterator will always return `None`") + } else { + (format!("`{}` called with `1` split", method_name), + if lang_items.slice_impl() == Some(impl_id) { + "the resulting iterator will always return the entire slice followed by `None`" + } else { + "the resulting iterator will always return the entire string followed by `None`" + }) + }; + + span_lint_and_note( + cx, + SUSPICIOUS_SPLITN, + expr.span, + &msg, + None, + note_msg, + ); + } + } +} diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index fcbe9af9f56..1abd2b7883d 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -25,8 +25,8 @@ fn main() { x.rsplit('x'); x.split_terminator('x'); x.rsplit_terminator('x'); - x.splitn(0, 'x'); - x.rsplitn(0, 'x'); + x.splitn(2, 'x'); + x.rsplitn(2, 'x'); x.matches('x'); x.rmatches('x'); x.match_indices('x'); diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index b8bc20f4070..e662bf34be2 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -25,8 +25,8 @@ fn main() { x.rsplit("x"); x.split_terminator("x"); x.rsplit_terminator("x"); - x.splitn(0, "x"); - x.rsplitn(0, "x"); + x.splitn(2, "x"); + x.rsplitn(2, "x"); x.matches("x"); x.rmatches("x"); x.match_indices("x"); diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 6d94d8a34e3..22d4b2d460f 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -75,13 +75,13 @@ LL | x.rsplit_terminator("x"); error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:28:17 | -LL | x.splitn(0, "x"); +LL | x.splitn(2, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:29:18 | -LL | x.rsplitn(0, "x"); +LL | x.rsplitn(2, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern diff --git a/tests/ui/suspicious_splitn.rs b/tests/ui/suspicious_splitn.rs new file mode 100644 index 00000000000..a944aa79cfe --- /dev/null +++ b/tests/ui/suspicious_splitn.rs @@ -0,0 +1,16 @@ +#![warn(clippy::suspicious_splitn)] + +fn main() { + let _ = "a,b,c".splitn(3, ','); + let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1); + let _ = "".splitn(0, ','); + let _ = [].splitn(0, |&x: &u32| x == 1); + + let _ = "a,b".splitn(0, ','); + let _ = "a,b".rsplitn(0, ','); + let _ = "a,b".splitn(1, ','); + let _ = [0, 1, 2].splitn(0, |&x| x == 1); + let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); + let _ = [0, 1, 2].splitn(1, |&x| x == 1); + let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); +} diff --git a/tests/ui/suspicious_splitn.stderr b/tests/ui/suspicious_splitn.stderr new file mode 100644 index 00000000000..2e4bfe93b94 --- /dev/null +++ b/tests/ui/suspicious_splitn.stderr @@ -0,0 +1,59 @@ +error: `splitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:9:13 + | +LL | let _ = "a,b".splitn(0, ','); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::suspicious-splitn` implied by `-D warnings` + = note: the resulting iterator will always return `None` + +error: `rsplitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:10:13 + | +LL | let _ = "a,b".rsplitn(0, ','); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: `splitn` called with `1` split + --> $DIR/suspicious_splitn.rs:11:13 + | +LL | let _ = "a,b".splitn(1, ','); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire string followed by `None` + +error: `splitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:12:13 + | +LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: `splitn_mut` called with `0` splits + --> $DIR/suspicious_splitn.rs:13:13 + | +LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: `splitn` called with `1` split + --> $DIR/suspicious_splitn.rs:14:13 + | +LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire slice followed by `None` + +error: `rsplitn_mut` called with `1` split + --> $DIR/suspicious_splitn.rs:15:13 + | +LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire slice followed by `None` + +error: aborting due to 7 previous errors + -- cgit 1.4.1-3-g733a5 From 5fa08eaf53f0c895e73f4841c240389fda951554 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 30 May 2021 13:25:24 -0400 Subject: Evaluate constant expressions in `suspicious_splitn` --- clippy_lints/src/methods/mod.rs | 5 +++-- clippy_lints/src/methods/suspicious_splitn.rs | 16 ++++++++++------ tests/ui/suspicious_splitn.rs | 4 ++++ tests/ui/suspicious_splitn.stderr | 18 +++++++++++++++++- 4 files changed, 34 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3904572c627..a6e2e0baadb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1635,8 +1635,9 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `splitn` and related functions with - /// either zero or one splits. + /// **What it does:** Checks for calls to [`splitn`] + /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and + /// related functions with either zero or one splits. /// /// **Why is this bad?** These calls don't actually split the value and are /// likely to be intended as a different number. diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 43affe20dc5..a271df60572 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -1,3 +1,4 @@ +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_note; use if_chain::if_chain; use rustc_ast::LitKind; @@ -15,18 +16,21 @@ pub(super) fn check( count_arg: &Expr<'_>, ) { if_chain! { - // Ignore empty slice literal - if !matches!(self_arg.kind, ExprKind::Array([])); - // Ignore empty string literal - if !matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()); - if let ExprKind::Lit(count_lit) = &count_arg.kind; - if let LitKind::Int(count, _) = count_lit.node; + if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg); if count <= 1; if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(call_id); let lang_items = cx.tcx.lang_items(); if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id); then { + // Ignore empty slice and string literals when used with a literal count. + if (matches!(self_arg.kind, ExprKind::Array([])) + || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) + ) && matches!(count_arg.kind, ExprKind::Lit(_)) + { + return; + } + let (msg, note_msg) = if count == 0 { (format!("`{}` called with `0` splits", method_name), "the resulting iterator will always return `None`") diff --git a/tests/ui/suspicious_splitn.rs b/tests/ui/suspicious_splitn.rs index a944aa79cfe..a21d94cf20b 100644 --- a/tests/ui/suspicious_splitn.rs +++ b/tests/ui/suspicious_splitn.rs @@ -13,4 +13,8 @@ fn main() { let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); let _ = [0, 1, 2].splitn(1, |&x| x == 1); let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); + + const X: usize = 0; + let _ = "a,b".splitn(X + 1, ','); + let _ = "a,b".splitn(X, ','); } diff --git a/tests/ui/suspicious_splitn.stderr b/tests/ui/suspicious_splitn.stderr index 2e4bfe93b94..b6220ae2393 100644 --- a/tests/ui/suspicious_splitn.stderr +++ b/tests/ui/suspicious_splitn.stderr @@ -55,5 +55,21 @@ LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); | = note: the resulting iterator will always return the entire slice followed by `None` -error: aborting due to 7 previous errors +error: `splitn` called with `1` split + --> $DIR/suspicious_splitn.rs:18:13 + | +LL | let _ = "a,b".splitn(X + 1, ','); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire string followed by `None` + +error: `splitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:19:13 + | +LL | let _ = "a,b".splitn(X, ','); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From 97311f0906ca89656f5942b326a665fe98d84c17 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 22 May 2021 17:08:17 -0400 Subject: Add lint `manual_str_repeat` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/mem_discriminant.rs | 3 +- clippy_lints/src/methods/clone_on_copy.rs | 5 +- clippy_lints/src/methods/manual_str_repeat.rs | 89 +++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 35 ++++++++++- clippy_utils/src/msrvs.rs | 1 + tests/ui/manual_str_repeat.fixed | 31 ++++++++++ tests/ui/manual_str_repeat.rs | 31 ++++++++++ tests/ui/manual_str_repeat.stderr | 46 ++++++++++++++ 10 files changed, 238 insertions(+), 7 deletions(-) create mode 100644 clippy_lints/src/methods/manual_str_repeat.rs create mode 100644 tests/ui/manual_str_repeat.fixed create mode 100644 tests/ui/manual_str_repeat.rs create mode 100644 tests/ui/manual_str_repeat.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 59daa074282..41af8e190dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2493,6 +2493,7 @@ Released 2018-09-13 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic +[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0e815be9bd5..e7dd3952b3a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -762,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, methods::MANUAL_SATURATING_ARITHMETIC, + methods::MANUAL_STR_REPEAT, methods::MAP_COLLECT_RESULT_UNIT, methods::MAP_FLATTEN, methods::MAP_UNWRAP_OR, @@ -1298,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OK_EXPECT), @@ -1735,6 +1737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(loops::NEEDLESS_COLLECT), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::ITER_NTH), + LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::SINGLE_CHAR_PATTERN), LintId::of(misc::CMP_OWNED), diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index a735c616f6e..aca96e06ef2 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use std::iter; declare_clippy_lint! { /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type. @@ -67,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { } } - let derefs: String = iter::repeat('*').take(derefs_needed).collect(); + let derefs = "*".repeat(derefs_needed); diag.span_suggestion( param.span, "try dereferencing", diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index ce2e8fa8b10..1a32af5dc7a 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -8,7 +8,6 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; -use std::iter; use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; @@ -54,8 +53,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, ty = inner; n += 1; } - let refs: String = iter::repeat('&').take(n + 1).collect(); - let derefs: String = iter::repeat('*').take(n).collect(); + let refs = "&".repeat(n + 1); + let derefs = "*".repeat(n); let explicit = format!("<{}{}>::clone({})", refs, ty, snip); diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs new file mode 100644 index 00000000000..3f28412fbf7 --- /dev/null +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -0,0 +1,89 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; +use clippy_utils::{is_expr_path_def_path, paths}; +use if_chain::if_chain; +use rustc_ast::util::parser::PREC_POSTFIX; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem}; +use rustc_lint::LateContext; +use rustc_span::symbol::{sym, Symbol}; + +use super::MANUAL_STR_REPEAT; + +enum RepeatKind { + Str, + String, + Char, +} + +fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { + if let ExprKind::Lit(lit) = &e.kind { + match lit.node { + LitKind::Str(..) => Some(RepeatKind::Str), + LitKind::Char(_) => Some(RepeatKind::Char), + _ => None, + } + } else { + let ty = cx.typeck_results().expr_ty(e); + if is_type_diagnostic_item(cx, ty, sym::string_type) + || is_type_lang_item(cx, ty, LangItem::OwnedBox) + || match_type(cx, ty, &paths::COW) + { + Some(RepeatKind::String) + } else { + let ty = ty.peel_refs(); + (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::Str) + } + } +} + +pub(super) fn check( + cx: &LateContext<'_>, + collect_expr: &Expr<'_>, + take_expr: &Expr<'_>, + take_self_arg: &Expr<'_>, + take_arg: &Expr<'_>, +) { + if_chain! { + if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; + if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type); + if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id); + if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); + if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id); + if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id); + if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg); + let ctxt = collect_expr.span.ctxt(); + if ctxt == take_expr.span.ctxt(); + if ctxt == take_self_arg.span.ctxt(); + then { + let mut app = Applicability::MachineApplicable; + let (val_snip, val_is_mac) = snippet_with_context(cx, repeat_arg.span, ctxt, "..", &mut app); + let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0; + + let val_str = match repeat_kind { + RepeatKind::String => format!("(&{})", val_snip), + RepeatKind::Str if !val_is_mac && repeat_arg.precedence().order() < PREC_POSTFIX => { + format!("({})", val_snip) + }, + RepeatKind::Str => val_snip.into(), + RepeatKind::Char if val_snip == r#"'"'"# => r#""\"""#.into(), + RepeatKind::Char if val_snip == r#"'\''"# => r#""'""#.into(), + RepeatKind::Char => format!("\"{}\"", &val_snip[1..val_snip.len() - 1]), + }; + + span_lint_and_sugg( + cx, + MANUAL_STR_REPEAT, + collect_expr.span, + "manual implementation of `str::repeat` using iterators", + "try this", + format!("{}.repeat({})", val_str, count_snip), + app + ) + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a6e2e0baadb..62a56434b3c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -32,6 +32,7 @@ mod iter_nth_zero; mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; +mod manual_str_repeat; mod map_collect_result_unit; mod map_flatten; mod map_unwrap_or; @@ -60,9 +61,12 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty}; +use clippy_utils::{ + diagnostics::{span_lint, span_lint_and_help}, + meets_msrv, msrvs, +}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -1664,6 +1668,27 @@ declare_clippy_lint! { "checks for `.splitn(0, ..)` and `.splitn(1, ..)`" } +declare_clippy_lint! { + /// **What it does:** Checks for manual implementations of `str::repeat` + /// + /// **Why is this bad?** These are both harder to read, as well as less performant. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let x: String = std::iter::repeat('x').take(10).collect(); + /// + /// // Good + /// let x: String = "x".repeat(10); + /// ``` + pub MANUAL_STR_REPEAT, + perf, + "manual implementation of `str::repeat`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -1737,7 +1762,8 @@ impl_lint_pass!(Methods => [ FROM_ITER_INSTEAD_OF_COLLECT, INSPECT_FOR_EACH, IMPLICIT_CLONE, - SUSPICIOUS_SPLITN + SUSPICIOUS_SPLITN, + MANUAL_STR_REPEAT ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -1981,6 +2007,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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(msrv, &msrvs::STR_REPEAT) { + manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); + } + }, _ => {}, }, ("count", []) => match method_call!(recv) { diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 00df04c0144..4a9c4fd0276 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -26,4 +26,5 @@ msrv_aliases! { 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST } + 1,16,0 { STR_REPEAT } } diff --git a/tests/ui/manual_str_repeat.fixed b/tests/ui/manual_str_repeat.fixed new file mode 100644 index 00000000000..62225e7a7f8 --- /dev/null +++ b/tests/ui/manual_str_repeat.fixed @@ -0,0 +1,31 @@ +// run-rustfix + +#![warn(clippy::manual_str_repeat)] + +use std::iter::repeat; + +fn main() { + let _: String = "test".repeat(10); + let _: String = "x".repeat(10); + let _: String = "'".repeat(10); + let _: String = "\"".repeat(10); + + let x = "test"; + let count = 10; + let _ = x.repeat(count + 2); + + macro_rules! m { + ($e:expr) => {{ $e }}; + } + + let _: String = m!("test").repeat(m!(count)); + + let x = &x; + let _: String = (*x).repeat(count); + + macro_rules! repeat_m { + ($e:expr) => {{ repeat($e) }}; + } + // Don't lint, repeat is from a macro. + let _: String = repeat_m!("test").take(count).collect(); +} diff --git a/tests/ui/manual_str_repeat.rs b/tests/ui/manual_str_repeat.rs new file mode 100644 index 00000000000..1acd66da275 --- /dev/null +++ b/tests/ui/manual_str_repeat.rs @@ -0,0 +1,31 @@ +// run-rustfix + +#![warn(clippy::manual_str_repeat)] + +use std::iter::repeat; + +fn main() { + let _: String = std::iter::repeat("test").take(10).collect(); + let _: String = std::iter::repeat('x').take(10).collect(); + let _: String = std::iter::repeat('\'').take(10).collect(); + let _: String = std::iter::repeat('"').take(10).collect(); + + let x = "test"; + let count = 10; + let _ = repeat(x).take(count + 2).collect::(); + + macro_rules! m { + ($e:expr) => {{ $e }}; + } + + let _: String = repeat(m!("test")).take(m!(count)).collect(); + + let x = &x; + let _: String = repeat(*x).take(count).collect(); + + macro_rules! repeat_m { + ($e:expr) => {{ repeat($e) }}; + } + // Don't lint, repeat is from a macro. + let _: String = repeat_m!("test").take(count).collect(); +} diff --git a/tests/ui/manual_str_repeat.stderr b/tests/ui/manual_str_repeat.stderr new file mode 100644 index 00000000000..ef67ad2a1fd --- /dev/null +++ b/tests/ui/manual_str_repeat.stderr @@ -0,0 +1,46 @@ +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:8:21 + | +LL | let _: String = std::iter::repeat("test").take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` + | + = note: `-D clippy::manual-str-repeat` implied by `-D warnings` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:9:21 + | +LL | let _: String = std::iter::repeat('x').take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:10:21 + | +LL | let _: String = std::iter::repeat('/'').take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:11:21 + | +LL | let _: String = std::iter::repeat('"').take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:15:13 + | +LL | let _ = repeat(x).take(count + 2).collect::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:21:21 + | +LL | let _: String = repeat(m!("test")).take(m!(count)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `m!("test").repeat(m!(count))` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:24:21 + | +LL | let _: String = repeat(*x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)` + +error: aborting due to 7 previous errors + -- cgit 1.4.1-3-g733a5 From cfddf0927bd71b859bc1e749ec159285433a3849 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 23 May 2021 13:16:09 -0400 Subject: Fix type checks for `manual_str_repeat` --- clippy_lints/src/methods/manual_str_repeat.rs | 48 ++++++++++++++++----------- clippy_lints/src/methods/mod.rs | 7 ++-- clippy_lints/src/utils/conf.rs | 2 +- clippy_utils/src/sugg.rs | 27 +++++++++++++-- tests/ui/manual_str_repeat.fixed | 41 +++++++++++++++++++++-- tests/ui/manual_str_repeat.rs | 39 ++++++++++++++++++++-- tests/ui/manual_str_repeat.stderr | 42 ++++++++++++++++------- 7 files changed, 162 insertions(+), 44 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 3f28412fbf7..919e2628c52 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -1,40 +1,49 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; use clippy_utils::{is_expr_path_def_path, paths}; use if_chain::if_chain; -use rustc_ast::util::parser::PREC_POSTFIX; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::symbol::{sym, Symbol}; +use rustc_middle::ty::{self, Ty, TyS}; +use rustc_span::symbol::sym; +use std::borrow::Cow; use super::MANUAL_STR_REPEAT; enum RepeatKind { - Str, String, - Char, + Char(char), +} + +fn get_ty_param(ty: Ty<'_>) -> Option> { + if let ty::Adt(_, subs) = ty.kind() { + subs.types().next() + } else { + None + } } fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { if let ExprKind::Lit(lit) = &e.kind { match lit.node { - LitKind::Str(..) => Some(RepeatKind::Str), - LitKind::Char(_) => Some(RepeatKind::Char), + LitKind::Str(..) => Some(RepeatKind::String), + LitKind::Char(c) => Some(RepeatKind::Char(c)), _ => None, } } else { let ty = cx.typeck_results().expr_ty(e); if is_type_diagnostic_item(cx, ty, sym::string_type) - || is_type_lang_item(cx, ty, LangItem::OwnedBox) - || match_type(cx, ty, &paths::COW) + || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str)) + || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str)) { Some(RepeatKind::String) } else { let ty = ty.peel_refs(); - (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::Str) + (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String) } } } @@ -61,18 +70,19 @@ pub(super) fn check( if ctxt == take_self_arg.span.ctxt(); then { let mut app = Applicability::MachineApplicable; - let (val_snip, val_is_mac) = snippet_with_context(cx, repeat_arg.span, ctxt, "..", &mut app); let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0; let val_str = match repeat_kind { - RepeatKind::String => format!("(&{})", val_snip), - RepeatKind::Str if !val_is_mac && repeat_arg.precedence().order() < PREC_POSTFIX => { - format!("({})", val_snip) - }, - RepeatKind::Str => val_snip.into(), - RepeatKind::Char if val_snip == r#"'"'"# => r#""\"""#.into(), - RepeatKind::Char if val_snip == r#"'\''"# => r#""'""#.into(), - RepeatKind::Char => format!("\"{}\"", &val_snip[1..val_snip.len() - 1]), + RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return, + RepeatKind::Char('\'') => r#""'""#.into(), + RepeatKind::Char('"') => r#""\"""#.into(), + RepeatKind::Char(_) => + match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) { + Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])), + s @ Cow::Borrowed(_) => s, + }, + RepeatKind::String => + Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(), }; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 62a56434b3c..c8ae972f18c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -61,12 +61,9 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty}; -use clippy_utils::{ - diagnostics::{span_lint, span_lint_and_help}, - meets_msrv, msrvs, -}; +use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1bd38dc042c..0e33ae740d9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -124,7 +124,7 @@ macro_rules! define_Conf { define_Conf! { /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports + /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports (msrv: Option = None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names: Vec = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index e5a70f0beac..efc0ec50fdc 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -2,7 +2,7 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::higher; -use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite}; +use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ast, token}; use rustc_ast_pretty::pprust::token_kind_to_string; @@ -10,7 +10,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_span::source_map::{CharPos, Span}; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, SyntaxContext}; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; @@ -90,6 +90,29 @@ impl<'a> Sugg<'a> { Self::hir_from_snippet(expr, snippet) } + /// Same as `hir`, but first walks the span up to the given context. This will result in the + /// macro call, rather then the expansion, if the span is from a child context. If the span is + /// not from a child context, it will be used directly instead. + /// + /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR + /// node would result in `box []`. If given the context of the address of expression, this + /// function will correctly get a snippet of `vec![]`. + pub fn hir_with_context( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + ctxt: SyntaxContext, + default: &'a str, + applicability: &mut Applicability, + ) -> Self { + let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability); + + if in_macro { + Sugg::NonParen(snippet) + } else { + Self::hir_from_snippet(expr, snippet) + } + } + /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*` /// function variants of `Sugg`, since these use different snippet functions. fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self { diff --git a/tests/ui/manual_str_repeat.fixed b/tests/ui/manual_str_repeat.fixed index 62225e7a7f8..dc140257f32 100644 --- a/tests/ui/manual_str_repeat.fixed +++ b/tests/ui/manual_str_repeat.fixed @@ -1,8 +1,10 @@ // run-rustfix +#![feature(custom_inner_attributes)] #![warn(clippy::manual_str_repeat)] -use std::iter::repeat; +use std::borrow::Cow; +use std::iter::{repeat, FromIterator}; fn main() { let _: String = "test".repeat(10); @@ -17,8 +19,8 @@ fn main() { macro_rules! m { ($e:expr) => {{ $e }}; } - - let _: String = m!("test").repeat(m!(count)); + // FIXME: macro args are fine + let _: String = repeat(m!("test")).take(m!(count)).collect(); let x = &x; let _: String = (*x).repeat(count); @@ -28,4 +30,37 @@ fn main() { } // Don't lint, repeat is from a macro. let _: String = repeat_m!("test").take(count).collect(); + + let x: Box = Box::from("test"); + let _: String = x.repeat(count); + + #[derive(Clone)] + struct S; + impl FromIterator> for String { + fn from_iter>>(_: T) -> Self { + Self::new() + } + } + // Don't lint, wrong box type + let _: String = repeat(Box::new(S)).take(count).collect(); + + let _: String = Cow::Borrowed("test").repeat(count); + + let x = "x".to_owned(); + let _: String = x.repeat(count); + + let x = 'x'; + // Don't lint, not char literal + let _: String = repeat(x).take(count).collect(); +} + +fn _msrv_1_15() { + #![clippy::msrv = "1.15"] + // `str::repeat` was stabilized in 1.16. Do not lint this + let _: String = std::iter::repeat("test").take(10).collect(); +} + +fn _msrv_1_16() { + #![clippy::msrv = "1.16"] + let _: String = "test".repeat(10); } diff --git a/tests/ui/manual_str_repeat.rs b/tests/ui/manual_str_repeat.rs index 1acd66da275..0d69c989b2e 100644 --- a/tests/ui/manual_str_repeat.rs +++ b/tests/ui/manual_str_repeat.rs @@ -1,8 +1,10 @@ // run-rustfix +#![feature(custom_inner_attributes)] #![warn(clippy::manual_str_repeat)] -use std::iter::repeat; +use std::borrow::Cow; +use std::iter::{repeat, FromIterator}; fn main() { let _: String = std::iter::repeat("test").take(10).collect(); @@ -17,7 +19,7 @@ fn main() { macro_rules! m { ($e:expr) => {{ $e }}; } - + // FIXME: macro args are fine let _: String = repeat(m!("test")).take(m!(count)).collect(); let x = &x; @@ -28,4 +30,37 @@ fn main() { } // Don't lint, repeat is from a macro. let _: String = repeat_m!("test").take(count).collect(); + + let x: Box = Box::from("test"); + let _: String = repeat(x).take(count).collect(); + + #[derive(Clone)] + struct S; + impl FromIterator> for String { + fn from_iter>>(_: T) -> Self { + Self::new() + } + } + // Don't lint, wrong box type + let _: String = repeat(Box::new(S)).take(count).collect(); + + let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); + + let x = "x".to_owned(); + let _: String = repeat(x).take(count).collect(); + + let x = 'x'; + // Don't lint, not char literal + let _: String = repeat(x).take(count).collect(); +} + +fn _msrv_1_15() { + #![clippy::msrv = "1.15"] + // `str::repeat` was stabilized in 1.16. Do not lint this + let _: String = std::iter::repeat("test").take(10).collect(); +} + +fn _msrv_1_16() { + #![clippy::msrv = "1.16"] + let _: String = std::iter::repeat("test").take(10).collect(); } diff --git a/tests/ui/manual_str_repeat.stderr b/tests/ui/manual_str_repeat.stderr index ef67ad2a1fd..c6511689716 100644 --- a/tests/ui/manual_str_repeat.stderr +++ b/tests/ui/manual_str_repeat.stderr @@ -1,5 +1,5 @@ error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:8:21 + --> $DIR/manual_str_repeat.rs:10:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` @@ -7,40 +7,58 @@ LL | let _: String = std::iter::repeat("test").take(10).collect(); = note: `-D clippy::manual-str-repeat` implied by `-D warnings` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:9:21 + --> $DIR/manual_str_repeat.rs:11:21 | LL | let _: String = std::iter::repeat('x').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:10:21 + --> $DIR/manual_str_repeat.rs:12:21 | LL | let _: String = std::iter::repeat('/'').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:11:21 + --> $DIR/manual_str_repeat.rs:13:21 | LL | let _: String = std::iter::repeat('"').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:15:13 + --> $DIR/manual_str_repeat.rs:17:13 | LL | let _ = repeat(x).take(count + 2).collect::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:21:21 + --> $DIR/manual_str_repeat.rs:26:21 | -LL | let _: String = repeat(m!("test")).take(m!(count)).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `m!("test").repeat(m!(count))` +LL | let _: String = repeat(*x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:24:21 + --> $DIR/manual_str_repeat.rs:35:21 | -LL | let _: String = repeat(*x).take(count).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)` +LL | let _: String = repeat(x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:47:21 + | +LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:50:21 + | +LL | let _: String = repeat(x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:65:21 + | +LL | let _: String = std::iter::repeat("test").take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` -error: aborting due to 7 previous errors +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From bb3b58cfccdfbc4f95a2f03dc800aa87fd3fdd2c Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Jun 2021 23:10:42 +0200 Subject: Reuse `is_expr_identity_function` for `flat_map_identity` --- clippy_lints/src/methods/flat_map_identity.rs | 44 +++++++-------------------- tests/ui/flat_map_identity.fixed | 5 ++- tests/ui/flat_map_identity.rs | 5 ++- tests/ui/flat_map_identity.stderr | 12 ++++++-- 4 files changed, 28 insertions(+), 38 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 25f8434cb94..6f911d79d0b 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_path_def_path, is_trait_method, paths}; -use if_chain::if_chain; +use clippy_utils::{is_expr_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -15,36 +14,15 @@ pub(super) fn check<'tcx>( flat_map_arg: &'tcx hir::Expr<'_>, flat_map_span: Span, ) { - if is_trait_method(cx, expr, sym::Iterator) { - let apply_lint = |message: &str| { - span_lint_and_sugg( - cx, - FLAT_MAP_IDENTITY, - flat_map_span.with_hi(expr.span.hi()), - message, - "try", - "flatten()".to_string(), - Applicability::MachineApplicable, - ); - }; - - if_chain! { - if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind; - let body = cx.tcx.hir().body(body_id); - - if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind; - - if path.segments.len() == 1; - if path.segments[0].ident.name == binding_ident.name; - - then { - apply_lint("called `flat_map(|x| x)` on an `Iterator`"); - } - } - - if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) { - apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); - } + if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) { + span_lint_and_sugg( + cx, + FLAT_MAP_IDENTITY, + flat_map_span.with_hi(expr.span.hi()), + "use of `flat_map` with an identity function", + "try", + "flatten()".to_string(), + Applicability::MachineApplicable, + ); } } diff --git a/tests/ui/flat_map_identity.fixed b/tests/ui/flat_map_identity.fixed index dfe3bd47e13..1f4b880ef5b 100644 --- a/tests/ui/flat_map_identity.fixed +++ b/tests/ui/flat_map_identity.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] use std::convert; @@ -11,4 +11,7 @@ fn main() { let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flatten(); + + let iterator = [[0, 1], [2, 3], [4, 5]].iter(); + let _ = iterator.flatten(); } diff --git a/tests/ui/flat_map_identity.rs b/tests/ui/flat_map_identity.rs index 393b9569255..de14a06d4e6 100644 --- a/tests/ui/flat_map_identity.rs +++ b/tests/ui/flat_map_identity.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] use std::convert; @@ -11,4 +11,7 @@ fn main() { let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flat_map(convert::identity); + + let iterator = [[0, 1], [2, 3], [4, 5]].iter(); + let _ = iterator.flat_map(|x| return x); } diff --git a/tests/ui/flat_map_identity.stderr b/tests/ui/flat_map_identity.stderr index e4686ae5a54..e776c9fdf51 100644 --- a/tests/ui/flat_map_identity.stderr +++ b/tests/ui/flat_map_identity.stderr @@ -1,4 +1,4 @@ -error: called `flat_map(|x| x)` on an `Iterator` +error: use of `flat_map` with an identity function --> $DIR/flat_map_identity.rs:10:22 | LL | let _ = iterator.flat_map(|x| x); @@ -6,11 +6,17 @@ LL | let _ = iterator.flat_map(|x| x); | = note: `-D clippy::flat-map-identity` implied by `-D warnings` -error: called `flat_map(std::convert::identity)` on an `Iterator` +error: use of `flat_map` with an identity function --> $DIR/flat_map_identity.rs:13:22 | LL | let _ = iterator.flat_map(convert::identity); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` -error: aborting due to 2 previous errors +error: use of `flat_map` with an identity function + --> $DIR/flat_map_identity.rs:16:22 + | +LL | let _ = iterator.flat_map(|x| return x); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 9e54ce865c67af65370e1ec3822742a22fd20dfe Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Jun 2021 23:31:17 +0200 Subject: Reuse `is_expr_identity_function` for `filter_map_identity` --- clippy_lints/src/methods/filter_map_identity.rs | 40 +++++++------------------ tests/ui/filter_map_identity.fixed | 5 +++- tests/ui/filter_map_identity.rs | 5 +++- tests/ui/filter_map_identity.stderr | 14 ++++++--- 4 files changed, 29 insertions(+), 35 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 403fe8d3546..d1b5e945dfd 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_path_def_path, is_trait_method, path_to_local_id, paths}; -use if_chain::if_chain; +use clippy_utils::{is_expr_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,32 +8,15 @@ use rustc_span::{source_map::Span, sym}; use super::FILTER_MAP_IDENTITY; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { - if is_trait_method(cx, expr, sym::Iterator) { - let apply_lint = |message: &str| { - span_lint_and_sugg( - cx, - FILTER_MAP_IDENTITY, - filter_map_span.with_hi(expr.span.hi()), - message, - "try", - "flatten()".to_string(), - Applicability::MachineApplicable, - ); - }; - - if_chain! { - if let hir::ExprKind::Closure(_, _, body_id, _, _) = filter_map_arg.kind; - let body = cx.tcx.hir().body(body_id); - - if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind; - if path_to_local_id(&body.value, binding_id); - then { - apply_lint("called `filter_map(|x| x)` on an `Iterator`"); - } - } - - if is_expr_path_def_path(cx, filter_map_arg, &paths::CONVERT_IDENTITY) { - apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); - } + if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) { + span_lint_and_sugg( + cx, + FILTER_MAP_IDENTITY, + filter_map_span.with_hi(expr.span.hi()), + "use of `filter_map` with an identity function", + "try", + "flatten()".to_string(), + Applicability::MachineApplicable, + ); } } diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed index 23ce28d8e9b..a5860aa49b3 100644 --- a/tests/ui/filter_map_identity.fixed +++ b/tests/ui/filter_map_identity.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] fn main() { @@ -13,4 +13,7 @@ fn main() { use std::convert::identity; let iterator = vec![Some(1), None, Some(2)].into_iter(); let _ = iterator.flatten(); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); } diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs index e698df13eea..7e998b9cdf7 100644 --- a/tests/ui/filter_map_identity.rs +++ b/tests/ui/filter_map_identity.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_imports)] +#![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] fn main() { @@ -13,4 +13,7 @@ fn main() { use std::convert::identity; let iterator = vec![Some(1), None, Some(2)].into_iter(); let _ = iterator.filter_map(identity); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(|x| return x); } diff --git a/tests/ui/filter_map_identity.stderr b/tests/ui/filter_map_identity.stderr index 596a6320608..43c9fdca4fb 100644 --- a/tests/ui/filter_map_identity.stderr +++ b/tests/ui/filter_map_identity.stderr @@ -1,4 +1,4 @@ -error: called `filter_map(|x| x)` on an `Iterator` +error: use of `filter_map` with an identity function --> $DIR/filter_map_identity.rs:8:22 | LL | let _ = iterator.filter_map(|x| x); @@ -6,17 +6,23 @@ LL | let _ = iterator.filter_map(|x| x); | = note: `-D clippy::filter-map-identity` implied by `-D warnings` -error: called `filter_map(std::convert::identity)` on an `Iterator` +error: use of `filter_map` with an identity function --> $DIR/filter_map_identity.rs:11:22 | LL | let _ = iterator.filter_map(std::convert::identity); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` -error: called `filter_map(std::convert::identity)` on an `Iterator` +error: use of `filter_map` with an identity function --> $DIR/filter_map_identity.rs:15:22 | LL | let _ = iterator.filter_map(identity); | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` -error: aborting due to 3 previous errors +error: use of `filter_map` with an identity function + --> $DIR/filter_map_identity.rs:18:22 + | +LL | let _ = iterator.filter_map(|x| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 5336f88403aae270e1e8bbf0aee31707311c590f Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 8 Jun 2021 00:14:43 +0200 Subject: Move `map_identity` into the `methods` module --- clippy_lints/src/lib.rs | 8 ++-- clippy_lints/src/map_identity.rs | 76 -------------------------------- clippy_lints/src/methods/map_identity.rs | 38 ++++++++++++++++ clippy_lints/src/methods/mod.rs | 26 +++++++++++ 4 files changed, 67 insertions(+), 81 deletions(-) delete mode 100644 clippy_lints/src/map_identity.rs create mode 100644 clippy_lints/src/methods/map_identity.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e7dd3952b3a..c6d9b378603 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -254,7 +254,6 @@ mod manual_strip; mod manual_unwrap_or; mod map_clone; mod map_err_ignore; -mod map_identity; mod map_unit_fn; mod match_on_vec_items; mod matches; @@ -705,7 +704,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: manual_unwrap_or::MANUAL_UNWRAP_OR, map_clone::MAP_CLONE, map_err_ignore::MAP_ERR_IGNORE, - map_identity::MAP_IDENTITY, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, match_on_vec_items::MATCH_ON_VEC_ITEMS, @@ -765,6 +763,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::MANUAL_STR_REPEAT, methods::MAP_COLLECT_RESULT_UNIT, methods::MAP_FLATTEN, + methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, @@ -1260,7 +1259,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(manual_strip::MANUAL_STRIP), LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), LintId::of(map_clone::MAP_CLONE), - LintId::of(map_identity::MAP_IDENTITY), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), @@ -1301,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MAP_IDENTITY), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_AS_REF_DEREF), @@ -1586,7 +1585,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(loops::WHILE_LET_LOOP), LintId::of(manual_strip::MANUAL_STRIP), LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(map_identity::MAP_IDENTITY), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(matches::MATCH_AS_REF), @@ -1601,6 +1599,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::ITER_COUNT), LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MAP_IDENTITY), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::SEARCH_IS_SOME), @@ -2039,7 +2038,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: single_char_binding_names_threshold, }); store.register_late_pass(|| box macro_use::MacroUseImports::default()); - store.register_late_pass(|| box map_identity::MapIdentity); store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch); store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive); store.register_late_pass(|| box repeat_once::RepeatOnce); diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs deleted file mode 100644 index 9bcb010ff6d..00000000000 --- a/clippy_lints/src/map_identity.rs +++ /dev/null @@ -1,76 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expr_identity_function, is_trait_method}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function. - /// - /// **Why is this bad?** It can be written more concisely without the call to `map`. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// - /// ```rust - /// let x = [1, 2, 3]; - /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); - /// ``` - /// Use instead: - /// ```rust - /// let x = [1, 2, 3]; - /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); - /// ``` - pub MAP_IDENTITY, - complexity, - "using iterator.map(|x| x)" -} - -declare_lint_pass!(MapIdentity => [MAP_IDENTITY]); - -impl<'tcx> LateLintPass<'tcx> for MapIdentity { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if expr.span.from_expansion() { - return; - } - - if_chain! { - if let Some([caller, func]) = get_map_argument(cx, expr); - if is_expr_identity_function(cx, func); - then { - span_lint_and_sugg( - cx, - MAP_IDENTITY, - expr.span.trim_start(caller.span).unwrap(), - "unnecessary map of the identity function", - "remove the call to `map`", - String::new(), - Applicability::MachineApplicable - ) - } - } - } -} - -/// Returns the arguments passed into map() if the expression is a method call to -/// map(). Otherwise, returns None. -fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> { - if_chain! { - if let ExprKind::MethodCall(method, _, args, _) = expr.kind; - if args.len() == 2 && method.ident.name == sym::map; - let caller_ty = cx.typeck_results().expr_ty(&args[0]); - if is_trait_method(cx, expr, sym::Iterator) - || is_type_diagnostic_item(cx, caller_ty, sym::result_type) - || is_type_diagnostic_item(cx, caller_ty, sym::option_type); - then { - Some(args) - } else { - None - } - } -} diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs new file mode 100644 index 00000000000..538a12566e3 --- /dev/null +++ b/clippy_lints/src/methods/map_identity.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_expr_identity_function, is_trait_method}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::{source_map::Span, sym}; + +use super::MAP_IDENTITY; + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + caller: &hir::Expr<'_>, + map_arg: &hir::Expr<'_>, + _map_span: Span, +) { + let caller_ty = cx.typeck_results().expr_ty(caller); + + if_chain! { + if is_trait_method(cx, expr, sym::Iterator) + || is_type_diagnostic_item(cx, caller_ty, sym::result_type) + || is_type_diagnostic_item(cx, caller_ty, sym::option_type); + if is_expr_identity_function(cx, map_arg); + if let Some(sugg_span) = expr.span.trim_start(caller.span); + then { + span_lint_and_sugg( + cx, + MAP_IDENTITY, + sugg_span, + "unnecessary map of the identity function", + "remove the call to `map`", + String::new(), + Applicability::MachineApplicable, + ) + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c8ae972f18c..d4f8cef4f37 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -35,6 +35,7 @@ mod manual_saturating_arithmetic; mod manual_str_repeat; mod map_collect_result_unit; mod map_flatten; +mod map_identity; mod map_unwrap_or; mod ok_expect; mod option_as_ref_deref; @@ -1561,6 +1562,29 @@ declare_clippy_lint! { "call to `filter_map` where `flatten` is sufficient" } +declare_clippy_lint! { + /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function. + /// + /// **Why is this bad?** It can be written more concisely without the call to `map`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let x = [1, 2, 3]; + /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); + /// ``` + /// Use instead: + /// ```rust + /// let x = [1, 2, 3]; + /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); + /// ``` + pub MAP_IDENTITY, + complexity, + "using iterator.map(|x| x)" +} + declare_clippy_lint! { /// **What it does:** Checks for the use of `.bytes().nth()`. /// @@ -1728,6 +1752,7 @@ impl_lint_pass!(Methods => [ FILTER_NEXT, SKIP_WHILE_NEXT, FILTER_MAP_IDENTITY, + MAP_IDENTITY, MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, @@ -2058,6 +2083,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio _ => {}, } } + map_identity::check(cx, expr, recv, m_arg, span); }, ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), ("next", []) => { -- cgit 1.4.1-3-g733a5 From 44608b1857951ba82b630853da6fc6c2f40fde53 Mon Sep 17 00:00:00 2001 From: valentine-mario Date: Thu, 10 Jun 2021 09:12:06 +0100 Subject: added lint to check for full range of vector and suggest append --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 ++ .../src/methods/append_instead_of_extend.rs | 41 ++++++++++++++++ clippy_lints/src/methods/mod.rs | 33 ++++++++++++- tests/ui/append_instead_of_extend.fixed | 55 ++++++++++++++++++++++ tests/ui/append_instead_of_extend.rs | 55 ++++++++++++++++++++++ tests/ui/append_instead_of_extend.stderr | 22 +++++++++ 7 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/append_instead_of_extend.rs create mode 100644 tests/ui/append_instead_of_extend.fixed create mode 100644 tests/ui/append_instead_of_extend.rs create mode 100644 tests/ui/append_instead_of_extend.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 13f0fc8f609..52d0e8c7cde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2295,6 +2295,7 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped +[`append_instead_of_extend`]: https://rust-lang.github.io/rust-clippy/master/index.html#append_instead_of_extend [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 591bf68f927..5ab333f8aa1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -730,6 +730,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: mem_replace::MEM_REPLACE_OPTION_WITH_NONE, mem_replace::MEM_REPLACE_WITH_DEFAULT, mem_replace::MEM_REPLACE_WITH_UNINIT, + methods::APPEND_INSTEAD_OF_EXTEND, methods::BIND_INSTEAD_OF_MAP, methods::BYTES_NTH, methods::CHARS_LAST_CMP, @@ -1276,6 +1277,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::APPEND_INSTEAD_OF_EXTEND), LintId::of(methods::BIND_INSTEAD_OF_MAP), LintId::of(methods::BYTES_NTH), LintId::of(methods::CHARS_LAST_CMP), @@ -1736,6 +1738,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(loops::MANUAL_MEMCPY), LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(methods::APPEND_INSTEAD_OF_EXTEND), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::ITER_NTH), LintId::of(methods::MANUAL_STR_REPEAT), diff --git a/clippy_lints/src/methods/append_instead_of_extend.rs b/clippy_lints/src/methods/append_instead_of_extend.rs new file mode 100644 index 00000000000..e39a5a1efd1 --- /dev/null +++ b/clippy_lints/src/methods/append_instead_of_extend.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::APPEND_INSTEAD_OF_EXTEND; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if_chain! { + if is_type_diagnostic_item(cx, ty, sym::vec_type); + //check source object + if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind; + if src_method.ident.as_str() == "drain"; + if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs(); + if is_type_diagnostic_item(cx, src_ty, sym::vec_type); + //check drain range + if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs(); + if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + APPEND_INSTEAD_OF_EXTEND, + expr.span, + "use of `extend` instead of `append` for adding the full range of a second vector", + "try this", + format!( + "{}.append(&mut {})", + snippet_with_applicability(cx, recv.span, "..", &mut applicability), + snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability) + ), + applicability, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d4f8cef4f37..b556dcb4dfe 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,3 +1,4 @@ +mod append_instead_of_extend; mod bind_instead_of_map; mod bytes_nth; mod chars_cmp; @@ -1032,6 +1033,30 @@ declare_clippy_lint! { "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead" } +declare_clippy_lint! { + /// **What it does:** Checks for occurrences where one vector gets extended instead of append + /// + /// **Why is this bad?** Using `append` instead of `extend` is more concise and faster + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let mut a = vec![1, 2, 3]; + /// let mut b = vec![4, 5, 6]; + /// + /// // Bad + /// a.extend(b.drain(..)); + /// + /// // Good + /// a.append(&mut b); + /// ``` + pub APPEND_INSTEAD_OF_EXTEND, + perf, + "using vec.append(&mut vec) to move the full range of a vecor to another" +} + declare_clippy_lint! { /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a /// `&str` or `String`. @@ -1785,7 +1810,8 @@ impl_lint_pass!(Methods => [ INSPECT_FOR_EACH, IMPLICIT_CLONE, SUSPICIOUS_SPLITN, - MANUAL_STR_REPEAT + MANUAL_STR_REPEAT, + APPEND_INSTEAD_OF_EXTEND ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2047,7 +2073,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), _ => expect_used::check(cx, expr, recv), }, - ("extend", [arg]) => string_extend_chars::check(cx, expr, recv, arg), + ("extend", [arg]) => { + string_extend_chars::check(cx, expr, recv, arg); + append_instead_of_extend::check(cx, expr, recv, arg); + }, ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg); filter_map_identity::check(cx, expr, arg, span); diff --git a/tests/ui/append_instead_of_extend.fixed b/tests/ui/append_instead_of_extend.fixed new file mode 100644 index 00000000000..283358333cd --- /dev/null +++ b/tests/ui/append_instead_of_extend.fixed @@ -0,0 +1,55 @@ +// run-rustfix +#![warn(clippy::append_instead_of_extend)] +use std::collections::BinaryHeap; +fn main() { + //gets linted + let mut vec1 = vec![0u8; 1024]; + let mut vec2: std::vec::Vec = Vec::new(); + + vec2.append(&mut vec1); + + let mut vec3 = vec![0u8; 1024]; + let mut vec4: std::vec::Vec = Vec::new(); + + vec4.append(&mut vec3); + + let mut vec11: std::vec::Vec = Vec::new(); + + vec11.append(&mut return_vector()); + + //won't get linted it dosen't move the entire content of a vec into another + let mut test1 = vec![0u8, 10]; + let mut test2: std::vec::Vec = Vec::new(); + + test2.extend(test1.drain(4..10)); + + let mut vec3 = vec![0u8; 104]; + let mut vec7: std::vec::Vec = Vec::new(); + + vec3.append(&mut vec7); + + let mut vec5 = vec![0u8; 1024]; + let mut vec6: std::vec::Vec = Vec::new(); + + vec5.extend(vec6.drain(..4)); + + let mut vec9: std::vec::Vec = Vec::new(); + + return_vector().append(&mut vec9); + + //won't get linted because it is not a vec + + let mut heap = BinaryHeap::from(vec![1, 3]); + let mut heap2 = BinaryHeap::from(vec![]); + heap2.extend(heap.drain()) +} + +fn return_vector() -> Vec { + let mut new_vector = vec![]; + + for i in 1..10 { + new_vector.push(i) + } + + new_vector +} diff --git a/tests/ui/append_instead_of_extend.rs b/tests/ui/append_instead_of_extend.rs new file mode 100644 index 00000000000..abde5cdac5c --- /dev/null +++ b/tests/ui/append_instead_of_extend.rs @@ -0,0 +1,55 @@ +// run-rustfix +#![warn(clippy::append_instead_of_extend)] +use std::collections::BinaryHeap; +fn main() { + //gets linted + let mut vec1 = vec![0u8; 1024]; + let mut vec2: std::vec::Vec = Vec::new(); + + vec2.extend(vec1.drain(..)); + + let mut vec3 = vec![0u8; 1024]; + let mut vec4: std::vec::Vec = Vec::new(); + + vec4.extend(vec3.drain(..)); + + let mut vec11: std::vec::Vec = Vec::new(); + + vec11.extend(return_vector().drain(..)); + + //won't get linted it dosen't move the entire content of a vec into another + let mut test1 = vec![0u8, 10]; + let mut test2: std::vec::Vec = Vec::new(); + + test2.extend(test1.drain(4..10)); + + let mut vec3 = vec![0u8; 104]; + let mut vec7: std::vec::Vec = Vec::new(); + + vec3.append(&mut vec7); + + let mut vec5 = vec![0u8; 1024]; + let mut vec6: std::vec::Vec = Vec::new(); + + vec5.extend(vec6.drain(..4)); + + let mut vec9: std::vec::Vec = Vec::new(); + + return_vector().append(&mut vec9); + + //won't get linted because it is not a vec + + let mut heap = BinaryHeap::from(vec![1, 3]); + let mut heap2 = BinaryHeap::from(vec![]); + heap2.extend(heap.drain()) +} + +fn return_vector() -> Vec { + let mut new_vector = vec![]; + + for i in 1..10 { + new_vector.push(i) + } + + new_vector +} diff --git a/tests/ui/append_instead_of_extend.stderr b/tests/ui/append_instead_of_extend.stderr new file mode 100644 index 00000000000..9d309d981de --- /dev/null +++ b/tests/ui/append_instead_of_extend.stderr @@ -0,0 +1,22 @@ +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/append_instead_of_extend.rs:9:5 + | +LL | vec2.extend(vec1.drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)` + | + = note: `-D clippy::append-instead-of-extend` implied by `-D warnings` + +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/append_instead_of_extend.rs:14:5 + | +LL | vec4.extend(vec3.drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)` + +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/append_instead_of_extend.rs:18:5 + | +LL | vec11.extend(return_vector().drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From a40fd6da7e49eea2c8b77a95f274d249186ba7ce Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Fri, 18 Jun 2021 22:18:16 +0200 Subject: Move from-iter-instead-of-collect to pedantic Since FromIterator will become part of the prelude, this lint being warn by default is incongruous with the libs team position on the topic. --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5ab333f8aa1..f5082468a77 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1092,6 +1092,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::CLONED_INSTEAD_OF_COPIED), LintId::of(methods::FILTER_MAP_NEXT), LintId::of(methods::FLAT_MAP_OPTION), + LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), LintId::of(methods::MAP_FLATTEN), @@ -1288,7 +1289,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), - LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), @@ -1504,7 +1504,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::BYTES_NTH), LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), - LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::ITER_CLONED_COLLECT), LintId::of(methods::ITER_NEXT_SLICE), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b556dcb4dfe..c6bef7bc5d5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1530,7 +1530,7 @@ declare_clippy_lint! { /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` pub FROM_ITER_INSTEAD_OF_COLLECT, - style, + pedantic, "use `.collect()` instead of `::from_iter()`" } -- cgit 1.4.1-3-g733a5 From 10122e4a48c3a31276f8e117af66c949c8f962a3 Mon Sep 17 00:00:00 2001 From: Joe Ranweiler Date: Tue, 22 Jun 2021 18:45:12 -0700 Subject: Remove shadowed receiver in check invocation --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c6bef7bc5d5..21585543b0a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2036,7 +2036,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) { if let Some((name, [recv, args @ ..], span)) = method_call!(expr) { match (name, args) { - ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => { + ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); }, ("and_then", [arg]) => { -- cgit 1.4.1-3-g733a5 From f02632cee63137fb0184ecb3828fdd6d8f9ce6dd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 14 Jun 2021 14:09:17 -0500 Subject: Move some lints to suspicious --- clippy_lints/src/assign_ops.rs | 2 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/float_equality_without_abs.rs | 2 +- clippy_lints/src/formatting.rs | 6 ++--- clippy_lints/src/lib.rs | 31 ++++++++++++++------------ clippy_lints/src/loops/mod.rs | 6 ++--- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 4 ++-- tests/ui/mut_key.stderr | 2 +- tests/ui/suspicious_arithmetic_impl.stderr | 2 +- 12 files changed, 33 insertions(+), 30 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index bc6eec0051a..a8c527fe2e3 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -55,7 +55,7 @@ declare_clippy_lint! { /// a += a + b; /// ``` pub MISREFACTORED_ASSIGN_OP, - complexity, + suspicious, "having a variable on both sides of an assign op" } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 932cd58bf62..f272ed010a1 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -173,7 +173,7 @@ declare_clippy_lint! { /// #![deny(clippy::as_conversions)] /// ``` pub BLANKET_CLIPPY_RESTRICTION_LINTS, - style, + suspicious, "enabling the complete restriction group" } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 5fdf5bc9e9d..03a8b40df55 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// let a = tmp + x; /// ``` pub EVAL_ORDER_DEPENDENCE, - complexity, + suspicious, "whether a variable read occurs before a write depends on sub-expression evaluation order" } diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index b5ebe5f90ba..1e503cc795c 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// } /// ``` pub FLOAT_EQUALITY_WITHOUT_ABS, - correctness, + suspicious, "float equality check without `.abs()`" } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 3bd6a09d365..8aefb8d46f6 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`? /// ``` pub SUSPICIOUS_ASSIGNMENT_FORMATTING, - style, + suspicious, "suspicious formatting of `*=`, `-=` or `!=`" } @@ -44,7 +44,7 @@ declare_clippy_lint! { /// } /// ``` pub SUSPICIOUS_UNARY_OP_FORMATTING, - style, + suspicious, "suspicious formatting of unary `-` or `!` on the RHS of a BinOp" } @@ -80,7 +80,7 @@ declare_clippy_lint! { /// } /// ``` pub SUSPICIOUS_ELSE_FORMATTING, - style, + suspicious, "suspicious formatting of `else`" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4ce1d511d27..20eea61d78d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1461,7 +1461,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(assign_ops::ASSIGN_OP_PATTERN), - LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), @@ -1479,9 +1478,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(eq_op::OP_REF), LintId::of(eta_reduction::REDUNDANT_CLOSURE), LintId::of(float_literal::EXCESSIVE_PRECISION), - LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), LintId::of(from_over_into::FROM_OVER_INTO), LintId::of(from_str_radix_10::FROM_STR_RADIX_10), LintId::of(functions::DOUBLE_MUST_USE), @@ -1494,7 +1490,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(len_zero::LEN_ZERO), LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_KV_MAP), LintId::of(loops::NEEDLESS_RANGE_LOOP), LintId::of(loops::SAME_ITEM_PUSH), @@ -1574,7 +1569,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ]); store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(attrs::DEPRECATED_CFG_ATTR), LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(casts::CHAR_LIT_AS_U8), @@ -1584,7 +1578,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(double_parens::DOUBLE_PARENS), LintId::of(duration_subsec::DURATION_SUBSEC), LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), LintId::of(explicit_write::EXPLICIT_WRITE), LintId::of(format::USELESS_FORMAT), LintId::of(functions::TOO_MANY_ARGUMENTS), @@ -1595,7 +1588,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(lifetimes::NEEDLESS_LIFETIMES), LintId::of(loops::EXPLICIT_COUNTER_LOOP), LintId::of(loops::MANUAL_FLATTEN), - LintId::of(loops::MUT_RANGE_BOUND), LintId::of(loops::SINGLE_ELEMENT_LOOP), LintId::of(loops::WHILE_LET_LOOP), LintId::of(manual_strip::MANUAL_STRIP), @@ -1619,7 +1611,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), - LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::USELESS_ASREF), LintId::of(misc::SHORT_CIRCUIT_STATEMENT), @@ -1688,7 +1679,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(eq_op::EQ_OP), LintId::of(erasing_op::ERASING_OP), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(formatting::POSSIBLE_MISSING_COMMA), LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(if_let_mutex::IF_LET_MUTEX), @@ -1698,7 +1688,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), LintId::of(let_underscore::LET_UNDERSCORE_LOCK), LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::ITER_NEXT_LOOP), LintId::of(loops::NEVER_LOOP), LintId::of(loops::WHILE_IMMUTABLE_CONDITION), @@ -1713,7 +1702,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(misc::CMP_NAN), LintId::of(misc::FLOAT_CMP), LintId::of(misc::MODULO_ONE), - LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), @@ -1724,8 +1712,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(self_assignment::SELF_ASSIGNMENT), LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap::ALMOST_SWAPPED), LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), @@ -1742,6 +1728,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]); + store.register_group(true, "clippy::suspicious", None, vec![ + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + ]); + store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(entry::MAP_ENTRY), LintId::of(escape::BOXED_LOCAL), diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index a4bc3e6bd10..56a123b69c6 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -199,7 +199,7 @@ declare_clippy_lint! { /// } /// ``` pub FOR_LOOPS_OVER_FALLIBLES, - correctness, + suspicious, "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`" } @@ -313,7 +313,7 @@ declare_clippy_lint! { /// loop {} /// ``` pub EMPTY_LOOP, - style, + suspicious, "empty `loop {}`, which should block or sleep" } @@ -401,7 +401,7 @@ declare_clippy_lint! { /// } /// ``` pub MUT_RANGE_BOUND, - complexity, + suspicious, "for loop over a range where one of the bounds is a mutable variable" } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 21585543b0a..283fcf281df 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1248,7 +1248,7 @@ declare_clippy_lint! { /// let _ = (0..3).map(|x| x + 2).count(); /// ``` pub SUSPICIOUS_MAP, - complexity, + suspicious, "suspicious usage of map" } diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 1786d5805d7..6c87136e5e1 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { /// } /// ``` pub MUTABLE_KEY_TYPE, - correctness, + suspicious, "Check for mutable `Map`/`Set` key type" } diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 512abde11a6..2203ab57b10 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` pub SUSPICIOUS_ARITHMETIC_IMPL, - correctness, + suspicious, "suspicious use of operators in impl of arithmetic trait" } @@ -47,7 +47,7 @@ declare_clippy_lint! { /// } /// ``` pub SUSPICIOUS_OP_ASSIGN_IMPL, - correctness, + suspicious, "suspicious use of operators in impl of OpAssign trait" } diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index 8d6a259c7e3..a8460b06ca6 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -4,7 +4,7 @@ error: mutable key type LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[deny(clippy::mutable_key_type)]` on by default + = note: `-D clippy::mutable-key-type` implied by `-D warnings` error: mutable key type --> $DIR/mut_key.rs:27:72 diff --git a/tests/ui/suspicious_arithmetic_impl.stderr b/tests/ui/suspicious_arithmetic_impl.stderr index 388fc740082..63fc9ecb79a 100644 --- a/tests/ui/suspicious_arithmetic_impl.stderr +++ b/tests/ui/suspicious_arithmetic_impl.stderr @@ -12,7 +12,7 @@ error: suspicious use of binary operator in `AddAssign` impl LL | *self = *self - other; | ^ | - = note: `#[deny(clippy::suspicious_op_assign_impl)]` on by default + = note: `-D clippy::suspicious-op-assign-impl` implied by `-D warnings` error: suspicious use of binary operator in `MulAssign` impl --> $DIR/suspicious_arithmetic_impl.rs:32:16 -- cgit 1.4.1-3-g733a5 From e6ab222b814f20375041a5dd39e7605eed079c70 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 6 Jul 2021 11:51:15 -0500 Subject: Refactor format macro parsing --- clippy_lints/src/explicit_write.rs | 44 ++----- clippy_lints/src/format.rs | 192 ++++++++++------------------ clippy_lints/src/methods/expect_fun_call.rs | 72 +++-------- clippy_utils/src/higher.rs | 108 +++++++++++++++- clippy_utils/src/paths.rs | 4 - 5 files changed, 203 insertions(+), 217 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index da4936ff25b..eaea70a4294 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::higher::FormatArgsExpn; use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -34,29 +34,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // match call to unwrap - if let ExprKind::MethodCall(unwrap_fun, _, unwrap_args, _) = expr.kind; + if let ExprKind::MethodCall(unwrap_fun, _, [write_call], _) = expr.kind; if unwrap_fun.ident.name == sym::unwrap; // match call to write_fmt - if !unwrap_args.is_empty(); - if let ExprKind::MethodCall(write_fun, _, write_args, _) = - unwrap_args[0].kind; + if let ExprKind::MethodCall(write_fun, _, [write_recv, write_arg], _) = write_call.kind; if write_fun.ident.name == sym!(write_fmt); // match calls to std::io::stdout() / std::io::stderr () - if !write_args.is_empty(); - if let Some(dest_name) = if match_function_call(cx, &write_args[0], &paths::STDOUT).is_some() { + if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { Some("stdout") - } else if match_function_call(cx, &write_args[0], &paths::STDERR).is_some() { + } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { Some("stderr") } else { None }; + if let Some(format_args) = FormatArgsExpn::parse(write_arg); then { - let write_span = unwrap_args[0].span; let calling_macro = // ordering is important here, since `writeln!` uses `write!` internally - if is_expn_of(write_span, "writeln").is_some() { + if is_expn_of(write_call.span, "writeln").is_some() { Some("writeln") - } else if is_expn_of(write_span, "write").is_some() { + } else if is_expn_of(write_call.span, "write").is_some() { Some("write") } else { None @@ -70,7 +67,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { // We need to remove the last trailing newline from the string because the // underlying `fmt::write` function doesn't know whether `println!` or `print!` was // used. - if let Some(mut write_output) = write_output_string(write_args) { + if let [write_output] = *format_args.format_string_symbols { + let mut write_output = write_output.to_string(); if write_output.ends_with('\n') { write_output.pop(); } @@ -129,23 +127,3 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { } } } - -// Extract the output string from the given `write_args`. -fn write_output_string(write_args: &[Expr<'_>]) -> Option { - if_chain! { - // Obtain the string that should be printed - if write_args.len() > 1; - if let ExprKind::Call(_, output_args) = write_args[1].kind; - if !output_args.is_empty(); - if let ExprKind::AddrOf(BorrowKind::Ref, _, output_string_expr) = output_args[0].kind; - if let ExprKind::Array(string_exprs) = output_string_expr.kind; - // we only want to provide an automatic suggestion for simple (non-format) strings - if string_exprs.len() == 1; - if let ExprKind::Lit(ref lit) = string_exprs[0].kind; - if let LitKind::Str(ref write_output, _) = lit.node; - then { - return Some(write_output.to_string()) - } - } - None -} diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index de1b3ffecd0..ca3490d8eda 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,18 +1,16 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::FormatExpn; +use clippy_utils::last_path_segment; +use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expn_of, last_path_segment, match_def_path, match_function_call}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, MatchSource, PatKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_hir::{BorrowKind, Expr, ExprKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::sym; use rustc_span::symbol::kw; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for the use of `format!("string literal with no @@ -45,131 +43,78 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let span = match is_expn_of(expr.span, "format") { - Some(s) if !s.from_expansion() => s, + let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) { + Some(e) if !e.call_site.from_expansion() => e, _ => return, }; - // Operate on the only argument of `alloc::fmt::format`. - if let Some(sugg) = on_new_v1(cx, expr) { - span_useless_format(cx, span, "consider using `.to_string()`", sugg); - } else if let Some(sugg) = on_new_v1_fmt(cx, expr) { - span_useless_format(cx, span, "consider using `.to_string()`", sugg); - } - } -} - -fn span_useless_format(cx: &T, span: Span, help: &str, mut sugg: String) { - let to_replace = span.source_callsite(); - - // The callsite span contains the statement semicolon for some reason. - let snippet = snippet(cx, to_replace, ".."); - if snippet.ends_with(';') { - sugg.push(';'); - } - - span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |diag| { - diag.span_suggestion( - to_replace, - help, - sugg, - Applicability::MachineApplicable, // snippet - ); - }); -} - -fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) -> Option { - if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, format_args) = expr.kind; - if let ExprKind::Array(elems) = arms[0].body.kind; - if elems.len() == 1; - if let Some(args) = match_function_call(cx, &elems[0], &paths::FMT_ARGUMENTV1_NEW); - // matches `core::fmt::Display::fmt` - if args.len() == 2; - if let ExprKind::Path(ref qpath) = args[1].kind; - if let Some(did) = cx.qpath_res(qpath, args[1].hir_id).opt_def_id(); - if match_def_path(cx, did, &paths::DISPLAY_FMT_METHOD); - // check `(arg0,)` in match block - if let PatKind::Tuple(pats, None) = arms[0].pat.kind; - if pats.len() == 1; - then { - let ty = cx.typeck_results().pat_ty(pats[0]).peel_refs(); - if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym::string_type) { - return None; - } - if let ExprKind::Lit(ref lit) = format_args.kind { - if let LitKind::Str(ref s, _) = lit.node { - return Some(format!("{:?}.to_string()", s.as_str())); + let mut applicability = Applicability::MachineApplicable; + if format_args.value_args.is_empty() { + if_chain! { + if let [e] = &*format_args.format_string_parts; + if let ExprKind::Lit(lit) = &e.kind; + if let Some(s_src) = snippet_opt(cx, lit.span); + then { + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = s_src.replace("{{", "{").replace("}}", "}"); + let sugg = format!("{}.to_string()", s_expand); + span_useless_format(cx, call_site, sugg, applicability); } - } else { - let sugg = Sugg::hir(cx, format_args, ""); - if let ExprKind::MethodCall(path, _, _, _) = format_args.kind { - if path.ident.name == sym!(to_string) { - return Some(format!("{}", sugg)); - } - } else if let ExprKind::Binary(..) = format_args.kind { - return Some(format!("{}", sugg)); + } + } else if let [value] = *format_args.value_args { + if_chain! { + if format_args.format_string_symbols == [kw::Empty]; + if match cx.typeck_results().expr_ty(value).peel_refs().kind() { + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::string_type, adt.did), + ty::Str => true, + _ => false, + }; + if format_args.args.iter().all(|e| is_display_arg(e)); + if format_args.fmt_expr.map_or(true, |e| check_unformatted(e)); + then { + let is_new_string = match value.kind { + ExprKind::Binary(..) => true, + ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string", + _ => false, + }; + let sugg = if is_new_string { + snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned() + } else { + let sugg = Sugg::hir_with_applicability(cx, value, "", &mut applicability); + format!("{}.to_string()", sugg.maybe_par()) + }; + span_useless_format(cx, call_site, sugg, applicability); } - return Some(format!("{}.to_string()", sugg.maybe_par())); } - } + }; } - None } -fn on_new_v1<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - if_chain! { - if let Some(args) = match_function_call(cx, expr, &paths::FMT_ARGUMENTS_NEW_V1); - if args.len() == 2; - // Argument 1 in `new_v1()` - if let ExprKind::AddrOf(BorrowKind::Ref, _, arr) = args[0].kind; - if let ExprKind::Array(pieces) = arr.kind; - if pieces.len() == 1; - if let ExprKind::Lit(ref lit) = pieces[0].kind; - if let LitKind::Str(ref s, _) = lit.node; - // Argument 2 in `new_v1()` - if let ExprKind::AddrOf(BorrowKind::Ref, _, arg1) = args[1].kind; - if let ExprKind::Match(matchee, arms, MatchSource::Normal) = arg1.kind; - if arms.len() == 1; - if let ExprKind::Tup(tup) = matchee.kind; - then { - // `format!("foo")` expansion contains `match () { () => [], }` - if tup.is_empty() { - if let Some(s_src) = snippet_opt(cx, lit.span) { - // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = s_src.replace("{{", "{").replace("}}", "}"); - return Some(format!("{}.to_string()", s_expand)); - } - } else if s.as_str().is_empty() { - return on_argumentv1_new(cx, &tup[0], arms); - } - } +fn span_useless_format(cx: &LateContext<'_>, span: Span, mut sugg: String, mut applicability: Applicability) { + // The callsite span contains the statement semicolon for some reason. + if snippet_with_applicability(cx, span, "..", &mut applicability).ends_with(';') { + sugg.push(';'); } - None + + span_lint_and_sugg( + cx, + USELESS_FORMAT, + span, + "useless use of `format!`", + "consider using `.to_string()`", + sugg, + applicability, + ); } -fn on_new_v1_fmt<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { +fn is_display_arg(expr: &Expr<'_>) -> bool { if_chain! { - if let Some(args) = match_function_call(cx, expr, &paths::FMT_ARGUMENTS_NEW_V1_FORMATTED); - if args.len() == 3; - if check_unformatted(&args[2]); - // Argument 1 in `new_v1_formatted()` - if let ExprKind::AddrOf(BorrowKind::Ref, _, arr) = args[0].kind; - if let ExprKind::Array(pieces) = arr.kind; - if pieces.len() == 1; - if let ExprKind::Lit(ref lit) = pieces[0].kind; - if let LitKind::Str(symbol, _) = lit.node; - if symbol == kw::Empty; - // Argument 2 in `new_v1_formatted()` - if let ExprKind::AddrOf(BorrowKind::Ref, _, arg1) = args[1].kind; - if let ExprKind::Match(matchee, arms, MatchSource::Normal) = arg1.kind; - if arms.len() == 1; - if let ExprKind::Tup(tup) = matchee.kind; - then { - return on_argumentv1_new(cx, &tup[0], arms); - } + if let ExprKind::Call(_, [_, fmt]) = expr.kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind; + if let [.., t, _] = path.segments; + if t.ident.name.as_str() == "Display"; + then { true } else { false } } - None } /// Checks if the expression matches @@ -186,10 +131,9 @@ fn on_new_v1_fmt<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option) -> bool { if_chain! { if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; - if let ExprKind::Array(exprs) = expr.kind; - if exprs.len() == 1; + if let ExprKind::Array([expr]) = expr.kind; // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = exprs[0].kind; + if let ExprKind::Struct(_, fields, _) = expr.kind; if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); // struct `core::fmt::rt::v1::FormatSpec` if let ExprKind::Struct(_, fields, _) = format_field.expr.kind; diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 03cb41697d5..f8ee31a00df 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_expn_of; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::higher::FormatExpn; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -94,27 +93,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa } } - fn generate_format_arg_snippet( - cx: &LateContext<'_>, - a: &hir::Expr<'_>, - applicability: &mut Applicability, - ) -> Vec { - if_chain! { - if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, format_arg) = a.kind; - if let hir::ExprKind::Match(format_arg_expr, _, _) = format_arg.kind; - if let hir::ExprKind::Tup(format_arg_expr_tup) = format_arg_expr.kind; - - then { - format_arg_expr_tup - .iter() - .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned()) - .collect() - } else { - unreachable!() - } - } - } - fn is_call(node: &hir::ExprKind<'_>) -> bool { match node { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => { @@ -150,36 +128,22 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa let mut applicability = Applicability::MachineApplicable; //Special handling for `format!` as arg_root - if_chain! { - if let hir::ExprKind::Block(block, None) = &arg_root.kind; - if block.stmts.len() == 1; - if let hir::StmtKind::Local(local) = &block.stmts[0].kind; - if let Some(arg_root) = &local.init; - if let hir::ExprKind::Call(inner_fun, inner_args) = arg_root.kind; - if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1; - if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind; - then { - let fmt_spec = &format_args[0]; - let fmt_args = &format_args[1]; - - let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()]; - - args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability)); - - let sugg = args.join(", "); - - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - &format!("use of `{}` followed by a function call", name), - "try this", - format!("unwrap_or_else({} panic!({}))", closure_args, sugg), - applicability, - ); - - return; - } + if let Some(format_expn) = FormatExpn::parse(arg_root) { + let span = match *format_expn.format_args.value_args { + [] => format_expn.format_args.format_string_span, + [.., last] => format_expn.format_args.format_string_span.to(last.span), + }; + let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + &format!("use of `{}` followed by a function call", name), + "try this", + format!("unwrap_or_else({} panic!({}))", closure_args, sugg), + applicability, + ); + return; } let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability); diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 8be36756b33..5ffd88f4140 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -5,11 +5,11 @@ use crate::{is_expn_of, match_def_path, paths}; use if_chain::if_chain; -use rustc_ast::ast; +use rustc_ast::ast::{self, LitKind}; use rustc_hir as hir; use rustc_hir::{BorrowKind, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::LateContext; -use rustc_span::source_map::Span; +use rustc_span::{sym, ExpnKind, Span, Symbol}; /// Converts a hir binary operator to the corresponding `ast` type. #[must_use] @@ -266,3 +266,107 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option { + /// Span of `format!(..)` + pub call_site: Span, + /// Inner `format_args!` expansion + pub format_args: FormatArgsExpn<'tcx>, +} + +impl FormatExpn<'tcx> { + /// Parses an expanded `format!` invocation + pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { + if_chain! { + if let ExprKind::Block(block, _) = expr.kind; + if let [stmt] = block.stmts; + if let StmtKind::Local(local) = stmt.kind; + if let Some(init) = local.init; + if let ExprKind::Call(_, [format_args]) = init.kind; + let expn_data = expr.span.ctxt().outer_expn_data(); + if let ExpnKind::Macro { name: sym::format, .. } = expn_data.kind; + if let Some(format_args) = FormatArgsExpn::parse(format_args); + then { + Some(FormatExpn { + call_site: expn_data.call_site, + format_args, + }) + } else { + None + } + } + } +} + +/// A parsed `format_args!` expansion +pub struct FormatArgsExpn<'tcx> { + /// Span of the first argument, the format string + pub format_string_span: Span, + /// Values passed after the format string + pub value_args: Vec<&'tcx Expr<'tcx>>, + + /// String literal expressions which represent the format string split by "{}" + pub format_string_parts: &'tcx [Expr<'tcx>], + /// Symbols corresponding to [`format_string_parts`] + pub format_string_symbols: Vec, + /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)` + pub args: &'tcx [Expr<'tcx>], + /// The final argument passed to `Arguments::new_v1_formatted`, if applicable + pub fmt_expr: Option<&'tcx Expr<'tcx>>, +} + +impl FormatArgsExpn<'tcx> { + /// Parses an expanded `format_args!` or `format_args_nl!` invocation + pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { + if_chain! { + if let ExpnKind::Macro { name, .. } = expr.span.ctxt().outer_expn_data().kind; + let name = name.as_str(); + if name.ends_with("format_args") || name.ends_with("format_args_nl"); + if let ExprKind::Call(_, args) = expr.kind; + if let Some((strs_ref, args, fmt_expr)) = match args { + // Arguments::new_v1 + [strs_ref, args] => Some((strs_ref, args, None)), + // Arguments::new_v1_formatted + [strs_ref, args, fmt_expr] => Some((strs_ref, args, Some(fmt_expr))), + _ => None, + }; + if let ExprKind::AddrOf(BorrowKind::Ref, _, strs_arr) = strs_ref.kind; + if let ExprKind::Array(format_string_parts) = strs_arr.kind; + if let Some(format_string_symbols) = format_string_parts + .iter() + .map(|e| { + if let ExprKind::Lit(lit) = &e.kind { + if let LitKind::Str(symbol, _style) = lit.node { + return Some(symbol); + } + } + None + }) + .collect(); + if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args.kind; + if let ExprKind::Match(args, [arm], _) = args.kind; + if let ExprKind::Tup(value_args) = args.kind; + if let Some(value_args) = value_args + .iter() + .map(|e| match e.kind { + ExprKind::AddrOf(_, _, e) => Some(e), + _ => None, + }) + .collect(); + if let ExprKind::Array(args) = arm.body.kind; + then { + Some(FormatArgsExpn { + format_string_span: strs_ref.span, + value_args, + format_string_parts, + format_string_symbols, + args, + fmt_expr, + }) + } else { + None + } + } + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9ebfbd6b423..c960eec3064 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -38,7 +38,6 @@ pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "defa pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"]; -pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"]; pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; pub const DROP: [&str; 3] = ["core", "mem", "drop"]; @@ -50,9 +49,6 @@ pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; pub const FILE: [&str; 3] = ["std", "fs", "File"]; pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; -pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"]; -pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"]; -pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; -- cgit 1.4.1-3-g733a5 From 2ac21889bcc0634eabd1ff36491042fd0dae003f Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 14 Jul 2021 12:58:43 +0200 Subject: Use diagnostic items for `BinaryHeap`, `BTreeMap`, `BTreeSet`, `HashMap`, `HashSet`, `Borrow`, `Default` --- clippy_lints/src/implicit_hasher.rs | 7 +++---- clippy_lints/src/loops/explicit_iter_loop.rs | 6 +++--- clippy_lints/src/loops/for_kv_map.rs | 6 +++--- clippy_lints/src/matches.rs | 2 +- clippy_lints/src/methods/get_unwrap.rs | 6 +++--- clippy_lints/src/methods/iter_count.rs | 6 +++--- clippy_lints/src/methods/or_fun_call.rs | 4 ++-- clippy_lints/src/mut_key.rs | 7 ++++--- clippy_lints/src/needless_pass_by_value.rs | 3 +-- clippy_lints/src/new_without_default.rs | 5 ++--- clippy_lints/src/zero_sized_map_values.rs | 5 ++--- clippy_utils/src/paths.rs | 8 +++++++- 12 files changed, 34 insertions(+), 31 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 03fe0d16d48..7a5a37e2201 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -19,10 +19,9 @@ use rustc_typeck::hir_ty_to_ty; use if_chain::if_chain; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::paths; +use clippy_utils::differing_macro_contexts; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, match_def_path}; declare_clippy_lint! { /// **What it does:** Checks for public `impl` or `fn` missing generalization @@ -339,7 +338,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't return; } - if match_def_path(self.cx, ty_did, &paths::HASHMAP) { + if self.cx.tcx.is_diagnostic_item(sym::hashmap_type, ty_did) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashMap::default()".to_string()); @@ -352,7 +351,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't ), ); } - } else if match_def_path(self.cx, ty_did, &paths::HASHSET) { + } else if self.cx.tcx.is_diagnostic_item(sym::hashset_type, ty_did) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashSet::default()".to_string()); diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index f0327b5d777..3ba56a9294f 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -59,9 +59,9 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { is_type_diagnostic_item(cx, ty, sym::hashmap_type) || is_type_diagnostic_item(cx, ty, sym::hashset_type) || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || - match_type(cx, ty, &paths::BINARY_HEAP) || - match_type(cx, ty, &paths::BTREEMAP) || - match_type(cx, ty, &paths::BTREESET) + is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || + is_type_diagnostic_item(cx, ty, sym::BTreeMap) || + is_type_diagnostic_item(cx, ty, sym::BTreeSet) } fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 666b8c58728..82bf49f5b49 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,9 +1,9 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::sugg; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::LocalUsedVisitor; -use clippy_utils::{paths, sugg}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( _ => arg, }; - if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || match_type(cx, ty, &paths::BTREEMAP) { + if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) { span_lint_and_then( cx, FOR_KV_MAP, diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 986469a2b69..de73af8bf60 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1793,7 +1793,7 @@ mod redundant_pattern_match { || is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) || is_type_diagnostic_item(cx, ty, sym::cstring_type) - || match_type(cx, ty, &paths::BTREEMAP) + || is_type_diagnostic_item(cx, ty, sym::BTreeMap) || match_type(cx, ty, &paths::LINKED_LIST) || match_type(cx, ty, &paths::WEAK_RC) || match_type(cx, ty, &paths::WEAK_ARC) diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index 54f28064384..66fb85deae5 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -1,8 +1,8 @@ use super::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; -use clippy_utils::{get_parent_expr, paths}; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::hashmap_type) { needs_ref = true; "HashMap" - } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) { + } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::BTreeMap) { needs_ref = true; "BTreeMap" } else { diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index c6b7c7cd179..f8a38e67d00 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -22,13 +22,13 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E "HashSet" } else if is_type_diagnostic_item(cx, ty, sym::hashmap_type) { "HashMap" - } else if match_type(cx, ty, &paths::BTREEMAP) { + } else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) { "BTreeMap" - } else if match_type(cx, ty, &paths::BTREESET) { + } else if is_type_diagnostic_item(cx, ty, sym::BTreeSet) { "BTreeSet" } else if match_type(cx, ty, &paths::LINKED_LIST) { "LinkedList" - } else if match_type(cx, ty, &paths::BINARY_HEAP) { + } else if is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { "BinaryHeap" } else { return; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 073c5570a88..ef615b0aa40 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::is_lazyness_candidate; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; -use clippy_utils::{contains_return, get_trait_def_id, last_path_segment, paths}; +use clippy_utils::{contains_return, last_path_segment, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -41,7 +41,7 @@ pub(super) fn check<'tcx>( let path = last_path_segment(qpath).ident.name; if matches!(path, kw::Default | sym::new); let arg_ty = cx.typeck_results().expr_ty(arg); - if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); + if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); if implements_trait(cx, arg_ty, default_trait_id, &[]); then { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 6c87136e5e1..d86f9b36f90 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_def_path, paths, trait_ref_of_method}; +use clippy_utils::trait_ref_of_method; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::symbol::sym; use std::iter; declare_clippy_lint! { @@ -99,9 +100,9 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = ty.peel_refs(); if let Adt(def, substs) = ty.kind() { - if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET] + if [sym::hashmap_type, sym::BTreeMap, sym::hashset_type, sym::BTreeMap] .iter() - .any(|path| match_def_path(cx, def.did, &**path)) + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did)) && is_mutable_type(cx, substs.type_at(0), span) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index e33a33e2386..e03b3d25721 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -103,7 +103,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // Allow `Borrow` or functions to be taken by value - let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT)); let allowed_traits = [ need!(cx.tcx.lang_items().fn_trait()), need!(cx.tcx.lang_items().fn_once_trait()), @@ -167,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let preds = preds.iter().filter(|t| t.self_ty() == ty).collect::>(); ( - preds.iter().any(|t| t.def_id() == borrow_trait), + preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())), !preds.is_empty() && { let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty); preds.iter().all(|t| { diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index a5f91eb035f..4d9ff7479d6 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::paths; +use clippy_utils::return_ty; use clippy_utils::source::snippet; use clippy_utils::sugg::DiagnosticBuilderExt; -use clippy_utils::{get_trait_def_id, return_ty}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -104,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); let self_ty = cx.tcx.type_of(self_def_id); if TyS::same_type(self_ty, return_ty(cx, id)); - if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); + if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); then { if self.impling_types.is_none() { let mut impls = HirIdSet::default(); diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index f93f0047f51..1475c90721c 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::paths; -use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, match_type}; +use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -49,7 +48,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues { if !hir_ty.span.from_expansion(); if !in_trait_impl(cx, hir_ty.hir_id); let ty = ty_from_hir_ty(cx, hir_ty); - if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || match_type(cx, ty, &paths::BTREEMAP); + if is_type_diagnostic_item(cx, ty, sym::hashmap_type) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); if let Adt(_, substs) = ty.kind(); let ty = substs.type_at(1); // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`. diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index c960eec3064..3acde01b8c9 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -21,21 +21,25 @@ pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; pub(super) const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"]; +/// Preferably use the diagnostic item `sym::BinaryHeap` where possible pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"]; +/// Preferably use the diagnostic item `sym::Borrow` where possible pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; +/// Preferably use the diagnostic item `sym::BTreeMap` where possible pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; +/// Preferably use the diagnostic item `sym::BTreeSet` where possible pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; -pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; +/// Preferably use the diagnostic item `sym::deref_method` where possible pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"]; pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; @@ -55,10 +59,12 @@ pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect" pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; +/// Preferably use the diagnostic item `sym::hashmap_type` where possible pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"]; pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"]; +/// Preferably use the diagnostic item `sym::hashset_type` where possible pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"]; #[cfg(feature = "internal-lints")] pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; -- cgit 1.4.1-3-g733a5 From 6030428fd22912afeeaecfcc0220e979c2ffeb0a Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 14 Jul 2021 22:10:15 +0200 Subject: Use diagnostic items for `Into`, `IntoIterator`, `LinkedList`, `ptr::null`, `prt::null_mut` --- clippy_lints/src/from_over_into.rs | 6 +++--- clippy_lints/src/loops/explicit_into_iter_loop.rs | 5 +++-- clippy_lints/src/loops/explicit_iter_loop.rs | 8 ++++---- clippy_lints/src/matches.rs | 2 +- clippy_lints/src/methods/iter_count.rs | 5 ++--- clippy_lints/src/ptr.rs | 4 ++-- clippy_lints/src/transmuting_null.rs | 5 +++-- clippy_lints/src/types/linked_list.rs | 4 ++-- clippy_lints/src/useless_conversion.rs | 6 +++--- clippy_utils/src/lib.rs | 20 ++++++++++++++++++++ clippy_utils/src/paths.rs | 6 ++---- 11 files changed, 45 insertions(+), 26 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 3560672a748..48316c3a61d 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::paths::INTO; -use clippy_utils::{match_def_path, meets_msrv, msrvs}; +use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// **What it does:** Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. @@ -62,7 +62,7 @@ impl LateLintPass<'_> for FromOverInto { if_chain! { if let hir::ItemKind::Impl{ .. } = &item.kind; if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id); - if match_def_path(cx, impl_trait_ref.def_id, &INTO); + if cx.tcx.is_diagnostic_item(sym::into_trait, impl_trait_ref.def_id); then { span_lint_and_help( diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index c7a28f42ea1..1bab0d99b69 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -1,16 +1,17 @@ use super::EXPLICIT_INTO_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{match_trait_method, paths}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::TyS; +use rustc_span::symbol::sym; pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) { let self_ty = cx.typeck_results().expr_ty(self_arg); let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); - if !(TyS::same_type(self_ty, self_ty_adjusted) && match_trait_method(cx, call_expr, &paths::INTO_ITERATOR)) { + if !(TyS::same_type(self_ty, self_ty_adjusted) && is_trait_method(cx, call_expr, sym::IntoIterator)) { return; } diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 3ba56a9294f..50bc096ba22 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,8 +1,8 @@ use super::EXPLICIT_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; -use clippy_utils::{match_trait_method, paths}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ use rustc_span::sym; pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, method_name: &str) { let should_lint = match method_name { "iter" | "iter_mut" => is_ref_iterable_type(cx, self_arg), - "into_iter" if match_trait_method(cx, arg, &paths::INTO_ITERATOR) => { + "into_iter" if is_trait_method(cx, arg, sym::IntoIterator) => { let receiver_ty = cx.typeck_results().expr_ty(self_arg); let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); let ref_receiver_ty = cx.tcx.mk_ref( @@ -55,7 +55,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(e); is_iterable_array(ty, cx) || is_type_diagnostic_item(cx, ty, sym::vec_type) || - match_type(cx, ty, &paths::LINKED_LIST) || + is_type_diagnostic_item(cx, ty, sym::LinkedList) || is_type_diagnostic_item(cx, ty, sym::hashmap_type) || is_type_diagnostic_item(cx, ty, sym::hashset_type) || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index de73af8bf60..e4f6aae7f82 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1794,7 +1794,7 @@ mod redundant_pattern_match { || is_type_diagnostic_item(cx, ty, sym::Arc) || is_type_diagnostic_item(cx, ty, sym::cstring_type) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) - || match_type(cx, ty, &paths::LINKED_LIST) + || is_type_diagnostic_item(cx, ty, sym::LinkedList) || match_type(cx, ty, &paths::WEAK_RC) || match_type(cx, ty, &paths::WEAK_ARC) { diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index f8a38e67d00..b69f57f50e0 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -1,8 +1,7 @@ use super::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -26,7 +25,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E "BTreeMap" } else if is_type_diagnostic_item(cx, ty, sym::BTreeSet) { "BTreeSet" - } else if match_type(cx, ty, &paths::LINKED_LIST) { + } else if is_type_diagnostic_item(cx, ty, sym::LinkedList) { "LinkedList" } else if is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { "BinaryHeap" diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index dba3b1805cd..b15447622a8 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; -use clippy_utils::{expr_path_res, is_lint_allowed, match_any_def_paths, paths}; +use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ @@ -419,7 +419,7 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::Call(pathexp, []) = expr.kind { expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| { - match_any_def_paths(cx, id, &[&paths::PTR_NULL, &paths::PTR_NULL_MUT]).is_some() + match_any_diagnostic_items(cx, id, &[sym::ptr_null, sym::ptr_null_mut]).is_some() }) } else { false diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index b57d158293d..5bbaeedad5f 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,12 +1,13 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_path_def_path, paths}; +use clippy_utils::{is_expr_diagnostic_item, is_expr_path_def_path, paths}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// **What it does:** Checks for transmute calls which would receive a null pointer. @@ -67,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // `std::mem::transmute(std::ptr::null::())` if_chain! { if let ExprKind::Call(func1, []) = arg.kind; - if is_expr_path_def_path(cx, func1, &paths::PTR_NULL); + if is_expr_diagnostic_item(cx, func1, sym::ptr_null); then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/types/linked_list.rs b/clippy_lints/src/types/linked_list.rs index a9fbe7aa315..5fb708741e5 100644 --- a/clippy_lints/src/types/linked_list.rs +++ b/clippy_lints/src/types/linked_list.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{match_def_path, paths}; use rustc_hir::{self as hir, def_id::DefId}; use rustc_lint::LateContext; +use rustc_span::symbol::sym; use super::LINKEDLIST; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, def_id: DefId) -> bool { - if match_def_path(cx, def_id, &paths::LINKED_LIST) { + if cx.tcx.is_diagnostic_item(sym::LinkedList, def_id) { span_lint_and_help( cx, LINKEDLIST, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c97f7e1626e..a4bc8c09f53 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths}; +use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(name, .., args, _) => { - if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" { + if is_trait_method(cx, e, sym::into_trait) && &*name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); if same_type_and_consts(a, b) { @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if match_trait_method(cx, e, &paths::INTO_ITERATOR) && name.ident.name == sym::into_iter { + if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter { if let Some(parent_expr) = get_parent_expr(cx, e) { if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind { if parent_name.ident.name != sym::into_iter { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 364ae536ecd..b19d1430b6e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -411,12 +411,22 @@ pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, } /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. +/// +/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item. pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { expr_path_res(cx, expr) .opt_def_id() .map_or(false, |id| match_def_path(cx, id, segments)) } +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given +/// diagnostic item. +pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { + expr_path_res(cx, expr) + .opt_def_id() + .map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) +} + /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. @@ -1249,6 +1259,8 @@ pub fn match_function_call<'tcx>( /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if /// any. +/// +/// Please use `match_any_diagnostic_items` if the targets are all diagnostic items. pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option { let search_path = cx.get_def_path(did); paths @@ -1256,6 +1268,14 @@ pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied())) } +/// Checks if the given `DefId` matches any of provided diagnostic items. Returns the index of +/// matching path, if any. +pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option { + diag_items + .iter() + .position(|item| cx.tcx.is_diagnostic_item(*item, def_id)) +} + /// Checks if the given `DefId` matches the path. pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { // We should probably move to Symbols in Clippy as well rather than interning every time. diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 3acde01b8c9..e9e371e3e3e 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -73,8 +73,6 @@ pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; -pub const INTO: [&str; 3] = ["core", "convert", "Into"]; -pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; @@ -85,6 +83,7 @@ pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; #[cfg(feature = "internal-lints")] pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LIBC_STRLEN: [&str; 2] = ["libc", "strlen"]; +/// Preferably use the diagnostic item `sym::LinkedList` where possible pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"]; #[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; @@ -99,6 +98,7 @@ pub const MEM_SIZE_OF_VAL: [&str; 3] = ["core", "mem", "size_of_val"]; pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; +/// Preferably use the diagnostic item `sym::option_type` where possible pub const OPTION: [&str; 3] = ["core", "option", "Option"]; pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"]; pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"]; @@ -122,8 +122,6 @@ pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; -pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"]; -pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"]; pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"]; pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"]; pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"]; -- cgit 1.4.1-3-g733a5 From 12c61612f7a91df64121dd9c991828c26d665325 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 2 Jul 2021 20:37:11 +0200 Subject: Update lint documentation to use markdown headlines --- clippy_dev/src/new_lint.rs | 9 +- clippy_lints/src/absurd_extreme_comparisons.rs | 12 +- clippy_lints/src/approx_const.rs | 10 +- clippy_lints/src/arithmetic.rs | 20 +- clippy_lints/src/as_conversions.rs | 10 +- clippy_lints/src/asm_syntax.rs | 20 +- clippy_lints/src/assertions_on_constants.rs | 11 +- clippy_lints/src/assign_ops.rs | 22 +- clippy_lints/src/async_yields_async.rs | 11 +- clippy_lints/src/atomic_ordering.rs | 10 +- clippy_lints/src/attrs.rs | 74 +-- clippy_lints/src/await_holding_invalid.rs | 24 +- clippy_lints/src/bit_mask.rs | 32 +- clippy_lints/src/blacklisted_name.rs | 10 +- clippy_lints/src/blocks_in_if_conditions.rs | 10 +- clippy_lints/src/bool_assert_comparison.rs | 11 +- clippy_lints/src/booleans.rs | 22 +- clippy_lints/src/bytecount.rs | 12 +- clippy_lints/src/cargo_common_metadata.rs | 10 +- .../case_sensitive_file_extension_comparisons.rs | 9 +- clippy_lints/src/casts/mod.rs | 116 ++-- clippy_lints/src/checked_conversions.rs | 10 +- clippy_lints/src/cognitive_complexity.rs | 12 +- clippy_lints/src/collapsible_if.rs | 20 +- clippy_lints/src/collapsible_match.rs | 11 +- clippy_lints/src/comparison_chain.rs | 11 +- clippy_lints/src/copies.rs | 40 +- clippy_lints/src/copy_iterator.rs | 10 +- clippy_lints/src/create_dir.rs | 10 +- clippy_lints/src/dbg_macro.rs | 10 +- clippy_lints/src/default.rs | 21 +- clippy_lints/src/default_numeric_fallback.rs | 11 +- clippy_lints/src/deprecated_lints.rs | 96 ++-- clippy_lints/src/dereference.rs | 8 +- clippy_lints/src/derive.rs | 43 +- clippy_lints/src/disallowed_method.rs | 11 +- clippy_lints/src/disallowed_script_idents.rs | 10 +- clippy_lints/src/disallowed_type.rs | 11 +- clippy_lints/src/doc.rs | 53 +- clippy_lints/src/double_comparison.rs | 10 +- clippy_lints/src/double_parens.rs | 10 +- clippy_lints/src/drop_forget_ref.rs | 40 +- clippy_lints/src/duration_subsec.rs | 10 +- clippy_lints/src/else_if_without_else.rs | 10 +- clippy_lints/src/empty_enum.rs | 11 +- clippy_lints/src/entry.rs | 11 +- clippy_lints/src/enum_clike.rs | 10 +- clippy_lints/src/enum_variants.rs | 30 +- clippy_lints/src/eq_op.rs | 22 +- clippy_lints/src/erasing_op.rs | 10 +- clippy_lints/src/escape.rs | 10 +- clippy_lints/src/eta_reduction.rs | 22 +- clippy_lints/src/eval_order_dependence.rs | 22 +- clippy_lints/src/excessive_bools.rs | 20 +- clippy_lints/src/exhaustive_items.rs | 22 +- clippy_lints/src/exit.rs | 10 +- clippy_lints/src/explicit_write.rs | 10 +- clippy_lints/src/fallible_impl_from.rs | 10 +- clippy_lints/src/float_equality_without_abs.rs | 50 +- clippy_lints/src/float_literal.rs | 22 +- clippy_lints/src/floating_point_arithmetic.rs | 22 +- clippy_lints/src/format.rs | 10 +- clippy_lints/src/formatting.rs | 40 +- clippy_lints/src/from_over_into.rs | 11 +- clippy_lints/src/from_str_radix_10.rs | 12 +- clippy_lints/src/functions/mod.rs | 73 +-- clippy_lints/src/future_not_send.rs | 11 +- clippy_lints/src/get_last_with_len.rs | 11 +- clippy_lints/src/identity_op.rs | 10 +- clippy_lints/src/if_let_mutex.rs | 11 +- clippy_lints/src/if_let_some_result.rs | 10 +- clippy_lints/src/if_not_else.rs | 10 +- clippy_lints/src/if_then_some_else_none.rs | 11 +- clippy_lints/src/implicit_hasher.rs | 11 +- clippy_lints/src/implicit_return.rs | 10 +- clippy_lints/src/implicit_saturating_sub.rs | 11 +- .../src/inconsistent_struct_constructor.rs | 11 +- clippy_lints/src/indexing_slicing.rs | 22 +- clippy_lints/src/infinite_iter.rs | 21 +- clippy_lints/src/inherent_impl.rs | 10 +- clippy_lints/src/inherent_to_string.rs | 24 +- clippy_lints/src/inline_fn_without_body.rs | 10 +- clippy_lints/src/int_plus_one.rs | 10 +- clippy_lints/src/integer_division.rs | 10 +- clippy_lints/src/invalid_upcast_comparisons.rs | 10 +- clippy_lints/src/items_after_statements.rs | 10 +- clippy_lints/src/large_const_arrays.rs | 10 +- clippy_lints/src/large_enum_variant.rs | 12 +- clippy_lints/src/large_stack_arrays.rs | 10 +- clippy_lints/src/len_zero.rs | 30 +- clippy_lints/src/let_if_seq.rs | 10 +- clippy_lints/src/let_underscore.rs | 30 +- clippy_lints/src/lib.rs | 11 +- clippy_lints/src/lifetimes.rs | 20 +- clippy_lints/src/literal_representation.rs | 66 +-- clippy_lints/src/loops/mod.rs | 182 +++--- clippy_lints/src/macro_use.rs | 10 +- clippy_lints/src/main_recursion.rs | 10 +- clippy_lints/src/manual_async_fn.rs | 11 +- clippy_lints/src/manual_map.rs | 11 +- clippy_lints/src/manual_non_exhaustive.rs | 11 +- clippy_lints/src/manual_ok_or.rs | 10 +- clippy_lints/src/manual_strip.rs | 10 +- clippy_lints/src/manual_unwrap_or.rs | 8 +- clippy_lints/src/map_clone.rs | 11 +- clippy_lints/src/map_err_ignore.rs | 10 +- clippy_lints/src/map_unit_fn.rs | 22 +- clippy_lints/src/match_on_vec_items.rs | 10 +- clippy_lints/src/matches.rs | 170 +++--- clippy_lints/src/mem_discriminant.rs | 10 +- clippy_lints/src/mem_forget.rs | 10 +- clippy_lints/src/mem_replace.rs | 31 +- clippy_lints/src/methods/mod.rs | 636 +++++++++++---------- clippy_lints/src/minmax.rs | 10 +- clippy_lints/src/misc.rs | 93 +-- clippy_lints/src/misc_early/mod.rs | 90 +-- clippy_lints/src/missing_const_for_fn.rs | 12 +- clippy_lints/src/missing_doc.rs | 8 +- clippy_lints/src/missing_enforced_import_rename.rs | 11 +- clippy_lints/src/missing_inline.rs | 10 +- clippy_lints/src/modulo_arithmetic.rs | 10 +- clippy_lints/src/multiple_crate_versions.rs | 11 +- clippy_lints/src/mut_key.rs | 11 +- clippy_lints/src/mut_mut.rs | 10 +- clippy_lints/src/mut_mutex_lock.rs | 11 +- clippy_lints/src/mut_reference.rs | 10 +- clippy_lints/src/mutable_debug_assertion.rs | 10 +- clippy_lints/src/mutex_atomic.rs | 22 +- clippy_lints/src/needless_arbitrary_self_type.rs | 10 +- clippy_lints/src/needless_bitwise_bool.rs | 9 +- clippy_lints/src/needless_bool.rs | 21 +- clippy_lints/src/needless_borrow.rs | 20 +- clippy_lints/src/needless_borrowed_ref.rs | 11 +- clippy_lints/src/needless_continue.rs | 10 +- clippy_lints/src/needless_for_each.rs | 11 +- clippy_lints/src/needless_pass_by_value.rs | 10 +- clippy_lints/src/needless_question_mark.rs | 10 +- clippy_lints/src/needless_update.rs | 10 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 9 +- clippy_lints/src/neg_multiply.rs | 11 +- clippy_lints/src/new_without_default.rs | 11 +- clippy_lints/src/no_effect.rs | 20 +- clippy_lints/src/non_copy_const.rs | 22 +- clippy_lints/src/non_expressive_names.rs | 30 +- clippy_lints/src/non_octal_unix_permissions.rs | 11 +- clippy_lints/src/nonstandard_macro_braces.rs | 12 +- clippy_lints/src/open_options.rs | 10 +- clippy_lints/src/option_env_unwrap.rs | 11 +- clippy_lints/src/option_if_let_else.rs | 9 +- clippy_lints/src/overflow_check_conditional.rs | 10 +- clippy_lints/src/panic_in_result_fn.rs | 12 +- clippy_lints/src/panic_unimplemented.rs | 40 +- clippy_lints/src/partialeq_ne_impl.rs | 10 +- clippy_lints/src/pass_by_ref_or_value.rs | 20 +- clippy_lints/src/path_buf_push_overwrite.rs | 10 +- clippy_lints/src/pattern_type_mismatch.rs | 11 +- clippy_lints/src/precedence.rs | 10 +- clippy_lints/src/ptr.rs | 42 +- clippy_lints/src/ptr_eq.rs | 11 +- clippy_lints/src/ptr_offset_with_cast.rs | 10 +- clippy_lints/src/question_mark.rs | 10 +- clippy_lints/src/ranges.rs | 54 +- clippy_lints/src/redundant_clone.rs | 11 +- clippy_lints/src/redundant_closure_call.rs | 10 +- clippy_lints/src/redundant_else.rs | 12 +- clippy_lints/src/redundant_field_names.rs | 10 +- clippy_lints/src/redundant_pub_crate.rs | 11 +- clippy_lints/src/redundant_slicing.rs | 12 +- clippy_lints/src/redundant_static_lifetimes.rs | 10 +- clippy_lints/src/ref_option_ref.rs | 12 +- clippy_lints/src/reference.rs | 19 +- clippy_lints/src/regex.rs | 21 +- clippy_lints/src/repeat_once.rs | 11 +- clippy_lints/src/returns.rs | 20 +- clippy_lints/src/self_assignment.rs | 12 +- clippy_lints/src/self_named_constructor.rs | 11 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 11 +- clippy_lints/src/serde_api.rs | 11 +- clippy_lints/src/shadow.rs | 33 +- clippy_lints/src/single_component_path_imports.rs | 11 +- clippy_lints/src/size_of_in_element_count.rs | 10 +- clippy_lints/src/slow_vector_initialization.rs | 10 +- clippy_lints/src/stable_sort_primitive.rs | 10 +- clippy_lints/src/strings.rs | 63 +- clippy_lints/src/strlen_on_c_strings.rs | 11 +- clippy_lints/src/suspicious_operation_groupings.rs | 11 +- clippy_lints/src/suspicious_trait_impl.rs | 20 +- clippy_lints/src/swap.rs | 20 +- clippy_lints/src/tabs_in_doc_comments.rs | 10 +- clippy_lints/src/temporary_assignment.rs | 10 +- clippy_lints/src/to_digit_is_some.rs | 8 +- clippy_lints/src/to_string_in_display.rs | 10 +- clippy_lints/src/trait_bounds.rs | 20 +- clippy_lints/src/transmute/mod.rs | 122 ++-- clippy_lints/src/transmuting_null.rs | 11 +- clippy_lints/src/try_err.rs | 10 +- clippy_lints/src/types/mod.rs | 94 +-- clippy_lints/src/undropped_manually_drops.rs | 12 +- clippy_lints/src/unicode.rs | 32 +- clippy_lints/src/unit_return_expecting_ord.rs | 12 +- clippy_lints/src/unit_types/mod.rs | 30 +- clippy_lints/src/unnamed_address.rs | 22 +- clippy_lints/src/unnecessary_self_imports.rs | 12 +- clippy_lints/src/unnecessary_sort_by.rs | 9 +- clippy_lints/src/unnecessary_wraps.rs | 12 +- clippy_lints/src/unnested_or_patterns.rs | 11 +- clippy_lints/src/unsafe_removed_from_name.rs | 10 +- clippy_lints/src/unused_async.rs | 11 +- clippy_lints/src/unused_io_amount.rs | 11 +- clippy_lints/src/unused_self.rs | 10 +- clippy_lints/src/unused_unit.rs | 10 +- clippy_lints/src/unwrap.rs | 21 +- clippy_lints/src/unwrap_in_result.rs | 11 +- clippy_lints/src/upper_case_acronyms.rs | 12 +- clippy_lints/src/use_self.rs | 11 +- clippy_lints/src/useless_conversion.rs | 11 +- clippy_lints/src/utils/author.rs | 5 +- clippy_lints/src/utils/inspector.rs | 5 +- clippy_lints/src/utils/internal_lints.rs | 109 ++-- .../src/utils/internal_lints/metadata_collector.rs | 16 +- clippy_lints/src/vec.rs | 10 +- clippy_lints/src/vec_init_then_push.rs | 11 +- clippy_lints/src/vec_resize_to_zero.rs | 10 +- clippy_lints/src/verbose_file_reads.rs | 11 +- clippy_lints/src/wildcard_dependencies.rs | 11 +- clippy_lints/src/wildcard_imports.rs | 26 +- clippy_lints/src/write.rs | 92 +-- clippy_lints/src/zero_div_zero.rs | 10 +- clippy_lints/src/zero_sized_map_values.rs | 11 +- doc/adding_lints.md | 20 +- 230 files changed, 2717 insertions(+), 2474 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 4676c2affad..3a81aaba6de 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -169,14 +169,11 @@ use rustc_session::{{declare_lint_pass, declare_tool_lint}}; {pass_import} declare_clippy_lint! {{ - /// **What it does:** + /// ### What it does /// - /// **Why is this bad?** - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? /// + /// ### Example /// ```rust /// // example code where clippy issues a warning /// ``` diff --git a/clippy_lints/src/absurd_extreme_comparisons.rs b/clippy_lints/src/absurd_extreme_comparisons.rs index 49d4350123f..1483f3f9185 100644 --- a/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/absurd_extreme_comparisons.rs @@ -11,24 +11,26 @@ use clippy_utils::ty::is_isize_or_usize; use clippy_utils::{clip, int_bits, unsext}; declare_clippy_lint! { - /// **What it does:** Checks for comparisons where one side of the relation is + /// ### What it does + /// Checks for comparisons where one side of the relation is /// either the minimum or maximum value for its type and warns if it involves a /// case that is always true or always false. Only integer and boolean types are /// checked. /// - /// **Why is this bad?** An expression like `min <= x` may misleadingly imply + /// ### Why is this bad? + /// An expression like `min <= x` may misleadingly imply /// that it is possible for `x` to be less than the minimum. Expressions like /// `max < x` are probably mistakes. /// - /// **Known problems:** For `usize` the size of the current compile target will + /// ### Known problems + /// For `usize` the size of the current compile target will /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such /// a comparison to detect target pointer width will trigger this lint. One can /// use `mem::sizeof` and compare its value or conditional compilation /// attributes /// like `#[cfg(target_pointer_width = "64")] ..` instead. /// - /// **Example:** - /// + /// ### Example /// ```rust /// let vec: Vec = Vec::new(); /// if vec.len() <= 0 {} diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 3d04abe094d..6100f4e435a 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -7,21 +7,21 @@ use rustc_span::symbol; use std::f64::consts as f64; declare_clippy_lint! { - /// **What it does:** Checks for floating point literals that approximate + /// ### What it does + /// Checks for floating point literals that approximate /// constants which are defined in /// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) /// or /// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), /// respectively, suggesting to use the predefined constant. /// - /// **Why is this bad?** Usually, the definition in the standard library is more + /// ### Why is this bad? + /// Usually, the definition in the standard library is more /// precise than what people come up with. If you find that your definition is /// actually more precise, please [file a Rust /// issue](https://github.com/rust-lang/rust/issues). /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = 3.14; /// let y = 1_f64 / x; diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 24c2a972811..36fe7b7a867 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -6,7 +6,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for integer arithmetic operations which could overflow or panic. + /// ### What it does + /// Checks for integer arithmetic operations which could overflow or panic. /// /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable /// of overflowing according to the [Rust @@ -14,13 +15,12 @@ declare_clippy_lint! { /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is /// attempted. /// - /// **Why is this bad?** Integer overflow will trigger a panic in debug builds or will wrap in + /// ### Why is this bad? + /// Integer overflow will trigger a panic in debug builds or will wrap in /// release mode. Division by zero will cause a panic in either mode. In some applications one /// wants explicitly checked, wrapping or saturating arithmetic. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let a = 0; /// a + 1; @@ -31,14 +31,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for float arithmetic. + /// ### What it does + /// Checks for float arithmetic. /// - /// **Why is this bad?** For some embedded systems or kernel development, it + /// ### Why is this bad? + /// For some embedded systems or kernel development, it /// can be useful to rule out floating-point numbers. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let a = 0.0; /// a + 1.0; diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 4b31e16094e..7c39a3e2ce3 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -5,7 +5,8 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `as` conversions. + /// ### What it does + /// Checks for usage of `as` conversions. /// /// Note that this lint is specialized in linting *every single* use of `as` /// regardless of whether good alternatives exist or not. @@ -15,14 +16,13 @@ declare_clippy_lint! { /// There is a good explanation the reason why this lint should work in this way and how it is useful /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). /// - /// **Why is this bad?** `as` conversions will perform many kinds of + /// ### Why is this bad? + /// `as` conversions will perform many kinds of /// conversions, including silently lossy conversions and dangerous coercions. /// There are cases when it makes sense to use `as`, so the lint is /// Allow by default. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// let a: u32; /// ... diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index b970c71b753..825832eb79d 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -53,14 +53,14 @@ fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr } declare_clippy_lint! { - /// **What it does:** Checks for usage of Intel x86 assembly syntax. + /// ### What it does + /// Checks for usage of Intel x86 assembly syntax. /// - /// **Why is this bad?** The lint has been enabled to indicate a preference + /// ### Why is this bad? + /// The lint has been enabled to indicate a preference /// for AT&T x86 assembly syntax. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```rust,no_run /// # #![feature(asm)] @@ -89,14 +89,14 @@ impl EarlyLintPass for InlineAsmX86IntelSyntax { } declare_clippy_lint! { - /// **What it does:** Checks for usage of AT&T x86 assembly syntax. + /// ### What it does + /// Checks for usage of AT&T x86 assembly syntax. /// - /// **Why is this bad?** The lint has been enabled to indicate a preference + /// ### Why is this bad? + /// The lint has been enabled to indicate a preference /// for Intel x86 assembly syntax. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```rust,no_run /// # #![feature(asm)] diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 5235b2642d1..cb9347a923d 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -8,14 +8,17 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls. + /// ### What it does + /// Checks for `assert!(true)` and `assert!(false)` calls. /// - /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a + /// ### Why is this bad? + /// Will be optimized out by the compiler or should probably be replaced by a /// `panic!()` or `unreachable!()` /// - /// **Known problems:** None + /// ### Known problems + /// None /// - /// **Example:** + /// ### Example /// ```rust,ignore /// assert!(false) /// assert!(true) diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 17ce3cd809f..2097a1feff9 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -12,15 +12,18 @@ use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a` + /// ### What it does + /// Checks for `a = a op b` or `a = b commutative_op a` /// patterns. /// - /// **Why is this bad?** These can be written as the shorter `a op= b`. + /// ### Why is this bad? + /// These can be written as the shorter `a op= b`. /// - /// **Known problems:** While forbidden by the spec, `OpAssign` traits may have + /// ### Known problems + /// While forbidden by the spec, `OpAssign` traits may have /// implementations that differ from the regular `Op` impl. /// - /// **Example:** + /// ### Example /// ```rust /// let mut a = 5; /// let b = 0; @@ -37,17 +40,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns. + /// ### What it does + /// Checks for `a op= a op b` or `a op= b op a` patterns. /// - /// **Why is this bad?** Most likely these are bugs where one meant to write `a + /// ### Why is this bad? + /// Most likely these are bugs where one meant to write `a /// op= b`. /// - /// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have + /// ### Known problems + /// Clippy cannot know for sure if `a op= a op b` should have /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. /// If `a op= a op b` is really the correct behaviour it should be /// written as `a = a op a op b` as it's less confusing. /// - /// **Example:** + /// ### Example /// ```rust /// let mut a = 5; /// let b = 2; diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index e6c7c68f91a..182736a5a20 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -7,15 +7,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for async blocks that yield values of types + /// ### What it does + /// Checks for async blocks that yield values of types /// that can themselves be awaited. /// - /// **Why is this bad?** An await is likely missing. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// An await is likely missing. /// + /// ### Example /// ```rust /// async fn foo() {} /// diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 7ceb01f5590..cece28e8b3c 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -8,16 +8,16 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usage of invalid atomic + /// ### What it does + /// Checks for usage of invalid atomic /// ordering in atomic loads/stores/exchanges/updates and /// memory fences. /// - /// **Why is this bad?** Using an invalid atomic ordering + /// ### Why is this bad? + /// Using an invalid atomic ordering /// will cause a panic at run-time. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,no_run /// # use std::sync::atomic::{self, AtomicU8, Ordering}; /// diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index f272ed010a1..c9ff468874b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -41,10 +41,12 @@ static UNIX_SYSTEMS: &[&str] = &[ static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"]; declare_clippy_lint! { - /// **What it does:** Checks for items annotated with `#[inline(always)]`, + /// ### What it does + /// Checks for items annotated with `#[inline(always)]`, /// unless the annotated function is empty or simply panics. /// - /// **Why is this bad?** While there are valid uses of this annotation (and once + /// ### Why is this bad? + /// While there are valid uses of this annotation (and once /// you know when to use it, by all means `allow` this lint), it's a common /// newbie-mistake to pepper one's code with it. /// @@ -52,11 +54,12 @@ declare_clippy_lint! { /// measure if that additional function call really affects your runtime profile /// sufficiently to make up for the increase in compile time. /// - /// **Known problems:** False positives, big time. This lint is meant to be + /// ### Known problems + /// False positives, big time. This lint is meant to be /// deactivated by everyone doing serious performance work. This means having /// done the measurement. /// - /// **Example:** + /// ### Example /// ```ignore /// #[inline(always)] /// fn not_quite_hot_code(..) { ... } @@ -67,7 +70,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `extern crate` and `use` items annotated with + /// ### What it does + /// Checks for `extern crate` and `use` items annotated with /// lint attributes. /// /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, @@ -75,12 +79,11 @@ declare_clippy_lint! { /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on /// `extern crate` items with a `#[macro_use]` attribute. /// - /// **Why is this bad?** Lint attributes have no effect on crate imports. Most + /// ### Why is this bad? + /// Lint attributes have no effect on crate imports. Most /// likely a `!` was forgotten. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// // Bad /// #[deny(dead_code)] @@ -101,15 +104,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `#[deprecated]` annotations with a `since` + /// ### What it does + /// Checks for `#[deprecated]` annotations with a `since` /// field that is not a valid semantic version. /// - /// **Why is this bad?** For checking the version of the deprecation, it must be + /// ### Why is this bad? + /// For checking the version of the deprecation, it must be /// a valid semver. Failing that, the contained information is useless. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// #[deprecated(since = "forever")] /// fn something_else() { /* ... */ } @@ -120,20 +123,22 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for empty lines after outer attributes + /// ### What it does + /// Checks for empty lines after outer attributes /// - /// **Why is this bad?** + /// ### Why is this bad? /// Most likely the attribute was meant to be an inner attribute using a '!'. /// If it was meant to be an outer attribute, then the following item /// should not be separated by empty lines. /// - /// **Known problems:** Can cause false positives. + /// ### Known problems + /// Can cause false positives. /// /// From the clippy side it's difficult to detect empty lines between an attributes and the /// following item because empty lines and comments are not part of the AST. The parsing /// currently works for basic cases but is not perfect. /// - /// **Example:** + /// ### Example /// ```rust /// // Good (as inner attribute) /// #![allow(dead_code)] @@ -155,14 +160,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. + /// ### What it does + /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. /// - /// **Why is this bad?** Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. + /// ### Why is this bad? + /// Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust /// #![deny(clippy::restriction)] @@ -178,18 +183,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it + /// ### What it does + /// Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it /// with `#[rustfmt::skip]`. /// - /// **Why is this bad?** Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) + /// ### Why is this bad? + /// Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) /// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. /// - /// **Known problems:** This lint doesn't detect crate level inner attributes, because they get + /// ### Known problems + /// This lint doesn't detect crate level inner attributes, because they get /// processed before the PreExpansionPass lints get executed. See /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) /// - /// **Example:** - /// + /// ### Example /// Bad: /// ```rust /// #[cfg_attr(rustfmt, rustfmt_skip)] @@ -207,15 +214,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for cfg attributes having operating systems used in target family position. + /// ### What it does + /// Checks for cfg attributes having operating systems used in target family position. /// - /// **Why is this bad?** The configuration option will not be recognised and the related item will not be included + /// ### Why is this bad? + /// The configuration option will not be recognised and the related item will not be included /// by the conditional compilation engine. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// Bad: /// ```rust /// #[cfg(linux)] diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 1739a57a240..0cc79c8b6e8 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -8,10 +8,12 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for calls to await while holding a + /// ### What it does + /// Checks for calls to await while holding a /// non-async-aware MutexGuard. /// - /// **Why is this bad?** The Mutex types found in std::sync and parking_lot + /// ### Why is this bad? + /// The Mutex types found in std::sync and parking_lot /// are not designed to operate in an async context across await points. /// /// There are two potential solutions. One is to use an asynx-aware Mutex @@ -19,10 +21,10 @@ declare_clippy_lint! { /// other solution is to ensure the mutex is unlocked before calling await, /// either by introducing a scope or an explicit call to Drop::drop. /// - /// **Known problems:** Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). - /// - /// **Example:** + /// ### Known problems + /// Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). /// + /// ### Example /// ```rust,ignore /// use std::sync::Mutex; /// @@ -51,17 +53,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to await while holding a + /// ### What it does + /// Checks for calls to await while holding a /// `RefCell` `Ref` or `RefMut`. /// - /// **Why is this bad?** `RefCell` refs only check for exclusive mutable access + /// ### Why is this bad? + /// `RefCell` refs only check for exclusive mutable access /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point /// risks panics from a mutable ref shared while other refs are outstanding. /// - /// **Known problems:** Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). - /// - /// **Example:** + /// ### Known problems + /// Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). /// + /// ### Example /// ```rust,ignore /// use std::cell::RefCell; /// diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 991ed94572c..11346e7c96a 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -10,7 +10,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for incompatible bit masks in comparisons. + /// ### What it does + /// Checks for incompatible bit masks in comparisons. /// /// The formula for detecting if an expression of the type `_ m /// c` (where `` is one of {`&`, `|`} and `` is one of @@ -26,7 +27,8 @@ declare_clippy_lint! { /// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | /// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | /// - /// **Why is this bad?** If the bits that the comparison cares about are always + /// ### Why is this bad? + /// If the bits that the comparison cares about are always /// set to zero or one by the bit mask, the comparison is constant `true` or /// `false` (depending on mask, compared value, and operators). /// @@ -34,9 +36,7 @@ declare_clippy_lint! { /// this intentionally is to win an underhanded Rust contest or create a /// test-case for this lint. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// if (x & 1 == 2) { } @@ -47,7 +47,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for bit masks in comparisons which can be removed + /// ### What it does + /// Checks for bit masks in comparisons which can be removed /// without changing the outcome. The basic structure can be seen in the /// following table: /// @@ -56,16 +57,18 @@ declare_clippy_lint! { /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`| /// - /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask), + /// ### Why is this bad? + /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask), /// but still a bit misleading, because the bit mask is ineffective. /// - /// **Known problems:** False negatives: This lint will only match instances + /// ### Known problems + /// False negatives: This lint will only match instances /// where we have figured out the math (which is for a power-of-two compared /// value). This means things like `x | 1 >= 7` (which would be better written /// as `x >= 6`) will not be reported (but bit masks like this are fairly /// uncommon). /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// if (x | 1 > 3) { } @@ -76,15 +79,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for bit masks that can be replaced by a call + /// ### What it does + /// Checks for bit masks that can be replaced by a call /// to `trailing_zeros` /// - /// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15 + /// ### Why is this bad? + /// `x.trailing_zeros() > 4` is much clearer than `x & 15 /// == 0` /// - /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86 + /// ### Known problems + /// llvm generates better code for `x & 15 == 0` on x86 /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// if x & 0b1111 == 0 { } diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 8eb94f3c28e..916c78c982a 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -5,15 +5,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for usage of blacklisted names for variables, such + /// ### What it does + /// Checks for usage of blacklisted names for variables, such /// as `foo`. /// - /// **Why is this bad?** These names are usually placeholder names and should be + /// ### Why is this bad? + /// These names are usually placeholder names and should be /// avoided. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let foo = 3.14; /// ``` diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index badcf8d2a43..9b2e4f8998e 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -13,14 +13,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `if` conditions that use blocks containing an + /// ### What it does + /// Checks for `if` conditions that use blocks containing an /// expression, statements or conditions that use closures with blocks. /// - /// **Why is this bad?** Style, using blocks in the condition makes it hard to read. + /// ### Why is this bad? + /// Style, using blocks in the condition makes it hard to read. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust /// // Bad /// if { true } { /* ... */ } diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index bee706ed402..8d3f68565b2 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -6,14 +6,13 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** This lint warns about boolean comparisons in assert-like macros. + /// ### What it does + /// This lint warns about boolean comparisons in assert-like macros. /// - /// **Why is this bad?** It is shorter to use the equivalent. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// It is shorter to use the equivalent. /// + /// ### Example /// ```rust /// // Bad /// assert_eq!("a".is_empty(), false); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index e72399af232..4a83d35a568 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -14,16 +14,19 @@ use rustc_span::source_map::Span; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for boolean expressions that can be written more + /// ### What it does + /// Checks for boolean expressions that can be written more /// concisely. /// - /// **Why is this bad?** Readability of boolean expressions suffers from + /// ### Why is this bad? + /// Readability of boolean expressions suffers from /// unnecessary duplication. /// - /// **Known problems:** Ignores short circuiting behavior of `||` and + /// ### Known problems + /// Ignores short circuiting behavior of `||` and /// `&&`. Ignores `|`, `&` and `^`. /// - /// **Example:** + /// ### Example /// ```ignore /// if a && true // should be: if a /// if !(a == b) // should be: if a != b @@ -34,14 +37,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for boolean expressions that contain terminals that + /// ### What it does + /// Checks for boolean expressions that contain terminals that /// can be eliminated. /// - /// **Why is this bad?** This is most likely a logic bug. + /// ### Why is this bad? + /// This is most likely a logic bug. /// - /// **Known problems:** Ignores short circuiting behavior. + /// ### Known problems + /// Ignores short circuiting behavior. /// - /// **Example:** + /// ### Example /// ```ignore /// if a && b || a { ... } /// ``` diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 4f7ffdcdfb4..c444984bc13 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -12,18 +12,20 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for naive byte counts + /// ### What it does + /// Checks for naive byte counts /// - /// **Why is this bad?** The [`bytecount`](https://crates.io/crates/bytecount) + /// ### Why is this bad? + /// The [`bytecount`](https://crates.io/crates/bytecount) /// crate has methods to count your bytes faster, especially for large slices. /// - /// **Known problems:** If you have predominantly small slices, the + /// ### Known problems + /// If you have predominantly small slices, the /// `bytecount::count(..)` method may actually be slower. However, if you can /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be /// faster in those cases. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # let vec = vec![1_u8]; /// &vec.iter().filter(|x| **x == 0u8).count(); // use bytecount::count instead diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 21c7b2448ce..bd5426ba707 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -9,15 +9,15 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::DUMMY_SP; declare_clippy_lint! { - /// **What it does:** Checks to see if all common metadata is defined in + /// ### What it does + /// Checks to see if all common metadata is defined in /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata /// - /// **Why is this bad?** It will be more difficult for users to discover the + /// ### Why is this bad? + /// It will be more difficult for users to discover the /// purpose of the crate, and key information related to it. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```toml /// # This `Cargo.toml` is missing a description field: /// [package] diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index c9ef379be56..86b32475ceb 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -8,17 +8,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{source_map::Spanned, symbol::sym, Span}; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks for calls to `ends_with` with possible file extensions /// and suggests to use a case-insensitive approach instead. /// - /// **Why is this bad?** + /// ### Why is this bad? /// `ends_with` is case-sensitive and may not detect files with a valid extension. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// fn is_rust_file(filename: &str) -> bool { /// filename.ends_with(".rs") diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index ae4fdd12c41..27e1bea7993 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -20,7 +20,8 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for casts from any numerical to a float type where + /// ### What it does + /// Checks for casts from any numerical to a float type where /// the receiving type cannot store all values from the original type without /// rounding errors. This possible rounding is to be expected, so this lint is /// `Allow` by default. @@ -28,13 +29,12 @@ declare_clippy_lint! { /// Basically, this warns on casting any integer with 32 or more bits to `f32` /// or any 64-bit integer to `f64`. /// - /// **Why is this bad?** It's not bad at all. But in some applications it can be + /// ### Why is this bad? + /// It's not bad at all. But in some applications it can be /// helpful to know where precision loss can take place. This lint can help find /// those places in the code. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = u64::MAX; /// x as f64; @@ -45,17 +45,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts from a signed to an unsigned numerical + /// ### What it does + /// Checks for casts from a signed to an unsigned numerical /// type. In this case, negative values wrap around to large positive values, /// which can be quite surprising in practice. However, as the cast works as /// defined, this lint is `Allow` by default. /// - /// **Why is this bad?** Possibly surprising results. You can activate this lint + /// ### Why is this bad? + /// Possibly surprising results. You can activate this lint /// as a one-time check to see where numerical wrapping can arise. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let y: i8 = -1; /// y as u128; // will return 18446744073709551615 @@ -66,17 +66,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts between numerical types that may + /// ### What it does + /// Checks for casts between numerical types that may /// truncate large values. This is expected behavior, so the cast is `Allow` by /// default. /// - /// **Why is this bad?** In some problem domains, it is good practice to avoid + /// ### Why is this bad? + /// In some problem domains, it is good practice to avoid /// truncation. This lint can be activated to help assess where additional /// checks could be beneficial. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn as_u8(x: u64) -> u8 { /// x as u8 @@ -88,20 +88,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts from an unsigned type to a signed type of + /// ### What it does + /// Checks for casts from an unsigned type to a signed type of /// the same size. Performing such a cast is a 'no-op' for the compiler, /// i.e., nothing is changed at the bit level, and the binary representation of /// the value is reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. /// - /// **Why is this bad?** While such a cast is not bad in itself, the results can + /// ### Why is this bad? + /// While such a cast is not bad in itself, the results can /// be surprising when this is not the intended behavior, as demonstrated by the /// example below. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// u32::MAX as i32; // will yield a value of `-1` /// ``` @@ -111,19 +111,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts between numerical types that may + /// ### What it does + /// Checks for casts between numerical types that may /// be replaced by safe conversion functions. /// - /// **Why is this bad?** Rust's `as` keyword will perform many kinds of + /// ### Why is this bad? + /// Rust's `as` keyword will perform many kinds of /// conversions, including silently lossy conversions. Conversion functions such /// as `i32::from` will only perform lossless conversions. Using the conversion /// functions prevents conversions from turning into silent lossy conversions if /// the types of the input expressions ever change, and make it easier for /// people reading the code to know that the conversion is lossless. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn as_u64(x: u8) -> u64 { /// x as u64 @@ -143,14 +143,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts to the same type, casts of int literals to integer types + /// ### What it does + /// Checks for casts to the same type, casts of int literals to integer types /// and casts of float literals to float types. /// - /// **Why is this bad?** It's just unnecessary. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// It's just unnecessary. /// - /// **Example:** + /// ### Example /// ```rust /// let _ = 2i32 as i32; /// let _ = 0.5 as f32; @@ -168,17 +168,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts, using `as` or `pointer::cast`, + /// ### What it does + /// Checks for casts, using `as` or `pointer::cast`, /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer /// - /// **Why is this bad?** Dereferencing the resulting pointer may be undefined + /// ### Why is this bad? + /// Dereferencing the resulting pointer may be undefined /// behavior. /// - /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar + /// ### Known problems + /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. /// - /// **Example:** + /// ### Example /// ```rust /// let _ = (&1u8 as *const u8) as *const u16; /// let _ = (&mut 1u8 as *mut u8) as *mut u16; @@ -192,9 +195,10 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts of function pointers to something other than usize + /// ### What it does + /// Checks for casts of function pointers to something other than usize /// - /// **Why is this bad?** + /// ### Why is this bad? /// Casting a function pointer to anything other than usize/isize is not portable across /// architectures, because you end up losing bits if the target type is too small or end up with a /// bunch of extra bits that waste space and add more instructions to the final binary than @@ -202,8 +206,7 @@ declare_clippy_lint! { /// /// Casting to isize also doesn't make sense since there are no signed addresses. /// - /// **Example** - /// + /// ### Example /// ```rust /// // Bad /// fn fun() -> i32 { 1 } @@ -219,16 +222,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to + /// ### What it does + /// Checks for casts of a function pointer to a numeric type not wide enough to /// store address. /// - /// **Why is this bad?** + /// ### Why is this bad? /// Such a cast discards some bits of the function's address. If this is intended, it would be more /// clearly expressed by casting to usize first, then casting the usize to the intended type (with /// a comment) to perform the truncation. /// - /// **Example** - /// + /// ### Example /// ```rust /// // Bad /// fn fn1() -> i16 { @@ -249,15 +252,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code. + /// ### What it does + /// Checks for casts of `&T` to `&mut T` anywhere in the code. /// - /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour. + /// ### Why is this bad? + /// It’s basically guaranteed to be undefined behaviour. /// `UnsafeCell` is the only way to obtain aliasable data that is considered /// mutable. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// fn x(r: &i32) { /// unsafe { @@ -283,18 +286,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for expressions where a character literal is cast + /// ### What it does + /// Checks for expressions where a character literal is cast /// to `u8` and suggests using a byte literal instead. /// - /// **Why is this bad?** In general, casting values to smaller types is + /// ### Why is this bad? + /// In general, casting values to smaller types is /// error-prone and should be avoided where possible. In the particular case of /// converting a character literal to u8, it is easy to avoid by just using a /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter /// than `'a' as u8`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// 'x' as u8 /// ``` @@ -310,18 +313,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks for `as` casts between raw pointers without changing its mutability, /// namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// - /// **Why is this bad?** + /// ### Why is this bad? /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 8d3123e1ec8..842bbf006cc 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -13,13 +13,13 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for explicit bounds checking when casting. + /// ### What it does + /// Checks for explicit bounds checking when casting. /// - /// **Why is this bad?** Reduces the readability of statements & is error prone. + /// ### Why is this bad? + /// Reduces the readability of statements & is error prone. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let foo: u32 = 5; /// # let _ = diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index f62c6a9c325..96c30d57ee1 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -14,15 +14,19 @@ use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; declare_clippy_lint! { - /// **What it does:** Checks for methods with high cognitive complexity. + /// ### What it does + /// Checks for methods with high cognitive complexity. /// - /// **Why is this bad?** Methods of high cognitive complexity tend to be hard to + /// ### Why is this bad? + /// Methods of high cognitive complexity tend to be hard to /// both read and maintain. Also LLVM will tend to optimize small methods better. /// - /// **Known problems:** Sometimes it's hard to find a way to reduce the + /// ### Known problems + /// Sometimes it's hard to find a way to reduce the /// complexity. /// - /// **Example:** No. You'll see it when you get the warning. + /// ### Example + /// No. You'll see it when you get the warning. pub COGNITIVE_COMPLEXITY, nursery, "functions that should be split up into multiple functions" diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 6e950738239..4aa87980715 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -22,15 +22,15 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for nested `if` statements which can be collapsed + /// ### What it does + /// Checks for nested `if` statements which can be collapsed /// by `&&`-combining their conditions. /// - /// **Why is this bad?** Each `if`-statement adds one level of nesting, which + /// ### Why is this bad? + /// Each `if`-statement adds one level of nesting, which /// makes code look more complex than it really is. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// if x { /// if y { @@ -53,15 +53,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for collapsible `else { if ... }` expressions + /// ### What it does + /// Checks for collapsible `else { if ... }` expressions /// that can be collapsed to `else if ...`. /// - /// **Why is this bad?** Each `if`-statement adds one level of nesting, which + /// ### Why is this bad? + /// Each `if`-statement adds one level of nesting, which /// makes code look more complex than it really is. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// /// if x { diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index a6c3a5b0e83..a403a9846ba 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -9,18 +9,17 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{MultiSpan, Span}; declare_clippy_lint! { - /// **What it does:** Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together + /// ### What it does + /// Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together /// without adding any branches. /// /// Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only /// cases where merging would most likely make the code more readable. /// - /// **Why is this bad?** It is unnecessarily verbose and complex. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// It is unnecessarily verbose and complex. /// + /// ### Example /// ```rust /// fn func(opt: Option>) { /// let n = match opt { diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index b6999bef6e7..597a3c67024 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -6,16 +6,19 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks comparison chains written with `if` that can be + /// ### What it does + /// Checks comparison chains written with `if` that can be /// rewritten with `match` and `cmp`. /// - /// **Why is this bad?** `if` is not guaranteed to be exhaustive and conditionals can get + /// ### Why is this bad? + /// `if` is not guaranteed to be exhaustive and conditionals can get /// repetitive /// - /// **Known problems:** The match statement may be slower due to the compiler + /// ### Known problems + /// The match statement may be slower due to the compiler /// not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354) /// - /// **Example:** + /// ### Example /// ```rust,ignore /// # fn a() {} /// # fn b() {} diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 9cbcde59768..2dcd5545799 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -16,13 +16,13 @@ use rustc_span::{source_map::Span, symbol::Symbol, BytePos}; use std::borrow::Cow; declare_clippy_lint! { - /// **What it does:** Checks for consecutive `if`s with the same condition. + /// ### What it does + /// Checks for consecutive `if`s with the same condition. /// - /// **Why is this bad?** This is probably a copy & paste error. + /// ### Why is this bad? + /// This is probably a copy & paste error. /// - /// **Known problems:** Hopefully none. - /// - /// **Example:** + /// ### Example /// ```ignore /// if a == b { /// … @@ -47,15 +47,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for consecutive `if`s with the same function call. + /// ### What it does + /// Checks for consecutive `if`s with the same function call. /// - /// **Why is this bad?** This is probably a copy & paste error. + /// ### Why is this bad? + /// This is probably a copy & paste error. /// Despite the fact that function can have side effects and `if` works as /// intended, such an approach is implicit and can be considered a "code smell". /// - /// **Known problems:** Hopefully none. - /// - /// **Example:** + /// ### Example /// ```ignore /// if foo() == bar { /// … @@ -94,14 +94,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `if/else` with the same body as the *then* part + /// ### What it does + /// Checks for `if/else` with the same body as the *then* part /// and the *else* part. /// - /// **Why is this bad?** This is probably a copy & paste error. - /// - /// **Known problems:** Hopefully none. + /// ### Why is this bad? + /// This is probably a copy & paste error. /// - /// **Example:** + /// ### Example /// ```ignore /// let foo = if … { /// 42 @@ -115,17 +115,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks if the `if` and `else` block contain shared code that can be + /// ### What it does + /// Checks if the `if` and `else` block contain shared code that can be /// moved out of the blocks. /// - /// **Why is this bad?** Duplicate code is less maintainable. + /// ### Why is this bad? + /// Duplicate code is less maintainable. /// - /// **Known problems:** + /// ### Known problems /// * The lint doesn't check if the moved expressions modify values that are beeing used in /// the if condition. The suggestion can in that case modify the behavior of the program. /// See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452) /// - /// **Example:** + /// ### Example /// ```ignore /// let foo = if … { /// println!("Hello World"); diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 35079c6bedc..c2e9e8b3ab7 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -8,15 +8,15 @@ use rustc_span::sym; use if_chain::if_chain; declare_clippy_lint! { - /// **What it does:** Checks for types that implement `Copy` as well as + /// ### What it does + /// Checks for types that implement `Copy` as well as /// `Iterator`. /// - /// **Why is this bad?** Implicit copies can be confusing when working with + /// ### Why is this bad? + /// Implicit copies can be confusing when working with /// iterator combinators. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// #[derive(Copy, Clone)] /// struct Countdown(u8); diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 7b5cce6462a..e4ee2772483 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -8,13 +8,13 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. + /// ### What it does + /// Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. /// - /// **Why is this bad?** Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// ### Why is this bad? + /// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```rust /// std::fs::create_dir("foo"); diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 286cc7e223e..bab4a696f83 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -8,14 +8,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for usage of dbg!() macro. + /// ### What it does + /// Checks for usage of dbg!() macro. /// - /// **Why is this bad?** `dbg!` macro is intended as a debugging tool. It + /// ### Why is this bad? + /// `dbg!` macro is intended as a debugging tool. It /// should not be in version control. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// dbg!(true) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 947479db8f5..db8f2171348 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -13,14 +13,14 @@ use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for literal calls to `Default::default()`. + /// ### What it does + /// Checks for literal calls to `Default::default()`. /// - /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is + /// ### Why is this bad? + /// It's more clear to the reader to use the name of the type whose default is /// being gotten than the generic `Default`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let s: String = Default::default(); @@ -34,14 +34,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for immediate reassignment of fields initialized + /// ### What it does + /// Checks for immediate reassignment of fields initialized /// with Default::default(). /// - /// **Why is this bad?**It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax). + /// ### Why is this bad? + ///It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax). /// - /// **Known problems:** Assignments to patterns that are of tuple type are not linted. + /// ### Known problems + /// Assignments to patterns that are of tuple type are not linted. /// - /// **Example:** + /// ### Example /// Bad: /// ``` /// # #[derive(Default)] diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index e719a1b0abf..3f1b7ea6214 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -18,7 +18,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::iter; declare_clippy_lint! { - /// **What it does:** Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type + /// ### What it does + /// Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type /// inference. /// /// Default numeric fallback means that if numeric types have not yet been bound to concrete @@ -27,12 +28,14 @@ declare_clippy_lint! { /// /// See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback. /// - /// **Why is this bad?** For those who are very careful about types, default numeric fallback + /// ### Why is this bad? + /// For those who are very careful about types, default numeric fallback /// can be a pitfall that cause unexpected runtime behavior. /// - /// **Known problems:** This lint can only be allowed at the function level or above. + /// ### Known problems + /// This lint can only be allowed at the function level or above. /// - /// **Example:** + /// ### Example /// ```rust /// let i = 10; /// let f = 1.23; diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 2933fbc9341..c604516742c 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -12,27 +12,33 @@ macro_rules! declare_deprecated_lint { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This used to check for `assert!(a == b)` and recommend + /// ### Deprecation reason + /// This used to check for `assert!(a == b)` and recommend /// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011. pub SHOULD_ASSERT_EQ, "`assert!()` will be more flexible with RFC 2011" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This used to check for `Vec::extend`, which was slower than + /// ### Deprecation reason + /// This used to check for `Vec::extend`, which was slower than /// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true. pub EXTEND_FROM_SLICE, "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** `Range::step_by(0)` used to be linted since it's + /// ### Deprecation reason + /// `Range::step_by(0)` used to be linted since it's /// an infinite iterator, which is better expressed by `iter::repeat`, /// but the method has been removed for `Iterator::step_by` which panics /// if given a zero @@ -41,27 +47,33 @@ declare_deprecated_lint! { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This used to check for `Vec::as_slice`, which was unstable with good + /// ### Deprecation reason + /// This used to check for `Vec::as_slice`, which was unstable with good /// stable alternatives. `Vec::as_slice` has now been stabilized. pub UNSTABLE_AS_SLICE, "`Vec::as_slice` has been stabilized in 1.7" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This used to check for `Vec::as_mut_slice`, which was unstable with good + /// ### Deprecation reason + /// This used to check for `Vec::as_mut_slice`, which was unstable with good /// stable alternatives. `Vec::as_mut_slice` has now been stabilized. pub UNSTABLE_AS_MUT_SLICE, "`Vec::as_mut_slice` has been stabilized in 1.7" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This lint should never have applied to non-pointer types, as transmuting + /// ### Deprecation reason + /// This lint should never have applied to non-pointer types, as transmuting /// between non-pointer types of differing alignment is well-defined behavior (it's semantically /// equivalent to a memcpy). This lint has thus been refactored into two separate lints: /// cast_ptr_alignment and transmute_ptr_to_ptr. @@ -70,9 +82,11 @@ declare_deprecated_lint! { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This lint is too subjective, not having a good reason for being in clippy. + /// ### Deprecation reason + /// This lint is too subjective, not having a good reason for being in clippy. /// Additionally, compound assignment operators may be overloaded separately from their non-assigning /// counterparts, so this lint may suggest a change in behavior or the code may not compile. pub ASSIGN_OPS, @@ -80,9 +94,11 @@ declare_deprecated_lint! { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** The original rule will only lint for `if let`. After + /// ### Deprecation reason + /// The original rule will only lint for `if let`. After /// making it support to lint `match`, naming as `if let` is not suitable for it. /// So, this lint is deprecated. pub IF_LET_REDUNDANT_PATTERN_MATCHING, @@ -90,9 +106,11 @@ declare_deprecated_lint! { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This lint used to suggest replacing `let mut vec = + /// ### Deprecation reason + /// This lint used to suggest replacing `let mut vec = /// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The /// replacement has very different performance characteristics so the lint is /// deprecated. @@ -101,51 +119,63 @@ declare_deprecated_lint! { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This lint has been superseded by #[must_use] in rustc. + /// ### Deprecation reason + /// This lint has been superseded by #[must_use] in rustc. pub UNUSED_COLLECT, "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** Associated-constants are now preferred. + /// ### Deprecation reason + /// Associated-constants are now preferred. pub REPLACE_CONSTS, "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** The regex! macro does not exist anymore. + /// ### Deprecation reason + /// The regex! macro does not exist anymore. pub REGEX_MACRO, "the regex! macro has been removed from the regex crate in 2018" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This lint has been replaced by `manual_find_map`, a + /// ### Deprecation reason + /// This lint has been replaced by `manual_find_map`, a /// more specific lint. pub FIND_MAP, "this lint has been replaced by `manual_find_map`, a more specific lint" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** This lint has been replaced by `manual_filter_map`, a + /// ### Deprecation reason + /// This lint has been replaced by `manual_filter_map`, a /// more specific lint. pub FILTER_MAP, "this lint has been replaced by `manual_filter_map`, a more specific lint" } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which + /// ### Deprecation reason + /// The `avoid_breaking_exported_api` config option was added, which /// enables the `enum_variant_names` lint for public items. /// ``` pub PUB_ENUM_VARIANT_NAMES, @@ -153,9 +183,11 @@ declare_deprecated_lint! { } declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. + /// ### What it does + /// Nothing. This lint has been deprecated. /// - /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which + /// ### Deprecation reason + /// The `avoid_breaking_exported_api` config option was added, which /// enables the `wrong_self_conversion` lint for public items. pub WRONG_PUB_SELF_CONVENTION, "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items" diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 682003f9c2c..ded7001ad8c 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -11,12 +11,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for explicit `deref()` or `deref_mut()` method calls. + /// ### What it does + /// Checks for explicit `deref()` or `deref_mut()` method calls. /// - /// **Why is this bad?** Dereferencing by `&*x` or `&mut *x` is clearer and more concise, + /// ### Why is this bad? + /// Dereferencing by `&*x` or `&mut *x` is clearer and more concise, /// when not part of a method chain. /// - /// **Example:** + /// ### Example /// ```rust /// use std::ops::Deref; /// let a: &mut String = &mut String::from("foo"); diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 7aafaf71383..dcfa5253f83 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -15,10 +15,12 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq` + /// ### What it does + /// Checks for deriving `Hash` but implementing `PartialEq` /// explicitly or vice versa. /// - /// **Why is this bad?** The implementation of these traits must agree (for + /// ### Why is this bad? + /// The implementation of these traits must agree (for /// example for use with `HashMap`) so it’s probably a bad idea to use a /// default-generated `Hash` implementation with an explicitly defined /// `PartialEq`. In particular, the following must hold for any type: @@ -27,9 +29,7 @@ declare_clippy_lint! { /// k1 == k2 ⇒ hash(k1) == hash(k2) /// ``` /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// #[derive(Hash)] /// struct Foo; @@ -44,10 +44,12 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for deriving `Ord` but implementing `PartialOrd` + /// ### What it does + /// Checks for deriving `Ord` but implementing `PartialOrd` /// explicitly or vice versa. /// - /// **Why is this bad?** The implementation of these traits must agree (for + /// ### Why is this bad? + /// The implementation of these traits must agree (for /// example for use with `sort`) so it’s probably a bad idea to use a /// default-generated `Ord` implementation with an explicitly defined /// `PartialOrd`. In particular, the following must hold for any type @@ -57,10 +59,7 @@ declare_clippy_lint! { /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap() /// ``` /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// #[derive(Ord, PartialEq, Eq)] /// struct Foo; @@ -95,18 +94,21 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for explicit `Clone` implementations for `Copy` + /// ### What it does + /// Checks for explicit `Clone` implementations for `Copy` /// types. /// - /// **Why is this bad?** To avoid surprising behaviour, these traits should + /// ### Why is this bad? + /// To avoid surprising behaviour, these traits should /// agree and the behaviour of `Copy` cannot be overridden. In almost all /// situations a `Copy` type should have a `Clone` implementation that does /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]` /// gets you. /// - /// **Known problems:** Bounds of generic types are sometimes wrong: https://github.com/rust-lang/rust/issues/26925 + /// ### Known problems + /// Bounds of generic types are sometimes wrong: https://github.com/rust-lang/rust/issues/26925 /// - /// **Example:** + /// ### Example /// ```rust,ignore /// #[derive(Copy)] /// struct Foo; @@ -121,16 +123,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for deriving `serde::Deserialize` on a type that + /// ### What it does + /// Checks for deriving `serde::Deserialize` on a type that /// has methods using `unsafe`. /// - /// **Why is this bad?** Deriving `serde::Deserialize` will create a constructor + /// ### Why is this bad? + /// Deriving `serde::Deserialize` will create a constructor /// that may violate invariants hold by another constructor. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// use serde::Deserialize; /// diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs index aa1a609afed..7069cb4198c 100644 --- a/clippy_lints/src/disallowed_method.rs +++ b/clippy_lints/src/disallowed_method.rs @@ -8,15 +8,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; declare_clippy_lint! { - /// **What it does:** Denies the configured methods and functions in clippy.toml + /// ### What it does + /// Denies the configured methods and functions in clippy.toml /// - /// **Why is this bad?** Some methods are undesirable in certain contexts, + /// ### Why is this bad? + /// Some methods are undesirable in certain contexts, /// and it's beneficial to lint for them as needed. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// An example clippy.toml configuration: /// ```toml /// # clippy.toml diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 12c525634c5..6d38d30cd0b 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -6,7 +6,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use unicode_script::{Script, UnicodeScript}; declare_clippy_lint! { - /// **What it does:** Checks for usage of unicode scripts other than those explicitly allowed + /// ### What it does + /// Checks for usage of unicode scripts other than those explicitly allowed /// by the lint config. /// /// This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`. @@ -19,7 +20,8 @@ declare_clippy_lint! { /// [aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases /// [supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html /// - /// **Why is this bad?** It may be not desired to have many different scripts for + /// ### Why is this bad? + /// It may be not desired to have many different scripts for /// identifiers in the codebase. /// /// Note that if you only want to allow plain English, you might want to use @@ -27,9 +29,7 @@ declare_clippy_lint! { /// /// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Assuming that `clippy.toml` contains the following line: /// // allowed-locales = ["Latin", "Cyrillic"] diff --git a/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs index 7c76e2322c2..e627168b932 100644 --- a/clippy_lints/src/disallowed_type.rs +++ b/clippy_lints/src/disallowed_type.rs @@ -9,14 +9,13 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{Span, Symbol}; declare_clippy_lint! { - /// **What it does:** Denies the configured types in clippy.toml. + /// ### What it does + /// Denies the configured types in clippy.toml. /// - /// **Why is this bad?** Some types are undesirable in certain contexts. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Some types are undesirable in certain contexts. /// + /// ### Example: /// An example clippy.toml configuration: /// ```toml /// # clippy.toml diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 0c19988a975..c39829fdc7a 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -30,15 +30,18 @@ use std::thread; use url::Url; declare_clippy_lint! { - /// **What it does:** Checks for the presence of `_`, `::` or camel-case words + /// ### What it does + /// Checks for the presence of `_`, `::` or camel-case words /// outside ticks in documentation. /// - /// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and + /// ### Why is this bad? + /// *Rustdoc* supports markdown formatting, `_`, `::` and /// camel-case probably indicates some code which should be included between /// ticks. `_` can also be used for emphasis in markdown, this lint tries to /// consider that. /// - /// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks + /// ### Known problems + /// Lots of bad docs won’t be fixed, what the lint checks /// for is limited, and there are still false positives. HTML elements and their /// content are not linted. /// @@ -47,7 +50,7 @@ declare_clippy_lint! { /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec /// would fail. /// - /// **Examples:** + /// ### Examples /// ```rust /// /// Do something with the foo_bar parameter. See also /// /// that::other::module::foo. @@ -68,15 +71,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the doc comments of publicly visible + /// ### What it does + /// Checks for the doc comments of publicly visible /// unsafe functions and warns if there is no `# Safety` section. /// - /// **Why is this bad?** Unsafe functions should document their safety + /// ### Why is this bad? + /// Unsafe functions should document their safety /// preconditions, so that users can be sure they are using them safely. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust ///# type Universe = (); /// /// This function should really be documented @@ -102,16 +105,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks the doc comments of publicly visible functions that + /// ### What it does + /// Checks the doc comments of publicly visible functions that /// return a `Result` type and warns if there is no `# Errors` section. /// - /// **Why is this bad?** Documenting the type of errors that can be returned from a + /// ### Why is this bad? + /// Documenting the type of errors that can be returned from a /// function can help callers write code to handle the errors appropriately. /// - /// **Known problems:** None. - /// - /// **Examples:** - /// + /// ### Examples /// Since the following function returns a `Result` it has an `# Errors` section in /// its doc comment: /// @@ -131,16 +133,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks the doc comments of publicly visible functions that + /// ### What it does + /// Checks the doc comments of publicly visible functions that /// may panic and warns if there is no `# Panics` section. /// - /// **Why is this bad?** Documenting the scenarios in which panicking occurs + /// ### Why is this bad? + /// Documenting the scenarios in which panicking occurs /// can help callers who do not want to panic to avoid those situations. /// - /// **Known problems:** None. - /// - /// **Examples:** - /// + /// ### Examples /// Since the following function may panic it has a `# Panics` section in /// its doc comment: /// @@ -162,14 +163,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `fn main() { .. }` in doctests + /// ### What it does + /// Checks for `fn main() { .. }` in doctests /// - /// **Why is this bad?** The test can be shorter (and likely more readable) + /// ### Why is this bad? + /// The test can be shorter (and likely more readable) /// if the `fn main()` is left implicit. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ``````rust /// /// An example of a doctest with a `main()` function /// /// diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 4966638cb1b..6520bb91faf 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -10,14 +10,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for double comparisons that could be simplified to a single expression. + /// ### What it does + /// Checks for double comparisons that could be simplified to a single expression. /// /// - /// **Why is this bad?** Readability. + /// ### Why is this bad? + /// Readability. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// # let y = 2; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index e4e4a93b011..d0d87b6df9a 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -4,14 +4,14 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for unnecessary double parentheses. + /// ### What it does + /// Checks for unnecessary double parentheses. /// - /// **Why is this bad?** This makes code harder to read and might indicate a + /// ### Why is this bad? + /// This makes code harder to read and might indicate a /// mistake. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// fn simple_double_parens() -> i32 { diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index b5b29760636..0f3dc866afb 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -8,17 +8,17 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for calls to `std::mem::drop` with a reference + /// ### What it does + /// Checks for calls to `std::mem::drop` with a reference /// instead of an owned value. /// - /// **Why is this bad?** Calling `drop` on a reference will only drop the + /// ### Why is this bad? + /// Calling `drop` on a reference will only drop the /// reference itself, which is a no-op. It will not call the `drop` method (from /// the `Drop` trait implementation) on the underlying referenced value, which /// is likely what was intended. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// let mut lock_guard = mutex.lock(); /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex @@ -31,17 +31,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `std::mem::forget` with a reference + /// ### What it does + /// Checks for calls to `std::mem::forget` with a reference /// instead of an owned value. /// - /// **Why is this bad?** Calling `forget` on a reference will only forget the + /// ### Why is this bad? + /// Calling `forget` on a reference will only forget the /// reference itself, which is a no-op. It will not forget the underlying /// referenced /// value, which is likely what was intended. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = Box::new(1); /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped @@ -52,16 +52,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `std::mem::drop` with a value + /// ### What it does + /// Checks for calls to `std::mem::drop` with a value /// that derives the Copy trait /// - /// **Why is this bad?** Calling `std::mem::drop` [does nothing for types that + /// ### Why is this bad? + /// Calling `std::mem::drop` [does nothing for types that /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the /// value will be copied and moved into the function on invocation. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x: i32 = 42; // i32 implements Copy /// std::mem::drop(x) // A copy of x is passed to the function, leaving the @@ -73,10 +73,12 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `std::mem::forget` with a value that + /// ### What it does + /// Checks for calls to `std::mem::forget` with a value that /// derives the Copy trait /// - /// **Why is this bad?** Calling `std::mem::forget` [does nothing for types that + /// ### Why is this bad? + /// Calling `std::mem::forget` [does nothing for types that /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the /// value will be copied and moved into the function on invocation. /// @@ -86,9 +88,7 @@ declare_clippy_lint! { /// there /// is nothing for `std::mem::forget` to ignore. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x: i32 = 42; // i32 implements Copy /// std::mem::forget(x) // A copy of x is passed to the function, leaving the diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 94b09bf7173..3774de62521 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -12,15 +12,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; declare_clippy_lint! { - /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds + /// ### What it does + /// Checks for calculation of subsecond microseconds or milliseconds /// from other `Duration` methods. /// - /// **Why is this bad?** It's more concise to call `Duration::subsec_micros()` or + /// ### Why is this bad? + /// It's more concise to call `Duration::subsec_micros()` or /// `Duration::subsec_millis()` than to calculate them. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::time::Duration; /// let dur = Duration::new(5, 0); diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 26984df9539..0541ac5eccc 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -7,14 +7,14 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usage of if expressions with an `else if` branch, + /// ### What it does + /// Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. /// - /// **Why is this bad?** Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). + /// ### Why is this bad? + /// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # fn a() {} /// # fn b() {} diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index c92984a9834..3453c2da278 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -6,13 +6,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `enum`s with no variants. + /// ### What it does + /// Checks for `enum`s with no variants. /// /// As of this writing, the `never_type` is still a /// nightly-only experimental API. Therefore, this lint is only triggered /// if the `never_type` is enabled. /// - /// **Why is this bad?** If you want to introduce a type which + /// ### Why is this bad? + /// If you want to introduce a type which /// can't be instantiated, you should use `!` (the primitive type "never"), /// or a wrapper around it, because `!` has more extensive /// compiler support (type inference, etc...) and wrappers @@ -20,10 +22,7 @@ declare_clippy_lint! { /// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html) /// /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// Bad: /// ```rust /// enum Test {} diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 2eb8b1422ed..e1d0d65edb1 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -16,12 +16,15 @@ use rustc_span::{Span, SyntaxContext, DUMMY_SP}; use std::fmt::Write; declare_clippy_lint! { - /// **What it does:** Checks for uses of `contains_key` + `insert` on `HashMap` + /// ### What it does + /// Checks for uses of `contains_key` + `insert` on `HashMap` /// or `BTreeMap`. /// - /// **Why is this bad?** Using `entry` is more efficient. + /// ### Why is this bad? + /// Using `entry` is more efficient. /// - /// **Known problems:** The suggestion may have type inference errors in some cases. e.g. + /// ### Known problems + /// The suggestion may have type inference errors in some cases. e.g. /// ```rust /// let mut map = std::collections::HashMap::new(); /// let _ = if !map.contains_key(&0) { @@ -31,7 +34,7 @@ declare_clippy_lint! { /// }; /// ``` /// - /// **Example:** + /// ### Example /// ```rust /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 021136ac5e0..a2c3c7a7b49 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -11,15 +11,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::convert::TryFrom; declare_clippy_lint! { - /// **What it does:** Checks for C-like enumerations that are + /// ### What it does + /// Checks for C-like enumerations that are /// `repr(isize/usize)` and have values that don't fit into an `i32`. /// - /// **Why is this bad?** This will truncate the variant value on 32 bit + /// ### Why is this bad? + /// This will truncate the variant value on 32 bit /// architectures, but works fine on 64 bit. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # #[cfg(target_pointer_width = "64")] /// #[repr(usize)] diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index b1a105a51c1..32b95745b64 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -10,15 +10,15 @@ use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; declare_clippy_lint! { - /// **What it does:** Detects enumeration variants that are prefixed or suffixed + /// ### What it does + /// Detects enumeration variants that are prefixed or suffixed /// by the same characters. /// - /// **Why is this bad?** Enumeration variant names should specify their variant, + /// ### Why is this bad? + /// Enumeration variant names should specify their variant, /// not repeat the enumeration name. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// enum Cake { /// BlackForestCake, @@ -40,14 +40,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Detects type names that are prefixed or suffixed by the + /// ### What it does + /// Detects type names that are prefixed or suffixed by the /// containing module's name. /// - /// **Why is this bad?** It requires the user to type the module name twice. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// It requires the user to type the module name twice. /// - /// **Example:** + /// ### Example /// ```rust /// mod cake { /// struct BlackForestCake; @@ -65,10 +65,12 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for modules that have the same name as their + /// ### What it does + /// Checks for modules that have the same name as their /// parent module /// - /// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and + /// ### Why is this bad? + /// A typical beginner mistake is to have `mod foo;` and /// again `mod foo { .. /// }` in `foo.rs`. /// The expectation is that items inside the inner `mod foo { .. }` are then @@ -78,9 +80,7 @@ declare_clippy_lint! { /// If this is done on purpose, it would be better to choose a more /// representative module name. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// // lib.rs /// mod foo; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index d39cabfb282..51d5094e8c9 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -9,18 +9,21 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for equal operands to comparison, logical and + /// ### What it does + /// Checks for equal operands to comparison, logical and /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, /// `||`, `&`, `|`, `^`, `-` and `/`). /// - /// **Why is this bad?** This is usually just a typo or a copy and paste error. + /// ### Why is this bad? + /// This is usually just a typo or a copy and paste error. /// - /// **Known problems:** False negatives: We had some false positives regarding + /// ### Known problems + /// False negatives: We had some false positives regarding /// calls (notably [racer](https://github.com/phildawes/racer) had one instance /// of `x.pop() && x.pop()`), so we removed matching any function or method /// calls. We may introduce a list of known pure functions in the future. /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// if x + 1 == x + 1 {} @@ -37,15 +40,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for arguments to `==` which have their address + /// ### What it does + /// Checks for arguments to `==` which have their address /// taken to satisfy a bound /// and suggests to dereference the other argument instead /// - /// **Why is this bad?** It is more idiomatic to dereference the other argument. + /// ### Why is this bad? + /// It is more idiomatic to dereference the other argument. /// - /// **Known problems:** None + /// ### Known problems + /// None /// - /// **Example:** + /// ### Example /// ```ignore /// // Bad /// &x == y diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 4aa9c25b1b0..026d14d0ea2 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -6,15 +6,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for erasing operations, e.g., `x * 0`. + /// ### What it does + /// Checks for erasing operations, e.g., `x * 0`. /// - /// **Why is this bad?** The whole expression can be replaced by zero. + /// ### Why is this bad? + /// The whole expression can be replaced by zero. /// This is most likely not the intended outcome and should probably be /// corrected /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = 1; /// 0 / x; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 5f400d079da..8b0e9e6bc9b 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -19,16 +19,16 @@ pub struct BoxedLocal { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `Box` where an unboxed `T` would + /// ### What it does + /// Checks for usage of `Box` where an unboxed `T` would /// work fine. /// - /// **Why is this bad?** This is an unnecessary allocation, and bad for + /// ### Why is this bad? + /// This is an unnecessary allocation, and bad for /// performance. It is only necessary to allocate if you wish to move the box /// into something. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # fn foo(bar: usize) {} /// // Bad diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 667eb8eb283..192b69e18f9 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -14,19 +14,22 @@ use rustc_middle::ty::{self, ClosureKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for closures which just call another function where + /// ### What it does + /// Checks for closures which just call another function where /// the function can be called directly. `unsafe` functions or calls where types /// get adjusted are ignored. /// - /// **Why is this bad?** Needlessly creating a closure adds code for no benefit + /// ### Why is this bad? + /// Needlessly creating a closure adds code for no benefit /// and gives the optimizer more work. /// - /// **Known problems:** If creating the closure inside the closure has a side- + /// ### Known problems + /// If creating the closure inside the closure has a side- /// effect then moving the closure creation out will change when that side- /// effect runs. /// See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// xs.map(|x| foo(x)) @@ -42,17 +45,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for closures which only invoke a method on the closure + /// ### What it does + /// Checks for closures which only invoke a method on the closure /// argument and can be replaced by referencing the method directly. /// - /// **Why is this bad?** It's unnecessary to create the closure. + /// ### Why is this bad? + /// It's unnecessary to create the closure. /// - /// **Known problems:** [#3071](https://github.com/rust-lang/rust-clippy/issues/3071), + /// ### Known problems + /// [#3071](https://github.com/rust-lang/rust-clippy/issues/3071), /// [#3942](https://github.com/rust-lang/rust-clippy/issues/3942), /// [#4002](https://github.com/rust-lang/rust-clippy/issues/4002) /// /// - /// **Example:** + /// ### Example /// ```rust,ignore /// Some('a').map(|s| s.to_uppercase()); /// ``` diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 03a8b40df55..f72a1e446d5 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -9,17 +9,20 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for a read and a write to the same variable where + /// ### What it does + /// Checks for a read and a write to the same variable where /// whether the read occurs before or after the write depends on the evaluation /// order of sub-expressions. /// - /// **Why is this bad?** It is often confusing to read. In addition, the + /// ### Why is this bad? + /// It is often confusing to read. In addition, the /// sub-expression evaluation order for Rust is not well documented. /// - /// **Known problems:** Code which intentionally depends on the evaluation + /// ### Known problems + /// Code which intentionally depends on the evaluation /// order, or which is correct for any evaluation order. /// - /// **Example:** + /// ### Example /// ```rust /// let mut x = 0; /// @@ -43,16 +46,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for diverging calls that are not match arms or + /// ### What it does + /// Checks for diverging calls that are not match arms or /// statements. /// - /// **Why is this bad?** It is often confusing to read. In addition, the + /// ### Why is this bad? + /// It is often confusing to read. In addition, the /// sub-expression evaluation order for Rust is not well documented. /// - /// **Known problems:** Someone might want to use `some_bool || panic!()` as a + /// ### Known problems + /// Someone might want to use `some_bool || panic!()` as a /// shorthand. /// - /// **Example:** + /// ### Example /// ```rust,no_run /// # fn b() -> bool { true } /// # fn c() -> bool { true } diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 4e2dbf005d5..476e6d23f12 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -8,19 +8,19 @@ use rustc_span::{sym, Span}; use std::convert::TryInto; declare_clippy_lint! { - /// **What it does:** Checks for excessive + /// ### What it does + /// Checks for excessive /// use of bools in structs. /// - /// **Why is this bad?** Excessive bools in a struct + /// ### Why is this bad? + /// Excessive bools in a struct /// is often a sign that it's used as a state machine, /// which is much better implemented as an enum. /// If it's not the case, excessive bools usually benefit /// from refactoring into two-variant enums for better /// readability and API. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust /// struct S { @@ -44,19 +44,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for excessive use of + /// ### What it does + /// Checks for excessive use of /// bools in function definitions. /// - /// **Why is this bad?** Calls to such functions + /// ### Why is this bad? + /// Calls to such functions /// are confusing and error prone, because it's /// hard to remember argument order and you have /// no type system support to back you up. Using /// two-variant enums instead of bools often makes /// API easier to use. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// fn f(is_round: bool, is_hot: bool) { ... } diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 60ad2e8ee14..e00126046c0 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -8,16 +8,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` + /// ### What it does + /// Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` /// - /// **Why is this bad?** Exhaustive enums are typically fine, but a project which does + /// ### Why is this bad? + /// Exhaustive enums are typically fine, but a project which does /// not wish to make a stability commitment around exported enums may wish to /// disable them by default. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// enum Foo { /// Bar, @@ -38,16 +37,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` + /// ### What it does + /// Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` /// - /// **Why is this bad?** Exhaustive structs are typically fine, but a project which does + /// ### Why is this bad? + /// Exhaustive structs are typically fine, but a project which does /// not wish to make a stability commitment around exported structs may wish to /// disable them by default. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct Foo { /// bar: u8, diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 16246e548b6..9cd5b2d9f44 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -6,15 +6,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** `exit()` terminates the program and doesn't provide a + /// ### What it does + /// `exit()` terminates the program and doesn't provide a /// stack trace. /// - /// **Why is this bad?** Ideally a program is terminated by finishing + /// ### Why is this bad? + /// Ideally a program is terminated by finishing /// the main function. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// std::process::exit(0) /// ``` diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 66724294804..4f46ef906f4 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -9,14 +9,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be + /// ### What it does + /// Checks for usage of `write!()` / `writeln()!` which can be /// replaced with `(e)print!()` / `(e)println!()` /// - /// **Why is this bad?** Using `(e)println! is clearer and more concise + /// ### Why is this bad? + /// Using `(e)println! is clearer and more concise /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::io::Write; /// # let bar = "furchtbar"; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 2937fcb9ca0..7e4d1b3ef9f 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -10,13 +10,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` + /// ### What it does + /// Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` /// - /// **Why is this bad?** `TryFrom` should be used if there's a possibility of failure. + /// ### Why is this bad? + /// `TryFrom` should be used if there's a possibility of failure. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// struct Foo(i32); /// diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index 1e503cc795c..c33d80b8e8e 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -11,30 +11,32 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; declare_clippy_lint! { - /// **What it does:** Checks for statements of the form `(a - b) < f32::EPSILON` or - /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`. - /// - /// **Why is this bad?** The code without `.abs()` is more likely to have a bug. - /// - /// **Known problems:** If the user can ensure that b is larger than a, the `.abs()` is - /// technically unneccessary. However, it will make the code more robust and doesn't have any - /// large performance implications. If the abs call was deliberately left out for performance - /// reasons, it is probably better to state this explicitly in the code, which then can be done - /// with an allow. - /// - /// **Example:** - /// - /// ```rust - /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { - /// (a - b) < f32::EPSILON - /// } - /// ``` - /// Use instead: - /// ```rust - /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { - /// (a - b).abs() < f32::EPSILON - /// } - /// ``` + /// ### What it does + /// Checks for statements of the form `(a - b) < f32::EPSILON` or + /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`. + /// + /// ### Why is this bad? + /// The code without `.abs()` is more likely to have a bug. + /// + /// ### Known problems + /// If the user can ensure that b is larger than a, the `.abs()` is + /// technically unneccessary. However, it will make the code more robust and doesn't have any + /// large performance implications. If the abs call was deliberately left out for performance + /// reasons, it is probably better to state this explicitly in the code, which then can be done + /// with an allow. + /// + /// ### Example + /// ```rust + /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { + /// (a - b) < f32::EPSILON + /// } + /// ``` + /// Use instead: + /// ```rust + /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { + /// (a - b).abs() < f32::EPSILON + /// } + /// ``` pub FLOAT_EQUALITY_WITHOUT_ABS, suspicious, "float equality check without `.abs()`" diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 7968e7b764d..a3d70f31f00 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -10,15 +10,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt; declare_clippy_lint! { - /// **What it does:** Checks for float literals with a precision greater + /// ### What it does + /// Checks for float literals with a precision greater /// than that supported by the underlying type. /// - /// **Why is this bad?** Rust will truncate the literal silently. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Rust will truncate the literal silently. /// + /// ### Example /// ```rust /// // Bad /// let v: f32 = 0.123_456_789_9; @@ -34,16 +33,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for whole number float literals that + /// ### What it does + /// Checks for whole number float literals that /// cannot be represented as the underlying type without loss. /// - /// **Why is this bad?** Rust will silently lose precision during + /// ### Why is this bad? + /// Rust will silently lose precision during /// conversion to a float. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let _: f32 = 16_777_217.0; // 16_777_216.0 diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index e38384b01d4..b01c0cdd846 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -18,16 +18,15 @@ use std::f64::consts as f64_consts; use sugg::Sugg; declare_clippy_lint! { - /// **What it does:** Looks for floating-point expressions that + /// ### What it does + /// Looks for floating-point expressions that /// can be expressed using built-in methods to improve accuracy /// at the cost of performance. /// - /// **Why is this bad?** Negatively impacts accuracy. - /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Why is this bad? + /// Negatively impacts accuracy. /// + /// ### Example /// ```rust /// let a = 3f32; /// let _ = a.powf(1.0 / 3.0); @@ -49,16 +48,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Looks for floating-point expressions that + /// ### What it does + /// Looks for floating-point expressions that /// can be expressed using built-in methods to improve both /// accuracy and performance. /// - /// **Why is this bad?** Negatively impacts accuracy and performance. - /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Why is this bad? + /// Negatively impacts accuracy and performance. /// + /// ### Example /// ```rust /// use std::f32::consts::E; /// diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index ca3490d8eda..863c606f5a9 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -13,18 +13,18 @@ use rustc_span::symbol::kw; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for the use of `format!("string literal with no + /// ### What it does + /// Checks for the use of `format!("string literal with no /// argument")` and `format!("{}", foo)` where `foo` is a string. /// - /// **Why is this bad?** There is no point of doing that. `format!("foo")` can + /// ### Why is this bad? + /// There is no point of doing that. `format!("foo")` can /// be replaced by `"foo".to_owned()` if you really need a `String`. The even /// worse `&format!("foo")` is often encountered in the wild. `format!("{}", /// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()` /// if `foo: &str`. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust /// /// // Bad diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 8aefb8d46f6..b4cf1971d78 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -9,15 +9,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-` + /// ### What it does + /// Checks for use of the non-existent `=*`, `=!` and `=-` /// operators. /// - /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or + /// ### Why is this bad? + /// This is either a typo of `*=`, `!=` or `-=` or /// confusing. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`? /// ``` @@ -27,15 +27,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks the formatting of a unary operator on the right hand side + /// ### What it does + /// Checks the formatting of a unary operator on the right hand side /// of a binary operator. It lints if there is no space between the binary and unary operators, /// but there is a space between the unary and its operand. /// - /// **Why is this bad?** This is either a typo in the binary operator or confusing. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This is either a typo in the binary operator or confusing. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// if foo <- 30 { // this should be `foo < -30` but looks like a different operator /// } @@ -49,15 +49,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for formatting of `else`. It lints if the `else` + /// ### What it does + /// Checks for formatting of `else`. It lints if the `else` /// is followed immediately by a newline or the `else` seems to be missing. /// - /// **Why is this bad?** This is probably some refactoring remnant, even if the + /// ### Why is this bad? + /// This is probably some refactoring remnant, even if the /// code is correct, it might look confusing. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// if foo { /// } { // looks like an `else` is missing here @@ -85,14 +85,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for possible missing comma in an array. It lints if + /// ### What it does + /// Checks for possible missing comma in an array. It lints if /// an array element is a binary operator expression and it lies on two lines. /// - /// **Why is this bad?** This could lead to unexpected results. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This could lead to unexpected results. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// let a = &[ /// -1, -2, -3 // <= no comma here diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 48316c3a61d..623546cd1de 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -8,14 +8,13 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. + /// ### What it does + /// Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. /// - /// **Why is this bad?** According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. /// + /// ### Example /// ```rust /// struct StringWrapper(String); /// diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 3da5bc95b6d..cc4bb85c50f 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -10,20 +10,22 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** + /// ### What it does + /// /// Checks for function invocations of the form `primitive::from_str_radix(s, 10)` /// - /// **Why is this bad?** + /// ### Why is this bad? + /// /// This specific common use case can be rewritten as `s.parse::()` /// (and in most cases, the turbofish can be removed), which reduces code length /// and complexity. /// - /// **Known problems:** + /// ### Known problems + /// /// This lint may suggest using (&).parse() instead of .parse() directly /// in some cases, which is correct but adds unnecessary complexity to the code. /// - /// **Example:** - /// + /// ### Example /// ```ignore /// let input: &str = get_input(); /// let num = u16::from_str_radix(input, 10)?; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 2beb9bc94bf..ce23c0ce4a0 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -11,15 +11,15 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for functions with too many parameters. + /// ### What it does + /// Checks for functions with too many parameters. /// - /// **Why is this bad?** Functions with lots of parameters are considered bad + /// ### Why is this bad? + /// Functions with lots of parameters are considered bad /// style and reduce readability (“what does the 5th parameter mean?”). Consider /// grouping some parameters into a new type. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # struct Color; /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { @@ -32,16 +32,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for functions with a large amount of lines. + /// ### What it does + /// Checks for functions with a large amount of lines. /// - /// **Why is this bad?** Functions with a lot of lines are harder to understand + /// ### Why is this bad? + /// Functions with a lot of lines are harder to understand /// due to having to look at a larger amount of code to understand what the /// function is doing. Consider splitting the body of the function into /// multiple functions. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn im_too_long() { /// println!(""); @@ -55,15 +55,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for public functions that dereference raw pointer + /// ### What it does + /// Checks for public functions that dereference raw pointer /// arguments but are not marked `unsafe`. /// - /// **Why is this bad?** The function should probably be marked `unsafe`, since + /// ### Why is this bad? + /// The function should probably be marked `unsafe`, since /// for an arbitrary raw pointer, there is no way of telling for sure if it is /// valid. /// - /// **Known problems:** - /// + /// ### Known problems /// * It does not check functions recursively so if the pointer is passed to a /// private non-`unsafe` function which does the dereferencing, the lint won't /// trigger. @@ -71,7 +72,7 @@ declare_clippy_lint! { /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or /// `some_argument.get_raw_ptr()`). /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// pub fn foo(x: *const u8) { @@ -89,17 +90,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for a [`#[must_use]`] attribute on + /// ### What it does + /// Checks for a [`#[must_use]`] attribute on /// unit-returning functions and methods. /// /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute /// - /// **Why is this bad?** Unit values are useless. The attribute is likely + /// ### Why is this bad? + /// Unit values are useless. The attribute is likely /// a remnant of a refactoring that removed the return type. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust /// #[must_use] /// fn useless() { } @@ -110,19 +111,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for a [`#[must_use]`] attribute without + /// ### What it does + /// Checks for a [`#[must_use]`] attribute without /// further information on functions and methods that return a type already /// marked as `#[must_use]`. /// /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute /// - /// **Why is this bad?** The attribute isn't needed. Not using the result + /// ### Why is this bad? + /// The attribute isn't needed. Not using the result /// will already be reported. Alternatively, one can add some text to the /// attribute to improve the lint message. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust /// #[must_use] /// fn double_must_use() -> Result<(), ()> { @@ -135,16 +136,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for public functions that have no + /// ### What it does + /// Checks for public functions that have no /// [`#[must_use]`] attribute, but return something not already marked /// must-use, have no mutable arg and mutate no statics. /// /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute /// - /// **Why is this bad?** Not bad at all, this lint just shows places where + /// ### Why is this bad? + /// Not bad at all, this lint just shows places where /// you could add the attribute. /// - /// **Known problems:** The lint only checks the arguments for mutable + /// ### Known problems + /// The lint only checks the arguments for mutable /// types without looking if they are actually changed. On the other hand, /// it also ignores a broad range of potentially interesting side effects, /// because we cannot decide whether the programmer intends the function to @@ -152,7 +156,7 @@ declare_clippy_lint! { /// positives. At least we don't lint if the result type is unit or already /// `#[must_use]`. /// - /// **Examples:** + /// ### Examples /// ```rust /// // this could be annotated with `#[must_use]`. /// fn id(t: T) -> T { t } @@ -163,20 +167,23 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for public functions that return a `Result` + /// ### What it does + /// Checks for public functions that return a `Result` /// with an `Err` type of `()`. It suggests using a custom type that /// implements `std::error::Error`. /// - /// **Why is this bad?** Unit does not implement `Error` and carries no + /// ### Why is this bad? + /// Unit does not implement `Error` and carries no /// further information about what went wrong. /// - /// **Known problems:** Of course, this lint assumes that `Result` is used + /// ### Known problems + /// Of course, this lint assumes that `Result` is used /// for a fallible operation (which is after all the intended use). However /// code may opt to (mis)use it as a basic two-variant-enum. In that case, /// the suggestion is misguided, and the code should use a custom enum /// instead. /// - /// **Examples:** + /// ### Examples /// ```rust /// pub fn read_u8() -> Result { Err(()) } /// ``` diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 515b8887453..0be03969bcb 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -12,12 +12,14 @@ use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine}; declare_clippy_lint! { - /// **What it does:** This lint requires Future implementations returned from + /// ### What it does + /// This lint requires Future implementations returned from /// functions and methods to implement the `Send` marker trait. It is mostly /// used by library authors (public and internal) that target an audience where /// multithreaded executors are likely to be used for running these Futures. /// - /// **Why is this bad?** A Future implementation captures some state that it + /// ### Why is this bad? + /// A Future implementation captures some state that it /// needs to eventually produce its final value. When targeting a multithreaded /// executor (which is the norm on non-embedded devices) this means that this /// state may need to be transported to other threads, in other words the @@ -31,10 +33,7 @@ declare_clippy_lint! { /// modifying the library where the offending Future implementation is /// produced. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// async fn not_send(bytes: std::rc::Rc<[u8]>) {} /// ``` diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 8e45fdfecc4..ced35030de8 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -14,10 +14,12 @@ use rustc_span::source_map::Spanned; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for using `x.get(x.len() - 1)` instead of + /// ### What it does + /// Checks for using `x.get(x.len() - 1)` instead of /// `x.last()`. /// - /// **Why is this bad?** Using `x.last()` is easier to read and has the same + /// ### Why is this bad? + /// Using `x.last()` is easier to read and has the same /// result. /// /// Note that using `x[x.len() - 1]` is semantically different from @@ -27,10 +29,7 @@ declare_clippy_lint! { /// There is another lint (get_unwrap) that covers the case of using /// `x.get(index).unwrap()` instead of `x[index]`. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let x = vec![2, 3, 5]; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 99c461930e4..5feb0ce8dec 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -11,14 +11,14 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::{clip, unsext}; declare_clippy_lint! { - /// **What it does:** Checks for identity operations, e.g., `x + 0`. + /// ### What it does + /// Checks for identity operations, e.g., `x + 0`. /// - /// **Why is this bad?** This code can be removed without changing the + /// ### Why is this bad? + /// This code can be removed without changing the /// meaning. So it just obscures what's going on. Delete it mercilessly. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// x / 1 + 0 * 1 - 0 | 0; diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 5403d76ea30..d3ddeda9fd1 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -9,16 +9,15 @@ use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `Mutex::lock` calls in `if let` expression + /// ### What it does + /// Checks for `Mutex::lock` calls in `if let` expression /// with lock calls in any of the else blocks. /// - /// **Why is this bad?** The Mutex lock remains held for the whole + /// ### Why is this bad? + /// The Mutex lock remains held for the whole /// `if let ... else` block and deadlocks. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// if let Ok(thing) = mutex.lock() { /// do_thing(); diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 611da3744ee..587307811a1 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -10,14 +10,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:*** Checks for unnecessary `ok()` in if let. + /// ### What it does + ///* Checks for unnecessary `ok()` in if let. /// - /// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match + /// ### Why is this bad? + /// Calling `ok()` in if let is unnecessary, instead match /// on `Ok(pat)` /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// for i in iter { /// if let Some(value) = i.parse().ok() { diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index c56f67df061..28db7233d70 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -8,14 +8,14 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an + /// ### What it does + /// Checks for usage of `!` or `!=` in an if condition with an /// else branch. /// - /// **Why is this bad?** Negations reduce the readability of statements. + /// ### Why is this bad? + /// Negations reduce the readability of statements. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let v: Vec = vec![]; /// # fn a() {} diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index eadcd0867a8..17b9a2f888e 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -10,14 +10,13 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for if-else that could be written to `bool::then`. + /// ### What it does + /// Checks for if-else that could be written to `bool::then`. /// - /// **Why is this bad?** Looks a little redundant. Using `bool::then` helps it have less lines of code. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Looks a little redundant. Using `bool::then` helps it have less lines of code. /// + /// ### Example /// ```rust /// # let v = vec![0]; /// let a = if v.is_empty() { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 879d6a75bbe..aae44f64e66 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -22,18 +22,21 @@ use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { - /// **What it does:** Checks for public `impl` or `fn` missing generalization + /// ### What it does + /// Checks for public `impl` or `fn` missing generalization /// over different hashers and implicitly defaulting to the default hashing /// algorithm (`SipHash`). /// - /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be + /// ### Why is this bad? + /// `HashMap` or `HashSet` with custom hashers cannot be /// used with them. /// - /// **Known problems:** Suggestions for replacing constructors can contain + /// ### Known problems + /// Suggestions for replacing constructors can contain /// false-positives. Also applying suggestions can require modification of other /// pieces of code, possibly including external crates. /// - /// **Example:** + /// ### Example /// ```rust /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index f2f830ca5c0..fa7b5302cb1 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -13,17 +13,17 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { - /// **What it does:** Checks for missing return statements at the end of a block. + /// ### What it does + /// Checks for missing return statements at the end of a block. /// - /// **Why is this bad?** Actually omitting the return keyword is idiomatic Rust code. Programmers + /// ### Why is this bad? + /// Actually omitting the return keyword is idiomatic Rust code. Programmers /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss /// the last returning statement because the only difference is a missing `;`. Especially in bigger /// code with multiple return paths having a `return` keyword makes it easier to find the /// corresponding statements. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn foo(x: usize) -> usize { /// x diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 4069a685ea0..0a7d31dce2f 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -8,14 +8,13 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for implicit saturating subtraction. + /// ### What it does + /// Checks for implicit saturating subtraction. /// - /// **Why is this bad?** Simplicity and readability. Instead we can easily use an builtin function. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Simplicity and readability. Instead we can easily use an builtin function. /// + /// ### Example /// ```rust /// let end: u32 = 10; /// let start: u32 = 5; diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 3b635071f28..1f8240a1f63 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -10,11 +10,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; declare_clippy_lint! { - /// **What it does:** Checks for struct constructors where all fields are shorthand and + /// ### What it does + /// Checks for struct constructors where all fields are shorthand and /// the order of the field init shorthand in the constructor is inconsistent /// with the order in the struct definition. /// - /// **Why is this bad?** Since the order of fields in a constructor doesn't affect the + /// ### Why is this bad? + /// Since the order of fields in a constructor doesn't affect the /// resulted instance as the below example indicates, /// /// ```rust @@ -32,10 +34,7 @@ declare_clippy_lint! { /// /// inconsistent order can be confusing and decreases readability and consistency. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct Foo { /// x: i32, diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index bfa284f333a..8c1f1073309 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -10,14 +10,17 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for out of bounds array indexing with a constant + /// ### What it does + /// Checks for out of bounds array indexing with a constant /// index. /// - /// **Why is this bad?** This will always panic at runtime. + /// ### Why is this bad? + /// This will always panic at runtime. /// - /// **Known problems:** Hopefully none. + /// ### Known problems + /// Hopefully none. /// - /// **Example:** + /// ### Example /// ```no_run /// # #![allow(const_err)] /// let x = [1, 2, 3, 4]; @@ -36,16 +39,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of indexing or slicing. Arrays are special cases, this lint + /// ### What it does + /// Checks for usage of indexing or slicing. Arrays are special cases, this lint /// does report on arrays if we can tell that slicing operations are in bounds and does not /// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint. /// - /// **Why is this bad?** Indexing and slicing can panic at runtime and there are + /// ### Why is this bad? + /// Indexing and slicing can panic at runtime and there are /// safe alternatives. /// - /// **Known problems:** Hopefully none. + /// ### Known problems + /// Hopefully none. /// - /// **Example:** + /// ### Example /// ```rust,no_run /// // Vector /// let x = vec![0; 5]; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 295a4e1fccb..2411a3175b9 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -7,14 +7,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{sym, Symbol}; declare_clippy_lint! { - /// **What it does:** Checks for iteration that is guaranteed to be infinite. + /// ### What it does + /// Checks for iteration that is guaranteed to be infinite. /// - /// **Why is this bad?** While there may be places where this is acceptable + /// ### Why is this bad? + /// While there may be places where this is acceptable /// (e.g., in event streams), in most cases this is simply an error. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```no_run /// use std::iter; /// @@ -26,15 +26,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for iteration that may be infinite. + /// ### What it does + /// Checks for iteration that may be infinite. /// - /// **Why is this bad?** While there may be places where this is acceptable + /// ### Why is this bad? + /// While there may be places where this is acceptable /// (e.g., in event streams), in most cases this is simply an error. /// - /// **Known problems:** The code may have a condition to stop iteration, but + /// ### Known problems + /// The code may have a condition to stop iteration, but /// this lint is not clever enough to analyze it. /// - /// **Example:** + /// ### Example /// ```rust /// let infinite_iter = 0..; /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 9641784eb9a..d87055c842c 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -10,13 +10,13 @@ use rustc_span::Span; use std::collections::hash_map::Entry; declare_clippy_lint! { - /// **What it does:** Checks for multiple inherent implementations of a struct + /// ### What it does + /// Checks for multiple inherent implementations of a struct /// - /// **Why is this bad?** Splitting the implementation of a type makes the code harder to navigate. + /// ### Why is this bad? + /// Splitting the implementation of a type makes the code harder to navigate. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// struct X; /// impl X { diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index b023e13e846..b62fad4bd39 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -8,14 +8,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. + /// ### What it does + /// Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. /// - /// **Why is this bad?** This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. + /// ### Why is this bad? + /// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. /// - /// **Known problems:** None - /// - /// ** Example:** + /// ### Known problems + /// None /// + /// ### Example /// ```rust /// // Bad /// pub struct A; @@ -45,14 +47,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait. - /// - /// **Why is this bad?** This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. + /// ### What it does + /// Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait. /// - /// **Known problems:** None + /// ### Why is this bad? + /// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. /// - /// ** Example:** + /// ### Known problems + /// None /// + /// ### Example /// ```rust /// // Bad /// use std::fmt; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 20f00bd51ba..3e3df903f17 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -10,14 +10,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Symbol}; declare_clippy_lint! { - /// **What it does:** Checks for `#[inline]` on trait methods without bodies + /// ### What it does + /// Checks for `#[inline]` on trait methods without bodies /// - /// **Why is this bad?** Only implementations of trait methods may be inlined. + /// ### Why is this bad? + /// Only implementations of trait methods may be inlined. /// The inline attribute is ignored for trait methods without bodies. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// trait Animal { /// #[inline] diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index c4a1222b51f..49b69dd072a 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -8,13 +8,13 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block + /// ### What it does + /// Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// - /// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`. + /// ### Why is this bad? + /// Readability -- better to use `> y` instead of `>= y + 1`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// # let y = 1; diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index e5482f675e7..a0e6f12b812 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -5,15 +5,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for division of integers + /// ### What it does + /// Checks for division of integers /// - /// **Why is this bad?** When outside of some very specific algorithms, + /// ### Why is this bad? + /// When outside of some very specific algorithms, /// integer division is very often a mistake because it discards the /// remainder. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let x = 3 / 2; diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 37011f5578d..3b28b121204 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -14,18 +14,20 @@ use clippy_utils::source::snippet; use clippy_utils::{comparisons, sext}; declare_clippy_lint! { - /// **What it does:** Checks for comparisons where the relation is always either + /// ### What it does + /// Checks for comparisons where the relation is always either /// true or false, but where one side has been upcast so that the comparison is /// necessary. Only integer types are checked. /// - /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300` + /// ### Why is this bad? + /// An expression like `let x : u8 = ...; (x as u32) > 300` /// will mistakenly imply that it is possible for `x` to be outside the range of /// `u8`. /// - /// **Known problems:** + /// ### Known problems /// https://github.com/rust-lang/rust-clippy/issues/886 /// - /// **Example:** + /// ### Example /// ```rust /// let x: u8 = 1; /// (x as u32) > 300; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index c69571f32a2..429c6ed7d2d 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -7,15 +7,15 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for items declared after some statement in a block. + /// ### What it does + /// Checks for items declared after some statement in a block. /// - /// **Why is this bad?** Items live for the entire scope they are declared + /// ### Why is this bad? + /// Items live for the entire scope they are declared /// in. But statements are processed in order. This might cause confusion as /// it's hard to figure out which item is meant in a statement. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// fn foo() { diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 48dc5fefe99..5d4e06c2af0 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -11,15 +11,15 @@ use rustc_span::{BytePos, Pos, Span}; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { - /// **What it does:** Checks for large `const` arrays that should + /// ### What it does + /// Checks for large `const` arrays that should /// be defined as `static` instead. /// - /// **Why is this bad?** Performance: const variables are inlined upon use. + /// ### Why is this bad? + /// Performance: const variables are inlined upon use. /// Static items result in only one instance and has a fixed location in memory. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// pub const a = [0u32; 1_000_000]; diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index f166748d86b..cde2336b690 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -10,20 +10,22 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_target::abi::LayoutOf; declare_clippy_lint! { - /// **What it does:** Checks for large size differences between variants on + /// ### What it does + /// Checks for large size differences between variants on /// `enum`s. /// - /// **Why is this bad?** Enum size is bounded by the largest variant. Having a + /// ### Why is this bad? + /// Enum size is bounded by the largest variant. Having a /// large variant can penalize the memory layout of that enum. /// - /// **Known problems:** This lint obviously cannot take the distribution of + /// ### Known problems + /// This lint obviously cannot take the distribution of /// variants in your running program into account. It is possible that the /// smaller variants make up less than 1% of all instances, in which case /// the overhead is negligible and the boxing is counter-productive. Always /// measure the change this lint suggests. /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// enum Test { diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index c46b98022c6..7088630bfdb 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -10,13 +10,13 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use crate::rustc_target::abi::LayoutOf; declare_clippy_lint! { - /// **What it does:** Checks for local arrays that may be too large. + /// ### What it does + /// Checks for local arrays that may be too large. /// - /// **Why is this bad?** Large local arrays may cause stack overflow. + /// ### Why is this bad? + /// Large local arrays may cause stack overflow. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// let a = [0u32; 1_000_000]; /// ``` diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 892b3af0b32..b66d7a9f729 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -18,17 +18,17 @@ use rustc_span::{ }; declare_clippy_lint! { - /// **What it does:** Checks for getting the length of something via `.len()` + /// ### What it does + /// Checks for getting the length of something via `.len()` /// just to compare to zero, and suggests using `.is_empty()` where applicable. /// - /// **Why is this bad?** Some structures can answer `.is_empty()` much faster + /// ### Why is this bad? + /// Some structures can answer `.is_empty()` much faster /// than calculating their length. So it is good to get into the habit of using /// `.is_empty()`, and having it is cheap. /// Besides, it makes the intent clearer than a manual comparison in some contexts. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// if x.len() == 0 { /// .. @@ -52,18 +52,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for items that implement `.len()` but not + /// ### What it does + /// Checks for items that implement `.len()` but not /// `.is_empty()`. /// - /// **Why is this bad?** It is good custom to have both methods, because for + /// ### Why is this bad? + /// It is good custom to have both methods, because for /// some data structures, asking about the length will be a costly operation, /// whereas `.is_empty()` can usually answer in constant time. Also it used to /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that /// lint will ignore such entities. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// impl X { /// pub fn len(&self) -> usize { @@ -77,17 +77,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`, + /// ### What it does + /// Checks for comparing to an empty slice such as `""` or `[]`, /// and suggests using `.is_empty()` where applicable. /// - /// **Why is this bad?** Some structures can answer `.is_empty()` much faster + /// ### Why is this bad? + /// Some structures can answer `.is_empty()` much faster /// than checking for equality. So it is good to get into the habit of using /// `.is_empty()`, and having it is cheap. /// Besides, it makes the intent clearer than a manual comparison in some contexts. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```ignore /// if s == "" { diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 67eae4d87bb..13f0d43cf8d 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -9,14 +9,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for variable declarations immediately followed by a + /// ### What it does + /// Checks for variable declarations immediately followed by a /// conditional affectation. /// - /// **Why is this bad?** This is not idiomatic Rust. + /// ### Why is this bad? + /// This is not idiomatic Rust. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// let foo; /// diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index e627b1385bc..8992d25932c 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -9,15 +9,15 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `let _ = ` + /// ### What it does + /// Checks for `let _ = ` /// where expr is #[must_use] /// - /// **Why is this bad?** It's better to explicitly + /// ### Why is this bad? + /// It's better to explicitly /// handle the value of a #[must_use] expr /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn f() -> Result { /// Ok(0) @@ -33,17 +33,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `let _ = sync_lock` + /// ### What it does + /// Checks for `let _ = sync_lock` /// - /// **Why is this bad?** This statement immediately drops the lock instead of + /// ### Why is this bad? + /// This statement immediately drops the lock instead of /// extending its lifetime to the end of the scope, which is often not intended. /// To extend lock lifetime to the end of the scope, use an underscore-prefixed /// name instead (i.e. _lock). If you want to explicitly drop the lock, /// `std::mem::drop` conveys your intention better and is less error-prone. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// Bad: /// ```rust,ignore @@ -60,19 +60,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `let _ = ` + /// ### What it does + /// Checks for `let _ = ` /// where expr has a type that implements `Drop` /// - /// **Why is this bad?** This statement immediately drops the initializer + /// ### Why is this bad? + /// This statement immediately drops the initializer /// expression instead of extending its lifetime to the end of the scope, which /// is often not intended. To extend the expression's lifetime to the end of the /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to /// explicitly drop the expression, `std::mem::drop` conveys your intention /// better and is less error-prone. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// Bad: /// ```rust,ignore diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index aa763b5c5e6..3cffb507f70 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -73,14 +73,13 @@ use rustc_session::Session; /// use clippy_lints::declare_clippy_lint; /// /// declare_clippy_lint! { -/// /// **What it does:** Checks for ... (describe what the lint matches). +/// /// ### What it does +/// /// Checks for ... (describe what the lint matches). /// /// -/// /// **Why is this bad?** Supply the reason for linting the code. -/// /// -/// /// **Known problems:** None. (Or describe where it could go wrong.) -/// /// -/// /// **Example:** +/// /// ### Why is this bad? +/// /// Supply the reason for linting the code. /// /// +/// /// ### Example /// /// ```rust /// /// // Bad /// /// Insert a short example of code that triggers the lint diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5ae68ba5b2f..e5e6f8d25cc 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -18,20 +18,22 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{kw, Symbol}; declare_clippy_lint! { - /// **What it does:** Checks for lifetime annotations which can be removed by + /// ### What it does + /// Checks for lifetime annotations which can be removed by /// relying on lifetime elision. /// - /// **Why is this bad?** The additional lifetimes make the code look more + /// ### Why is this bad? + /// The additional lifetimes make the code look more /// complicated, while there is nothing out of the ordinary going on. Removing /// them leads to more readable code. /// - /// **Known problems:** + /// ### Known problems /// - We bail out if the function has a `where` clause where lifetimes /// are mentioned due to potenial false positives. /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`. /// - /// **Example:** + /// ### Example /// ```rust /// // Bad: unnecessary lifetime annotations /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { @@ -50,16 +52,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for lifetimes in generics that are never used + /// ### What it does + /// Checks for lifetimes in generics that are never used /// anywhere else. /// - /// **Why is this bad?** The additional lifetimes make the code look more + /// ### Why is this bad? + /// The additional lifetimes make the code look more /// complicated, while there is nothing out of the ordinary going on. Removing /// them leads to more readable code. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad: unnecessary lifetimes /// fn unused_lifetime<'a>(x: u8) { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index e0c5578bd60..699ddce0cff 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -16,15 +16,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use std::iter; declare_clippy_lint! { - /// **What it does:** Warns if a long integral or floating-point constant does + /// ### What it does + /// Warns if a long integral or floating-point constant does /// not contain underscores. /// - /// **Why is this bad?** Reading long numbers is difficult without separators. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Reading long numbers is difficult without separators. /// + /// ### Example /// ```rust /// // Bad /// let x: u64 = 61864918973511; @@ -38,17 +37,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns for mistyped suffix in literals + /// ### What it does + /// Warns for mistyped suffix in literals /// - /// **Why is this bad?** This is most probably a typo + /// ### Why is this bad? + /// This is most probably a typo /// - /// **Known problems:** + /// ### Known problems /// - Recommends a signed suffix, even though the number might be too big and an unsigned /// suffix is required /// - Does not match on `_127` since that is a valid grouping for decimal and octal numbers /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Probably mistyped /// 2_32; @@ -62,16 +62,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if an integral or floating-point constant is + /// ### What it does + /// Warns if an integral or floating-point constant is /// grouped inconsistently with underscores. /// - /// **Why is this bad?** Readers may incorrectly interpret inconsistently + /// ### Why is this bad? + /// Readers may incorrectly interpret inconsistently /// grouped digits. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let x: u64 = 618_64_9189_73_511; @@ -85,15 +84,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if hexadecimal or binary literals are not grouped + /// ### What it does + /// Warns if hexadecimal or binary literals are not grouped /// by nibble or byte. /// - /// **Why is this bad?** Negatively impacts readability. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Negatively impacts readability. /// + /// ### Example /// ```rust /// let x: u32 = 0xFFF_FFF; /// let y: u8 = 0b01_011_101; @@ -104,16 +102,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if the digits of an integral or floating-point + /// ### What it does + /// Warns if the digits of an integral or floating-point /// constant are grouped into groups that /// are too large. /// - /// **Why is this bad?** Negatively impacts readability. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Negatively impacts readability. /// + /// ### Example /// ```rust /// let x: u64 = 6186491_8973511; /// ``` @@ -123,15 +120,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if there is a better representation for a numeric literal. + /// ### What it does + /// Warns if there is a better representation for a numeric literal. /// - /// **Why is this bad?** Especially for big powers of 2 a hexadecimal representation is more + /// ### Why is this bad? + /// Especially for big powers of 2 a hexadecimal representation is more /// readable than a decimal representation. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// `255` => `0xFF` /// `65_535` => `0xFFFF` /// `4_042_322_160` => `0xF0F0_F0F0` diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 56a123b69c6..7ca54d53972 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -26,14 +26,14 @@ use rustc_span::source_map::Span; use utils::{get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor}; declare_clippy_lint! { - /// **What it does:** Checks for for-loops that manually copy items between + /// ### What it does + /// Checks for for-loops that manually copy items between /// slices that could be optimized by having a memcpy. /// - /// **Why is this bad?** It is not as fast as a memcpy. + /// ### Why is this bad? + /// It is not as fast as a memcpy. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; @@ -53,15 +53,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for looping over the range of `0..len` of some + /// ### What it does + /// Checks for looping over the range of `0..len` of some /// collection just to get the values by index. /// - /// **Why is this bad?** Just iterating the collection itself makes the intent + /// ### Why is this bad? + /// Just iterating the collection itself makes the intent /// more clear and is probably faster. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let vec = vec!['a', 'b', 'c']; /// for i in 0..vec.len() { @@ -81,15 +81,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for loops on `x.iter()` where `&x` will do, and + /// ### What it does + /// Checks for loops on `x.iter()` where `&x` will do, and /// suggests the latter. /// - /// **Why is this bad?** Readability. + /// ### Why is this bad? + /// Readability. /// - /// **Known problems:** False negatives. We currently only warn on some known + /// ### Known problems + /// False negatives. We currently only warn on some known /// types. /// - /// **Example:** + /// ### Example /// ```rust /// // with `y` a `Vec` or slice: /// # let y = vec![1]; @@ -110,14 +113,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for loops on `y.into_iter()` where `y` will do, and + /// ### What it does + /// Checks for loops on `y.into_iter()` where `y` will do, and /// suggests the latter. /// - /// **Why is this bad?** Readability. + /// ### Why is this bad? + /// Readability. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// # let y = vec![1]; /// // with `y` a `Vec` or slice: @@ -138,18 +141,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for loops on `x.next()`. + /// ### What it does + /// Checks for loops on `x.next()`. /// - /// **Why is this bad?** `next()` returns either `Some(value)` if there was a + /// ### Why is this bad? + /// `next()` returns either `Some(value)` if there was a /// value, or `None` otherwise. The insidious thing is that `Option<_>` /// implements `IntoIterator`, so that possibly one value will be iterated, /// leading to some hard to find bugs. No one will want to write such code /// [except to win an Underhanded Rust /// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// for x in y.next() { /// .. @@ -161,14 +164,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `for` loops over `Option` or `Result` values. + /// ### What it does + /// Checks for `for` loops over `Option` or `Result` values. /// - /// **Why is this bad?** Readability. This is more clearly expressed as an `if + /// ### Why is this bad? + /// Readability. This is more clearly expressed as an `if /// let`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let opt = Some(1); /// @@ -204,15 +207,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Detects `loop + match` combinations that are easier + /// ### What it does + /// Detects `loop + match` combinations that are easier /// written as a `while let` loop. /// - /// **Why is this bad?** The `while let` loop is usually shorter and more + /// ### Why is this bad? + /// The `while let` loop is usually shorter and more /// readable. /// - /// **Known problems:** Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). + /// ### Known problems + /// Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). /// - /// **Example:** + /// ### Example /// ```rust,no_run /// # let y = Some(1); /// loop { @@ -233,16 +239,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for functions collecting an iterator when collect + /// ### 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, + /// ### Why is this bad? + /// `collect` causes the allocation of a new data structure, /// when this allocation may not be needed. /// - /// **Known problems:** - /// None - /// - /// **Example:** + /// ### Example /// ```rust /// # let iterator = vec![1].into_iter(); /// let len = iterator.clone().collect::>().len(); @@ -255,15 +260,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks `for` loops over slices with an explicit counter + /// ### What it does + /// Checks `for` loops over slices with an explicit counter /// and suggests the use of `.enumerate()`. /// - /// **Why is it bad?** Using `.enumerate()` makes the intent more clear, + /// ### Why is this bad? + /// Using `.enumerate()` makes the intent more clear, /// declutters the code and may be faster in some instances. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} @@ -285,9 +290,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for empty `loop` expressions. + /// ### What it does + /// Checks for empty `loop` expressions. /// - /// **Why is this bad?** These busy loops burn CPU cycles without doing + /// ### Why is this bad? + /// These busy loops burn CPU cycles without doing /// anything. It is _almost always_ a better idea to `panic!` than to have /// a busy loop. /// @@ -306,9 +313,7 @@ declare_clippy_lint! { /// - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html) /// - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html) /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```no_run /// loop {} /// ``` @@ -318,14 +323,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `while let` expressions on iterators. + /// ### What it does + /// Checks for `while let` expressions on iterators. /// - /// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys + /// ### Why is this bad? + /// Readability. A simple `for` loop is shorter and conveys /// the intent better. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// while let Some(val) = iter() { /// .. @@ -337,15 +342,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for iterating a map (`HashMap` or `BTreeMap`) and + /// ### What it does + /// Checks for iterating a map (`HashMap` or `BTreeMap`) and /// ignoring either the keys or values. /// - /// **Why is this bad?** Readability. There are `keys` and `values` methods that + /// ### Why is this bad? + /// Readability. There are `keys` and `values` methods that /// can be used to express that don't need the values or keys. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// for (k, _) in &map { /// .. @@ -365,15 +370,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for loops that will always `break`, `return` or + /// ### What it does + /// Checks for loops that will always `break`, `return` or /// `continue` an outer loop. /// - /// **Why is this bad?** This loop never loops, all it does is obfuscating the + /// ### Why is this bad? + /// This loop never loops, all it does is obfuscating the /// code. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// loop { /// ..; @@ -386,13 +391,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for loops which have a range bound that is a mutable variable - /// - /// **Why is this bad?** One might think that modifying the mutable variable changes the loop bounds + /// ### What it does + /// Checks for loops which have a range bound that is a mutable variable /// - /// **Known problems:** None + /// ### Why is this bad? + /// One might think that modifying the mutable variable changes the loop bounds /// - /// **Example:** + /// ### Example /// ```rust /// let mut foo = 42; /// for i in 0..foo { @@ -406,17 +411,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks whether variables used within while loop condition + /// ### What it does + /// Checks whether variables used within while loop condition /// can be (and are) mutated in the body. /// - /// **Why is this bad?** If the condition is unchanged, entering the body of the loop + /// ### Why is this bad? + /// If the condition is unchanged, entering the body of the loop /// will lead to an infinite loop. /// - /// **Known problems:** If the `while`-loop is in a closure, the check for mutation of the + /// ### Known problems + /// If the `while`-loop is in a closure, the check for mutation of the /// condition variables in the body can cause false negatives. For example when only `Upvar` `a` is /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger. /// - /// **Example:** + /// ### Example /// ```rust /// let i = 0; /// while i > 10 { @@ -429,15 +437,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks whether a for loop is being used to push a constant + /// ### What it does + /// Checks whether a for loop is being used to push a constant /// value into a Vec. /// - /// **Why is this bad?** This kind of operation can be expressed more succinctly with + /// ### Why is this bad? + /// This kind of operation can be expressed more succinctly with /// `vec![item;SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also /// have better performance. - /// **Known problems:** None /// - /// **Example:** + /// ### Example /// ```rust /// let item1 = 2; /// let item2 = 3; @@ -462,13 +471,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks whether a for loop has a single element. + /// ### What it does + /// Checks whether a for loop has a single element. /// - /// **Why is this bad?** There is no reason to have a loop of a + /// ### Why is this bad? + /// There is no reason to have a loop of a /// single element. - /// **Known problems:** None /// - /// **Example:** + /// ### Example /// ```rust /// let item1 = 2; /// for item in &[item1] { @@ -487,15 +497,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Check for unnecessary `if let` usage in a for loop + /// ### What it does + /// Check for unnecessary `if let` usage in a for loop /// where only the `Some` or `Ok` variant of the iterator element is used. /// - /// **Why is this bad?** It is verbose and can be simplified + /// ### Why is this bad? + /// It is verbose and can be simplified /// by first calling the `flatten` method on the `Iterator`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```rust /// let x = vec![Some(1), Some(2), Some(3)]; diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 66479ae264e..a371f8bbd3c 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -12,14 +12,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{edition::Edition, sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for `#[macro_use] use...`. + /// ### What it does + /// Checks for `#[macro_use] use...`. /// - /// **Why is this bad?** Since the Rust 2018 edition you can import + /// ### Why is this bad? + /// Since the Rust 2018 edition you can import /// macro's directly, this is considered idiomatic. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// #[macro_use] /// use some_macro; diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 07d8a440aea..776e4b3fe76 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -7,14 +7,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for recursion using the entrypoint. + /// ### What it does + /// Checks for recursion using the entrypoint. /// - /// **Why is this bad?** Apart from special setups (which we could detect following attributes like #![no_std]), + /// ### Why is this bad? + /// Apart from special setups (which we could detect following attributes like #![no_std]), /// recursing into main() seems like an unintuitive antipattern we should be able to detect. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```no_run /// fn main() { /// main(); diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 5d88ff3b99f..8e1385fb83a 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -14,14 +14,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** It checks for manual implementations of `async` functions. + /// ### What it does + /// It checks for manual implementations of `async` functions. /// - /// **Why is this bad?** It's more idiomatic to use the dedicated syntax. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// It's more idiomatic to use the dedicated syntax. /// + /// ### Example /// ```rust /// use std::future::Future; /// diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 563d5cdb5fb..7dec1595e0d 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -16,14 +16,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { - /// **What it does:** Checks for usages of `match` which could be implemented using `map` + /// ### What it does + /// Checks for usages of `match` which could be implemented using `map` /// - /// **Why is this bad?** Using the `map` method is clearer and more concise. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Using the `map` method is clearer and more concise. /// + /// ### Example /// ```rust /// match Some(0) { /// Some(x) => Some(x + 1), diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 54f714b54b6..335ea001ee4 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -11,15 +11,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. + /// ### What it does + /// Checks for manual implementations of the non-exhaustive pattern. /// - /// **Why is this bad?** Using the #[non_exhaustive] attribute expresses better the intent + /// ### Why is this bad? + /// Using the #[non_exhaustive] attribute expresses better the intent /// and allows possible optimizations when applied to enums. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct S { /// pub a: i32, diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 847c8c648b0..b2f287af697 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -13,15 +13,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** + /// ### What it does + /// /// Finds patterns that reimplement `Option::ok_or`. /// - /// **Why is this bad?** - /// Concise code helps focusing on behavior instead of boilerplate. + /// ### Why is this bad? /// - /// **Known problems:** None. + /// Concise code helps focusing on behavior instead of boilerplate. /// - /// **Examples:** + /// ### Examples /// ```rust /// let foo: Option = None; /// foo.map_or(Err("error"), |v| Ok(v)); diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 61b5fe81fa9..db12c377488 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -18,21 +18,17 @@ use rustc_span::source_map::Spanned; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using /// the pattern's length. /// - /// **Why is this bad?** + /// ### Why is this bad? /// Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no /// slicing which may panic and the compiler does not need to insert this panic code. It is /// also sometimes more readable as it removes the need for duplicating or storing the pattern /// used by `str::{starts,ends}_with` and in the slicing. /// - /// **Known problems:** - /// None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let s = "hello, world!"; /// if s.starts_with("hello, ") { diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 9d8d77cf8f0..426789742d5 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -15,15 +15,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`. /// - /// **Why is this bad?** + /// ### Why is this bad? /// Concise code helps focusing on behavior instead of boilerplate. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let foo: Option = None; /// match foo { diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index e1f80ab025c..394606200bb 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -15,16 +15,15 @@ use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `map(|x| x.clone())` or + /// ### What it does + /// Checks for usage of `map(|x| x.clone())` or /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, /// and suggests `cloned()` or `copied()` instead /// - /// **Why is this bad?** Readability, this can be written more concisely - /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Why is this bad? + /// Readability, this can be written more concisely /// + /// ### Example /// ```rust /// let x = vec![42, 43]; /// let y = x.iter(); diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 425a9734e5f..82d3732326e 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -4,13 +4,13 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for instances of `map_err(|_| Some::Enum)` + /// ### What it does + /// Checks for instances of `map_err(|_| Some::Enum)` /// - /// **Why is this bad?** This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + /// ### Why is this bad? + /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Before: /// ```rust /// use std::fmt; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 57cd907e77e..fd40590d077 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -12,16 +12,15 @@ use rustc_span::source_map::Span; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for usage of `option.map(f)` where f is a function + /// ### What it does + /// Checks for usage of `option.map(f)` where f is a function /// or closure that returns the unit type `()`. /// - /// **Why is this bad?** Readability, this can be written more clearly with + /// ### Why is this bad? + /// Readability, this can be written more clearly with /// an if let statement /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// # fn do_stuff() -> Option { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option { Some(foo) } @@ -54,16 +53,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `result.map(f)` where f is a function + /// ### What it does + /// Checks for usage of `result.map(f)` where f is a function /// or closure that returns the unit type `()`. /// - /// **Why is this bad?** Readability, this can be written more clearly with + /// ### Why is this bad? + /// Readability, this can be written more clearly with /// an if let statement /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// # fn do_stuff() -> Result { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result { Ok(foo) } diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index ca6fb0831fe..e66a35452f0 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -10,13 +10,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`. + /// ### What it does + /// Checks for `match vec[idx]` or `match vec[n..m]`. /// - /// **Why is this bad?** This can panic at runtime. + /// ### Why is this bad? + /// This can panic at runtime. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust, no_run /// let arr = vec![0, 1, 2, 3]; /// let idx = 1; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index d7f600b3ab2..5360c02f905 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -35,14 +35,14 @@ use std::iter; use std::ops::Bound; declare_clippy_lint! { - /// **What it does:** Checks for matches with a single arm where an `if let` + /// ### What it does + /// Checks for matches with a single arm where an `if let` /// will usually suffice. /// - /// **Why is this bad?** Just readability – `if let` nests less than a `match`. + /// ### Why is this bad? + /// Just readability – `if let` nests less than a `match`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # fn bar(stool: &str) {} /// # let x = Some("abc"); @@ -63,15 +63,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for matches with two arms where an `if let else` will + /// ### What it does + /// Checks for matches with two arms where an `if let else` will /// usually suffice. /// - /// **Why is this bad?** Just readability – `if let` nests less than a `match`. - /// - /// **Known problems:** Personal style preferences may differ. + /// ### Why is this bad? + /// Just readability – `if let` nests less than a `match`. /// - /// **Example:** + /// ### Known problems + /// Personal style preferences may differ. /// + /// ### Example /// Using `match`: /// /// ```rust @@ -102,16 +104,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for matches where all arms match a reference, + /// ### What it does + /// Checks for matches where all arms match a reference, /// suggesting to remove the reference and deref the matched expression /// instead. It also checks for `if let &foo = bar` blocks. /// - /// **Why is this bad?** It just makes the code less readable. That reference + /// ### Why is this bad? + /// It just makes the code less readable. That reference /// destructuring adds nothing to the code. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// match x { @@ -133,14 +135,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for matches where match expression is a `bool`. It + /// ### What it does + /// Checks for matches where match expression is a `bool`. It /// suggests to replace the expression with an `if...else` block. /// - /// **Why is this bad?** It makes the code less readable. + /// ### Why is this bad? + /// It makes the code less readable. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # fn foo() {} /// # fn bar() {} @@ -167,14 +169,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for overlapping match arms. + /// ### What it does + /// Checks for overlapping match arms. /// - /// **Why is this bad?** It is likely to be an error and if not, makes the code + /// ### Why is this bad? + /// It is likely to be an error and if not, makes the code /// less obvious. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = 5; /// match x { @@ -189,15 +191,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for arm which matches all errors with `Err(_)` + /// ### What it does + /// Checks for arm which matches all errors with `Err(_)` /// and take drastic actions like `panic!`. /// - /// **Why is this bad?** It is generally a bad practice, similar to + /// ### Why is this bad? + /// It is generally a bad practice, similar to /// catching all exceptions in java with `catch(Exception)` /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x: Result = Ok(3); /// match x { @@ -211,14 +213,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for match which is used to add a reference to an + /// ### What it does + /// Checks for match which is used to add a reference to an /// `Option` value. /// - /// **Why is this bad?** Using `as_ref()` or `as_mut()` instead is shorter. + /// ### Why is this bad? + /// Using `as_ref()` or `as_mut()` instead is shorter. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x: Option<()> = None; /// @@ -237,14 +239,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for wildcard enum matches using `_`. + /// ### What it does + /// Checks for wildcard enum matches using `_`. /// - /// **Why is this bad?** New enum variants added by library updates can be missed. + /// ### Why is this bad? + /// New enum variants added by library updates can be missed. /// - /// **Known problems:** Suggested replacements may be incorrect if guards exhaustively cover some + /// ### Known problems + /// Suggested replacements may be incorrect if guards exhaustively cover some /// variants, and also may not use correct path to enum if it's not present in the current scope. /// - /// **Example:** + /// ### Example /// ```rust /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); @@ -266,15 +271,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for wildcard enum matches for a single variant. + /// ### What it does + /// Checks for wildcard enum matches for a single variant. /// - /// **Why is this bad?** New enum variants added by library updates can be missed. + /// ### Why is this bad? + /// New enum variants added by library updates can be missed. /// - /// **Known problems:** Suggested replacements may not use correct path to enum + /// ### Known problems + /// Suggested replacements may not use correct path to enum /// if it's not present in the current scope. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # enum Foo { A, B, C } /// # let x = Foo::B; @@ -298,14 +305,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for wildcard pattern used with others patterns in same match arm. + /// ### What it does + /// Checks for wildcard pattern used with others patterns in same match arm. /// - /// **Why is this bad?** Wildcard pattern already covers any other pattern as it will match anyway. + /// ### Why is this bad? + /// Wildcard pattern already covers any other pattern as it will match anyway. /// It makes the code less readable, especially to spot wildcard pattern use in match arm. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// match "foo" { @@ -325,14 +332,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for matches being used to destructure a single-variant enum + /// ### What it does + /// Checks for matches being used to destructure a single-variant enum /// or tuple struct where a `let` will suffice. /// - /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does. + /// ### Why is this bad? + /// Just readability – `let` doesn't nest, whereas a `match` does. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// enum Wrapper { /// Data(i32), @@ -360,14 +367,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for useless match that binds to only one value. + /// ### What it does + /// Checks for useless match that binds to only one value. /// - /// **Why is this bad?** Readability and needless complexity. + /// ### Why is this bad? + /// Readability and needless complexity. /// - /// **Known problems:** Suggested replacements may be incorrect when `match` + /// ### Known problems + /// Suggested replacements may be incorrect when `match` /// is actually binding temporary value, bringing a 'dropped while borrowed' error. /// - /// **Example:** + /// ### Example /// ```rust /// # let a = 1; /// # let b = 2; @@ -388,14 +398,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. + /// ### What it does + /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. /// - /// **Why is this bad?** Correctness and readability. It's like having a wildcard pattern after + /// ### Why is this bad? + /// Correctness and readability. It's like having a wildcard pattern after /// matching all enum variants explicitly. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # struct A { a: i32 } /// let a = A { a: 5 }; @@ -418,21 +428,23 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Lint for redundant pattern matching over `Result`, `Option`, + /// ### What it does + /// Lint for redundant pattern matching over `Result`, `Option`, /// `std::task::Poll` or `std::net::IpAddr` /// - /// **Why is this bad?** It's more concise and clear to just use the proper + /// ### Why is this bad? + /// It's more concise and clear to just use the proper /// utility function /// - /// **Known problems:** This will change the drop order for the matched type. Both `if let` and + /// ### Known problems + /// This will change the drop order for the matched type. Both `if let` and /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the /// value before entering the block. For most types this change will not matter, but for a few /// types this will not be an acceptable change (e.g. locks). See the /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about /// drop order. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -471,15 +483,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `match` or `if let` expressions producing a + /// ### What it does + /// Checks for `match` or `if let` expressions producing a /// `bool` that could be written using `matches!` /// - /// **Why is this bad?** Readability and needless complexity. + /// ### Why is this bad? + /// Readability and needless complexity. /// - /// **Known problems:** This lint falsely triggers, if there are arms with + /// ### Known problems + /// This lint falsely triggers, if there are arms with /// `cfg` attributes that remove an arm evaluating to `false`. /// - /// **Example:** + /// ### Example /// ```rust /// let x = Some(5); /// @@ -504,17 +519,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `match` with identical arm bodies. + /// ### What it does + /// Checks for `match` with identical arm bodies. /// - /// **Why is this bad?** This is probably a copy & paste error. If arm bodies + /// ### Why is this bad? + /// This is probably a copy & paste error. If arm bodies /// are the same on purpose, you can factor them /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). /// - /// **Known problems:** False positive possible with order dependent `match` + /// ### Known problems + /// False positive possible with order dependent `match` /// (see issue /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)). /// - /// **Example:** + /// ### Example /// ```rust,ignore /// match foo { /// Bar => bar(), diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index aca96e06ef2..59176c4b846 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -9,14 +9,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type. + /// ### What it does + /// Checks for calls of `mem::discriminant()` on a non-enum type. /// - /// **Why is this bad?** The value of `mem::discriminant()` on non-enum types + /// ### Why is this bad? + /// The value of `mem::discriminant()` on non-enum types /// is unspecified. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// use std::mem; /// diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index a28cb5f32fe..07202a59c4b 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -5,15 +5,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is + /// ### What it does + /// Checks for usage of `std::mem::forget(t)` where `t` is /// `Drop`. /// - /// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its + /// ### Why is this bad? + /// `std::mem::forget(t)` prevents `t` from running its /// destructor, possibly causing leaks. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::mem; /// # use std::rc::Rc; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 183daee3617..3d071c9081b 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -14,16 +14,16 @@ use rustc_span::source_map::Span; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Checks for `mem::replace()` on an `Option` with + /// ### What it does + /// Checks for `mem::replace()` on an `Option` with /// `None`. /// - /// **Why is this bad?** `Option` already has the method `take()` for + /// ### Why is this bad? + /// `Option` already has the method `take()` for /// taking its current value (Some(..) or None) and replacing it with /// `None`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// use std::mem; /// @@ -41,17 +41,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `mem::replace(&mut _, mem::uninitialized())` + /// ### What it does + /// Checks for `mem::replace(&mut _, mem::uninitialized())` /// and `mem::replace(&mut _, mem::zeroed())`. /// - /// **Why is this bad?** This will lead to undefined behavior even if the + /// ### Why is this bad? + /// This will lead to undefined behavior even if the /// value is overwritten later, because the uninitialized value may be /// observed in the case of a panic. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ``` /// use std::mem; ///# fn may_panic(v: Vec) -> Vec { v } @@ -73,15 +72,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `std::mem::replace` on a value of type + /// ### What it does + /// Checks for `std::mem::replace` on a value of type /// `T` with `T::default()`. /// - /// **Why is this bad?** `std::mem` module already has the method `take` to + /// ### Why is this bad? + /// `std::mem` module already has the method `take` to /// take the current value and replace it with the default value of that type. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let mut text = String::from("foo"); /// let replaced = std::mem::replace(&mut text, String::default()); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 283fcf281df..d3e12023814 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -80,16 +80,15 @@ use rustc_span::{sym, Span}; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { - /// **What it does:** Checks for usages of `cloned()` on an `Iterator` or `Option` where + /// ### What it does + /// Checks for usages of `cloned()` on an `Iterator` or `Option` where /// `copied()` could be used instead. /// - /// **Why is this bad?** `copied()` is better because it guarantees that the type being cloned + /// ### Why is this bad? + /// `copied()` is better because it guarantees that the type being cloned /// implements `Copy`. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// [1, 2, 3].iter().cloned(); /// ``` @@ -103,16 +102,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usages of `Iterator::flat_map()` where `filter_map()` could be + /// ### What it does + /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be /// used instead. /// - /// **Why is this bad?** When applicable, `filter_map()` is more clear since it shows that + /// ### Why is this bad? + /// When applicable, `filter_map()` is more clear since it shows that /// `Option` is used to produce 0 or 1 items. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let nums: Vec = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); /// ``` @@ -126,9 +124,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. + /// ### What it does + /// Checks for `.unwrap()` calls on `Option`s and on `Result`s. /// - /// **Why is this bad?** It is better to handle the `None` or `Err` case, + /// ### Why is this bad? + /// It is better to handle the `None` or `Err` case, /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is /// `Allow` by default. @@ -141,9 +141,7 @@ declare_clippy_lint! { /// messages on display. Therefore, it may be beneficial to look at the places /// where they may get displayed. Activate this lint to do just that. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust /// # let opt = Some(1); /// @@ -171,9 +169,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `.expect()` calls on `Option`s and `Result`s. + /// ### What it does + /// Checks for `.expect()` calls on `Option`s and `Result`s. /// - /// **Why is this bad?** Usually it is better to handle the `None` or `Err` case. + /// ### Why is this bad? + /// Usually it is better to handle the `None` or `Err` case. /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why /// this lint is `Allow` by default. /// @@ -181,9 +181,7 @@ declare_clippy_lint! { /// values. Normally, you want to implement more sophisticated error handling, /// and propagate errors upwards with `?` operator. /// - /// **Known problems:** None. - /// - /// **Examples:** + /// ### Examples /// ```rust,ignore /// # let opt = Some(1); /// @@ -213,20 +211,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for methods that should live in a trait + /// ### What it does + /// Checks for methods that should live in a trait /// implementation of a `std` trait (see [llogiq's blog /// post](http://llogiq.github.io/2015/07/30/traits.html) for further /// information) instead of an inherent implementation. /// - /// **Why is this bad?** Implementing the traits improve ergonomics for users of + /// ### Why is this bad? + /// Implementing the traits improve ergonomics for users of /// the code, often with very little cost. Also people seeing a `mul(...)` /// method /// may expect `*` to work equally, so you should have good reason to disappoint /// them. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// struct X; /// impl X { @@ -242,7 +240,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for methods with certain name prefixes and which + /// ### What it does + /// Checks for methods with certain name prefixes and which /// doesn't match how self is taken. The actual rules are: /// /// |Prefix |Postfix |`self` taken | `self` type | @@ -265,13 +264,12 @@ declare_clippy_lint! { /// Please find more info here: /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv /// - /// **Why is this bad?** Consistency breeds readability. If you follow the + /// ### Why is this bad? + /// Consistency breeds readability. If you follow the /// conventions, your users won't be surprised that they, e.g., need to supply a /// mutable reference to a `as_..` function. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # struct X; /// impl X { @@ -287,14 +285,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `ok().expect(..)`. + /// ### What it does + /// Checks for usage of `ok().expect(..)`. /// - /// **Why is this bad?** Because you usually call `expect()` on the `Result` + /// ### Why is this bad? + /// Because you usually call `expect()` on the `Result` /// directly to get a better error message. /// - /// **Known problems:** The error type needs to implement `Debug` + /// ### Known problems + /// The error type needs to implement `Debug` /// - /// **Example:** + /// ### Example /// ```rust /// # let x = Ok::<_, ()>(()); /// @@ -310,15 +311,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or + /// ### What it does + /// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or /// `result.map(_).unwrap_or_else(_)`. /// - /// **Why is this bad?** Readability, these can be written more concisely (resp.) as + /// ### Why is this bad? + /// Readability, these can be written more concisely (resp.) as /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`. /// - /// **Known problems:** The order of the arguments is not in execution order + /// ### Known problems + /// The order of the arguments is not in execution order /// - /// **Examples:** + /// ### Examples /// ```rust /// # let x = Some(1); /// @@ -347,14 +351,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map_or(None, _)`. + /// ### What it does + /// Checks for usage of `_.map_or(None, _)`. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.and_then(_)`. /// - /// **Known problems:** The order of the arguments is not in execution order. + /// ### Known problems + /// The order of the arguments is not in execution order. /// - /// **Example:** + /// ### Example /// ```rust /// # let opt = Some(1); /// @@ -370,15 +377,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map_or(None, Some)`. + /// ### What it does + /// Checks for usage of `_.map_or(None, Some)`. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.ok()`. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// Bad: /// ```rust /// # let r: Result = Ok(1); @@ -396,16 +402,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or + /// ### What it does + /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or /// `_.or_else(|x| Err(y))`. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.map(|x| y)` or `_.map_err(|x| y)`. /// - /// **Known problems:** None - /// - /// **Example:** - /// + /// ### Example /// ```rust /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } @@ -429,14 +434,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.filter(_).next()`. + /// ### What it does + /// Checks for usage of `_.filter(_).next()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.find(_)`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let vec = vec![1]; /// vec.iter().filter(|x| **x == 0).next(); @@ -452,14 +457,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.skip_while(condition).next()`. + /// ### What it does + /// Checks for usage of `_.skip_while(condition).next()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.find(!condition)`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let vec = vec![1]; /// vec.iter().skip_while(|x| **x == 0).next(); @@ -475,14 +480,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option` + /// ### What it does + /// Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option` /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.flat_map(_)` /// - /// **Known problems:** - /// - /// **Example:** + /// ### Example /// ```rust /// let vec = vec![vec![1]]; /// @@ -498,15 +503,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.filter(_).map(_)` that can be written more simply + /// ### What it does + /// Checks for usage of `_.filter(_).map(_)` that can be written more simply /// as `filter_map(_)`. /// - /// **Why is this bad?** Redundant code in the `filter` and `map` operations is poor style and + /// ### Why is this bad? + /// Redundant code in the `filter` and `map` operations is poor style and /// less performant. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust /// (0_i32..10) @@ -524,15 +529,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.find(_).map(_)` that can be written more simply + /// ### What it does + /// Checks for usage of `_.find(_).map(_)` that can be written more simply /// as `find_map(_)`. /// - /// **Why is this bad?** Redundant code in the `find` and `map` operations is poor style and + /// ### Why is this bad? + /// Redundant code in the `find` and `map` operations is poor style and /// less performant. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust /// (0_i32..10) @@ -550,14 +555,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.filter_map(_).next()`. + /// ### What it does + /// Checks for usage of `_.filter_map(_).next()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.find_map(_)`. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next(); /// ``` @@ -572,13 +577,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `flat_map(|x| x)`. + /// ### What it does + /// Checks for usage of `flat_map(|x| x)`. /// - /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// ### Why is this bad? + /// Readability, this can be written more concisely by using `flatten`. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// # let iter = vec![vec![0]].into_iter(); /// iter.flat_map(|x| x); @@ -594,16 +599,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for an iterator or string search (such as `find()`, + /// ### What it does + /// Checks for an iterator or string search (such as `find()`, /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`. /// - /// **Why is this bad?** Readability, this can be written more concisely as: + /// ### Why is this bad? + /// Readability, this can be written more concisely as: /// * `_.any(_)`, or `_.contains(_)` for `is_some()`, /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let vec = vec![1]; /// vec.iter().find(|x| **x == 0).is_some(); @@ -623,15 +628,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.chars().next()` on a `str` to check + /// ### What it does + /// Checks for usage of `.chars().next()` on a `str` to check /// if it starts with a given char. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.starts_with(_)`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let name = "foo"; /// if name.chars().next() == Some('_') {}; @@ -647,17 +652,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, + /// ### What it does + /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or /// `unwrap_or_default` instead. /// - /// **Why is this bad?** The function will always be called and potentially + /// ### Why is this bad? + /// The function will always be called and potentially /// allocate an object acting as the default. /// - /// **Known problems:** If the function has side-effects, not calling it will + /// ### 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. /// - /// **Example:** + /// ### Example /// ```rust /// # let foo = Some(String::new()); /// foo.unwrap_or(String::new()); @@ -678,15 +686,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`, + /// ### What it does + /// Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`, /// etc., and suggests to use `unwrap_or_else` instead /// - /// **Why is this bad?** The function will always be called. + /// ### Why is this bad? + /// The function will always be called. /// - /// **Known problems:** If the function has side-effects, not calling it will + /// ### Known problems + /// If the function has side-effects, not calling it will /// change the semantics of the program, but you shouldn't rely on that anyway. /// - /// **Example:** + /// ### Example /// ```rust /// # let foo = Some(String::new()); /// # let err_code = "418"; @@ -713,14 +724,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.clone()` on a `Copy` type. + /// ### What it does + /// Checks for usage of `.clone()` on a `Copy` type. /// - /// **Why is this bad?** The only reason `Copy` types implement `Clone` is for + /// ### Why is this bad? + /// The only reason `Copy` types implement `Clone` is for /// generics, not for using the `clone` method on a concrete type. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// 42u64.clone(); /// ``` @@ -730,15 +741,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer, + /// ### What it does + /// Checks for usage of `.clone()` on a ref-counted pointer, /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified /// function syntax instead (e.g., `Rc::clone(foo)`). /// - /// **Why is this bad?** Calling '.clone()' on an Rc, Arc, or Weak + /// ### Why is this bad? + /// Calling '.clone()' on an Rc, Arc, or Weak /// can obscure the fact that only the pointer is being cloned, not the underlying /// data. /// - /// **Example:** + /// ### Example /// ```rust /// # use std::rc::Rc; /// let x = Rc::new(1); @@ -755,14 +768,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.clone()` on an `&&T`. + /// ### What it does + /// Checks for usage of `.clone()` on an `&&T`. /// - /// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of + /// ### Why is this bad? + /// Cloning an `&&T` copies the inner `&T`, instead of /// cloning the underlying `T`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn main() { /// let x = vec![1]; @@ -777,16 +790,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.to_string()` on an `&&T` where + /// ### What it does + /// Checks for usage of `.to_string()` on an `&&T` where /// `T` implements `ToString` directly (like `&&str` or `&&String`). /// - /// **Why is this bad?** This bypasses the specialized implementation of + /// ### Why is this bad? + /// This bypasses the specialized implementation of /// `ToString` and instead goes through the more expensive string formatting /// facilities. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Generic implementation for `T: Display` is used (slow) /// ["foo", "bar"].iter().map(|s| s.to_string()); @@ -800,14 +813,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `new` not returning a type that contains `Self`. + /// ### What it does + /// Checks for `new` not returning a type that contains `Self`. /// - /// **Why is this bad?** As a convention, `new` methods are used to make a new + /// ### Why is this bad? + /// As a convention, `new` methods are used to make a new /// instance of a type. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// In an impl block: /// ```rust /// # struct Foo; @@ -861,15 +874,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for string methods that receive a single-character + /// ### What it does + /// Checks for string methods that receive a single-character /// `str` as an argument, e.g., `_.split("x")`. /// - /// **Why is this bad?** Performing these methods using a `char` is faster than + /// ### Why is this bad? + /// Performing these methods using a `char` is faster than /// using a `str`. /// - /// **Known problems:** Does not catch multi-byte unicode characters. + /// ### Known problems + /// Does not catch multi-byte unicode characters. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// _.split("x"); @@ -882,14 +898,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calling `.step_by(0)` on iterators which panics. + /// ### What it does + /// Checks for calling `.step_by(0)` on iterators which panics. /// - /// **Why is this bad?** This very much looks like an oversight. Use `panic!()` instead if you + /// ### Why is this bad? + /// This very much looks like an oversight. Use `panic!()` instead if you /// actually intend to panic. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,should_panic /// for x in (0..100).step_by(0) { /// //.. @@ -901,15 +917,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for indirect collection of populated `Option` + /// ### What it does + /// Checks for indirect collection of populated `Option` /// - /// **Why is this bad?** `Option` is like a collection of 0-1 things, so `flatten` + /// ### Why is this bad? + /// `Option` is like a collection of 0-1 things, so `flatten` /// automatically does this without suspicious-looking `unwrap` calls. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let _ = std::iter::empty::>().filter(Option::is_some).map(Option::unwrap); /// ``` @@ -923,16 +938,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of `iter.nth(0)`. + /// ### What it does + /// Checks for the use of `iter.nth(0)`. /// - /// **Why is this bad?** `iter.next()` is equivalent to + /// ### Why is this bad? + /// `iter.next()` is equivalent to /// `iter.nth(0)`, as they both consume the next element, /// but is more readable. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// # use std::collections::HashSet; /// // Bad @@ -951,15 +965,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `.iter().nth()` (and the related + /// ### What it does + /// Checks for use of `.iter().nth()` (and the related /// `.iter_mut().nth()`) on standard library types with O(1) element access. /// - /// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more + /// ### Why is this bad? + /// `.get()` and `.get_mut()` are more efficient and more /// readable. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); @@ -977,13 +991,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `.skip(x).next()` on iterators. - /// - /// **Why is this bad?** `.nth(x)` is cleaner + /// ### What it does + /// Checks for use of `.skip(x).next()` on iterators. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// `.nth(x)` is cleaner /// - /// **Example:** + /// ### Example /// ```rust /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().skip(3).next(); @@ -1001,13 +1015,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `.get().unwrap()` (or + /// ### What it does + /// Checks for use of `.get().unwrap()` (or /// `.get_mut().unwrap`) on a standard library type which implements `Index` /// - /// **Why is this bad?** Using the Index trait (`[]`) is more clear and more + /// ### Why is this bad? + /// Using the Index trait (`[]`) is more clear and more /// concise. /// - /// **Known problems:** Not a replacement for error handling: Using either + /// ### Known problems + /// Not a replacement for error handling: Using either /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic` /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a /// temporary placeholder for dealing with the `Option` type, then this does @@ -1016,7 +1033,7 @@ declare_clippy_lint! { /// is handled in a future refactor instead of using `.unwrap()` or the Index /// trait. /// - /// **Example:** + /// ### Example /// ```rust /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec.get(3).unwrap(); @@ -1034,14 +1051,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for occurrences where one vector gets extended instead of append + /// ### What it does + /// Checks for occurrences where one vector gets extended instead of append /// - /// **Why is this bad?** Using `append` instead of `extend` is more concise and faster - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Using `append` instead of `extend` is more concise and faster /// + /// ### Example /// ```rust /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; @@ -1058,14 +1074,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a + /// ### What it does + /// Checks for the use of `.extend(s.chars())` where s is a /// `&str` or `String`. /// - /// **Why is this bad?** `.push_str(s)` is clearer + /// ### Why is this bad? + /// `.push_str(s)` is clearer /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let abc = "abc"; /// let def = String::from("def"); @@ -1087,14 +1103,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of `.cloned().collect()` on slice to + /// ### What it does + /// Checks for the use of `.cloned().collect()` on slice to /// create a `Vec`. /// - /// **Why is this bad?** `.to_vec()` is clearer - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// `.to_vec()` is clearer /// - /// **Example:** + /// ### Example /// ```rust /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec = s[..].iter().cloned().collect(); @@ -1110,15 +1126,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.chars().last()` or + /// ### What it does + /// Checks for usage of `_.chars().last()` or /// `_.chars().next_back()` on a `str` to check if it ends with a given char. /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.ends_with(_)`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let name = "_"; /// @@ -1134,14 +1150,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the + /// ### What it does + /// Checks for usage of `.as_ref()` or `.as_mut()` where the /// types before and after the call are the same. /// - /// **Why is this bad?** The call is unnecessary. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// The call is unnecessary. /// - /// **Example:** + /// ### Example /// ```rust /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; @@ -1159,15 +1175,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for using `fold` when a more succinct alternative exists. + /// ### What it does + /// Checks for using `fold` when a more succinct alternative exists. /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`, /// `sum` or `product`. /// - /// **Why is this bad?** Readability. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// Readability. /// - /// **Example:** + /// ### Example /// ```rust /// let _ = (0..3).fold(false, |acc, x| acc || x > 2); /// ``` @@ -1181,16 +1197,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`. + /// ### What it does + /// Checks for `filter_map` calls which could be replaced by `filter` or `map`. /// More specifically it checks if the closure provided is only performing one of the /// filter or map operations and suggests the appropriate option. /// - /// **Why is this bad?** Complexity. The intent is also clearer if only a single + /// ### Why is this bad? + /// Complexity. The intent is also clearer if only a single /// operation is being performed. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); /// @@ -1210,17 +1226,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter` + /// ### What it does + /// Checks for `into_iter` calls on references which should be replaced by `iter` /// or `iter_mut`. /// - /// **Why is this bad?** Readability. Calling `into_iter` on a reference will not move out its + /// ### Why is this bad? + /// Readability. Calling `into_iter` on a reference will not move out its /// content into the resulting iterator, which is confusing. It is better just call `iter` or /// `iter_mut` directly. /// - /// **Known problems:** None - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let _ = (&vec![3, 4, 5]).into_iter(); @@ -1234,16 +1249,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `map` followed by a `count`. + /// ### What it does + /// Checks for calls to `map` followed by a `count`. /// - /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`. + /// ### Why is this bad? + /// It looks suspicious. Maybe `map` was confused with `filter`. /// If the `map` call is intentional, this should be rewritten. Or, if you intend to /// drive the iterator to completion, you can just use `for_each` instead. /// - /// **Known problems:** None - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let _ = (0..3).map(|x| x + 2).count(); /// ``` @@ -1253,16 +1267,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `MaybeUninit::uninit().assume_init()`. + /// ### What it does + /// Checks for `MaybeUninit::uninit().assume_init()`. /// - /// **Why is this bad?** For most types, this is undefined behavior. + /// ### Why is this bad? + /// For most types, this is undefined behavior. /// - /// **Known problems:** For now, we accept empty tuples and tuples / arrays + /// ### Known problems + /// For now, we accept empty tuples and tuples / arrays /// of `MaybeUninit`. There may be other types that allow uninitialized /// data, but those are not yet rigorously defined. /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Beware the UB /// use std::mem::MaybeUninit; @@ -1285,12 +1301,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`. + /// ### What it does + /// Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`. /// - /// **Why is this bad?** These can be written simply with `saturating_add/sub` methods. - /// - /// **Example:** + /// ### Why is this bad? + /// These can be written simply with `saturating_add/sub` methods. /// + /// ### Example /// ```rust /// # let y: u32 = 0; /// # let x: u32 = 100; @@ -1312,14 +1329,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to + /// ### What it does + /// Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to /// zero-sized types /// - /// **Why is this bad?** This is a no-op, and likely unintended - /// - /// **Known problems:** None + /// ### Why is this bad? + /// This is a no-op, and likely unintended /// - /// **Example:** + /// ### Example /// ```rust /// unsafe { (&() as *const ()).offset(1) }; /// ``` @@ -1329,15 +1346,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `FileType::is_file()`. + /// ### What it does + /// Checks for `FileType::is_file()`. /// - /// **Why is this bad?** When people testing a file type with `FileType::is_file` + /// ### Why is this bad? + /// When people testing a file type with `FileType::is_file` /// they are testing whether a path is something they can get bytes from. But /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # || { /// let metadata = std::fs::metadata("foo.txt")?; @@ -1369,14 +1387,14 @@ 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). + /// ### What it does + /// Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str). /// - /// **Why is this bad?** Readability, this can be written more concisely as + /// ### Why is this bad? + /// Readability, this can be written more concisely as /// `_.as_deref()`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let opt = Some("".to_string()); /// opt.as_ref().map(String::as_str) @@ -1394,13 +1412,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array - /// - /// **Why is this bad?** These can be shortened into `.get()` + /// ### What it does + /// Checks for usage of `iter().next()` on a Slice or an Array /// - /// **Known problems:** None. + /// ### Why is this bad? + /// These can be shortened into `.get()` /// - /// **Example:** + /// ### Example /// ```rust /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; @@ -1420,14 +1438,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal + /// ### What it does + /// Warns when using `push_str`/`insert_str` with a single-character string literal /// where `push`/`insert` with a `char` would work fine. /// - /// **Why is this bad?** It's less clear that we are pushing a single character. + /// ### Why is this bad? + /// It's less clear that we are pushing a single character. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// let mut string = String::new(); /// string.insert_str(0, "R"); @@ -1445,7 +1463,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary + /// ### What it does + /// As the counterpart to `or_fun_call`, this lint looks for unnecessary /// lazily evaluated closures on `Option` and `Result`. /// /// This lint suggests changing the following functions, when eager evaluation results in @@ -1456,13 +1475,14 @@ declare_clippy_lint! { /// - `get_or_insert_with` to `get_or_insert` /// - `ok_or_else` to `ok_or` /// - /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases. + /// ### Why is this bad? + /// Using eager evaluation is shorter and simpler in some cases. /// - /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have + /// ### Known problems + /// It is possible, but not recommended for `Deref` and `Index` to have /// side effects. Eagerly evaluating them can change the semantics of the program. /// - /// **Example:** - /// + /// ### Example /// ```rust /// // example code where clippy issues a warning /// let opt: Option = None; @@ -1481,14 +1501,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).collect::()`. - /// - /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. - /// - /// **Known problems:** None + /// ### What it does + /// Checks for usage of `_.map(_).collect::()`. /// - /// **Example:** + /// ### Why is this bad? + /// Using `try_for_each` instead is more readable and idiomatic. /// + /// ### Example /// ```rust /// (0..3).map(|t| Err(t)).collect::>(); /// ``` @@ -1502,16 +1521,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator` + /// ### What it does + /// Checks for `from_iter()` function calls on types that implement the `FromIterator` /// trait. /// - /// **Why is this bad?** It is recommended style to use collect. See + /// ### Why is this bad? + /// It is recommended style to use collect. See /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// use std::iter::FromIterator; /// @@ -1535,15 +1553,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `inspect().for_each()`. + /// ### What it does + /// Checks for usage of `inspect().for_each()`. /// - /// **Why is this bad?** It is the same as performing the computation + /// ### Why is this bad? + /// It is the same as performing the computation /// inside `inspect` at the beginning of the closure in `for_each`. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// [1,2,3,4,5].iter() /// .inspect(|&x| println!("inspect the number: {}", x)) @@ -1565,14 +1582,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `filter_map(|x| x)`. - /// - /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// ### What it does + /// Checks for usage of `filter_map(|x| x)`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Readability, this can be written more concisely by using `flatten`. /// + /// ### Example /// ```rust /// # let iter = vec![Some(1)].into_iter(); /// iter.filter_map(|x| x); @@ -1588,14 +1604,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function. - /// - /// **Why is this bad?** It can be written more concisely without the call to `map`. + /// ### What it does + /// Checks for instances of `map(f)` where `f` is the identity function. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// It can be written more concisely without the call to `map`. /// + /// ### Example /// ```rust /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); @@ -1611,15 +1626,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of `.bytes().nth()`. + /// ### What it does + /// Checks for the use of `.bytes().nth()`. /// - /// **Why is this bad?** `.as_bytes().get()` is more efficient and more + /// ### Why is this bad? + /// `.as_bytes().get()` is more efficient and more /// readable. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let _ = "Hello".bytes().nth(3); @@ -1633,15 +1647,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer. + /// ### What it does + /// Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer. /// - /// **Why is this bad?** These methods do the same thing as `_.clone()` but may be confusing as + /// ### Why is this bad? + /// These methods do the same thing as `_.clone()` but may be confusing as /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let a = vec![1, 2, 3]; /// let b = a.to_vec(); @@ -1659,15 +1672,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of `.iter().count()`. + /// ### What it does + /// Checks for the use of `.iter().count()`. /// - /// **Why is this bad?** `.len()` is more efficient and more + /// ### Why is this bad? + /// `.len()` is more efficient and more /// readable. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let some_vec = vec![0, 1, 2, 3]; @@ -1685,17 +1697,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to [`splitn`] + /// ### What it does + /// Checks for calls to [`splitn`] /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and /// related functions with either zero or one splits. /// - /// **Why is this bad?** These calls don't actually split the value and are + /// ### Why is this bad? + /// These calls don't actually split the value and are /// likely to be intended as a different number. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let s = ""; @@ -1715,14 +1726,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for manual implementations of `str::repeat` - /// - /// **Why is this bad?** These are both harder to read, as well as less performant. - /// - /// **Known problems:** None. + /// ### What it does + /// Checks for manual implementations of `str::repeat` /// - /// **Example:** + /// ### Why is this bad? + /// These are both harder to read, as well as less performant. /// + /// ### Example /// ```rust /// // Bad /// let x: String = std::iter::repeat('x').take(10).collect(); diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index ff3473b744e..dc2dd45e4ed 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -8,15 +8,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::cmp::Ordering; declare_clippy_lint! { - /// **What it does:** Checks for expressions where `std::cmp::min` and `max` are + /// ### What it does + /// Checks for expressions where `std::cmp::min` and `max` are /// used to clamp values, but switched so that the result is constant. /// - /// **Why is this bad?** This is in all probability not the intended outcome. At + /// ### Why is this bad? + /// This is in all probability not the intended outcome. At /// the least it hurts readability of the code. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```ignore /// min(0, max(100, x)) /// ``` diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 7cfce2e61cc..c796abe9815 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -25,10 +25,12 @@ use clippy_utils::{ }; declare_clippy_lint! { - /// **What it does:** Checks for function arguments and let bindings denoted as + /// ### What it does + /// Checks for function arguments and let bindings denoted as /// `ref`. /// - /// **Why is this bad?** The `ref` declaration makes the function take an owned + /// ### Why is this bad? + /// The `ref` declaration makes the function take an owned /// value, but turns the argument into a reference (which means that the value /// is destroyed when exiting the function). This adds not much value: either /// take a reference type, or take an owned value and create references in the @@ -37,11 +39,12 @@ declare_clippy_lint! { /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The /// type of `x` is more obvious with the former. /// - /// **Known problems:** If the argument is dereferenced within the function, + /// ### Known problems + /// If the argument is dereferenced within the function, /// removing the `ref` will lead to errors. This can be fixed by removing the /// dereferences, e.g., changing `*x` to `x` within the function. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// fn foo(ref x: u8) -> bool { @@ -59,14 +62,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparisons to NaN. + /// ### What it does + /// Checks for comparisons to NaN. /// - /// **Why is this bad?** NaN does not compare meaningfully to anything – not + /// ### Why is this bad? + /// NaN does not compare meaningfully to anything – not /// even itself – so those comparisons are simply wrong. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1.0; /// @@ -82,18 +85,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for (in-)equality comparisons on floating-point + /// ### What it does + /// Checks for (in-)equality comparisons on floating-point /// values (apart from zero), except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// - /// **Why is this bad?** Floating point calculations are usually imprecise, so + /// ### Why is this bad? + /// Floating point calculations are usually imprecise, so /// asking if two values are *exactly* equal is asking for trouble. For a good /// guide on what to do, see [the floating point /// guide](http://www.floating-point-gui.de/errors/comparison). /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = 1.2331f64; /// let y = 1.2332f64; @@ -115,16 +118,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for conversions to owned values just for the sake + /// ### What it does + /// Checks for conversions to owned values just for the sake /// of a comparison. /// - /// **Why is this bad?** The comparison can operate on a reference, so creating + /// ### Why is this bad? + /// The comparison can operate on a reference, so creating /// an owned value effectively throws it away directly afterwards, which is /// needlessly consuming code and heap space. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = "foo"; /// # let y = String::from("foo"); @@ -142,18 +145,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for getting the remainder of a division by one or minus + /// ### What it does + /// Checks for getting the remainder of a division by one or minus /// one. /// - /// **Why is this bad?** The result for a divisor of one can only ever be zero; for + /// ### Why is this bad? + /// The result for a divisor of one can only ever be zero; for /// minus one it can cause panic/overflow (if the left operand is the minimal value of /// the respective integer type) or results in zero. No one will write such code /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that /// contest, it's probably a bad idea. Use something more underhanded. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// let a = x % 1; @@ -165,17 +168,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of bindings with a single leading + /// ### What it does + /// Checks for the use of bindings with a single leading /// underscore. /// - /// **Why is this bad?** A single leading underscore is usually used to indicate + /// ### Why is this bad? + /// A single leading underscore is usually used to indicate /// that a binding will not be used. Using such a binding breaks this /// expectation. /// - /// **Known problems:** The lint does not work properly with desugaring and + /// ### Known problems + /// The lint does not work properly with desugaring and /// macro, it has been allowed in the mean time. /// - /// **Example:** + /// ### Example /// ```rust /// let _x = 0; /// let y = _x + 1; // Here we are using `_x`, even though it has a leading @@ -187,17 +193,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the use of short circuit boolean conditions as + /// ### What it does + /// Checks for the use of short circuit boolean conditions as /// a /// statement. /// - /// **Why is this bad?** Using a short circuit boolean condition as a statement + /// ### Why is this bad? + /// Using a short circuit boolean condition as a statement /// may hide the fact that the second part is executed or not depending on the /// outcome of the first part. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// f() && g(); // We should write `if f() { g(); }`. /// ``` @@ -207,15 +213,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Catch casts from `0` to some pointer type + /// ### What it does + /// Catch casts from `0` to some pointer type /// - /// **Why is this bad?** This generally means `null` and is better expressed as + /// ### Why is this bad? + /// This generally means `null` and is better expressed as /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// let a = 0 as *const u32; @@ -229,18 +234,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for (in-)equality comparisons on floating-point + /// ### What it does + /// Checks for (in-)equality comparisons on floating-point /// value and constant, except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// - /// **Why is this bad?** Floating point calculations are usually imprecise, so + /// ### Why is this bad? + /// Floating point calculations are usually imprecise, so /// asking if two values are *exactly* equal is asking for trouble. For a good /// guide on what to do, see [the floating point /// guide](http://www.floating-point-gui.de/errors/comparison). /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 050b6805b7c..06fe967dafc 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -18,14 +18,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for structure field patterns bound to wildcards. + /// ### What it does + /// Checks for structure field patterns bound to wildcards. /// - /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on + /// ### Why is this bad? + /// Using `..` instead is shorter and leaves the focus on /// the fields that are actually bound. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # struct Foo { /// # a: i32, @@ -52,14 +52,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for function arguments having the similar names + /// ### What it does + /// Checks for function arguments having the similar names /// differing by an underscore. /// - /// **Why is this bad?** It affects code readability. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// It affects code readability. /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// fn foo(a: i32, _a: i32) {} @@ -73,14 +73,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Detects expressions of the form `--x`. + /// ### What it does + /// Detects expressions of the form `--x`. /// - /// **Why is this bad?** It can mislead C/C++ programmers to think `x` was + /// ### Why is this bad? + /// It can mislead C/C++ programmers to think `x` was /// decremented. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let mut x = 3; /// --x; @@ -91,14 +91,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns on hexadecimal literals with mixed-case letter + /// ### What it does + /// Warns on hexadecimal literals with mixed-case letter /// digits. /// - /// **Why is this bad?** It looks confusing. + /// ### Why is this bad? + /// It looks confusing. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let y = 0x1a9BAcD; @@ -112,14 +112,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if literal suffixes are not separated by an + /// ### What it does + /// Warns if literal suffixes are not separated by an /// underscore. /// - /// **Why is this bad?** It is much less readable. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// It is much less readable. /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let y = 123832i32; @@ -133,17 +133,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if an integral constant literal starts with `0`. + /// ### What it does + /// Warns if an integral constant literal starts with `0`. /// - /// **Why is this bad?** In some languages (including the infamous C language + /// ### Why is this bad? + /// In some languages (including the infamous C language /// and most of its /// family), this marks an octal constant. In Rust however, this is a decimal /// constant. This could /// be confusing for both the writer and a reader of the constant. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// In Rust: /// ```rust @@ -171,13 +171,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns if a generic shadows a built-in type. - /// - /// **Why is this bad?** This gives surprising type errors. + /// ### What it does + /// Warns if a generic shadows a built-in type. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This gives surprising type errors. /// - /// **Example:** + /// ### Example /// /// ```ignore /// impl Foo { @@ -192,14 +192,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for patterns in the form `name @ _`. + /// ### What it does + /// Checks for patterns in the form `name @ _`. /// - /// **Why is this bad?** It's almost always more readable to just use direct + /// ### Why is this bad? + /// It's almost always more readable to just use direct /// bindings. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let v = Some("abc"); /// @@ -221,19 +221,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for tuple patterns with a wildcard + /// ### What it does + /// Checks for tuple patterns with a wildcard /// pattern (`_`) is next to a rest pattern (`..`). /// /// _NOTE_: While `_, ..` means there is at least one element left, `..` /// means there are 0 or more elements left. This can make a difference /// when refactoring, but shouldn't result in errors in the refactored code, /// since the wildcard pattern isn't used anyway. - /// **Why is this bad?** The wildcard pattern is unneeded as the rest pattern + /// ### Why is this bad? + /// The wildcard pattern is unneeded as the rest pattern /// can match that element as well. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 59cbc481ed4..5b2584d43a1 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -13,16 +13,13 @@ use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { - /// **What it does:** - /// + /// ### What it does /// Suggests the use of `const` in functions and methods where possible. /// - /// **Why is this bad?** - /// + /// ### Why is this bad? /// Not having the function const prevents callers of the function from being const as well. /// - /// **Known problems:** - /// + /// ### Known problems /// Const functions are currently still being worked on, with some features only being available /// on nightly. This lint does not consider all edge cases currently and the suggestions may be /// incorrect if you are using this lint on stable. @@ -42,8 +39,7 @@ declare_clippy_lint! { /// can't be const as it calls a non-const function. Making `a` const and running Clippy again, /// will suggest to make `b` const, too. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # struct Foo { /// # random_number: usize, diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ec1572c26c2..aeed8268902 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -17,15 +17,15 @@ use rustc_span::source_map::Span; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Warns if there is missing doc for any documentable item + /// ### What it does + /// Warns if there is missing doc for any documentable item /// (public or private). /// - /// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS` + /// ### Why is this bad? + /// Doc is good. *rustc* has a `MISSING_DOCS` /// allowed-by-default lint for /// public members, but has no way to enforce documentation of private items. /// This lint fixes that. - /// - /// **Known problems:** None. pub MISSING_DOCS_IN_PRIVATE_ITEMS, restriction, "detects missing documentation for public and private members" diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 59565350f72..9d27870321c 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -10,17 +10,16 @@ use rustc_span::Symbol; use crate::utils::conf::Rename; declare_clippy_lint! { - /// **What it does:** Checks for imports that do not rename the item as specified + /// ### What it does + /// Checks for imports that do not rename the item as specified /// in the `enforce-import-renames` config option. /// - /// **Why is this bad?** Consistency is important, if a project has defined import + /// ### Why is this bad? + /// Consistency is important, if a project has defined import /// renames they should be followed. More practically, some item names are too /// vague outside of their defining scope this can enforce a more meaningful naming. /// - /// **Known problems:** None - /// - /// **Example:** - /// + /// ### Example /// An example clippy.toml configuration: /// ```toml /// # clippy.toml diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 041fe64a1a9..be5b4b4006f 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -7,10 +7,12 @@ use rustc_span::source_map::Span; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** it lints if an exported function, method, trait method with default impl, + /// ### What it does + /// it lints if an exported function, method, trait method with default impl, /// or trait method impl is not `#[inline]`. /// - /// **Why is this bad?** In general, it is not. Functions can be inlined across + /// ### Why is this bad? + /// In general, it is not. Functions can be inlined across /// crates when that's profitable as long as any form of LTO is used. When LTO is disabled, /// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates /// might intend for most of the methods in their public API to be able to be inlined across @@ -18,9 +20,7 @@ declare_clippy_lint! { /// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and /// then opt out for specific methods where this might not make sense. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// pub fn foo() {} // missing #[inline] /// fn ok() {} // ok diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 1414fdc1b11..2d14943b56c 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -9,18 +9,18 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; declare_clippy_lint! { - /// **What it does:** Checks for modulo arithmetic. + /// ### What it does + /// Checks for modulo arithmetic. /// - /// **Why is this bad?** The results of modulo (%) operation might differ + /// ### Why is this bad? + /// The results of modulo (%) operation might differ /// depending on the language, when negative numbers are involved. /// If you interop with different languages it might be beneficial /// to double check all places that use modulo arithmetic. /// /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = -17 % 3; /// ``` diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index f5ce3e32551..1c61970fdc8 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -13,17 +13,20 @@ use if_chain::if_chain; use itertools::Itertools; declare_clippy_lint! { - /// **What it does:** Checks to see if multiple versions of a crate are being + /// ### What it does + /// Checks to see if multiple versions of a crate are being /// used. /// - /// **Why is this bad?** This bloats the size of targets, and can lead to + /// ### Why is this bad? + /// This bloats the size of targets, and can lead to /// confusing error messages when structs or traits are used interchangeably /// between different versions of a crate. /// - /// **Known problems:** Because this can be caused purely by the dependencies + /// ### Known problems + /// Because this can be caused purely by the dependencies /// themselves, it's not always possible to fix this issue. /// - /// **Example:** + /// ### Example /// ```toml /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning. /// [dependencies] diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 68f7cdf6ea0..2c7681c45a4 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -10,18 +10,21 @@ use rustc_span::symbol::sym; use std::iter; declare_clippy_lint! { - /// **What it does:** Checks for sets/maps with mutable key types. + /// ### What it does + /// Checks for sets/maps with mutable key types. /// - /// **Why is this bad?** All of `HashMap`, `HashSet`, `BTreeMap` and + /// ### Why is this bad? + /// All of `HashMap`, `HashSet`, `BTreeMap` and /// `BtreeSet` rely on either the hash or the order of keys be unchanging, /// so having types with interior mutability is a bad idea. /// - /// **Known problems:** It's correct to use a struct, that contains interior mutability + /// ### Known problems + /// It's correct to use a struct, that contains interior mutability /// as a key, when its `Hash` implementation doesn't access any of the interior mutable types. /// However, this lint is unable to recognize this, so it causes a false positive in theses cases. /// The `bytes` crate is a great example of this. /// - /// **Example:** + /// ### Example /// ```rust /// use std::cmp::{PartialEq, Eq}; /// use std::collections::HashSet; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 4b9c51d0c16..d5032c5ba7f 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -9,15 +9,15 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for instances of `mut mut` references. + /// ### What it does + /// Checks for instances of `mut mut` references. /// - /// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the + /// ### Why is this bad? + /// Multiple `mut`s don't add anything meaningful to the /// source. This is either a copy'n'paste error, or it shows a fundamental /// misunderstanding of references. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let mut y = 1; /// let x = &mut &mut y; diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs index b9ba74c7d02..85e870632a5 100644 --- a/clippy_lints/src/mut_mutex_lock.rs +++ b/clippy_lints/src/mut_mutex_lock.rs @@ -8,17 +8,16 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `&mut Mutex::lock` calls + /// ### What it does + /// Checks for `&mut Mutex::lock` calls /// - /// **Why is this bad?** `Mutex::lock` is less efficient than + /// ### Why is this bad? + /// `Mutex::lock` is less efficient than /// calling `Mutex::get_mut`. In addition you also have a statically /// guarantee that the mutex isn't locked, instead of just a runtime /// guarantee. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// use std::sync::{Arc, Mutex}; /// diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 6efe8ffcde0..8d5d7951fc5 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -7,15 +7,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::iter; declare_clippy_lint! { - /// **What it does:** Detects passing a mutable reference to a function that only + /// ### What it does + /// Detects passing a mutable reference to a function that only /// requires an immutable reference. /// - /// **Why is this bad?** The mutable reference rules out all other references to + /// ### Why is this bad? + /// The mutable reference rules out all other references to /// the value. Also the code misleads about the intent of the call site. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// // Bad /// my_vec.push(&mut value) diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 81bf853300f..ee50891cc31 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -9,17 +9,17 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for function/method calls with a mutable + /// ### What it does + /// Checks for function/method calls with a mutable /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros. /// - /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the + /// ### Why is this bad? + /// In release builds `debug_assert!` macros are optimized out by the /// compiler. /// Therefore mutating something in a `debug_assert!` macro results in different behaviour /// between a release and debug build. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// debug_assert_eq!(vec![3].pop(), Some(3)); /// // or diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 354e2c3fb74..436ceec6cfa 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -10,17 +10,20 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for usages of `Mutex` where an atomic will do. + /// ### What it does + /// Checks for usages of `Mutex` where an atomic will do. /// - /// **Why is this bad?** Using a mutex just to make access to a plain bool or + /// ### Why is this bad? + /// Using a mutex just to make access to a plain bool or /// reference sequential is shooting flies with cannons. /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and /// faster. /// - /// **Known problems:** This lint cannot detect if the mutex is actually used + /// ### Known problems + /// This lint cannot detect if the mutex is actually used /// for waiting before a critical section. /// - /// **Example:** + /// ### Example /// ```rust /// # let y = true; /// @@ -38,17 +41,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usages of `Mutex` where `X` is an integral + /// ### What it does + /// Checks for usages of `Mutex` where `X` is an integral /// type. /// - /// **Why is this bad?** Using a mutex just to make access to a plain integer + /// ### Why is this bad? + /// Using a mutex just to make access to a plain integer /// sequential is /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. /// - /// **Known problems:** This lint cannot detect if the mutex is actually used + /// ### Known problems + /// This lint cannot detect if the mutex is actually used /// for waiting before a critical section. /// - /// **Example:** + /// ### Example /// ```rust /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index fe3c4455be5..9a3d9383cd9 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -9,13 +9,13 @@ use rustc_span::symbol::kw; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** The lint checks for `self` in fn parameters that + /// ### What it does + /// The lint checks for `self` in fn parameters that /// specify the `Self`-type explicitly - /// **Why is this bad?** Increases the amount and decreases the readability of code + /// ### Why is this bad? + /// Increases the amount and decreases the readability of code /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// enum ValType { /// I32, diff --git a/clippy_lints/src/needless_bitwise_bool.rs b/clippy_lints/src/needless_bitwise_bool.rs index b30bfbd4294..203da29cb91 100644 --- a/clippy_lints/src/needless_bitwise_bool.rs +++ b/clippy_lints/src/needless_bitwise_bool.rs @@ -9,20 +9,19 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using /// a lazy and. /// - /// **Why is this bad?** + /// ### Why is this bad? /// The bitwise operators do not support short-circuiting, so it may hinder code performance. /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` /// - /// **Known problems:** + /// ### Known problems /// This lint evaluates only when the right side is determined to have no side effects. At this time, that /// determination is quite conservative. /// - /// **Example:** - /// + /// ### Example /// ```rust /// let (x,y) = (true, false); /// if x & !y {} // where both x and y are booleans diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 780690548e5..36f2829a5b9 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -15,17 +15,20 @@ use rustc_span::source_map::Spanned; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for expressions of the form `if c { true } else { + /// ### What it does + /// Checks for expressions of the form `if c { true } else { /// false }` (or vice versa) and suggests using the condition directly. /// - /// **Why is this bad?** Redundant code. + /// ### Why is this bad? + /// Redundant code. /// - /// **Known problems:** Maybe false positives: Sometimes, the two branches are + /// ### Known problems + /// Maybe false positives: Sometimes, the two branches are /// painstakingly documented (which we, of course, do not detect), so they *may* /// have some value. Even then, the documentation can be rewritten to match the /// shorter code. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// if x { /// false @@ -43,15 +46,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for expressions of the form `x == true`, + /// ### What it does + /// Checks for expressions of the form `x == true`, /// `x != true` and order comparisons such as `x < true` (or vice versa) and /// suggest using the variable directly. /// - /// **Why is this bad?** Unnecessary code. + /// ### Why is this bad? + /// Unnecessary code. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// if x == true {} /// if y == false {} diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index dd1dfa2bdfb..3f0b23ee4d3 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -17,15 +17,15 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for address of operations (`&`) that are going to + /// ### What it does + /// Checks for address of operations (`&`) that are going to /// be dereferenced immediately by the compiler. /// - /// **Why is this bad?** Suggests that the receiver of the expression borrows + /// ### Why is this bad? + /// Suggests that the receiver of the expression borrows /// the expression. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let x: &i32 = &&&&&&5; @@ -39,13 +39,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `ref` bindings which create a reference to a reference. - /// - /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference. + /// ### What it does + /// Checks for `ref` bindings which create a reference to a reference. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// The address-of operator at the use site is clearer about the need for a reference. /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let x = Some(""); diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 0e976b130eb..36879eda7c0 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -7,12 +7,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for bindings that destructure a reference and borrow the inner + /// ### What it does + /// Checks for bindings that destructure a reference and borrow the inner /// value with `&ref`. /// - /// **Why is this bad?** This pattern has no effect in almost all cases. + /// ### Why is this bad? + /// This pattern has no effect in almost all cases. /// - /// **Known problems:** In some cases, `&ref` is needed to avoid a lifetime mismatch error. + /// ### Known problems + /// In some cases, `&ref` is needed to avoid a lifetime mismatch error. /// Example: /// ```rust /// fn foo(a: &Option, b: &Option) { @@ -23,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// **Example:** + /// ### Example /// Bad: /// ```rust /// let mut v = Vec::::new(); diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 1d19413e0d0..5088b8bb0d3 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -42,20 +42,20 @@ use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** The lint checks for `if`-statements appearing in loops + /// ### What it does + /// The lint checks for `if`-statements appearing in loops /// that contain a `continue` statement in either their main blocks or their /// `else`-blocks, when omitting the `else`-block possibly with some /// rearrangement of code can make the code easier to understand. /// - /// **Why is this bad?** Having explicit `else` blocks for `if` statements + /// ### Why is this bad? + /// Having explicit `else` blocks for `if` statements /// containing `continue` in their THEN branch adds unnecessary branching and /// nesting to the code. Having an else block containing just `continue` can /// also be better written by grouping the statements following the whole `if` /// statement within the THEN block and omitting the else block completely. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// # fn condition() -> bool { false } /// # fn update_condition() {} diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index a723a472a25..d9aa42fe8ee 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -16,18 +16,17 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::has_iter_method; declare_clippy_lint! { - /// **What it does:** Checks for usage of `for_each` that would be more simply written as a + /// ### What it does + /// Checks for usage of `for_each` that would be more simply written as a /// `for` loop. /// - /// **Why is this bad?** `for_each` may be used after applying iterator transformers like + /// ### Why is this bad? + /// `for_each` may be used after applying iterator transformers like /// `filter` for better readability and performance. It may also be used to fit a simple /// operation on one line. /// But when none of these apply, a simple `for` loop is more idiomatic. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let v = vec![0, 1, 2]; /// v.iter().for_each(|elem| { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 283b1847b6c..03eeb54d8d1 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -24,20 +24,22 @@ use rustc_typeck::expr_use_visitor as euv; use std::borrow::Cow; declare_clippy_lint! { - /// **What it does:** Checks for functions taking arguments by value, but not + /// ### What it does + /// Checks for functions taking arguments by value, but not /// consuming them in its /// body. /// - /// **Why is this bad?** Taking arguments by reference is more flexible and can + /// ### Why is this bad? + /// Taking arguments by reference is more flexible and can /// sometimes avoid /// unnecessary allocations. /// - /// **Known problems:** + /// ### Known problems /// * This lint suggests taking an argument by reference, /// however sometimes it is better to let users decide the argument type /// (by using `Borrow` trait, for example), depending on how the function is used. /// - /// **Example:** + /// ### Example /// ```rust /// fn foo(v: Vec) { /// assert_eq!(v.len(), 42); diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index c64491c63e2..42e48336e15 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -10,15 +10,13 @@ use rustc_middle::ty::TyS; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Suggests alternatives for useless applications of `?` in terminating expressions /// - /// **Why is this bad?** There's no reason to use `?` to short-circuit when execution of the body will end there anyway. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// + /// ### Example /// ```rust /// struct TO { /// magic: Option, diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 8f325404deb..2a33b7392ca 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -5,18 +5,18 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for needlessly including a base struct on update + /// ### What it does + /// Checks for needlessly including a base struct on update /// when all fields are changed anyway. /// /// This lint is not applied to structs marked with /// [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html). /// - /// **Why is this bad?** This will cost resources (because the base has to be + /// ### Why is this bad? + /// This will cost resources (because the base has to be /// somewhere), and make the code less readable. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # struct Point { /// # x: i32, diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index c824f6f54b5..6ad49b70605 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -8,19 +8,16 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks for the usage of negated comparison operators on types which only implement /// `PartialOrd` (e.g., `f64`). /// - /// **Why is this bad?** + /// ### Why is this bad? /// These operators make it easy to forget that the underlying types actually allow not only three /// potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is /// especially easy to miss if the operator based comparison result is negated. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// use std::cmp::Ordering; /// diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index d5e1ea6d242..fa36d8fb1b3 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -7,13 +7,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for multiplication by -1 as a form of negation. + /// ### What it does + /// Checks for multiplication by -1 as a form of negation. /// - /// **Why is this bad?** It's more readable to just negate. + /// ### Why is this bad? + /// It's more readable to just negate. /// - /// **Known problems:** This only catches integers (for now). + /// ### Known problems + /// This only catches integers (for now). /// - /// **Example:** + /// ### Example /// ```ignore /// x * -1 /// ``` diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index bc409dd6efb..5c63d245bf1 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -13,18 +13,17 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for types with a `fn new() -> Self` method and no + /// ### What it does + /// Checks for types with a `fn new() -> Self` method and no /// implementation of /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html). /// - /// **Why is this bad?** The user might expect to be able to use + /// ### Why is this bad? + /// The user might expect to be able to use /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the /// type can be constructed without arguments. /// - /// **Known problems:** Hopefully none. - /// - /// **Example:** - /// + /// ### Example /// ```ignore /// struct Foo(Bar); /// diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 910b0536092..e07518b2586 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -9,15 +9,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::ops::Deref; declare_clippy_lint! { - /// **What it does:** Checks for statements which have no effect. + /// ### What it does + /// Checks for statements which have no effect. /// - /// **Why is this bad?** Similar to dead code, these statements are actually + /// ### Why is this bad? + /// Similar to dead code, these statements are actually /// executed. However, as they have no effect, all they do is make the code less /// readable. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// 0; /// ``` @@ -27,15 +27,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for expression statements that can be reduced to a + /// ### What it does + /// Checks for expression statements that can be reduced to a /// sub-expression. /// - /// **Why is this bad?** Expressions by themselves often have no side-effects. + /// ### Why is this bad? + /// Expressions by themselves often have no side-effects. /// Having such expressions reduces readability. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// compute_array()[0]; /// ``` diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index d775cd7c7f7..aa3067876eb 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -24,10 +24,12 @@ use rustc_typeck::hir_ty_to_ty; // FIXME: this is a correctness problem but there's no suitable // warn-by-default category. declare_clippy_lint! { - /// **What it does:** Checks for declaration of `const` items which is interior + /// ### What it does + /// Checks for declaration of `const` items which is interior /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). /// - /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e., + /// ### Why is this bad? + /// Consts are copied everywhere they are referenced, i.e., /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` /// or `AtomicXxxx` will be created, which defeats the whole purpose of using /// these types in the first place. @@ -35,7 +37,8 @@ declare_clippy_lint! { /// The `const` should better be replaced by a `static` item if a global /// variable is wanted, or replaced by a `const fn` if a constructor is wanted. /// - /// **Known problems:** A "non-constant" const item is a legacy way to supply an + /// ### Known problems + /// A "non-constant" const item is a legacy way to supply an /// initialized value to downstream `static` items (e.g., the /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, /// and this lint should be suppressed. @@ -52,7 +55,7 @@ declare_clippy_lint! { /// the interior mutable field is used or not. See issues /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and /// - /// **Example:** + /// ### Example /// ```rust /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// @@ -74,17 +77,20 @@ declare_clippy_lint! { // FIXME: this is a correctness problem but there's no suitable // warn-by-default category. declare_clippy_lint! { - /// **What it does:** Checks if `const` items which is interior mutable (e.g., + /// ### What it does + /// Checks if `const` items which is interior mutable (e.g., /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. /// - /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e., + /// ### Why is this bad? + /// Consts are copied everywhere they are referenced, i.e., /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` /// or `AtomicXxxx` will be created, which defeats the whole purpose of using /// these types in the first place. /// /// The `const` value should be stored inside a `static` item. /// - /// **Known problems:** When an enum has variants with interior mutability, use of its non + /// ### Known problems + /// When an enum has variants with interior mutability, use of its non /// interior mutable variants can generate false positives. See issue /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) /// @@ -93,7 +99,7 @@ declare_clippy_lint! { /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// - /// **Example:** + /// ### Example /// ```rust /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 7183a7c3858..dc55b103eb6 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -12,14 +12,14 @@ use rustc_span::symbol::{Ident, Symbol}; use std::cmp::Ordering; declare_clippy_lint! { - /// **What it does:** Checks for names that are very similar and thus confusing. + /// ### What it does + /// Checks for names that are very similar and thus confusing. /// - /// **Why is this bad?** It's hard to distinguish between names that differ only + /// ### Why is this bad? + /// It's hard to distinguish between names that differ only /// by a single character. /// - /// **Known problems:** None? - /// - /// **Example:** + /// ### Example /// ```ignore /// let checked_exp = something; /// let checked_expr = something_else; @@ -30,15 +30,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for too many variables whose name consists of a + /// ### What it does + /// Checks for too many variables whose name consists of a /// single character. /// - /// **Why is this bad?** It's hard to memorize what a variable means without a + /// ### Why is this bad? + /// It's hard to memorize what a variable means without a /// descriptive name. /// - /// **Known problems:** None? - /// - /// **Example:** + /// ### Example /// ```ignore /// let (a, b, c, d, e, f, g) = (...); /// ``` @@ -48,15 +48,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks if you have variables whose name consists of just + /// ### What it does + /// Checks if you have variables whose name consists of just /// underscores and digits. /// - /// **Why is this bad?** It's hard to memorize what a variable means without a + /// ### Why is this bad? + /// It's hard to memorize what a variable means without a /// descriptive name. /// - /// **Known problems:** None? - /// - /// **Example:** + /// ### Example /// ```rust /// let _1 = 1; /// let ___1 = 1; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index a83daea97bf..3b74f69d375 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -9,15 +9,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for non-octal values used to set Unix file permissions. + /// ### What it does + /// Checks for non-octal values used to set Unix file permissions. /// - /// **Why is this bad?** They will be converted into octal, creating potentially + /// ### Why is this bad? + /// They will be converted into octal, creating potentially /// unintended file permissions. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// use std::fs::OpenOptions; /// use std::os::unix::fs::OpenOptionsExt; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 043e7fa30d6..dbe9cbe0ded 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -13,16 +13,14 @@ use rustc_span::Span; use serde::{de, Deserialize}; declare_clippy_lint! { - /// **What it does:** Checks that common macros are used with consistent bracing. + /// ### What it does + /// Checks that common macros are used with consistent bracing. /// - /// **Why is this bad?** This is mostly a consistency lint although using () or [] + /// ### Why is this bad? + /// This is mostly a consistency lint although using () or [] /// doesn't give you a semicolon in item position, which can be unexpected. /// - /// **Known problems:** - /// None - /// - /// **Example:** - /// + /// ### Example /// ```rust /// vec!{1, 2, 3}; /// ``` diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index fded48038e3..4064d94da2a 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -8,15 +8,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{Span, Spanned}; declare_clippy_lint! { - /// **What it does:** Checks for duplicate open options as well as combinations + /// ### What it does + /// Checks for duplicate open options as well as combinations /// that make no sense. /// - /// **Why is this bad?** In the best case, the code will be harder to read than + /// ### Why is this bad? + /// In the best case, the code will be harder to read than /// necessary. I don't know the worst case. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// use std::fs::OpenOptions; /// diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index b6f518661bd..d7306628030 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -7,17 +7,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for usage of `option_env!(...).unwrap()` and + /// ### What it does + /// Checks for usage of `option_env!(...).unwrap()` and /// suggests usage of the `env!` macro. /// - /// **Why is this bad?** Unwrapping the result of `option_env!` will panic + /// ### Why is this bad? + /// Unwrapping the result of `option_env!` will panic /// at run-time if the environment variable doesn't exist, whereas `env!` /// catches it at compile-time. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,no_run /// let _ = option_env!("HOME").unwrap(); /// ``` diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index b2be35bdddb..7aef3a5f34c 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -12,24 +12,23 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more /// idiomatically done with `Option::map_or` (if the else bit is a pure /// expression) or `Option::map_or_else` (if the else bit is an impure /// expression). /// - /// **Why is this bad?** + /// ### Why is this bad? /// Using the dedicated functions of the Option type is clearer and /// more concise than an `if let` expression. /// - /// **Known problems:** + /// ### Known problems /// This lint uses a deliberately conservative metric for checking /// if the inside of either body contains breaks or continues which will /// cause it to not suggest a fix if either block contains a loop with /// continues or breaks contained within the loop. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # let optional: Option = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index e222782c2cc..34755afdb72 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -6,14 +6,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Detects classic underflow/overflow checks. + /// ### What it does + /// Detects classic underflow/overflow checks. /// - /// **Why is this bad?** Most classic C underflow/overflow checks will fail in + /// ### Why is this bad? + /// Most classic C underflow/overflow checks will fail in /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let a = 1; /// # let b = 2; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index cef74d87e7c..e2b6ba8e2d2 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -8,14 +8,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result. + /// ### What it does + /// Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result. /// - /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. + /// ### Why is this bad? + /// For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. /// - /// **Known problems:** Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. - /// - /// **Example:** + /// ### Known problems + /// Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. /// + /// ### Example /// ```rust /// fn result_with_panic() -> Result /// { diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index dc28874c16e..d8d9081d6f1 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -7,13 +7,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for usage of `panic!`. + /// ### What it does + /// Checks for usage of `panic!`. /// - /// **Why is this bad?** `panic!` will stop the execution of the executable + /// ### Why is this bad? + /// `panic!` will stop the execution of the executable /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```no_run /// panic!("even with a good reason"); /// ``` @@ -23,13 +23,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `unimplemented!`. - /// - /// **Why is this bad?** This macro should not be present in production code + /// ### What it does + /// Checks for usage of `unimplemented!`. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This macro should not be present in production code /// - /// **Example:** + /// ### Example /// ```no_run /// unimplemented!(); /// ``` @@ -39,13 +39,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `todo!`. + /// ### What it does + /// Checks for usage of `todo!`. /// - /// **Why is this bad?** This macro should not be present in production code + /// ### Why is this bad? + /// This macro should not be present in production code /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```no_run /// todo!(); /// ``` @@ -55,13 +55,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `unreachable!`. - /// - /// **Why is this bad?** This macro can cause code to panic + /// ### What it does + /// Checks for usage of `unreachable!`. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This macro can cause code to panic /// - /// **Example:** + /// ### Example /// ```no_run /// unreachable!(); /// ``` diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 1251ddd9a02..4ec493e5f45 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -7,16 +7,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`. + /// ### What it does + /// Checks for manual re-implementations of `PartialEq::ne`. /// - /// **Why is this bad?** `PartialEq::ne` is required to always return the + /// ### Why is this bad? + /// `PartialEq::ne` is required to always return the /// negated result of `PartialEq::eq`, which is exactly what the default /// implementation does. Therefore, there should never be any need to /// re-implement it. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// struct Foo; /// diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index f6a70478559..f738ac25417 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -20,15 +20,18 @@ use rustc_target::spec::abi::Abi; use rustc_target::spec::Target; declare_clippy_lint! { - /// **What it does:** Checks for functions taking arguments by reference, where + /// ### What it does + /// Checks for functions taking arguments by reference, where /// the argument type is `Copy` and small enough to be more efficient to always /// pass by value. /// - /// **Why is this bad?** In many calling conventions instances of structs will + /// ### Why is this bad? + /// In many calling conventions instances of structs will /// be passed through registers if they fit into two or less general purpose /// registers. /// - /// **Known problems:** This lint is target register size dependent, it is + /// ### Known problems + /// This lint is target register size dependent, it is /// limited to 32-bit to try and reduce portability problems between 32 and /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit /// will be different. @@ -50,7 +53,7 @@ declare_clippy_lint! { /// that explains a real case in which this false positive /// led to an **undefined behaviour** introduced with unsafe code. /// - /// **Example:** + /// ### Example /// /// ```rust /// // Bad @@ -67,18 +70,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for functions taking arguments by value, where + /// ### What it does + /// Checks for functions taking arguments by value, where /// the argument type is `Copy` and large enough to be worth considering /// passing by reference. Does not trigger if the function is being exported, /// because that might induce API breakage, if the parameter is declared as mutable, /// or if the argument is a `self`. /// - /// **Why is this bad?** Arguments passed by value might result in an unnecessary + /// ### Why is this bad? + /// Arguments passed by value might result in an unnecessary /// shallow copy, taking up more space in the stack and requiring a call to /// `memcpy`, which can be expensive. /// - /// **Example:** - /// + /// ### Example /// ```rust /// #[derive(Clone, Copy)] /// struct TooLarge([u8; 2048]); diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 00245926381..3df7a72d295 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -10,15 +10,15 @@ use rustc_span::symbol::sym; use std::path::{Component, Path}; declare_clippy_lint! { - /// **What it does:*** Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) + /// ### What it does + ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) /// calls on `PathBuf` that can cause overwrites. /// - /// **Why is this bad?** Calling `push` with a root path at the start can overwrite the + /// ### Why is this bad? + /// Calling `push` with a root path at the start can overwrite the /// previous defined path. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// use std::path::PathBuf; /// diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index ea4065d371b..4534f6e2516 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -13,7 +13,8 @@ use rustc_span::source_map::Span; use std::iter; declare_clippy_lint! { - /// **What it does:** Checks for patterns that aren't exact representations of the types + /// ### What it does + /// Checks for patterns that aren't exact representations of the types /// they are applied to. /// /// To satisfy this lint, you will have to adjust either the expression that is matched @@ -32,14 +33,12 @@ declare_clippy_lint! { /// this lint can still be used to highlight areas of interest and ensure a good understanding /// of ownership semantics. /// - /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable + /// ### Why is this bad? + /// It isn't bad in general. But in some contexts it can be desirable /// because it increases ownership hints in the code, and will guard against some changes /// in ownership. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// This example shows the basic adjustments necessary to satisfy the lint. Note how /// the matched expression is explicitly dereferenced with `*` and the `inner` variable /// is bound to a shared borrow via `ref inner`. diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 9cf00c953b9..1a8da00d9d6 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -25,7 +25,8 @@ const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ ]; declare_clippy_lint! { - /// **What it does:** Checks for operations where precedence may be unclear + /// ### What it does + /// Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without /// parentheses @@ -33,13 +34,12 @@ declare_clippy_lint! { /// numeric literal) /// followed by a method call /// - /// **Why is this bad?** Not everyone knows the precedence of those operators by + /// ### Why is this bad? + /// Not everyone knows the precedence of those operators by /// heart, so expressions like these may trip others trying to reason about the /// code. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 pub PRECEDENCE, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index b15447622a8..c0d1f1eb6e6 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -20,16 +20,19 @@ use rustc_span::{sym, MultiSpan}; use std::borrow::Cow; declare_clippy_lint! { - /// **What it does:** This lint checks for function arguments of type `&String` + /// ### What it does + /// This lint checks for function arguments of type `&String` /// or `&Vec` unless the references are mutable. It will also suggest you /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()` /// calls. /// - /// **Why is this bad?** Requiring the argument to be of the specific size + /// ### Why is this bad? + /// Requiring the argument to be of the specific size /// makes the function less useful for no benefit; slices in the form of `&[T]` /// or `&str` usually suffice and can be obtained from other types, too. /// - /// **Known problems:** The lint does not follow data. So if you have an + /// ### Known problems + /// The lint does not follow data. So if you have an /// argument `x` and write `let y = x; y.clone()` the lint will not suggest /// changing that `.clone()` to `.to_owned()`. /// @@ -59,7 +62,7 @@ declare_clippy_lint! { /// other crates referencing it, of which you may not be aware. Carefully /// deprecate the function before applying the lint suggestions in this case. /// - /// **Example:** + /// ### Example /// ```ignore /// // Bad /// fn foo(&Vec) { .. } @@ -73,15 +76,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint checks for equality comparisons with `ptr::null` + /// ### What it does + /// This lint checks for equality comparisons with `ptr::null` /// - /// **Why is this bad?** It's easier and more readable to use the inherent + /// ### Why is this bad? + /// It's easier and more readable to use the inherent /// `.is_null()` /// method instead /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// // Bad /// if x == ptr::null { @@ -99,19 +102,22 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint checks for functions that take immutable + /// ### What it does + /// This lint checks for functions that take immutable /// references and return mutable ones. /// - /// **Why is this bad?** This is trivially unsound, as one can create two + /// ### Why is this bad? + /// This is trivially unsound, as one can create two /// mutable references from the same (immutable!) source. /// This [error](https://github.com/rust-lang/rust/issues/39465) /// actually lead to an interim Rust release 1.15.1. /// - /// **Known problems:** To be on the conservative side, if there's at least one + /// ### Known problems + /// To be on the conservative side, if there's at least one /// mutable reference with the output lifetime, this lint will not trigger. /// In practice, this case is unlikely anyway. /// - /// **Example:** + /// ### Example /// ```ignore /// fn foo(&Foo) -> &mut Bar { .. } /// ``` @@ -121,13 +127,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint checks for invalid usages of `ptr::null`. - /// - /// **Why is this bad?** This causes undefined behavior. + /// ### What it does + /// This lint checks for invalid usages of `ptr::null`. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This causes undefined behavior. /// - /// **Example:** + /// ### Example /// ```ignore /// // Bad. Undefined behavior /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); } diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 77cfa3f6b17..d6d7049fb61 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -8,16 +8,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Use `std::ptr::eq` when applicable + /// ### What it does + /// Use `std::ptr::eq` when applicable /// - /// **Why is this bad?** `ptr::eq` can be used to compare `&T` references + /// ### Why is this bad? + /// `ptr::eq` can be used to compare `&T` references /// (which coerce to `*const T` implicitly) by their address rather than /// comparing the values they point to. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index afb198f4955..f1975056ddc 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -8,15 +8,15 @@ use rustc_span::sym; use std::fmt; declare_clippy_lint! { - /// **What it does:** Checks for usage of the `offset` pointer method with a `usize` casted to an + /// ### What it does + /// Checks for usage of the `offset` pointer method with a `usize` casted to an /// `isize`. /// - /// **Why is this bad?** If we’re always increasing the pointer address, we can avoid the numeric + /// ### Why is this bad? + /// If we’re always increasing the pointer address, we can avoid the numeric /// cast by using the `add` method instead. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d66bac52243..0e682c692c7 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -13,13 +13,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for expressions that could be replaced by the question mark operator. + /// ### What it does + /// Checks for expressions that could be replaced by the question mark operator. /// - /// **Why is this bad?** Question mark usage is more idiomatic. + /// ### Why is this bad? + /// Question mark usage is more idiomatic. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```ignore /// if option.is_none() { /// return None; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index b41c478c266..0179bd48ee3 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -18,14 +18,14 @@ use rustc_span::symbol::Ident; use std::cmp::Ordering; declare_clippy_lint! { - /// **What it does:** Checks for zipping a collection with the range of + /// ### What it does + /// Checks for zipping a collection with the range of /// `0.._.len()`. /// - /// **Why is this bad?** The code is better expressed with `.enumerate()`. + /// ### Why is this bad? + /// The code is better expressed with `.enumerate()`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let x = vec![1]; /// x.iter().zip(0..x.len()); @@ -41,13 +41,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for exclusive ranges where 1 is added to the + /// ### What it does + /// Checks for exclusive ranges where 1 is added to the /// upper bound, e.g., `x..(y+1)`. /// - /// **Why is this bad?** The code is more readable with an inclusive range + /// ### Why is this bad? + /// The code is more readable with an inclusive range /// like `x..=y`. /// - /// **Known problems:** Will add unnecessary pair of parentheses when the + /// ### Known problems + /// Will add unnecessary pair of parentheses when the /// expression is not wrapped in a pair but starts with a opening parenthesis /// and ends with a closing one. /// I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`. @@ -61,7 +64,7 @@ declare_clippy_lint! { /// `RangeBounds` trait /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// - /// **Example:** + /// ### Example /// ```rust,ignore /// for x..(y+1) { .. } /// ``` @@ -75,18 +78,21 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for inclusive ranges where 1 is subtracted from + /// ### What it does + /// Checks for inclusive ranges where 1 is subtracted from /// the upper bound, e.g., `x..=(y-1)`. /// - /// **Why is this bad?** The code is more readable with an exclusive range + /// ### Why is this bad? + /// The code is more readable with an exclusive range /// like `x..y`. /// - /// **Known problems:** This will cause a warning that cannot be fixed if + /// ### Known problems + /// This will cause a warning that cannot be fixed if /// the consumer of the range only accepts a specific range type, instead of /// the generic `RangeBounds` trait /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// - /// **Example:** + /// ### Example /// ```rust,ignore /// for x..=(y-1) { .. } /// ``` @@ -100,16 +106,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for range expressions `x..y` where both `x` and `y` + /// ### What it does + /// Checks for range expressions `x..y` where both `x` and `y` /// are constant and `x` is greater or equal to `y`. /// - /// **Why is this bad?** Empty ranges yield no values so iterating them is a no-op. + /// ### Why is this bad? + /// Empty ranges yield no values so iterating them is a no-op. /// Moreover, trying to use a reversed range to index a slice will panic at run-time. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,no_run /// fn main() { /// (10..=0).for_each(|x| println!("{}", x)); @@ -133,16 +138,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for expressions like `x >= 3 && x < 8` that could + /// ### What it does + /// Checks for expressions like `x >= 3 && x < 8` that could /// be more readably expressed as `(3..8).contains(x)`. /// - /// **Why is this bad?** `contains` expresses the intent better and has less + /// ### Why is this bad? + /// `contains` expresses the intent better and has less /// failure modes (such as fencepost errors or using `||` instead of `&&`). /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // given /// let x = 6; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 56ef95a88c8..530b3396abe 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -32,17 +32,18 @@ macro_rules! unwrap_or_continue { } declare_clippy_lint! { - /// **What it does:** Checks for a redundant `clone()` (and its relatives) which clones an owned + /// ### What it does + /// Checks for a redundant `clone()` (and its relatives) which clones an owned /// value that is going to be dropped without further use. /// - /// **Why is this bad?** It is not always possible for the compiler to eliminate useless + /// ### Why is this bad? + /// It is not always possible for the compiler to eliminate useless /// allocations and deallocations generated by redundant `clone()`s. /// - /// **Known problems:** - /// + /// ### Known problems /// False-negatives: analysis performed by this lint is conservative and limited. /// - /// **Example:** + /// ### Example /// ```rust /// # use std::path::Path; /// # #[derive(Clone)] diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 8f56a21ac5b..a79b2fe76e2 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -14,15 +14,15 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Detects closures called in the same expression where they + /// ### What it does + /// Detects closures called in the same expression where they /// are defined. /// - /// **Why is this bad?** It is unnecessarily adding to the expression's + /// ### Why is this bad? + /// It is unnecessarily adding to the expression's /// complexity. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// let a = (|| 42)() diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 061526c6f09..68b256d2944 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -6,14 +6,16 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `else` blocks that can be removed without changing semantics. + /// ### What it does + /// Checks for `else` blocks that can be removed without changing semantics. /// - /// **Why is this bad?** The `else` block adds unnecessary indentation and verbosity. + /// ### Why is this bad? + /// The `else` block adds unnecessary indentation and verbosity. /// - /// **Known problems:** Some may prefer to keep the `else` block for clarity. - /// - /// **Example:** + /// ### Known problems + /// Some may prefer to keep the `else` block for clarity. /// + /// ### Example /// ```rust /// fn my_func(count: u32) { /// if count == 0 { diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index d5ee8d3468d..47df4917510 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -8,15 +8,15 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for fields in struct literals where shorthands + /// ### What it does + /// Checks for fields in struct literals where shorthands /// could be used. /// - /// **Why is this bad?** If the field and variable names are the same, + /// ### Why is this bad? + /// If the field and variable names are the same, /// the field name is redundant. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let bar: u8 = 123; /// diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 05f9e01acb4..59a55b9dffa 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -5,16 +5,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for items declared `pub(crate)` that are not crate visible because they + /// ### What it does + /// Checks for items declared `pub(crate)` that are not crate visible because they /// are inside a private module. /// - /// **Why is this bad?** Writing `pub(crate)` is misleading when it's redundant due to the parent + /// ### Why is this bad? + /// Writing `pub(crate)` is misleading when it's redundant due to the parent /// module's visibility. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// mod internal { /// pub(crate) fn internal_fn() { } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 9c6cd7b4fa6..290348c4509 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -10,17 +10,19 @@ use rustc_middle::ty::TyS; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for redundant slicing expressions which use the full range, and + /// ### What it does + /// Checks for redundant slicing expressions which use the full range, and /// do not change the type. /// - /// **Why is this bad?** It unnecessarily adds complexity to the expression. + /// ### Why is this bad? + /// It unnecessarily adds complexity to the expression. /// - /// **Known problems:** If the type being sliced has an implementation of `Index` + /// ### Known problems + /// If the type being sliced has an implementation of `Index` /// that actually changes anything then it can't be removed. However, this would be surprising /// to people reading the code and should have a note with it. /// - /// **Example:** - /// + /// ### Example /// ```ignore /// fn get_slice(x: &[u32]) -> &[u32] { /// &x[..] diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 48107d9c037..d5a1a61da6b 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -8,14 +8,14 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime. + /// ### What it does + /// Checks for constants and statics with an explicit `'static` lifetime. /// - /// **Why is this bad?** Adding `'static` to every reference can create very + /// ### Why is this bad? + /// Adding `'static` to every reference can create very /// complicated types. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = /// &[...] diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 0cf4e0ce7fe..65ab6cac442 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -9,16 +9,18 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Checks for usage of `&Option<&T>`. + /// ### What it does + /// Checks for usage of `&Option<&T>`. /// - /// **Why is this bad?** Since `&` is Copy, it's useless to have a + /// ### Why is this bad? + /// Since `&` is Copy, it's useless to have a /// reference on `Option<&T>`. /// - /// **Known problems:** It may be irrelevant to use this lint on + /// ### Known problems + /// It may be irrelevant to use this lint on /// public API code as it will make a breaking change to apply it. /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// let x: &Option<&u32> = &Some(&0u32); /// ``` diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index d6336389b0a..e0930d69ab9 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -10,15 +10,18 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::BytePos; declare_clippy_lint! { - /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. + /// ### What it does + /// Checks for usage of `*&` and `*&mut` in expressions. /// - /// **Why is this bad?** Immediately dereferencing a reference is no-op and + /// ### Why is this bad? + /// Immediately dereferencing a reference is no-op and /// makes the code less clear. /// - /// **Known problems:** Multiple dereference/addrof pairs are not handled so + /// ### Known problems + /// Multiple dereference/addrof pairs are not handled so /// the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// let a = f(*&mut b); @@ -101,13 +104,15 @@ impl EarlyLintPass for DerefAddrOf { } declare_clippy_lint! { - /// **What it does:** Checks for references in expressions that use + /// ### What it does + /// Checks for references in expressions that use /// auto dereference. /// - /// **Why is this bad?** The reference is a no-op and is automatically + /// ### Why is this bad? + /// The reference is a no-op and is automatically /// dereferenced by the compiler and makes the code less clear. /// - /// **Example:** + /// ### Example /// ```rust /// struct Point(u32, u32); /// let point = Point(30, 20); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 75151167454..eab09733730 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -11,15 +11,15 @@ use rustc_span::source_map::{BytePos, Span}; use std::convert::TryFrom; declare_clippy_lint! { - /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation + /// ### What it does + /// Checks [regex](https://crates.io/crates/regex) creation /// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct /// regex syntax. /// - /// **Why is this bad?** This will lead to a runtime panic. + /// ### Why is this bad? + /// This will lead to a runtime panic. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// Regex::new("|") /// ``` @@ -29,18 +29,21 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex) + /// ### What it does + /// Checks for trivial [regex](https://crates.io/crates/regex) /// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). /// - /// **Why is this bad?** Matching the regex can likely be replaced by `==` or + /// ### Why is this bad? + /// Matching the regex can likely be replaced by `==` or /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` /// methods. /// - /// **Known problems:** If the same regex is going to be applied to multiple + /// ### Known problems + /// If the same regex is going to be applied to multiple /// inputs, the precomputations done by `Regex` construction can give /// significantly better performance than any of the `str`-based methods. /// - /// **Example:** + /// ### Example /// ```ignore /// Regex::new("^foobar") /// ``` diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 17cb96bc4eb..54b9c8b3275 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -11,7 +11,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types. + /// ### What it does + /// Checks for usage of `.repeat(1)` and suggest the following method for each types. /// - `.to_string()` for `str` /// - `.clone()` for `String` /// - `.to_vec()` for `slice` @@ -19,13 +20,11 @@ declare_clippy_lint! { /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) /// - /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning + /// ### Why is this bad? + /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning /// the string is the intention behind this, `clone()` should be used. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// fn main() { /// let x = String::from("hello world").repeat(1); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 251d527c265..db4b1002ce1 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -15,15 +15,15 @@ use rustc_span::source_map::Span; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `let`-bindings, which are subsequently + /// ### What it does + /// Checks for `let`-bindings, which are subsequently /// returned. /// - /// **Why is this bad?** It is just extraneous code. Remove it to make your code + /// ### Why is this bad? + /// It is just extraneous code. Remove it to make your code /// more rusty. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn foo() -> String { /// let x = String::new(); @@ -42,14 +42,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for return statements at the end of a block. + /// ### What it does + /// Checks for return statements at the end of a block. /// - /// **Why is this bad?** Removing the `return` and semicolon will make the code + /// ### Why is this bad? + /// Removing the `return` and semicolon will make the code /// more rusty. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn foo(x: usize) -> usize { /// return x; diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs index e7925c4fbde..fbd65fef7d1 100644 --- a/clippy_lints/src/self_assignment.rs +++ b/clippy_lints/src/self_assignment.rs @@ -6,16 +6,18 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for explicit self-assignments. + /// ### What it does + /// Checks for explicit self-assignments. /// - /// **Why is this bad?** Self-assignments are redundant and unlikely to be + /// ### Why is this bad? + /// Self-assignments are redundant and unlikely to be /// intentional. /// - /// **Known problems:** If expression contains any deref coercions or + /// ### Known problems + /// If expression contains any deref coercions or /// indexing operations they are assumed not to have any side effects. /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct Event { /// id: usize, diff --git a/clippy_lints/src/self_named_constructor.rs b/clippy_lints/src/self_named_constructor.rs index da991e1d90c..2123a14cc1b 100644 --- a/clippy_lints/src/self_named_constructor.rs +++ b/clippy_lints/src/self_named_constructor.rs @@ -6,14 +6,13 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Warns when constructors have the same name as their types. + /// ### What it does + /// Warns when constructors have the same name as their types. /// - /// **Why is this bad?** Repeating the name of the type is redundant. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Repeating the name of the type is redundant. /// + /// ### Example /// ```rust,ignore /// struct Foo {} /// diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index da3e30af35c..6966230156c 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -9,16 +9,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Looks for blocks of expressions and fires if the last expression returns + /// ### What it does + /// Looks for blocks of expressions and fires if the last expression returns /// `()` but is not followed by a semicolon. /// - /// **Why is this bad?** The semicolon might be optional but when extending the block with new + /// ### Why is this bad? + /// The semicolon might be optional but when extending the block with new /// code, it doesn't require a change in previous last line. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// fn main() { /// println!("Hello world") diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 169f7d26285..2cd0f85999c 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -5,14 +5,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for mis-uses of the serde API. + /// ### What it does + /// Checks for mis-uses of the serde API. /// - /// **Why is this bad?** Serde is very finnicky about how its API should be + /// ### Why is this bad? + /// Serde is very finnicky about how its API should be /// used, but the type system can't be used to enforce it (yet?). /// - /// **Known problems:** None. - /// - /// **Example:** Implementing `Visitor::visit_string` but not + /// ### Example + /// Implementing `Visitor::visit_string` but not /// `Visitor::visit_str`. pub SERDE_API_MISUSE, correctness, diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index ac3f7ebd14b..b28a37cabd4 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -14,17 +14,20 @@ use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; declare_clippy_lint! { - /// **What it does:** Checks for bindings that shadow other bindings already in + /// ### What it does + /// Checks for bindings that shadow other bindings already in /// scope, while just changing reference level or mutability. /// - /// **Why is this bad?** Not much, in fact it's a very common pattern in Rust + /// ### Why is this bad? + /// Not much, in fact it's a very common pattern in Rust /// code. Still, some may opt to avoid it in their code base, they can set this /// lint to `Warn`. /// - /// **Known problems:** This lint, as the other shadowing related lints, + /// ### Known problems + /// This lint, as the other shadowing related lints, /// currently only catches very simple patterns. /// - /// **Example:** + /// ### Example /// ```rust /// # let x = 1; /// // Bad @@ -39,18 +42,21 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for bindings that shadow other bindings already in + /// ### What it does + /// Checks for bindings that shadow other bindings already in /// scope, while reusing the original value. /// - /// **Why is this bad?** Not too much, in fact it's a common pattern in Rust + /// ### Why is this bad? + /// Not too much, in fact it's a common pattern in Rust /// code. Still, some argue that name shadowing like this hurts readability, /// because a value may be bound to different things depending on position in /// the code. /// - /// **Known problems:** This lint, as the other shadowing related lints, + /// ### Known problems + /// This lint, as the other shadowing related lints, /// currently only catches very simple patterns. /// - /// **Example:** + /// ### Example /// ```rust /// let x = 2; /// let x = x + 1; @@ -66,21 +72,24 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for bindings that shadow other bindings already in + /// ### What it does + /// Checks for bindings that shadow other bindings already in /// scope, either without a initialization or with one that does not even use /// the original value. /// - /// **Why is this bad?** Name shadowing can hurt readability, especially in + /// ### Why is this bad? + /// Name shadowing can hurt readability, especially in /// large code bases, because it is easy to lose track of the active binding at /// any place in the code. This can be alleviated by either giving more specific /// names to bindings or introducing more scopes to contain the bindings. /// - /// **Known problems:** This lint, as the other shadowing related lints, + /// ### Known problems + /// This lint, as the other shadowing related lints, /// currently only catches very simple patterns. Note that /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level /// for this lint. /// - /// **Example:** + /// ### Example /// ```rust /// # let y = 1; /// # let z = 2; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 1eaad438237..f6487b8c46b 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -7,15 +7,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{edition::Edition, symbol::kw, Span, Symbol}; declare_clippy_lint! { - /// **What it does:** Checking for imports with single component use path. + /// ### What it does + /// Checking for imports with single component use path. /// - /// **Why is this bad?** Import with single component use path such as `use cratename;` + /// ### Why is this bad? + /// Import with single component use path such as `use cratename;` /// is not necessary, and thus should be removed. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// use regex; /// diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index b1965cfd601..3e4e4a8d0c0 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -11,16 +11,16 @@ use rustc_middle::ty::{self, Ty, TyS, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Detects expressions where + /// ### What it does + /// Detects expressions where /// `size_of::` or `size_of_val::` is used as a /// count of elements of type `T` /// - /// **Why is this bad?** These functions expect a count + /// ### Why is this bad? + /// These functions expect a count /// of `T` and not a number of bytes /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,no_run /// # use std::ptr::copy_nonoverlapping; /// # use std::mem::size_of; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index e5c58d70b60..3d039e13065 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -13,14 +13,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Checks slow zero-filled vector initialization + /// ### What it does + /// Checks slow zero-filled vector initialization /// - /// **Why is this bad?** These structures are non-idiomatic and less efficient than simply using + /// ### Why is this bad? + /// These structures are non-idiomatic and less efficient than simply using /// `vec![0; len]`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use core::iter::repeat; /// # let len = 4; diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index 65790375c73..4ea1293d504 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -7,22 +7,18 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// When sorting primitive values (integers, bools, chars, as well /// as arrays, slices, and tuples of such items), it is better to /// use an unstable sort than a stable sort. /// - /// **Why is this bad?** + /// ### Why is this bad? /// Using a stable sort consumes more memory and cpu cycles. Because /// values which compare equal are identical, preserving their /// relative order (the guarantee that a stable sort provides) means /// nothing, while the extra costs still apply. /// - /// **Known problems:** - /// None - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let mut vec = vec![2, 1, 3]; /// vec.sort(); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 958e462125e..1a78a4968e5 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -14,16 +14,15 @@ use rustc_span::source_map::Spanned; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for string appends of the form `x = x + y` (without + /// ### What it does + /// Checks for string appends of the form `x = x + y` (without /// `let`!). /// - /// **Why is this bad?** It's not really bad, but some people think that the + /// ### Why is this bad? + /// It's not really bad, but some people think that the /// `.push_str(_)` method is more readable. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let mut x = "Hello".to_owned(); /// x = x + ", World"; @@ -38,11 +37,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for all instances of `x + _` where `x` is of type + /// ### What it does + /// Checks for all instances of `x + _` where `x` is of type /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not* /// match. /// - /// **Why is this bad?** It's not bad in and of itself. However, this particular + /// ### Why is this bad? + /// It's not bad in and of itself. However, this particular /// `Add` implementation is asymmetric (the other operand need not be `String`, /// but `x` does), while addition as mathematically defined is symmetric, also /// the `String::push_str(_)` function is a perfectly good replacement. @@ -52,10 +53,7 @@ declare_clippy_lint! { /// in other languages is actually fine, which is why we decided to make this /// particular lint `allow` by default. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let x = "Hello".to_owned(); /// x + ", World"; @@ -66,13 +64,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for the `as_bytes` method called on string literals + /// ### What it does + /// Checks for the `as_bytes` method called on string literals /// that contain only ASCII characters. /// - /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used + /// ### Why is this bad? + /// Byte string literals (e.g., `b"foo"`) can be used /// instead. They are shorter but less discoverable than `as_bytes()`. /// - /// **Known Problems:** + /// ### Known problems /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not /// equivalent because they have different types. The former is `&[u8]` /// while the latter is `&[u8; 3]`. That means in general they will have a @@ -94,7 +94,7 @@ declare_clippy_lint! { /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not /// more readable than a function call. /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let bs = "a byte string".as_bytes(); @@ -177,13 +177,13 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { } declare_clippy_lint! { - /// **What it does:** Check if the string is transformed to byte array and casted back to string. + /// ### What it does + /// Check if the string is transformed to byte array and casted back to string. /// - /// **Why is this bad?** It's unnecessary, the string can be used directly. + /// ### Why is this bad? + /// It's unnecessary, the string can be used directly. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); /// ``` @@ -317,16 +317,15 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } declare_clippy_lint! { - /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. + /// ### What it does + /// This lint checks for `.to_string()` method calls on values of type `&str`. /// - /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string. + /// ### Why is this bad? + /// The `to_string` method is also used on other types to convert them to a string. /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better /// expressed with `.to_owned()`. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // example code where clippy issues a warning /// let _ = "str".to_string(); @@ -366,14 +365,14 @@ impl LateLintPass<'_> for StrToString { } declare_clippy_lint! { - /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. + /// ### What it does + /// This lint checks for `.to_string()` method calls on values of type `String`. /// - /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string. + /// ### Why is this bad? + /// The `to_string` method is also used on other types to convert them to a string. /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. - /// **Known problems:** None. - /// - /// **Example:** /// + /// ### Example /// ```rust /// // example code where clippy issues a warning /// let msg = String::from("Hello World"); diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 2ccf3a3796d..516fa3d95b4 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -11,16 +11,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{sym, Symbol}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `libc::strlen` on a `CString` or `CStr` value, + /// ### What it does + /// Checks for usage of `libc::strlen` on a `CString` or `CStr` value, /// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. /// - /// **Why is this bad?** This avoids calling an unsafe `libc` function. + /// ### Why is this bad? + /// This avoids calling an unsafe `libc` function. /// Currently, it also avoids calculating the length. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust, ignore /// use std::ffi::CString; /// let cstring = CString::new("foo").expect("CString::new failed"); diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index bb707f78fcc..a8e962d1af3 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -13,20 +13,21 @@ use rustc_span::symbol::Ident; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks for unlikely usages of binary operators that are almost /// certainly typos and/or copy/paste errors, given the other usages /// of binary operators nearby. - /// **Why is this bad?** + /// + /// ### Why is this bad? /// They are probably bugs and if they aren't then they look like bugs /// and you should add a comment explaining why you are doing such an /// odd set of operations. - /// **Known problems:** + /// + /// ### Known problems /// There may be some false positives if you are trying to do something /// unusual that happens to look like a typo. /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct Vec3 { /// x: f64, diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index f2bffd55321..682fad00a13 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -8,14 +8,14 @@ use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g. + /// ### What it does + /// Lints for suspicious operations in impls of arithmetic operators, e.g. /// subtracting elements in an Add impl. /// - /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended. + /// ### Why is this bad? + /// This is probably a typo or copy-and-paste error and not intended. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```ignore /// impl Add for Foo { /// type Output = Foo; @@ -31,14 +31,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Lints for suspicious operations in impls of OpAssign, e.g. + /// ### What it does + /// Lints for suspicious operations in impls of OpAssign, e.g. /// subtracting elements in an AddAssign impl. /// - /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This is probably a typo or copy-and-paste error and not intended. /// - /// **Example:** + /// ### Example /// ```ignore /// impl AddAssign for Foo { /// fn add_assign(&mut self, other: Foo) { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 19967e2c970..4fa8e77a67b 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -12,14 +12,14 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for manual swapping. + /// ### What it does + /// Checks for manual swapping. /// - /// **Why is this bad?** The `std::mem::swap` function exposes the intent better + /// ### Why is this bad? + /// The `std::mem::swap` function exposes the intent better /// without deinitializing or copying either variable. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let mut a = 42; /// let mut b = 1337; @@ -40,13 +40,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `foo = bar; bar = foo` sequences. - /// - /// **Why is this bad?** This looks like a failed attempt to swap. + /// ### What it does + /// Checks for `foo = bar; bar = foo` sequences. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This looks like a failed attempt to swap. /// - /// **Example:** + /// ### Example /// ```rust /// # let mut a = 1; /// # let mut b = 2; diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index e2c144709f5..6a73b94d87e 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -7,16 +7,16 @@ use rustc_span::source_map::{BytePos, Span}; use std::convert::TryFrom; declare_clippy_lint! { - /// **What it does:** Checks doc comments for usage of tab characters. + /// ### What it does + /// Checks doc comments for usage of tab characters. /// - /// **Why is this bad?** The rust style-guide promotes spaces instead of tabs for indentation. + /// ### Why is this bad? + /// The rust style-guide promotes spaces instead of tabs for indentation. /// To keep a consistent view on the source, also doc comments should not have tabs. /// Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the /// display settings of the author and reader differ. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// /// /// /// Struct to hold two strings: diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 8ef25dc816c..a9da690339c 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -5,15 +5,15 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for construction of a structure or tuple just to + /// ### What it does + /// Checks for construction of a structure or tuple just to /// assign a value in it. /// - /// **Why is this bad?** Readability. If the structure is only created to be + /// ### Why is this bad? + /// Readability. If the structure is only created to be /// updated, why not write the structure you want in the first place? /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// (0, 0).0 = 1 /// ``` diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index c66a596c784..1c14a919995 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -9,12 +9,14 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `.to_digit(..).is_some()` on `char`s. + /// ### What it does + /// Checks for `.to_digit(..).is_some()` on `char`s. /// - /// **Why is this bad?** This is a convoluted way of checking if a `char` is a digit. It's + /// ### Why is this bad? + /// This is a convoluted way of checking if a `char` is a digit. It's /// more straight forward to use the dedicated `is_digit` method. /// - /// **Example:** + /// ### Example /// ```rust /// # let c = 'c'; /// # let radix = 10; diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index 4fb297ac6c6..b036ed9a3d2 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -7,15 +7,15 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Checks for uses of `to_string()` in `Display` traits. + /// ### What it does + /// Checks for uses of `to_string()` in `Display` traits. /// - /// **Why is this bad?** Usually `to_string` is implemented indirectly + /// ### Why is this bad? + /// Usually `to_string` is implemented indirectly /// via `Display`. Hence using it while implementing `Display` would /// lead to infinite recursion. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```rust /// use std::fmt; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 74a94db1800..79367c4230c 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -11,14 +11,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** This lint warns about unnecessary type repetitions in trait bounds + /// ### What it does + /// This lint warns about unnecessary type repetitions in trait bounds /// - /// **Why is this bad?** Repeating the type for every bound makes the code + /// ### Why is this bad? + /// Repeating the type for every bound makes the code /// less readable than combining the bounds /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// pub fn foo(t: T) where T: Copy, T: Clone {} /// ``` @@ -34,15 +34,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for cases where generics are being used and multiple + /// ### What it does + /// Checks for cases where generics are being used and multiple /// syntax specifications for trait bounds are used simultaneously. /// - /// **Why is this bad?** Duplicate bounds makes the code + /// ### Why is this bad? + /// Duplicate bounds makes the code /// less readable than specifing them only once. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn func(arg: T) where T: Clone + Default {} /// ``` diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 89fd5faa165..33ec9c331ce 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -20,15 +20,18 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Checks for transmutes that can't ever be correct on any + /// ### What it does + /// Checks for transmutes that can't ever be correct on any /// architecture. /// - /// **Why is this bad?** It's basically guaranteed to be undefined behaviour. + /// ### Why is this bad? + /// It's basically guaranteed to be undefined behaviour. /// - /// **Known problems:** When accessing C, users might want to store pointer + /// ### Known problems + /// When accessing C, users might want to store pointer /// sized objects in `extradata` arguments to save an allocation. /// - /// **Example:** + /// ### Example /// ```ignore /// let ptr: *const T = core::intrinsics::transmute('x') /// ``` @@ -39,15 +42,15 @@ declare_clippy_lint! { // FIXME: Move this to `complexity` again, after #5343 is fixed declare_clippy_lint! { - /// **What it does:** Checks for transmutes to the original type of the object + /// ### What it does + /// Checks for transmutes to the original type of the object /// and transmutes that could be a cast. /// - /// **Why is this bad?** Readability. The code tricks people into thinking that + /// ### Why is this bad? + /// Readability. The code tricks people into thinking that /// something complex is going on. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s /// ``` @@ -58,14 +61,14 @@ declare_clippy_lint! { // FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery. declare_clippy_lint! { - /// **What it does:**Checks for transmutes that could be a pointer cast. + /// ### What it does + ///Checks for transmutes that could be a pointer cast. /// - /// **Why is this bad?** Readability. The code tricks people into thinking that + /// ### Why is this bad? + /// Readability. The code tricks people into thinking that /// something complex is going on. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// /// ```rust /// # let p: *const [i32] = &[]; @@ -82,14 +85,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes between a type `T` and `*T`. + /// ### What it does + /// Checks for transmutes between a type `T` and `*T`. /// - /// **Why is this bad?** It's easy to mistakenly transmute between a type and a + /// ### Why is this bad? + /// It's easy to mistakenly transmute between a type and a /// pointer to that type. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// core::intrinsics::transmute(t) // where the result type is the same as /// // `*t` or `&t`'s @@ -100,17 +103,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from a pointer to a reference. + /// ### What it does + /// Checks for transmutes from a pointer to a reference. /// - /// **Why is this bad?** This can always be rewritten with `&` and `*`. + /// ### Why is this bad? + /// This can always be rewritten with `&` and `*`. /// - /// **Known problems:** + /// ### Known problems /// - `mem::transmute` in statics and constants is stable from Rust 1.46.0, /// while dereferencing raw pointer is not stable yet. /// If you need to do this in those places, /// you would have to use `transmute` instead. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// unsafe { /// let _: &T = std::mem::transmute(p); // where p: *const T @@ -125,11 +130,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from an integer to a `char`. + /// ### What it does + /// Checks for transmutes from an integer to a `char`. /// - /// **Why is this bad?** Not every integer is a Unicode scalar value. + /// ### Why is this bad? + /// Not every integer is a Unicode scalar value. /// - /// **Known problems:** + /// ### Known problems /// - [`from_u32`] which this lint suggests using is slower than `transmute` /// as it needs to validate the input. /// If you are certain that the input is always a valid Unicode scalar value, @@ -140,7 +147,7 @@ declare_clippy_lint! { /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html /// - /// **Example:** + /// ### Example /// ```rust /// let x = 1_u32; /// unsafe { @@ -156,11 +163,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from a `&[u8]` to a `&str`. + /// ### What it does + /// Checks for transmutes from a `&[u8]` to a `&str`. /// - /// **Why is this bad?** Not every byte slice is a valid UTF-8 string. + /// ### Why is this bad? + /// Not every byte slice is a valid UTF-8 string. /// - /// **Known problems:** + /// ### Known problems /// - [`from_utf8`] which this lint suggests using is slower than `transmute` /// as it needs to validate the input. /// If you are certain that the input is always a valid UTF-8, @@ -171,7 +180,7 @@ declare_clippy_lint! { /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html /// - /// **Example:** + /// ### Example /// ```rust /// let b: &[u8] = &[1_u8, 2_u8]; /// unsafe { @@ -187,13 +196,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from an integer to a `bool`. - /// - /// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`. + /// ### What it does + /// Checks for transmutes from an integer to a `bool`. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This might result in an invalid in-memory representation of a `bool`. /// - /// **Example:** + /// ### Example /// ```rust /// let x = 1_u8; /// unsafe { @@ -209,14 +218,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from an integer to a float. + /// ### What it does + /// Checks for transmutes from an integer to a float. /// - /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive + /// ### Why is this bad? + /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive /// and safe. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// unsafe { /// let _: f32 = std::mem::transmute(1_u32); // where x: u32 @@ -231,14 +240,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from a float to an integer. + /// ### What it does + /// Checks for transmutes from a float to an integer. /// - /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive + /// ### Why is this bad? + /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive /// and safe. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// unsafe { /// let _: u32 = std::mem::transmute(1f32); @@ -253,15 +262,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes from a pointer to a pointer, or + /// ### What it does + /// Checks for transmutes from a pointer to a pointer, or /// from a reference to a reference. /// - /// **Why is this bad?** Transmutes are dangerous, and these can instead be + /// ### Why is this bad? + /// Transmutes are dangerous, and these can instead be /// written as casts. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let ptr = &1u32 as *const u32; /// unsafe { @@ -280,15 +289,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for transmutes between collections whose + /// ### What it does + /// Checks for transmutes between collections whose /// types have different ABI, size or alignment. /// - /// **Why is this bad?** This is undefined behavior. + /// ### Why is this bad? + /// This is undefined behavior. /// - /// **Known problems:** Currently, we cannot know whether a type is a + /// ### Known problems + /// Currently, we cannot know whether a type is a /// collection, so we just lint the ones that come with `std`. /// - /// **Example:** + /// ### Example /// ```rust /// // different size, therefore likely out-of-bounds memory access /// // You absolutely do not want this in your code! diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 0c39d4d8cf4..a67fa792205 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -10,15 +10,18 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; declare_clippy_lint! { - /// **What it does:** Checks for transmute calls which would receive a null pointer. + /// ### What it does + /// Checks for transmute calls which would receive a null pointer. /// - /// **Why is this bad?** Transmuting a null pointer is undefined behavior. + /// ### Why is this bad? + /// Transmuting a null pointer is undefined behavior. /// - /// **Known problems:** Not all cases can be detected at the moment of this writing. + /// ### Known problems + /// Not all cases can be detected at the moment of this writing. /// For example, variables which hold a null pointer and are then fed to a `transmute` /// call, aren't detectable yet. /// - /// **Example:** + /// ### Example /// ```rust /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; /// ``` diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index f2ba2b2ecf6..1196271d5dd 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -13,16 +13,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for usages of `Err(x)?`. + /// ### What it does + /// Checks for usages of `Err(x)?`. /// - /// **Why is this bad?** The `?` operator is designed to allow calls that + /// ### Why is this bad? + /// The `?` operator is designed to allow calls that /// can fail to be easily chained. For example, `foo()?.bar()` or /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will /// always return), it is more clear to write `return Err(x)`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn foo(fail: bool) -> Result { /// if fail { diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 7d629b5455b..ad7409fe3a9 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -20,16 +20,16 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for use of `Box>` anywhere in the code. + /// ### What it does + /// Checks for use of `Box>` anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// - /// **Why is this bad?** `Vec` already keeps its contents in a separate area on + /// ### Why is this bad? + /// `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` it, you just add another level of indirection /// without any benefit whatsoever. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// struct X { /// values: Box>, @@ -49,16 +49,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `Vec>` where T: Sized anywhere in the code. + /// ### What it does + /// Checks for use of `Vec>` where T: Sized anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// - /// **Why is this bad?** `Vec` already keeps its contents in a separate area on + /// ### Why is this bad? + /// `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` its contents, you just add another level of indirection. /// - /// **Known problems:** Vec> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530), + /// ### Known problems + /// Vec> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530), /// 1st comment). /// - /// **Example:** + /// ### Example /// ```rust /// struct X { /// values: Vec>, @@ -78,19 +81,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `Option>` in function signatures and type + /// ### What it does + /// Checks for use of `Option>` in function signatures and type /// definitions /// - /// **Why is this bad?** `Option<_>` represents an optional value. `Option>` + /// ### Why is this bad? + /// `Option<_>` represents an optional value. `Option>` /// represents an optional optional value which is logically the same thing as an optional /// value but has an unneeded extra level of wrapping. /// /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases, /// consider a custom `enum` instead, with clear names for each case. /// - /// **Known problems:** None. - /// - /// **Example** + /// ### Example /// ```rust /// fn get_data() -> Option> { /// None @@ -116,10 +119,12 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a + /// ### What it does + /// Checks for usage of any `LinkedList`, suggesting to use a /// `Vec` or a `VecDeque` (formerly called `RingBuf`). /// - /// **Why is this bad?** Gankro says: + /// ### Why is this bad? + /// Gankro says: /// /// > The TL;DR of `LinkedList` is that it's built on a massive amount of /// pointers and indirection. @@ -138,10 +143,11 @@ declare_clippy_lint! { /// can still be better /// > because of how expensive it is to seek to the middle of a `LinkedList`. /// - /// **Known problems:** False positives – the instances where using a + /// ### Known problems + /// False positives – the instances where using a /// `LinkedList` makes sense are few and far between, but they can still happen. /// - /// **Example:** + /// ### Example /// ```rust /// # use std::collections::LinkedList; /// let x: LinkedList = LinkedList::new(); @@ -152,15 +158,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `&Box` anywhere in the code. + /// ### What it does + /// Checks for use of `&Box` anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// - /// **Why is this bad?** Any `&Box` can also be a `&T`, which is more + /// ### Why is this bad? + /// Any `&Box` can also be a `&T`, which is more /// general. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// fn foo(bar: &Box) { ... } /// ``` @@ -176,14 +182,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of redundant allocations anywhere in the code. + /// ### What it does + /// Checks for use of redundant allocations anywhere in the code. /// - /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc>`, `Rc>`, `Rc>`, Arc<&T>`, `Arc>`, + /// ### Why is this bad? + /// Expressions such as `Rc<&T>`, `Rc>`, `Rc>`, `Rc>`, Arc<&T>`, `Arc>`, /// `Arc>`, `Arc>`, `Box<&T>`, `Box>`, `Box>`, `Box>`, add an unnecessary level of indirection. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::rc::Rc; /// fn foo(bar: Rc<&usize>) {} @@ -200,9 +206,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. + /// ### What it does + /// Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. /// - /// **Why is this bad?** Expressions such as `Rc` usually have no advantage over `Rc`, since + /// ### Why is this bad? + /// Expressions such as `Rc` usually have no advantage over `Rc`, since /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow`. /// /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only @@ -211,10 +219,11 @@ declare_clippy_lint! { /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally /// be used. /// - /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for + /// ### Known problems + /// This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for /// cases where mutation only happens before there are any additional references. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// # use std::rc::Rc; /// fn foo(interned: Rc) { ... } @@ -231,15 +240,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for types used in structs, parameters and `let` + /// ### What it does + /// Checks for types used in structs, parameters and `let` /// declarations above a certain complexity threshold. /// - /// **Why is this bad?** Too complex types make the code less readable. Consider + /// ### Why is this bad? + /// Too complex types make the code less readable. Consider /// using a `type` definition to simplify them. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::rc::Rc; /// struct Foo { @@ -252,16 +261,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `Rc>`. + /// ### What it does + /// Checks for `Rc>`. /// - /// **Why is this bad?** `Rc` is used in single thread and `Mutex` is used in multi thread. + /// ### Why is this bad? + /// `Rc` is used in single thread and `Mutex` is used in multi thread. /// Consider using `Rc>` in single thread or `Arc>` in multi thread. /// - /// **Known problems:** Sometimes combining generic types can lead to the requirement that a + /// ### Known problems + /// Sometimes combining generic types can lead to the requirement that a /// type use Rc in conjunction with Mutex. We must consider those cases false positives, but /// alas they are quite hard to rule out. Luckily they are also rare. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// use std::rc::Rc; /// use std::sync::Mutex; diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index f4f5e1233e3..47571e608c7 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -6,15 +6,17 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`. + /// ### What it does + /// Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`. /// - /// **Why is this bad?** The safe `drop` function does not drop the inner value of a `ManuallyDrop`. + /// ### Why is this bad? + /// The safe `drop` function does not drop the inner value of a `ManuallyDrop`. /// - /// **Known problems:** Does not catch cases if the user binds `std::mem::drop` + /// ### Known problems + /// Does not catch cases if the user binds `std::mem::drop` /// to a different name and calls it that way. /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct S; /// drop(std::mem::ManuallyDrop::new(S)); diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 2f0a61898ba..f337dec8f2b 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -10,14 +10,15 @@ use rustc_span::source_map::Span; use unicode_normalization::UnicodeNormalization; declare_clippy_lint! { - /// **What it does:** Checks for invisible Unicode characters in the code. + /// ### What it does + /// Checks for invisible Unicode characters in the code. /// - /// **Why is this bad?** Having an invisible character in the code makes for all + /// ### Why is this bad? + /// Having an invisible character in the code makes for all /// sorts of April fools, but otherwise is very much frowned upon. /// - /// **Known problems:** None. - /// - /// **Example:** You don't see it, but there may be a zero-width space or soft hyphen + /// ### Example + /// You don't see it, but there may be a zero-width space or soft hyphen /// some­where in this text. pub INVISIBLE_CHARACTERS, correctness, @@ -25,17 +26,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for non-ASCII characters in string literals. + /// ### What it does + /// Checks for non-ASCII characters in string literals. /// - /// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset + /// ### Why is this bad? + /// Yeah, we know, the 90's called and wanted their charset /// back. Even so, there still are editors and other programs out there that /// don't work well with Unicode. So if the code is meant to be used /// internationally, on multiple operating systems, or has other portability /// requirements, activating this lint could be useful. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = String::from("€"); /// ``` @@ -49,16 +50,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for string literals that contain Unicode in a form + /// ### What it does + /// Checks for string literals that contain Unicode in a form /// that is not equal to its /// [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). /// - /// **Why is this bad?** If such a string is compared to another, the results + /// ### Why is this bad? + /// If such a string is compared to another, the results /// may be surprising. /// - /// **Known problems** None. - /// - /// **Example:** You may not see it, but "à"" and "à"" aren't the same string. The + /// ### Example + /// You may not see it, but "à"" and "à"" aren't the same string. The /// former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`. pub UNICODE_NOT_NFC, pedantic, diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 1c420a50427..900d4531760 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -10,20 +10,22 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{BytePos, Span}; declare_clippy_lint! { - /// **What it does:** Checks for functions that expect closures of type + /// ### What it does + /// Checks for functions that expect closures of type /// Fn(...) -> Ord where the implemented closure returns the unit type. /// The lint also suggests to remove the semi-colon at the end of the statement if present. /// - /// **Why is this bad?** Likely, returning the unit type is unintentional, and + /// ### Why is this bad? + /// Likely, returning the unit type is unintentional, and /// could simply be caused by an extra semi-colon. Since () implements Ord /// it doesn't cause a compilation error. /// This is the same reasoning behind the unit_cmp lint. /// - /// **Known problems:** If returning unit is intentional, then there is no + /// ### Known problems + /// If returning unit is intentional, then there is no /// way of specifying this without triggering needless_return lint /// - /// **Example:** - /// + /// ### Example /// ```rust /// let mut twins = vec!((1, 1), (2, 2)); /// twins.sort_by_key(|x| { x.1; }); diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 64420a03933..66b1abbe50b 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -8,14 +8,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for binding a unit value. + /// ### What it does + /// Checks for binding a unit value. /// - /// **Why is this bad?** A unit value cannot usefully be used anywhere. So + /// ### Why is this bad? + /// A unit value cannot usefully be used anywhere. So /// binding one is kind of pointless. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// let x = { /// 1; @@ -27,16 +27,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparisons to unit. This includes all binary + /// ### What it does + /// Checks for comparisons to unit. This includes all binary /// comparisons (like `==` and `<`) and asserts. /// - /// **Why is this bad?** Unit is always equal to itself, and thus is just a + /// ### Why is this bad? + /// Unit is always equal to itself, and thus is just a /// clumsily written constant. Mostly this happens when someone accidentally /// adds semicolons at the end of the operands. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # fn foo() {}; /// # fn bar() {}; @@ -74,14 +74,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for passing a unit value as an argument to a function without using a + /// ### What it does + /// Checks for passing a unit value as an argument to a function without using a /// unit literal (`()`). /// - /// **Why is this bad?** This is likely the result of an accidental semicolon. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// This is likely the result of an accidental semicolon. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// foo({ /// let a = bar(); diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 9cca05b1f1a..1eafdee0352 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -7,16 +7,15 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for comparisons with an address of a function item. + /// ### What it does + /// Checks for comparisons with an address of a function item. /// - /// **Why is this bad?** Function item address is not guaranteed to be unique and could vary + /// ### Why is this bad? + /// Function item address is not guaranteed to be unique and could vary /// between different code generation units. Furthermore different function items could have /// the same address after being merged together. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// type F = fn(); /// fn a() {} @@ -31,17 +30,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparisons with an address of a trait vtable. + /// ### What it does + /// Checks for comparisons with an address of a trait vtable. /// - /// **Why is this bad?** Comparing trait objects pointers compares an vtable addresses which + /// ### Why is this bad? + /// Comparing trait objects pointers compares an vtable addresses which /// are not guaranteed to be unique and could vary between different code generation units. /// Furthermore vtables for different types could have the same address after being merged /// together. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// let a: Rc = ... /// let b: Rc = ... diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 48c54d79cf1..4cfd2df551f 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -7,16 +7,18 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; declare_clippy_lint! { - /// **What it does:** Checks for imports ending in `::{self}`. + /// ### What it does + /// Checks for imports ending in `::{self}`. /// - /// **Why is this bad?** In most cases, this can be written much more cleanly by omitting `::{self}`. + /// ### Why is this bad? + /// In most cases, this can be written much more cleanly by omitting `::{self}`. /// - /// **Known problems:** Removing `::{self}` will cause any non-module items at the same path to also be imported. + /// ### Known problems + /// Removing `::{self}` will cause any non-module items at the same path to also be imported. /// This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt /// to detect this scenario and that is why it is a restriction lint. /// - /// **Example:** - /// + /// ### Example /// ```rust /// use std::io::{self}; /// ``` diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 347d858b640..6fc5707a4ee 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -12,21 +12,20 @@ use rustc_span::symbol::Ident; use std::iter; declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Detects uses of `Vec::sort_by` passing in a closure /// which compares the two arguments, either directly or indirectly. /// - /// **Why is this bad?** + /// ### Why is this bad? /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if /// possible) than to use `Vec::sort_by` and a more complicated /// closure. /// - /// **Known problems:** + /// ### Known problems /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already /// imported by a use statement, then it will need to be added manually. /// - /// **Example:** - /// + /// ### Example /// ```rust /// # struct A; /// # impl A { fn foo(&self) {} } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index a85ffa6aa95..7a62b21937f 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -13,15 +13,17 @@ use rustc_span::symbol::sym; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for private functions that only return `Ok` or `Some`. + /// ### What it does + /// Checks for private functions that only return `Ok` or `Some`. /// - /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned. + /// ### Why is this bad? + /// It is not meaningful to wrap values when no `None` or `Err` is returned. /// - /// **Known problems:** There can be false positives if the function signature is designed to + /// ### Known problems + /// There can be false positives if the function signature is designed to /// fit some external requirement. /// - /// **Example:** - /// + /// ### Example /// ```rust /// fn get_cool_number(a: bool, b: bool) -> Option { /// if a && b { diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 07a4e294049..9acfbc994b3 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -17,22 +17,17 @@ use std::cell::Cell; use std::mem; declare_clippy_lint! { - /// **What it does:** - /// + /// ### What it does /// Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and /// suggests replacing the pattern with a nested one, `Some(0 | 2)`. /// /// Another way to think of this is that it rewrites patterns in /// *disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*. /// - /// **Why is this bad?** - /// + /// ### Why is this bad? /// In the example above, `Some` is repeated, which unncessarily complicates the pattern. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// fn main() { /// if let Some(0) | Some(2) = Some(0) {} diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 16ad9d2dfd3..3c694af2b9d 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -6,15 +6,15 @@ use rustc_span::source_map::Span; use rustc_span::symbol::Ident; declare_clippy_lint! { - /// **What it does:** Checks for imports that remove "unsafe" from an item's + /// ### What it does + /// Checks for imports that remove "unsafe" from an item's /// name. /// - /// **Why is this bad?** Renaming makes it less clear which traits and + /// ### Why is this bad? + /// Renaming makes it less clear which traits and /// structures are unsafe. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// use std::cell::{UnsafeCell as TotallySafeCell}; /// diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 18ee07d3a95..3a6a07c5226 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -7,16 +7,15 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; declare_clippy_lint! { - /// **What it does:** Checks for functions that are declared `async` but have no `.await`s inside of them. + /// ### What it does + /// Checks for functions that are declared `async` but have no `.await`s inside of them. /// - /// **Why is this bad?** Async functions with no async code create overhead, both mentally and computationally. + /// ### Why is this bad? + /// Async functions with no async code create overhead, both mentally and computationally. /// Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which /// causes runtime overhead and hassle for the caller. /// - /// **Known problems:** None - /// - /// **Example:** - /// + /// ### Example /// ```rust /// // Bad /// async fn get_random_number() -> i64 { diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index ee082d30d93..82bc4a6d153 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -5,9 +5,11 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for unused written/read amount. + /// ### What it does + /// Checks for unused written/read amount. /// - /// **Why is this bad?** `io::Write::write(_vectored)` and + /// ### Why is this bad? + /// `io::Write::write(_vectored)` and /// `io::Read::read(_vectored)` are not guaranteed to /// process the entire buffer. They return how many bytes were processed, which /// might be smaller @@ -15,9 +17,10 @@ declare_clippy_lint! { /// partial-write/read, use /// `write_all`/`read_exact` instead. /// - /// **Known problems:** Detects only common patterns. + /// ### Known problems + /// Detects only common patterns. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// use std::io; /// fn foo(w: &mut W) -> io::Result<()> { diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 15343cf90f2..658ac81f6ea 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -6,14 +6,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks methods that contain a `self` argument but don't use it + /// ### What it does + /// Checks methods that contain a `self` argument but don't use it /// - /// **Why is this bad?** It may be clearer to define the method as an associated function instead + /// ### Why is this bad? + /// It may be clearer to define the method as an associated function instead /// of an instance method if it doesn't require `self`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust,ignore /// struct A; /// impl A { diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index ab0cdf75ffe..9ed5e585f84 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -10,15 +10,15 @@ use rustc_span::source_map::Span; use rustc_span::BytePos; declare_clippy_lint! { - /// **What it does:** Checks for unit (`()`) expressions that can be removed. + /// ### What it does + /// Checks for unit (`()`) expressions that can be removed. /// - /// **Why is this bad?** Such expressions add no value, but can make the code + /// ### Why is this bad? + /// Such expressions add no value, but can make the code /// less readable. Depending on formatting they can make a `break` or `return` /// statement look like a function call. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// fn return_unit() -> () { /// () diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index d4efee56eff..c5b8acb9982 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -13,13 +13,13 @@ use rustc_span::source_map::Span; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail. + /// ### What it does + /// Checks for calls of `unwrap[_err]()` that cannot fail. /// - /// **Why is this bad?** Using `if let` or `match` is more idiomatic. + /// ### Why is this bad? + /// Using `if let` or `match` is more idiomatic. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} @@ -43,14 +43,17 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls of `unwrap[_err]()` that will always fail. + /// ### What it does + /// Checks for calls of `unwrap[_err]()` that will always fail. /// - /// **Why is this bad?** If panicking is desired, an explicit `panic!()` should be used. + /// ### Why is this bad? + /// If panicking is desired, an explicit `panic!()` should be used. /// - /// **Known problems:** This lint only checks `if` conditions not assignments. + /// ### Known problems + /// This lint only checks `if` conditions not assignments. /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized. /// - /// **Example:** + /// ### Example /// ```rust /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index d17aa6d8424..6eadd1fc1c9 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -12,13 +12,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for functions of type Result that contain `expect()` or `unwrap()` + /// ### What it does + /// Checks for functions of type Result that contain `expect()` or `unwrap()` /// - /// **Why is this bad?** These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. + /// ### Why is this bad? + /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. /// - /// **Known problems:** This can cause false positives in functions that handle both recoverable and non recoverable errors. + /// ### Known problems + /// This can cause false positives in functions that handle both recoverable and non recoverable errors. /// - /// **Example:** + /// ### Example /// Before: /// ```rust /// fn divisible_by_3(i_str: String) -> Result<(), String> { diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 0b58c6c0917..7fa0e23ee73 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -8,9 +8,11 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::Ident; declare_clippy_lint! { - /// **What it does:** Checks for fully capitalized names and optionally names containing a capitalized acronym. + /// ### What it does + /// Checks for fully capitalized names and optionally names containing a capitalized acronym. /// - /// **Why is this bad?** In CamelCase, acronyms count as one word. + /// ### Why is this bad? + /// In CamelCase, acronyms count as one word. /// See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case) /// for more. /// @@ -18,12 +20,12 @@ declare_clippy_lint! { /// You can use the `upper-case-acronyms-aggressive: true` config option to enable linting /// on all camel case names /// - /// **Known problems:** When two acronyms are contiguous, the lint can't tell where + /// ### Known problems + /// When two acronyms are contiguous, the lint can't tell where /// the first acronym ends and the second starts, so it suggests to lowercase all of /// the letters in the second acronym. /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct HTTPResponse; /// ``` diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 71117e967e3..fbd552186df 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -20,19 +20,20 @@ use rustc_span::Span; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { - /// **What it does:** Checks for unnecessary repetition of structure name when a + /// ### What it does + /// Checks for unnecessary repetition of structure name when a /// replacement with `Self` is applicable. /// - /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct + /// ### Why is this bad? + /// Unnecessary repetition. Mixed use of `Self` and struct /// name /// feels inconsistent. /// - /// **Known problems:** + /// ### Known problems /// - Unaddressed false negative in fn bodies of trait implementations /// - False positive with assotiated types in traits (#4140) /// - /// **Example:** - /// + /// ### Example /// ```rust /// struct Foo {} /// impl Foo { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 25a959d3e41..2861b432919 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,15 +12,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls + /// ### What it does + /// Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls /// which uselessly convert to the same type. /// - /// **Why is this bad?** Redundant code. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// Redundant code. /// + /// ### Example /// ```rust /// // Bad /// // format!() returns a `String` diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index c1e7fd7fe95..61fd375a989 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -13,9 +13,10 @@ use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Generates clippy code that detects the offending pattern + /// ### What it does + /// Generates clippy code that detects the offending pattern /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // ./tests/ui/my_lint.rs /// fn foo() { diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 4665eeeff7b..f7ddee12dcf 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -8,10 +8,11 @@ use rustc_session::Session; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Dumps every ast/hir node which has the `#[clippy::dump]` + /// ### What it does + /// Dumps every ast/hir node which has the `#[clippy::dump]` /// attribute /// - /// **Example:** + /// ### Example /// ```rust,ignore /// #[clippy::dump] /// extern crate foo; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 668807f499f..d660008e7d1 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -36,29 +36,33 @@ use std::borrow::{Borrow, Cow}; pub mod metadata_collector; declare_clippy_lint! { - /// **What it does:** Checks for various things we like to keep tidy in clippy. + /// ### What it does + /// Checks for various things we like to keep tidy in clippy. /// - /// **Why is this bad?** We like to pretend we're an example of tidy code. + /// ### Why is this bad? + /// We like to pretend we're an example of tidy code. /// - /// **Known problems:** None. - /// - /// **Example:** Wrong ordering of the util::paths constants. + /// ### Example + /// Wrong ordering of the util::paths constants. pub CLIPPY_LINTS_INTERNAL, internal, "various things that will negatively affect your clippy experience" } declare_clippy_lint! { - /// **What it does:** Ensures every lint is associated to a `LintPass`. + /// ### What it does + /// Ensures every lint is associated to a `LintPass`. /// - /// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without + /// ### Why is this bad? + /// The compiler only knows lints via a `LintPass`. Without /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not /// know the name of the lint. /// - /// **Known problems:** Only checks for lints associated using the + /// ### Known problems + /// Only checks for lints associated using the /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// declare_lint! { pub LINT_1, ... } /// declare_lint! { pub LINT_2, ... } @@ -73,15 +77,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `cx.span_lint*` and suggests to use the `utils::*` + /// ### What it does + /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*` /// variant of the function. /// - /// **Why is this bad?** The `utils::*` variants also add a link to the Clippy documentation to the + /// ### Why is this bad? + /// The `utils::*` variants also add a link to the Clippy documentation to the /// warning/error messages. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// cx.span_lint(LINT_NAME, "message"); @@ -97,14 +101,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `cx.outer().expn_data()` and suggests to use + /// ### What it does + /// Checks for calls to `cx.outer().expn_data()` and suggests to use /// the `cx.outer_expn_data()` /// - /// **Why is this bad?** `cx.outer_expn_data()` is faster and more concise. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// `cx.outer_expn_data()` is faster and more concise. /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// expr.span.ctxt().outer().expn_data() @@ -120,14 +124,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Not an actual lint. This lint is only meant for testing our customized internal compiler + /// ### What it does + /// Not an actual lint. This lint is only meant for testing our customized internal compiler /// error message by calling `panic`. /// - /// **Why is this bad?** ICE in large quantities can damage your teeth + /// ### Why is this bad? + /// ICE in large quantities can damage your teeth /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// 🍦🍦🍦🍦🍦 @@ -138,14 +142,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for cases of an auto-generated lint without an updated description, + /// ### What it does + /// Checks for cases of an auto-generated lint without an updated description, /// i.e. `default lint description`. /// - /// **Why is this bad?** Indicates that the lint is not finished. - /// - /// **Known problems:** None + /// ### Why is this bad? + /// Indicates that the lint is not finished. /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// declare_lint! { pub COOL_LINT, nursery, "default lint description" } @@ -161,7 +165,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Lints `span_lint_and_then` function calls, where the + /// ### What it does + /// Lints `span_lint_and_then` function calls, where the /// closure argument has only one statement and that statement is a method /// call to `span_suggestion`, `span_help`, `span_note` (using the same /// span), `help` or `note`. @@ -170,12 +175,11 @@ declare_clippy_lint! { /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or /// `span_lint_and_note`. /// - /// **Why is this bad?** Using the wrapper `span_lint_and_*` functions, is more + /// ### Why is this bad? + /// Using the wrapper `span_lint_and_*` functions, is more /// convenient, readable and less error prone. /// - /// **Known problems:** None - /// - /// *Example:** + /// ### Example /// Bad: /// ```rust,ignore /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { @@ -222,14 +226,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for calls to `utils::match_type()` on a type diagnostic item + /// ### What it does + /// Checks for calls to `utils::match_type()` on a type diagnostic item /// and suggests to use `utils::is_type_diagnostic_item()` instead. /// - /// **Why is this bad?** `utils::is_type_diagnostic_item()` does not require hardcoded paths. - /// - /// **Known problems:** None. + /// ### Why is this bad? + /// `utils::is_type_diagnostic_item()` does not require hardcoded paths. /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// utils::match_type(cx, ty, &paths::VEC) @@ -245,30 +249,27 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks the paths module for invalid paths. /// - /// **Why is this bad?** + /// ### Why is this bad? /// It indicates a bug in the code. /// - /// **Known problems:** None. - /// - /// **Example:** None. + /// ### Example + /// None. pub INVALID_PATHS, internal, "invalid path" } declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// Checks for interning symbols that have already been pre-interned and defined as constants. /// - /// **Why is this bad?** + /// ### Why is this bad? /// It's faster and easier to use the symbol constant. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// let _ = sym!(f32); @@ -284,13 +285,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for unnecessary conversion from Symbol to a string. - /// - /// **Why is this bad?** It's faster use symbols directly intead of strings. + /// ### What it does + /// Checks for unnecessary conversion from Symbol to a string. /// - /// **Known problems:** None. + /// ### Why is this bad? + /// It's faster use symbols directly intead of strings. /// - /// **Example:** + /// ### Example /// Bad: /// ```rust,ignore /// symbol.as_str() == "clippy"; diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 3eccc89cdeb..3244677b301 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -68,7 +68,7 @@ const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::"; macro_rules! CONFIGURATION_SECTION_TEMPLATE { () => { r#" -**Configuration** +### Configuration This lint has the following configuration variables: {configurations} @@ -116,18 +116,21 @@ const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "Cl const APPLICABILITY_NAME_INDEX: usize = 2; declare_clippy_lint! { - /// **What it does:** Collects metadata about clippy lints for the website. + /// ### What it does + /// Collects metadata about clippy lints for the website. /// /// This lint will be used to report problems of syntax parsing. You should hopefully never /// see this but never say never I guess ^^ /// - /// **Why is this bad?** This is not a bad thing but definitely a hacky way to do it. See + /// ### Why is this bad? + /// This is not a bad thing but definitely a hacky way to do it. See /// issue [#4310](https://github.com/rust-lang/rust-clippy/issues/4310) for a discussion /// about the implementation. /// - /// **Known problems:** Hopefully none. It would be pretty uncool to have a problem here :) + /// ### Known problems + /// Hopefully none. It would be pretty uncool to have a problem here :) /// - /// **Example output:** + /// ### Example output /// ```json,ignore /// { /// "id": "internal_metadata_collector", @@ -374,7 +377,8 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { /// Collecting lint declarations like: /// ```rust, ignore /// declare_clippy_lint! { - /// /// **What it does:** Something IDK. + /// /// ### What it does + /// /// Something IDK. /// pub SOME_LINT, /// internal, /// "Who am I?" diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 1d5b7c98d31..32fa46f042c 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -19,14 +19,14 @@ pub struct UselessVec { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would + /// ### What it does + /// Checks for usage of `&vec![..]` when using `&[..]` would /// be possible. /// - /// **Why is this bad?** This is less efficient. + /// ### Why is this bad? + /// This is less efficient. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # fn foo(my_vec: &[u8]) {} /// diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index c7190e2f979..0413c02b230 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -13,15 +13,14 @@ use rustc_span::{symbol::sym, Span}; use std::convert::TryInto; declare_clippy_lint! { - /// **What it does:** Checks for calls to `push` immediately after creating a new `Vec`. + /// ### What it does + /// Checks for calls to `push` immediately after creating a new `Vec`. /// - /// **Why is this bad?** The `vec![]` macro is both more performant and easier to read than + /// ### Why is this bad? + /// The `vec![]` macro is both more performant and easier to read than /// multiple `push` calls. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust /// let mut v = Vec::new(); /// v.push(0); diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index 5540e87405f..5c0429db6b8 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -10,13 +10,13 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; declare_clippy_lint! { - /// **What it does:** Finds occurrences of `Vec::resize(0, an_int)` + /// ### What it does + /// Finds occurrences of `Vec::resize(0, an_int)` /// - /// **Why is this bad?** This is probably an argument inversion mistake. + /// ### Why is this bad? + /// This is probably an argument inversion mistake. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// vec!(1, 2, 3, 4, 5).resize(0, 5) /// ``` diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 3ab68df2b6d..e07c12f4f16 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -7,15 +7,14 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for use of File::read_to_end and File::read_to_string. + /// ### What it does + /// Checks for use of File::read_to_end and File::read_to_string. /// - /// **Why is this bad?** `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. + /// ### Why is this bad? + /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```rust,no_run /// # use std::io::Read; /// # use std::fs::File; diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index 1ca1117a41e..fd3872bacbe 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -7,16 +7,15 @@ use rustc_span::source_map::DUMMY_SP; use if_chain::if_chain; declare_clippy_lint! { - /// **What it does:** Checks for wildcard dependencies in the `Cargo.toml`. + /// ### What it does + /// Checks for wildcard dependencies in the `Cargo.toml`. /// - /// **Why is this bad?** [As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html), + /// ### Why is this bad? + /// [As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html), /// it is highly unlikely that you work with any possible version of your dependency, /// and wildcard dependencies would cause unnecessary breakage in the ecosystem. /// - /// **Known problems:** None. - /// - /// **Example:** - /// + /// ### Example /// ```toml /// [dependencies] /// regex = "*" diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 520586b3a1f..bafb9d3e3b1 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -13,15 +13,18 @@ use rustc_span::symbol::kw; use rustc_span::{sym, BytePos}; declare_clippy_lint! { - /// **What it does:** Checks for `use Enum::*`. + /// ### What it does + /// Checks for `use Enum::*`. /// - /// **Why is this bad?** It is usually better style to use the prefixed name of + /// ### Why is this bad? + /// It is usually better style to use the prefixed name of /// an enumeration variant, rather than importing variants. /// - /// **Known problems:** Old-style enumerations that prefix the variants are + /// ### Known problems + /// Old-style enumerations that prefix the variants are /// still around. /// - /// **Example:** + /// ### Example /// ```rust,ignore /// // Bad /// use std::cmp::Ordering::*; @@ -37,9 +40,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for wildcard imports `use _::*`. + /// ### What it does + /// Checks for wildcard imports `use _::*`. /// - /// **Why is this bad?** wildcard imports can pollute the namespace. This is especially bad if + /// ### Why is this bad? + /// wildcard imports can pollute the namespace. This is especially bad if /// you try to import something through a wildcard, that already has been imported by name from /// a different source: /// @@ -52,8 +57,7 @@ declare_clippy_lint! { /// /// This can lead to confusing error messages at best and to unexpected behavior at worst. /// - /// **Exceptions:** - /// + /// ### Exceptions /// Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library) /// provide modules named "prelude" specifically designed for wildcard import. /// @@ -61,14 +65,14 @@ declare_clippy_lint! { /// /// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag. /// - /// **Known problems:** If macros are imported through the wildcard, this macro is not included + /// ### Known problems + /// If macros are imported through the wildcard, this macro is not included /// by the suggestion and has to be added by hand. /// /// Applying the suggestion when explicit imports of the things imported with a glob import /// exist, may result in `unused_imports` warnings. /// - /// **Example:** - /// + /// ### Example /// ```rust,ignore /// // Bad /// use crate1::*; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 5229a705865..4553ac704a2 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -16,14 +16,14 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; declare_clippy_lint! { - /// **What it does:** This lint warns when you use `println!("")` to + /// ### What it does + /// This lint warns when you use `println!("")` to /// print a newline. /// - /// **Why is this bad?** You should use `println!()`, which is simpler. + /// ### Why is this bad? + /// You should use `println!()`, which is simpler. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// println!(""); @@ -37,15 +37,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint warns when you use `print!()` with a format + /// ### What it does + /// This lint warns when you use `print!()` with a format /// string that ends in a newline. /// - /// **Why is this bad?** You should use `println!()` instead, which appends the + /// ### Why is this bad? + /// You should use `println!()` instead, which appends the /// newline. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # let name = "World"; /// print!("Hello {}!\n", name); @@ -61,15 +61,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for printing on *stdout*. The purpose of this lint + /// ### What it does + /// Checks for printing on *stdout*. The purpose of this lint /// is to catch debugging remnants. /// - /// **Why is this bad?** People often print on *stdout* while debugging an + /// ### Why is this bad? + /// People often print on *stdout* while debugging an /// application and might forget to remove those prints afterward. /// - /// **Known problems:** Only catches `print!` and `println!` calls. + /// ### Known problems + /// Only catches `print!` and `println!` calls. /// - /// **Example:** + /// ### Example /// ```rust /// println!("Hello world!"); /// ``` @@ -79,15 +82,18 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for printing on *stderr*. The purpose of this lint + /// ### What it does + /// Checks for printing on *stderr*. The purpose of this lint /// is to catch debugging remnants. /// - /// **Why is this bad?** People often print on *stderr* while debugging an + /// ### Why is this bad? + /// People often print on *stderr* while debugging an /// application and might forget to remove those prints afterward. /// - /// **Known problems:** Only catches `eprint!` and `eprintln!` calls. + /// ### Known problems + /// Only catches `eprint!` and `eprintln!` calls. /// - /// **Example:** + /// ### Example /// ```rust /// eprintln!("Hello world!"); /// ``` @@ -97,13 +103,15 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for use of `Debug` formatting. The purpose of this + /// ### What it does + /// Checks for use of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. /// - /// **Why is this bad?** The purpose of the `Debug` trait is to facilitate + /// ### Why is this bad? + /// The purpose of the `Debug` trait is to facilitate /// debugging Rust code. It should not be used in user-facing output. /// - /// **Example:** + /// ### Example /// ```rust /// # let foo = "bar"; /// println!("{:?}", foo); @@ -114,16 +122,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint warns about the use of literals as `print!`/`println!` args. + /// ### What it does + /// This lint warns about the use of literals as `print!`/`println!` args. /// - /// **Why is this bad?** Using literals as `println!` args is inefficient + /// ### Why is this bad? + /// Using literals as `println!` args is inefficient /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary /// (i.e., just put the literal in the format string) /// - /// **Known problems:** Will also warn with macro calls as arguments that expand to literals + /// ### Known problems + /// Will also warn with macro calls as arguments that expand to literals /// -- e.g., `println!("{}", env!("FOO"))`. /// - /// **Example:** + /// ### Example /// ```rust /// println!("{}", "foo"); /// ``` @@ -137,14 +148,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint warns when you use `writeln!(buf, "")` to + /// ### What it does + /// This lint warns when you use `writeln!(buf, "")` to /// print a newline. /// - /// **Why is this bad?** You should use `writeln!(buf)`, which is simpler. + /// ### Why is this bad? + /// You should use `writeln!(buf)`, which is simpler. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); @@ -160,16 +171,16 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint warns when you use `write!()` with a format + /// ### What it does + /// This lint warns when you use `write!()` with a format /// string that /// ends in a newline. /// - /// **Why is this bad?** You should use `writeln!()` instead, which appends the + /// ### Why is this bad? + /// You should use `writeln!()` instead, which appends the /// newline. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); @@ -186,16 +197,19 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args. + /// ### What it does + /// This lint warns about the use of literals as `write!`/`writeln!` args. /// - /// **Why is this bad?** Using literals as `writeln!` args is inefficient + /// ### Why is this bad? + /// Using literals as `writeln!` args is inefficient /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary /// (i.e., just put the literal in the format string) /// - /// **Known problems:** Will also warn with macro calls as arguments that expand to literals + /// ### Known problems + /// Will also warn with macro calls as arguments that expand to literals /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`. /// - /// **Example:** + /// ### Example /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index a1ea743ba80..b29ced28ac4 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -6,13 +6,13 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `0.0 / 0.0`. + /// ### What it does + /// Checks for `0.0 / 0.0`. /// - /// **Why is this bad?** It's less readable than `f32::NAN` or `f64::NAN`. + /// ### Why is this bad? + /// It's less readable than `f32::NAN` or `f64::NAN`. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// ```rust /// // Bad /// let nan = 0.0f32 / 0.0; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index d6a8112218f..2fbe27f9479 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -10,18 +10,19 @@ use rustc_target::abi::LayoutOf as _; use rustc_typeck::hir_ty_to_ty; declare_clippy_lint! { - /// **What it does:** Checks for maps with zero-sized value types anywhere in the code. + /// ### What it does + /// Checks for maps with zero-sized value types anywhere in the code. /// - /// **Why is this bad?** Since there is only a single value for a zero-sized type, a map + /// ### Why is this bad? + /// Since there is only a single value for a zero-sized type, a map /// containing zero sized values is effectively a set. Using a set in that case improves /// readability and communicates intent more clearly. /// - /// **Known problems:** + /// ### Known problems /// * A zero-sized type cannot be recovered later if it contains private fields. /// * This lints the signature of public items /// - /// **Example:** - /// + /// ### Example /// ```rust /// # use std::collections::HashMap; /// fn unique_words(text: &str) -> HashMap<&str, ()> { diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 5a06afedbf4..f2260c3d1a2 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -11,6 +11,7 @@ because that's clearly a non-descriptive name. - [Setup](#setup) - [Getting Started](#getting-started) - [Testing](#testing) + - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Edition 2018 tests](#edition-2018-tests) - [Testing manually](#testing-manually) @@ -179,14 +180,11 @@ the auto-generated lint declaration to have a real description, something like t ```rust declare_clippy_lint! { - /// **What it does:** + /// ### What it does /// - /// **Why is this bad?** - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? /// + /// ### Example /// ```rust /// // example code /// ``` @@ -487,13 +485,13 @@ Please document your lint with a doc comment akin to the following: ```rust declare_clippy_lint! { - /// **What it does:** Checks for ... (describe what the lint matches). - /// - /// **Why is this bad?** Supply the reason for linting the code. + /// ### What it does + /// Checks for ... (describe what the lint matches). /// - /// **Known problems:** None. (Or describe where it could go wrong.) + /// ### Why is this bad? + /// Supply the reason for linting the code. /// - /// **Example:** + /// ### Example /// /// ```rust,ignore /// // Bad -- cgit 1.4.1-3-g733a5 From 54e539121d7911933157519a80e8dd30219dc9e0 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 29 Jul 2021 12:10:18 +0200 Subject: Rename two lints to comply with our lint naming convention self_named_constructor -> self_named_constructors append_instead_of_extend -> extend_with_drain --- CHANGELOG.md | 4 +- clippy_lints/src/lib.rs | 16 ++-- .../src/methods/append_instead_of_extend.rs | 41 ---------- clippy_lints/src/methods/extend_with_drain.rs | 41 ++++++++++ clippy_lints/src/methods/mod.rs | 8 +- clippy_lints/src/self_named_constructor.rs | 90 ---------------------- clippy_lints/src/self_named_constructors.rs | 90 ++++++++++++++++++++++ tests/ui/append_instead_of_extend.fixed | 55 ------------- tests/ui/append_instead_of_extend.rs | 55 ------------- tests/ui/append_instead_of_extend.stderr | 22 ------ tests/ui/extend_with_drain.fixed | 55 +++++++++++++ tests/ui/extend_with_drain.rs | 55 +++++++++++++ tests/ui/extend_with_drain.stderr | 22 ++++++ tests/ui/needless_bool/fixable.fixed | 2 +- tests/ui/needless_bool/fixable.rs | 2 +- tests/ui/self_named_constructor.rs | 59 -------------- tests/ui/self_named_constructor.stderr | 12 --- tests/ui/self_named_constructors.rs | 59 ++++++++++++++ tests/ui/self_named_constructors.stderr | 12 +++ tests/ui/unit_arg.rs | 2 +- tests/ui/use_self.fixed | 2 +- tests/ui/use_self.rs | 2 +- 22 files changed, 353 insertions(+), 353 deletions(-) delete mode 100644 clippy_lints/src/methods/append_instead_of_extend.rs create mode 100644 clippy_lints/src/methods/extend_with_drain.rs delete mode 100644 clippy_lints/src/self_named_constructor.rs create mode 100644 clippy_lints/src/self_named_constructors.rs delete mode 100644 tests/ui/append_instead_of_extend.fixed delete mode 100644 tests/ui/append_instead_of_extend.rs delete mode 100644 tests/ui/append_instead_of_extend.stderr create mode 100644 tests/ui/extend_with_drain.fixed create mode 100644 tests/ui/extend_with_drain.rs create mode 100644 tests/ui/extend_with_drain.stderr delete mode 100644 tests/ui/self_named_constructor.rs delete mode 100644 tests/ui/self_named_constructor.stderr create mode 100644 tests/ui/self_named_constructors.rs create mode 100644 tests/ui/self_named_constructors.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e00dec2e77..acbefc8064d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2423,7 +2423,6 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped -[`append_instead_of_extend`]: https://rust-lang.github.io/rust-clippy/master/index.html#append_instead_of_extend [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants @@ -2522,6 +2521,7 @@ Released 2018-09-13 [`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop [`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write [`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice +[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain [`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default @@ -2772,7 +2772,7 @@ Released 2018-09-13 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment -[`self_named_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructor +[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3cffb507f70..f49b382c5ea 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -329,7 +329,7 @@ mod regex; mod repeat_once; mod returns; mod self_assignment; -mod self_named_constructor; +mod self_named_constructors; mod semicolon_if_nothing_returned; mod serde_api; mod shadow; @@ -740,7 +740,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: mem_replace::MEM_REPLACE_OPTION_WITH_NONE, mem_replace::MEM_REPLACE_WITH_DEFAULT, mem_replace::MEM_REPLACE_WITH_UNINIT, - methods::APPEND_INSTEAD_OF_EXTEND, methods::BIND_INSTEAD_OF_MAP, methods::BYTES_NTH, methods::CHARS_LAST_CMP, @@ -751,6 +750,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::CLONE_ON_REF_PTR, methods::EXPECT_FUN_CALL, methods::EXPECT_USED, + methods::EXTEND_WITH_DRAIN, methods::FILETYPE_IS_FILE, methods::FILTER_MAP_IDENTITY, methods::FILTER_MAP_NEXT, @@ -900,7 +900,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, self_assignment::SELF_ASSIGNMENT, - self_named_constructor::SELF_NAMED_CONSTRUCTOR, + self_named_constructors::SELF_NAMED_CONSTRUCTORS, semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, serde_api::SERDE_API_MISUSE, shadow::SHADOW_REUSE, @@ -1296,7 +1296,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(methods::APPEND_INSTEAD_OF_EXTEND), LintId::of(methods::BIND_INSTEAD_OF_MAP), LintId::of(methods::BYTES_NTH), LintId::of(methods::CHARS_LAST_CMP), @@ -1304,6 +1303,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::CLONE_ON_COPY), LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), @@ -1407,7 +1407,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), LintId::of(self_assignment::SELF_ASSIGNMENT), - LintId::of(self_named_constructor::SELF_NAMED_CONSTRUCTOR), + LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), @@ -1561,7 +1561,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), - LintId::of(self_named_constructor::SELF_NAMED_CONSTRUCTOR), + LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), @@ -1762,8 +1762,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(loops::MANUAL_MEMCPY), LintId::of(loops::NEEDLESS_COLLECT), - LintId::of(methods::APPEND_INSTEAD_OF_EXTEND), LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::ITER_NTH), LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::OR_FUN_CALL), @@ -2104,7 +2104,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let scripts = conf.allowed_scripts.clone(); store.register_early_pass(move || box disallowed_script_idents::DisallowedScriptIdents::new(&scripts)); store.register_late_pass(|| box strlen_on_c_strings::StrlenOnCStrings); - store.register_late_pass(move || box self_named_constructor::SelfNamedConstructor); + store.register_late_pass(move || box self_named_constructors::SelfNamedConstructors); } #[rustfmt::skip] diff --git a/clippy_lints/src/methods/append_instead_of_extend.rs b/clippy_lints/src/methods/append_instead_of_extend.rs deleted file mode 100644 index e39a5a1efd1..00000000000 --- a/clippy_lints/src/methods/append_instead_of_extend.rs +++ /dev/null @@ -1,41 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem}; -use rustc_lint::LateContext; -use rustc_span::symbol::sym; - -use super::APPEND_INSTEAD_OF_EXTEND; - -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { - let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if_chain! { - if is_type_diagnostic_item(cx, ty, sym::vec_type); - //check source object - if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind; - if src_method.ident.as_str() == "drain"; - if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs(); - if is_type_diagnostic_item(cx, src_ty, sym::vec_type); - //check drain range - if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs(); - if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - APPEND_INSTEAD_OF_EXTEND, - expr.span, - "use of `extend` instead of `append` for adding the full range of a second vector", - "try this", - format!( - "{}.append(&mut {})", - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability) - ), - applicability, - ); - } - } -} diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs new file mode 100644 index 00000000000..57e10ce42f8 --- /dev/null +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::EXTEND_WITH_DRAIN; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if_chain! { + if is_type_diagnostic_item(cx, ty, sym::vec_type); + //check source object + if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind; + if src_method.ident.as_str() == "drain"; + if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs(); + if is_type_diagnostic_item(cx, src_ty, sym::vec_type); + //check drain range + if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs(); + if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + EXTEND_WITH_DRAIN, + expr.span, + "use of `extend` instead of `append` for adding the full range of a second vector", + "try this", + format!( + "{}.append(&mut {})", + snippet_with_applicability(cx, recv.span, "..", &mut applicability), + snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability) + ), + applicability, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d3e12023814..5aa29424349 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,3 @@ -mod append_instead_of_extend; mod bind_instead_of_map; mod bytes_nth; mod chars_cmp; @@ -12,6 +11,7 @@ mod clone_on_ref_ptr; mod cloned_instead_of_copied; mod expect_fun_call; mod expect_used; +mod extend_with_drain; mod filetype_is_file; mod filter_map; mod filter_map_identity; @@ -1068,7 +1068,7 @@ declare_clippy_lint! { /// // Good /// a.append(&mut b); /// ``` - pub APPEND_INSTEAD_OF_EXTEND, + pub EXTEND_WITH_DRAIN, perf, "using vec.append(&mut vec) to move the full range of a vecor to another" } @@ -1821,7 +1821,7 @@ impl_lint_pass!(Methods => [ IMPLICIT_CLONE, SUSPICIOUS_SPLITN, MANUAL_STR_REPEAT, - APPEND_INSTEAD_OF_EXTEND + EXTEND_WITH_DRAIN ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2085,7 +2085,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); - append_instead_of_extend::check(cx, expr, recv, arg); + extend_with_drain::check(cx, expr, recv, arg); }, ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg); diff --git a/clippy_lints/src/self_named_constructor.rs b/clippy_lints/src/self_named_constructor.rs deleted file mode 100644 index 2123a14cc1b..00000000000 --- a/clippy_lints/src/self_named_constructor.rs +++ /dev/null @@ -1,90 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::return_ty; -use clippy_utils::ty::{contains_adt_constructor, contains_ty}; -use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Warns when constructors have the same name as their types. - /// - /// ### Why is this bad? - /// Repeating the name of the type is redundant. - /// - /// ### Example - /// ```rust,ignore - /// struct Foo {} - /// - /// impl Foo { - /// pub fn foo() -> Foo { - /// Foo {} - /// } - /// } - /// ``` - /// Use instead: - /// ```rust,ignore - /// struct Foo {} - /// - /// impl Foo { - /// pub fn new() -> Foo { - /// Foo {} - /// } - /// } - /// ``` - pub SELF_NAMED_CONSTRUCTOR, - style, - "method should not have the same name as the type it is implemented for" -} - -declare_lint_pass!(SelfNamedConstructor => [SELF_NAMED_CONSTRUCTOR]); - -impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructor { - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - match impl_item.kind { - ImplItemKind::Fn(ref sig, _) => { - if sig.decl.implicit_self.has_implicit_self() { - return; - } - }, - _ => return, - } - - let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); - let item = cx.tcx.hir().expect_item(parent); - let self_ty = cx.tcx.type_of(item.def_id); - let ret_ty = return_ty(cx, impl_item.hir_id()); - - // Do not check trait impls - if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) { - return; - } - - // Ensure method is constructor-like - if let Some(self_adt) = self_ty.ty_adt_def() { - if !contains_adt_constructor(ret_ty, self_adt) { - return; - } - } else if !contains_ty(ret_ty, self_ty) { - return; - } - - if_chain! { - if let Some(self_def) = self_ty.ty_adt_def(); - if let Some(self_local_did) = self_def.did.as_local(); - let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); - if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id); - let type_name = x.ident.name.as_str().to_lowercase(); - if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace("_", "") == type_name; - - then { - span_lint( - cx, - SELF_NAMED_CONSTRUCTOR, - impl_item.span, - &format!("constructor `{}` has the same name as the type", impl_item.ident.name), - ); - } - } - } -} diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs new file mode 100644 index 00000000000..4472edecbed --- /dev/null +++ b/clippy_lints/src/self_named_constructors.rs @@ -0,0 +1,90 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::return_ty; +use clippy_utils::ty::{contains_adt_constructor, contains_ty}; +use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Warns when constructors have the same name as their types. + /// + /// ### Why is this bad? + /// Repeating the name of the type is redundant. + /// + /// ### Example + /// ```rust,ignore + /// struct Foo {} + /// + /// impl Foo { + /// pub fn foo() -> Foo { + /// Foo {} + /// } + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// struct Foo {} + /// + /// impl Foo { + /// pub fn new() -> Foo { + /// Foo {} + /// } + /// } + /// ``` + pub SELF_NAMED_CONSTRUCTORS, + style, + "method should not have the same name as the type it is implemented for" +} + +declare_lint_pass!(SelfNamedConstructors => [SELF_NAMED_CONSTRUCTORS]); + +impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { + match impl_item.kind { + ImplItemKind::Fn(ref sig, _) => { + if sig.decl.implicit_self.has_implicit_self() { + return; + } + }, + _ => return, + } + + let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); + let item = cx.tcx.hir().expect_item(parent); + let self_ty = cx.tcx.type_of(item.def_id); + let ret_ty = return_ty(cx, impl_item.hir_id()); + + // Do not check trait impls + if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) { + return; + } + + // Ensure method is constructor-like + if let Some(self_adt) = self_ty.ty_adt_def() { + if !contains_adt_constructor(ret_ty, self_adt) { + return; + } + } else if !contains_ty(ret_ty, self_ty) { + return; + } + + if_chain! { + if let Some(self_def) = self_ty.ty_adt_def(); + if let Some(self_local_did) = self_def.did.as_local(); + let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); + if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id); + let type_name = x.ident.name.as_str().to_lowercase(); + if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace("_", "") == type_name; + + then { + span_lint( + cx, + SELF_NAMED_CONSTRUCTORS, + impl_item.span, + &format!("constructor `{}` has the same name as the type", impl_item.ident.name), + ); + } + } + } +} diff --git a/tests/ui/append_instead_of_extend.fixed b/tests/ui/append_instead_of_extend.fixed deleted file mode 100644 index 283358333cd..00000000000 --- a/tests/ui/append_instead_of_extend.fixed +++ /dev/null @@ -1,55 +0,0 @@ -// run-rustfix -#![warn(clippy::append_instead_of_extend)] -use std::collections::BinaryHeap; -fn main() { - //gets linted - let mut vec1 = vec![0u8; 1024]; - let mut vec2: std::vec::Vec = Vec::new(); - - vec2.append(&mut vec1); - - let mut vec3 = vec![0u8; 1024]; - let mut vec4: std::vec::Vec = Vec::new(); - - vec4.append(&mut vec3); - - let mut vec11: std::vec::Vec = Vec::new(); - - vec11.append(&mut return_vector()); - - //won't get linted it dosen't move the entire content of a vec into another - let mut test1 = vec![0u8, 10]; - let mut test2: std::vec::Vec = Vec::new(); - - test2.extend(test1.drain(4..10)); - - let mut vec3 = vec![0u8; 104]; - let mut vec7: std::vec::Vec = Vec::new(); - - vec3.append(&mut vec7); - - let mut vec5 = vec![0u8; 1024]; - let mut vec6: std::vec::Vec = Vec::new(); - - vec5.extend(vec6.drain(..4)); - - let mut vec9: std::vec::Vec = Vec::new(); - - return_vector().append(&mut vec9); - - //won't get linted because it is not a vec - - let mut heap = BinaryHeap::from(vec![1, 3]); - let mut heap2 = BinaryHeap::from(vec![]); - heap2.extend(heap.drain()) -} - -fn return_vector() -> Vec { - let mut new_vector = vec![]; - - for i in 1..10 { - new_vector.push(i) - } - - new_vector -} diff --git a/tests/ui/append_instead_of_extend.rs b/tests/ui/append_instead_of_extend.rs deleted file mode 100644 index abde5cdac5c..00000000000 --- a/tests/ui/append_instead_of_extend.rs +++ /dev/null @@ -1,55 +0,0 @@ -// run-rustfix -#![warn(clippy::append_instead_of_extend)] -use std::collections::BinaryHeap; -fn main() { - //gets linted - let mut vec1 = vec![0u8; 1024]; - let mut vec2: std::vec::Vec = Vec::new(); - - vec2.extend(vec1.drain(..)); - - let mut vec3 = vec![0u8; 1024]; - let mut vec4: std::vec::Vec = Vec::new(); - - vec4.extend(vec3.drain(..)); - - let mut vec11: std::vec::Vec = Vec::new(); - - vec11.extend(return_vector().drain(..)); - - //won't get linted it dosen't move the entire content of a vec into another - let mut test1 = vec![0u8, 10]; - let mut test2: std::vec::Vec = Vec::new(); - - test2.extend(test1.drain(4..10)); - - let mut vec3 = vec![0u8; 104]; - let mut vec7: std::vec::Vec = Vec::new(); - - vec3.append(&mut vec7); - - let mut vec5 = vec![0u8; 1024]; - let mut vec6: std::vec::Vec = Vec::new(); - - vec5.extend(vec6.drain(..4)); - - let mut vec9: std::vec::Vec = Vec::new(); - - return_vector().append(&mut vec9); - - //won't get linted because it is not a vec - - let mut heap = BinaryHeap::from(vec![1, 3]); - let mut heap2 = BinaryHeap::from(vec![]); - heap2.extend(heap.drain()) -} - -fn return_vector() -> Vec { - let mut new_vector = vec![]; - - for i in 1..10 { - new_vector.push(i) - } - - new_vector -} diff --git a/tests/ui/append_instead_of_extend.stderr b/tests/ui/append_instead_of_extend.stderr deleted file mode 100644 index 9d309d981de..00000000000 --- a/tests/ui/append_instead_of_extend.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: use of `extend` instead of `append` for adding the full range of a second vector - --> $DIR/append_instead_of_extend.rs:9:5 - | -LL | vec2.extend(vec1.drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)` - | - = note: `-D clippy::append-instead-of-extend` implied by `-D warnings` - -error: use of `extend` instead of `append` for adding the full range of a second vector - --> $DIR/append_instead_of_extend.rs:14:5 - | -LL | vec4.extend(vec3.drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)` - -error: use of `extend` instead of `append` for adding the full range of a second vector - --> $DIR/append_instead_of_extend.rs:18:5 - | -LL | vec11.extend(return_vector().drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/extend_with_drain.fixed b/tests/ui/extend_with_drain.fixed new file mode 100644 index 00000000000..00170e649e2 --- /dev/null +++ b/tests/ui/extend_with_drain.fixed @@ -0,0 +1,55 @@ +// run-rustfix +#![warn(clippy::extend_with_drain)] +use std::collections::BinaryHeap; +fn main() { + //gets linted + let mut vec1 = vec![0u8; 1024]; + let mut vec2: std::vec::Vec = Vec::new(); + + vec2.append(&mut vec1); + + let mut vec3 = vec![0u8; 1024]; + let mut vec4: std::vec::Vec = Vec::new(); + + vec4.append(&mut vec3); + + let mut vec11: std::vec::Vec = Vec::new(); + + vec11.append(&mut return_vector()); + + //won't get linted it dosen't move the entire content of a vec into another + let mut test1 = vec![0u8, 10]; + let mut test2: std::vec::Vec = Vec::new(); + + test2.extend(test1.drain(4..10)); + + let mut vec3 = vec![0u8; 104]; + let mut vec7: std::vec::Vec = Vec::new(); + + vec3.append(&mut vec7); + + let mut vec5 = vec![0u8; 1024]; + let mut vec6: std::vec::Vec = Vec::new(); + + vec5.extend(vec6.drain(..4)); + + let mut vec9: std::vec::Vec = Vec::new(); + + return_vector().append(&mut vec9); + + //won't get linted because it is not a vec + + let mut heap = BinaryHeap::from(vec![1, 3]); + let mut heap2 = BinaryHeap::from(vec![]); + heap2.extend(heap.drain()) +} + +fn return_vector() -> Vec { + let mut new_vector = vec![]; + + for i in 1..10 { + new_vector.push(i) + } + + new_vector +} diff --git a/tests/ui/extend_with_drain.rs b/tests/ui/extend_with_drain.rs new file mode 100644 index 00000000000..d76458c3289 --- /dev/null +++ b/tests/ui/extend_with_drain.rs @@ -0,0 +1,55 @@ +// run-rustfix +#![warn(clippy::extend_with_drain)] +use std::collections::BinaryHeap; +fn main() { + //gets linted + let mut vec1 = vec![0u8; 1024]; + let mut vec2: std::vec::Vec = Vec::new(); + + vec2.extend(vec1.drain(..)); + + let mut vec3 = vec![0u8; 1024]; + let mut vec4: std::vec::Vec = Vec::new(); + + vec4.extend(vec3.drain(..)); + + let mut vec11: std::vec::Vec = Vec::new(); + + vec11.extend(return_vector().drain(..)); + + //won't get linted it dosen't move the entire content of a vec into another + let mut test1 = vec![0u8, 10]; + let mut test2: std::vec::Vec = Vec::new(); + + test2.extend(test1.drain(4..10)); + + let mut vec3 = vec![0u8; 104]; + let mut vec7: std::vec::Vec = Vec::new(); + + vec3.append(&mut vec7); + + let mut vec5 = vec![0u8; 1024]; + let mut vec6: std::vec::Vec = Vec::new(); + + vec5.extend(vec6.drain(..4)); + + let mut vec9: std::vec::Vec = Vec::new(); + + return_vector().append(&mut vec9); + + //won't get linted because it is not a vec + + let mut heap = BinaryHeap::from(vec![1, 3]); + let mut heap2 = BinaryHeap::from(vec![]); + heap2.extend(heap.drain()) +} + +fn return_vector() -> Vec { + let mut new_vector = vec![]; + + for i in 1..10 { + new_vector.push(i) + } + + new_vector +} diff --git a/tests/ui/extend_with_drain.stderr b/tests/ui/extend_with_drain.stderr new file mode 100644 index 00000000000..57f344716a1 --- /dev/null +++ b/tests/ui/extend_with_drain.stderr @@ -0,0 +1,22 @@ +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/extend_with_drain.rs:9:5 + | +LL | vec2.extend(vec1.drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)` + | + = note: `-D clippy::extend-with-drain` implied by `-D warnings` + +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/extend_with_drain.rs:14:5 + | +LL | vec4.extend(vec3.drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)` + +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/extend_with_drain.rs:18:5 + | +LL | vec11.extend(return_vector().drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 5917ffc3e12..639eac8b8b3 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -7,7 +7,7 @@ clippy::no_effect, clippy::if_same_then_else, clippy::needless_return, - clippy::self_named_constructor + clippy::self_named_constructors )] use std::cell::Cell; diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index d26dcb9fcc3..a3ce086a1c9 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -7,7 +7,7 @@ clippy::no_effect, clippy::if_same_then_else, clippy::needless_return, - clippy::self_named_constructor + clippy::self_named_constructors )] use std::cell::Cell; diff --git a/tests/ui/self_named_constructor.rs b/tests/ui/self_named_constructor.rs deleted file mode 100644 index 7658b86a8d6..00000000000 --- a/tests/ui/self_named_constructor.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![warn(clippy::self_named_constructor)] - -struct ShouldSpawn; -struct ShouldNotSpawn; - -impl ShouldSpawn { - pub fn should_spawn() -> ShouldSpawn { - ShouldSpawn - } - - fn should_not_spawn() -> ShouldNotSpawn { - ShouldNotSpawn - } -} - -impl ShouldNotSpawn { - pub fn new() -> ShouldNotSpawn { - ShouldNotSpawn - } -} - -struct ShouldNotSpawnWithTrait; - -trait ShouldNotSpawnTrait { - type Item; -} - -impl ShouldNotSpawnTrait for ShouldNotSpawnWithTrait { - type Item = Self; -} - -impl ShouldNotSpawnWithTrait { - pub fn should_not_spawn_with_trait() -> impl ShouldNotSpawnTrait { - ShouldNotSpawnWithTrait - } -} - -// Same trait name and same type name should not spawn the lint -#[derive(Default)] -pub struct Default; - -trait TraitSameTypeName { - fn should_not_spawn() -> Self; -} -impl TraitSameTypeName for ShouldNotSpawn { - fn should_not_spawn() -> Self { - ShouldNotSpawn - } -} - -struct SelfMethodShouldNotSpawn; - -impl SelfMethodShouldNotSpawn { - fn self_method_should_not_spawn(self) -> Self { - SelfMethodShouldNotSpawn - } -} - -fn main() {} diff --git a/tests/ui/self_named_constructor.stderr b/tests/ui/self_named_constructor.stderr deleted file mode 100644 index 1e2c34ac2f7..00000000000 --- a/tests/ui/self_named_constructor.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: constructor `should_spawn` has the same name as the type - --> $DIR/self_named_constructor.rs:7:5 - | -LL | / pub fn should_spawn() -> ShouldSpawn { -LL | | ShouldSpawn -LL | | } - | |_____^ - | - = note: `-D clippy::self-named-constructor` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui/self_named_constructors.rs b/tests/ui/self_named_constructors.rs new file mode 100644 index 00000000000..356f701c985 --- /dev/null +++ b/tests/ui/self_named_constructors.rs @@ -0,0 +1,59 @@ +#![warn(clippy::self_named_constructors)] + +struct ShouldSpawn; +struct ShouldNotSpawn; + +impl ShouldSpawn { + pub fn should_spawn() -> ShouldSpawn { + ShouldSpawn + } + + fn should_not_spawn() -> ShouldNotSpawn { + ShouldNotSpawn + } +} + +impl ShouldNotSpawn { + pub fn new() -> ShouldNotSpawn { + ShouldNotSpawn + } +} + +struct ShouldNotSpawnWithTrait; + +trait ShouldNotSpawnTrait { + type Item; +} + +impl ShouldNotSpawnTrait for ShouldNotSpawnWithTrait { + type Item = Self; +} + +impl ShouldNotSpawnWithTrait { + pub fn should_not_spawn_with_trait() -> impl ShouldNotSpawnTrait { + ShouldNotSpawnWithTrait + } +} + +// Same trait name and same type name should not spawn the lint +#[derive(Default)] +pub struct Default; + +trait TraitSameTypeName { + fn should_not_spawn() -> Self; +} +impl TraitSameTypeName for ShouldNotSpawn { + fn should_not_spawn() -> Self { + ShouldNotSpawn + } +} + +struct SelfMethodShouldNotSpawn; + +impl SelfMethodShouldNotSpawn { + fn self_method_should_not_spawn(self) -> Self { + SelfMethodShouldNotSpawn + } +} + +fn main() {} diff --git a/tests/ui/self_named_constructors.stderr b/tests/ui/self_named_constructors.stderr new file mode 100644 index 00000000000..ba989f06dc8 --- /dev/null +++ b/tests/ui/self_named_constructors.stderr @@ -0,0 +1,12 @@ +error: constructor `should_spawn` has the same name as the type + --> $DIR/self_named_constructors.rs:7:5 + | +LL | / pub fn should_spawn() -> ShouldSpawn { +LL | | ShouldSpawn +LL | | } + | |_____^ + | + = note: `-D clippy::self-named-constructors` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index df0fdaccb34..535683729f6 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -7,7 +7,7 @@ clippy::unnecessary_wraps, clippy::or_fun_call, clippy::needless_question_mark, - clippy::self_named_constructor + clippy::self_named_constructors )] use std::fmt::Debug; diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 23fc7632511..dcf818f8076 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -8,7 +8,7 @@ clippy::should_implement_trait, clippy::upper_case_acronyms, clippy::from_over_into, - clippy::self_named_constructor + clippy::self_named_constructors )] #[macro_use] diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index bb46a339923..9da6fef7a38 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -8,7 +8,7 @@ clippy::should_implement_trait, clippy::upper_case_acronyms, clippy::from_over_into, - clippy::self_named_constructor + clippy::self_named_constructors )] #[macro_use] -- cgit 1.4.1-3-g733a5 From 69d439065eccef7f554e7506236fafa0b4af19eb Mon Sep 17 00:00:00 2001 From: Dharma Saputra Wijaya Date: Sun, 1 Aug 2021 17:47:29 +0800 Subject: Handle `Result` on `map_flatten` lint Adds a check on `.map(..).flatten()` on `Result` type that follows the behaviour on `Option` type. --- clippy_lints/src/methods/map_flatten.rs | 42 ++++++++++++++++++++++----------- tests/ui/map_flatten.fixed | 4 ++++ tests/ui/map_flatten.rs | 4 ++++ tests/ui/map_flatten.stderr | 20 ++++++++++------ 4 files changed, 49 insertions(+), 21 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index e8ad16bc0de..08d3a7ce92b 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -52,18 +52,32 @@ pub(super) fn check<'tcx>( ); } - // lint if caller of `.map().flatten()` is an Option - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) { - let func_snippet = snippet(cx, map_arg.span, ".."); - let hint = format!(".and_then({})", func_snippet); - span_lint_and_sugg( - cx, - MAP_FLATTEN, - expr.span.with_lo(recv.span.hi()), - "called `map(..).flatten()` on an `Option`", - "try using `and_then` instead", - hint, - Applicability::MachineApplicable, - ); - } + // lint if caller of `.map().flatten()` is an Option or Result + let caller_type = match cx.typeck_results().expr_ty(recv).kind() { + ty::Adt(adt, _) => { + if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) { + "Option" + } else if cx.tcx.is_diagnostic_item(sym::result_type, adt.did) { + "Result" + } else { + return; + } + }, + _ => { + return; + }, + }; + + let func_snippet = snippet(cx, map_arg.span, ".."); + let hint = format!(".and_then({})", func_snippet); + let lint_info = format!("called `map(..).flatten()` on an `{}`", caller_type); + span_lint_and_sugg( + cx, + MAP_FLATTEN, + expr.span.with_lo(recv.span.hi()), + &lint_info, + "try using `and_then` instead", + hint, + Applicability::MachineApplicable, + ); } diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index 773b5914439..18846c898da 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -5,6 +5,7 @@ #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] #![allow(clippy::unnecessary_wraps)] +#![feature(result_flattening)] fn main() { // mapping to Option on Iterator @@ -23,4 +24,7 @@ fn main() { // mapping to Option on Option let _: Option<_> = (Some(Some(1))).and_then(|x| x); + + // mapping to Result on Result + let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x); } diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index 578bd877267..01db27876da 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -5,6 +5,7 @@ #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] #![allow(clippy::unnecessary_wraps)] +#![feature(result_flattening)] fn main() { // mapping to Option on Iterator @@ -23,4 +24,7 @@ fn main() { // mapping to Option on Option let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); + + // mapping to Result on Result + let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); } diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index 756e6e818ad..38457c8ea4d 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:16:46 + --> $DIR/map_flatten.rs:17:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` @@ -7,34 +7,40 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:17:46 + --> $DIR/map_flatten.rs:18:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:18:46 + --> $DIR/map_flatten.rs:19:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:19:46 + --> $DIR/map_flatten.rs:20:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:22:46 + --> $DIR/map_flatten.rs:23:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:25:39 + --> $DIR/map_flatten.rs:26:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` -error: aborting due to 6 previous errors +error: called `map(..).flatten()` on an `Result` + --> $DIR/map_flatten.rs:29:41 + | +LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` + +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 8a4ffb881d989be8e5bbbfa45cd5aa971a6179f2 Mon Sep 17 00:00:00 2001 From: valentine-mario Date: Thu, 5 Aug 2021 16:15:44 +0100 Subject: fixed bug that had to deal with mut and non mut suggestion --- clippy_lints/src/methods/extend_with_drain.rs | 8 ++++++-- tests/ui/extend_with_drain.fixed | 7 ++++++- tests/ui/extend_with_drain.rs | 7 ++++++- tests/ui/extend_with_drain.stderr | 8 +++++++- 4 files changed, 25 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index 57e10ce42f8..8829b8c5f4d 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -16,7 +16,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: //check source object if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind; if src_method.ident.as_str() == "drain"; - if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs(); + let src_ty = cx.typeck_results().expr_ty(drain_vec); + //check if actual src type is mutable for code suggestion + let immutable = src_ty.is_mutable_ptr(); + let src_ty = src_ty.peel_refs(); if is_type_diagnostic_item(cx, src_ty, sym::vec_type); //check drain range if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs(); @@ -30,8 +33,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: "use of `extend` instead of `append` for adding the full range of a second vector", "try this", format!( - "{}.append(&mut {})", + "{}.append({}{})", snippet_with_applicability(cx, recv.span, "..", &mut applicability), + if immutable { "" } else { "&mut " }, snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability) ), applicability, diff --git a/tests/ui/extend_with_drain.fixed b/tests/ui/extend_with_drain.fixed index 00170e649e2..e863870e7d6 100644 --- a/tests/ui/extend_with_drain.fixed +++ b/tests/ui/extend_with_drain.fixed @@ -41,7 +41,12 @@ fn main() { let mut heap = BinaryHeap::from(vec![1, 3]); let mut heap2 = BinaryHeap::from(vec![]); - heap2.extend(heap.drain()) + heap2.extend(heap.drain()); + + let mut x = vec![0, 1, 2, 3, 5]; + let ref_x = &mut x; + let mut y = Vec::new(); + y.append(ref_x); } fn return_vector() -> Vec { diff --git a/tests/ui/extend_with_drain.rs b/tests/ui/extend_with_drain.rs index d76458c3289..dcb36b5951c 100644 --- a/tests/ui/extend_with_drain.rs +++ b/tests/ui/extend_with_drain.rs @@ -41,7 +41,12 @@ fn main() { let mut heap = BinaryHeap::from(vec![1, 3]); let mut heap2 = BinaryHeap::from(vec![]); - heap2.extend(heap.drain()) + heap2.extend(heap.drain()); + + let mut x = vec![0, 1, 2, 3, 5]; + let ref_x = &mut x; + let mut y = Vec::new(); + y.extend(ref_x.drain(..)); } fn return_vector() -> Vec { diff --git a/tests/ui/extend_with_drain.stderr b/tests/ui/extend_with_drain.stderr index 57f344716a1..da14ddb25b3 100644 --- a/tests/ui/extend_with_drain.stderr +++ b/tests/ui/extend_with_drain.stderr @@ -18,5 +18,11 @@ error: use of `extend` instead of `append` for adding the full range of a second LL | vec11.extend(return_vector().drain(..)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())` -error: aborting due to 3 previous errors +error: use of `extend` instead of `append` for adding the full range of a second vector + --> $DIR/extend_with_drain.rs:49:5 + | +LL | y.extend(ref_x.drain(..)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `y.append(ref_x)` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 64ff2b05b9d2d346b456a72f1b5d602081a037e2 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 7 Aug 2021 01:01:27 +0200 Subject: Replace `span_to_snippet` calls with `snippet_opt` from `clippy_utils` --- .../src/methods/from_iter_instead_of_collect.rs | 5 +++-- .../src/misc_early/unneeded_field_pattern.rs | 5 +++-- clippy_lints/src/reference.rs | 3 ++- clippy_lints/src/unused_unit.rs | 25 +++++++++++----------- 4 files changed, 20 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index b4188d9ed30..99c03844f49 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_expr_path_def_path, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::sym; @@ -43,7 +44,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) - let call_site = expr.span.source_callsite(); if_chain! { - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); + if let Some(snippet) = snippet_opt(cx, call_site); let snippet_split = snippet.split("::").collect::>(); if let Some((_, elements)) = snippet_split.split_last(); diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 2201cf56d52..fff533167ed 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{Pat, PatKind}; -use rustc_lint::{EarlyContext, LintContext}; +use rustc_lint::EarlyContext; use super::UNNEEDED_FIELD_PATTERN; @@ -48,7 +49,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { match field.pat.kind { PatKind::Wild => {}, _ => { - if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) { + if let Some(n) = snippet_opt(cx, field.span) { normal.push(n); } }, diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index e0930d69ab9..77b6e60d893 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -54,7 +54,8 @@ impl EarlyLintPass for DerefAddrOf { then { let mut applicability = Applicability::MachineApplicable; let sugg = if e.span.from_expansion() { - if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) { + #[allow(clippy::option_if_let_else)] + if let Some(macro_source) = snippet_opt(cx, e.span) { // Remove leading whitespace from the given span // e.g: ` $visitor` turns into `$visitor` let trim_leading_whitespaces = |span| { diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 9ed5e585f84..1164ac4938f 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::position_before_rarrow; +use clippy_utils::source::{position_before_rarrow, snippet_opt}; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit::FnKind; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; @@ -125,17 +125,16 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { } fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { - let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { - ( - #[allow(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) - } else { - (ty.span, Applicability::MaybeIncorrect) - }; + let (ret_span, appl) = + snippet_opt(cx, span.with_hi(ty.span.hi())).map_or((ty.span, Applicability::MaybeIncorrect), |fn_source| { + position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) + }); span_lint_and_sugg( cx, UNUSED_UNIT, -- cgit 1.4.1-3-g733a5 From 11ef04728c90aa6105b20c681e3c12f231ba4f12 Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 29 Jul 2021 23:56:47 -0700 Subject: Add unwrap_or_else_default lint This will catch `unwrap_or_else(Default::default)` on Result and Option and suggest `unwrap_or_default()` instead. --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/methods/mod.rs | 32 +++++++++- clippy_lints/src/methods/or_fun_call.rs | 21 +++++-- clippy_lints/src/methods/unwrap_or_else_default.rs | 50 +++++++++++++++ clippy_utils/src/source.rs | 2 +- clippy_utils/src/ty.rs | 18 +++++- tests/ui/or_fun_call.fixed | 19 ++++++ tests/ui/or_fun_call.rs | 19 ++++++ tests/ui/or_fun_call.stderr | 58 +++++++++++------- tests/ui/unwrap_or_else_default.fixed | 71 ++++++++++++++++++++++ tests/ui/unwrap_or_else_default.rs | 71 ++++++++++++++++++++++ tests/ui/unwrap_or_else_default.stderr | 22 +++++++ 13 files changed, 356 insertions(+), 31 deletions(-) create mode 100644 clippy_lints/src/methods/unwrap_or_else_default.rs create mode 100644 tests/ui/unwrap_or_else_default.fixed create mode 100644 tests/ui/unwrap_or_else_default.rs create mode 100644 tests/ui/unwrap_or_else_default.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index ac745793dda..2b89170073b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2999,6 +2999,7 @@ Released 2018-09-13 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result +[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default [`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used [`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f49b382c5ea..dbdb4251b3b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -797,6 +797,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FOLD, methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, methods::USELESS_ASREF, methods::WRONG_SELF_CONVENTION, @@ -1341,6 +1342,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FOLD), LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), LintId::of(methods::WRONG_SELF_CONVENTION), LintId::of(methods::ZST_OFFSET), @@ -1535,6 +1537,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::STRING_EXTEND_CHARS), LintId::of(methods::UNNECESSARY_FOLD), LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::WRONG_SELF_CONVENTION), LintId::of(misc::TOPLEVEL_REF_ARG), LintId::of(misc::ZERO_PTR), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5aa29424349..12f7987fd3a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -56,6 +56,7 @@ mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_lazy_eval; +mod unwrap_or_else_default; mod unwrap_used; mod useless_asref; mod utils; @@ -310,6 +311,31 @@ declare_clippy_lint! { "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of `_.unwrap_or_else(Default::default)` on Option and + /// Result values. + /// + /// ### Why is this bad? + /// Readability, these can be written as `option.unwrap_or_default` or + /// `result.unwrap_or_default`. + /// + /// ### Examples + /// ```rust + /// # let x = Some(1); + /// + /// // Bad + /// x.unwrap_or_else(Default::default); + /// x.unwrap_or_else(u32::default); + /// + /// // Good + /// x.unwrap_or_default(); + /// ``` + pub UNWRAP_OR_ELSE_DEFAULT, + style, + "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or @@ -1766,6 +1792,7 @@ impl_lint_pass!(Methods => [ SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, OK_EXPECT, + UNWRAP_OR_ELSE_DEFAULT, MAP_UNWRAP_OR, RESULT_MAP_OR_INTO_OPTION, OPTION_MAP_OR_NONE, @@ -2172,7 +2199,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("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, msrv) => {}, - _ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"), + _ => { + unwrap_or_else_default::check(cx, expr, recv, u_arg); + unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); + }, }, _ => {}, } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index ef615b0aa40..378b0724170 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::is_lazyness_candidate; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type}; +use clippy_utils::ty::{implements_trait, qpath_target_trait}; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{contains_return, last_path_segment, paths}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -34,15 +35,25 @@ pub(super) fn check<'tcx>( or_has_args: bool, span: Span, ) -> bool { + let is_default_default = |qpath, default_trait_id| { + qpath_target_trait(cx, qpath, fun.hir_id).map_or(false, |target_trait| target_trait == default_trait_id) + }; + + let implements_default = |arg, default_trait_id| { + let arg_ty = cx.typeck_results().expr_ty(arg); + implements_trait(cx, arg_ty, default_trait_id, &[]) + }; + if_chain! { if !or_has_args; if name == "unwrap_or"; if let hir::ExprKind::Path(ref qpath) = fun.kind; - let path = last_path_segment(qpath).ident.name; - if matches!(path, kw::Default | sym::new); - let arg_ty = cx.typeck_results().expr_ty(arg); if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); - if implements_trait(cx, arg_ty, default_trait_id, &[]); + let path = last_path_segment(qpath).ident.name; + // needs to target Default::default in particular or be *::new and have a Default impl + // available + if (matches!(path, kw::Default) && is_default_default(qpath, default_trait_id)) + || (matches!(path, sym::new) && implements_default(arg, default_trait_id)); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs new file mode 100644 index 00000000000..f99ae6cae93 --- /dev/null +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -0,0 +1,50 @@ +//! Lint for `some_result_or_option.unwrap_or_else(Default::default)` + +use super::UNWRAP_OR_ELSE_DEFAULT; +use clippy_utils::{ + diagnostics::span_lint_and_sugg, + source::snippet_with_applicability, + ty::{is_type_diagnostic_item, qpath_target_trait}, +}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + u_arg: &'tcx hir::Expr<'_>, +) { + // something.unwrap_or_else(Default::default) + // ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr + let recv_ty = cx.typeck_results().expr_ty(recv); + let is_option = is_type_diagnostic_item(cx, recv_ty, sym::option_type); + let is_result = is_type_diagnostic_item(cx, recv_ty, sym::result_type); + + if_chain! { + if is_option || is_result; + if let hir::ExprKind::Path(ref qpath) = u_arg.kind; + if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); + if let Some(target_trait) = qpath_target_trait(cx, qpath, u_arg.hir_id); + if target_trait == default_trait_id; + then { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + UNWRAP_OR_ELSE_DEFAULT, + expr.span, + "use of `.unwrap_or_else(..)` to construct default value", + "try", + format!( + "{}.unwrap_or_default()", + snippet_with_applicability(cx, recv.span, "..", &mut applicability) + ), + applicability, + ); + } + } +} diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 4d49b43bde9..789079510c5 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -168,7 +168,7 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow< snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) } -/// Same as `snippet`, but it adapts the applicability level by following rules: +/// Same as [`snippet`], but it adapts the applicability level by following rules: /// /// - Applicability level `Unspecified` will never be changed. /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index e914dc1c222..bc31bea8b9f 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -2,6 +2,7 @@ #![allow(clippy::module_name_repetitions)] +use hir::{HirId, QPath}; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; @@ -114,7 +115,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option< /// Checks whether a type implements a trait. /// The function returns false in case the type contains an inference variable. -/// See also `get_trait_def_id`. +/// See also [`get_trait_def_id`]. pub fn implements_trait<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, @@ -136,6 +137,21 @@ pub fn implements_trait<'tcx>( }) } +/// Gets the trait that a path targets. For example `::a` would return the +/// [`DefId`] for `Trait`. +/// +/// `cx` must be in a body. +pub fn qpath_target_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, expr_id: HirId) -> Option { + let method_res = cx.typeck_results().qpath_res(qpath, expr_id); + let method_id = match method_res { + hir::def::Res::Def(_kind, id) => Some(id), + _ => None, + }; + let method_id = method_id?; + + cx.tcx.trait_of_item(method_id) +} + /// Checks whether this type implements `Drop`. pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.ty_adt_def() { diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 4390ff7dc30..c2f94d0e857 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -18,6 +18,19 @@ fn or_fun_call() { } } + struct FakeDefault; + impl FakeDefault { + fn default() -> Self { + FakeDefault + } + } + + impl Default for FakeDefault { + fn default() -> Self { + FakeDefault + } + } + enum Enum { A(i32), } @@ -53,6 +66,12 @@ fn or_fun_call() { let with_default_type = Some(1); with_default_type.unwrap_or_default(); + let self_default = None::; + self_default.unwrap_or_else(::default); + + let real_default = None::; + real_default.unwrap_or_default(); + let with_vec = Some(vec![1]); with_vec.unwrap_or_default(); diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 75908c974cc..afaf92961b0 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -18,6 +18,19 @@ fn or_fun_call() { } } + struct FakeDefault; + impl FakeDefault { + fn default() -> Self { + FakeDefault + } + } + + impl Default for FakeDefault { + fn default() -> Self { + FakeDefault + } + } + enum Enum { A(i32), } @@ -53,6 +66,12 @@ fn or_fun_call() { let with_default_type = Some(1); with_default_type.unwrap_or(u64::default()); + let self_default = None::; + self_default.unwrap_or(::default()); + + let real_default = None::; + real_default.unwrap_or(::default()); + let with_vec = Some(vec![1]); with_vec.unwrap_or(vec![]); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 9905029ce91..b2bcbd38c2d 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:33:19 + --> $DIR/or_fun_call.rs:46:19 | LL | with_const_fn.unwrap_or(Duration::from_secs(5)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))` @@ -7,130 +7,142 @@ LL | with_const_fn.unwrap_or(Duration::from_secs(5)); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:36:22 + --> $DIR/or_fun_call.rs:49:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:39:5 + --> $DIR/or_fun_call.rs:52:5 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:42:21 + --> $DIR/or_fun_call.rs:55:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:45:14 + --> $DIR/or_fun_call.rs:58:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:48:19 + --> $DIR/or_fun_call.rs:61:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:51:5 + --> $DIR/or_fun_call.rs:64:5 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:54:5 + --> $DIR/or_fun_call.rs:67:5 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:70:18 + | +LL | self_default.unwrap_or(::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(::default)` + +error: use of `unwrap_or` followed by a call to `default` + --> $DIR/or_fun_call.rs:73:5 + | +LL | real_default.unwrap_or(::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `real_default.unwrap_or_default()` + error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:57:5 + --> $DIR/or_fun_call.rs:76:5 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:60:21 + --> $DIR/or_fun_call.rs:79:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:63:19 + --> $DIR/or_fun_call.rs:82:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:66:23 + --> $DIR/or_fun_call.rs:85:23 | LL | map_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:69:21 + --> $DIR/or_fun_call.rs:88:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:72:25 + --> $DIR/or_fun_call.rs:91:25 | LL | btree_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:75:21 + --> $DIR/or_fun_call.rs:94:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:83:21 + --> $DIR/or_fun_call.rs:102:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:85:21 + --> $DIR/or_fun_call.rs:104:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:109:35 + --> $DIR/or_fun_call.rs:128:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:113:10 + --> $DIR/or_fun_call.rs:132:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:141:14 + --> $DIR/or_fun_call.rs:160:14 | LL | None.unwrap_or(s.as_mut_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:146:14 + --> $DIR/or_fun_call.rs:165:14 | LL | None.unwrap_or(unsafe { s.as_mut_vec() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:148:14 + --> $DIR/or_fun_call.rs:167:14 | LL | None.unwrap_or( unsafe { s.as_mut_vec() } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` -error: aborting due to 22 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed new file mode 100644 index 00000000000..7ac3f426c97 --- /dev/null +++ b/tests/ui/unwrap_or_else_default.fixed @@ -0,0 +1,71 @@ +// run-rustfix + +#![warn(clippy::unwrap_or_else_default)] +#![allow(dead_code)] +#![allow(clippy::unnecessary_wraps)] + +/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint. +fn unwrap_or_else_default() { + struct Foo; + + impl Foo { + fn new() -> Foo { + Foo + } + + // fake default, we should not trigger on this + fn default() -> Foo { + Foo + } + } + + struct HasDefaultAndDuplicate; + + impl HasDefaultAndDuplicate { + fn default() -> Self { + HasDefaultAndDuplicate + } + } + + impl Default for HasDefaultAndDuplicate { + fn default() -> Self { + HasDefaultAndDuplicate + } + } + + enum Enum { + A(), + } + + fn make(_: V) -> T { + unimplemented!(); + } + + let with_enum = Some(Enum::A()); + with_enum.unwrap_or_else(Enum::A); + + let with_new = Some(vec![1]); + with_new.unwrap_or_else(Vec::new); + + let with_err: Result<_, ()> = Ok(vec![1]); + with_err.unwrap_or_else(make); + + // should not be changed + let with_fake_default = None::; + with_fake_default.unwrap_or_else(Foo::default); + + // should not be changed + let with_fake_default2 = None::; + with_fake_default2.unwrap_or_else(::default); + + let with_real_default = None::; + with_real_default.unwrap_or_default(); + + let with_default_trait = Some(1); + with_default_trait.unwrap_or_default(); + + let with_default_type = Some(1); + with_default_type.unwrap_or_default(); +} + +fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs new file mode 100644 index 00000000000..82b727a039e --- /dev/null +++ b/tests/ui/unwrap_or_else_default.rs @@ -0,0 +1,71 @@ +// run-rustfix + +#![warn(clippy::unwrap_or_else_default)] +#![allow(dead_code)] +#![allow(clippy::unnecessary_wraps)] + +/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint. +fn unwrap_or_else_default() { + struct Foo; + + impl Foo { + fn new() -> Foo { + Foo + } + + // fake default, we should not trigger on this + fn default() -> Foo { + Foo + } + } + + struct HasDefaultAndDuplicate; + + impl HasDefaultAndDuplicate { + fn default() -> Self { + HasDefaultAndDuplicate + } + } + + impl Default for HasDefaultAndDuplicate { + fn default() -> Self { + HasDefaultAndDuplicate + } + } + + enum Enum { + A(), + } + + fn make(_: V) -> T { + unimplemented!(); + } + + let with_enum = Some(Enum::A()); + with_enum.unwrap_or_else(Enum::A); + + let with_new = Some(vec![1]); + with_new.unwrap_or_else(Vec::new); + + let with_err: Result<_, ()> = Ok(vec![1]); + with_err.unwrap_or_else(make); + + // should not be changed + let with_fake_default = None::; + with_fake_default.unwrap_or_else(Foo::default); + + // should not be changed + let with_fake_default2 = None::; + with_fake_default2.unwrap_or_else(::default); + + let with_real_default = None::; + with_real_default.unwrap_or_else(::default); + + let with_default_trait = Some(1); + with_default_trait.unwrap_or_else(Default::default); + + let with_default_type = Some(1); + with_default_type.unwrap_or_else(u64::default); +} + +fn main() {} diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr new file mode 100644 index 00000000000..feb215b09f6 --- /dev/null +++ b/tests/ui/unwrap_or_else_default.stderr @@ -0,0 +1,22 @@ +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:62:5 + | +LL | with_real_default.unwrap_or_else(::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()` + | + = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:65:5 + | +LL | with_default_trait.unwrap_or_else(Default::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:68:5 + | +LL | with_default_type.unwrap_or_else(u64::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From c78cc7ac1f1e89cd2e12d29374e1c5e6110d9217 Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 5 Aug 2021 20:08:52 -0700 Subject: Add is_trait_item, refactor or_fun_call and unwrap_or_else_default --- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/methods/or_fun_call.rs | 9 ++++----- clippy_lints/src/methods/unwrap_or_else_default.rs | 9 ++------- clippy_utils/src/lib.rs | 19 +++++++++++++++++++ clippy_utils/src/ty.rs | 16 ---------------- 5 files changed, 29 insertions(+), 32 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 12f7987fd3a..bf74cad039e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -313,12 +313,12 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `_.unwrap_or_else(Default::default)` on Option and - /// Result values. + /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and + /// `Result` values. /// /// ### Why is this bad? - /// Readability, these can be written as `option.unwrap_or_default` or - /// `result.unwrap_or_default`. + /// Readability, these can be written as `_.unwrap_or_default`, which is + /// simpler and more concise. /// /// ### Examples /// ```rust diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 378b0724170..c1d22e5d72c 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::is_lazyness_candidate; +use clippy_utils::is_trait_item; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; -use clippy_utils::ty::{implements_trait, qpath_target_trait}; +use clippy_utils::ty::implements_trait; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{contains_return, last_path_segment, paths}; use if_chain::if_chain; @@ -35,9 +36,7 @@ pub(super) fn check<'tcx>( or_has_args: bool, span: Span, ) -> bool { - let is_default_default = |qpath, default_trait_id| { - qpath_target_trait(cx, qpath, fun.hir_id).map_or(false, |target_trait| target_trait == default_trait_id) - }; + let is_default_default = || is_trait_item(cx, fun, sym::Default); let implements_default = |arg, default_trait_id| { let arg_ty = cx.typeck_results().expr_ty(arg); @@ -52,7 +51,7 @@ pub(super) fn check<'tcx>( let path = last_path_segment(qpath).ident.name; // needs to target Default::default in particular or be *::new and have a Default impl // available - if (matches!(path, kw::Default) && is_default_default(qpath, default_trait_id)) + if (matches!(path, kw::Default) && is_default_default()) || (matches!(path, sym::new) && implements_default(arg, default_trait_id)); then { diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index f99ae6cae93..677aa80e1b7 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -2,9 +2,7 @@ use super::UNWRAP_OR_ELSE_DEFAULT; use clippy_utils::{ - diagnostics::span_lint_and_sugg, - source::snippet_with_applicability, - ty::{is_type_diagnostic_item, qpath_target_trait}, + diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; use rustc_hir as hir; @@ -26,10 +24,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if let hir::ExprKind::Path(ref qpath) = u_arg.kind; - if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); - if let Some(target_trait) = qpath_target_trait(cx, qpath, u_arg.hir_id); - if target_trait == default_trait_id; + if is_trait_item(cx, u_arg, sym::Default); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 59f878f8b20..da9560f8ccf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -326,6 +326,25 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) .map_or(false, |did| is_diag_trait_item(cx, did, diag_item)) } +/// Checks if the given expression is a path referring an item on the trait +/// that is marked with the given diagnostic item. +/// +/// For checking method call expressions instead of path expressions, use +/// [`is_trait_method`]. +/// +/// For example, to find if an expression like `u64::default` refers to an item +/// of the trait `Default`, which is marked `#[rustc_diagnostic_item = "Default"]`, +/// a `diag_item` of `sym::Default` should be used. +pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { + if let hir::ExprKind::Path(ref qpath) = expr.kind { + cx.qpath_res(qpath, expr.hir_id) + .opt_def_id() + .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item)) + } else { + false + } +} + pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { match *path { QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"), diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index bc31bea8b9f..536d0f006e3 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -2,7 +2,6 @@ #![allow(clippy::module_name_repetitions)] -use hir::{HirId, QPath}; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; @@ -137,21 +136,6 @@ pub fn implements_trait<'tcx>( }) } -/// Gets the trait that a path targets. For example `::a` would return the -/// [`DefId`] for `Trait`. -/// -/// `cx` must be in a body. -pub fn qpath_target_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, expr_id: HirId) -> Option { - let method_res = cx.typeck_results().qpath_res(qpath, expr_id); - let method_id = match method_res { - hir::def::Res::Def(_kind, id) => Some(id), - _ => None, - }; - let method_id = method_id?; - - cx.tcx.trait_of_item(method_id) -} - /// Checks whether this type implements `Drop`. pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.ty_adt_def() { -- cgit 1.4.1-3-g733a5 From 91b598a8e484da328325ece3400e8612b6f854df Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 13 Aug 2021 14:36:40 +0800 Subject: Fix false positive on `filter_next` --- clippy_lints/src/methods/filter_next.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index 172714f6b01..bcf8d93b602 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet; +use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -16,7 +16,10 @@ pub(super) fn check<'tcx>( filter_arg: &'tcx hir::Expr<'_>, ) { // lint if caller of `.filter().next()` is an Iterator - if is_trait_method(cx, expr, sym::Iterator) { + let recv_impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[]) + }); + if recv_impls_iterator { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; let filter_snippet = snippet(cx, filter_arg.span, ".."); -- cgit 1.4.1-3-g733a5 From a7f376fbd3f30b58ec2bde5538b446eb4c2d615e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 17 Jul 2021 13:52:03 -0400 Subject: Add lint `manual_split_once` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/methods/manual_split_once.rs | 213 ++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 44 +++++- clippy_lints/src/methods/suspicious_splitn.rs | 14 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_utils/src/diagnostics.rs | 2 +- clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/paths.rs | 1 + clippy_utils/src/visitors.rs | 21 +-- tests/compile-test.rs | 1 + tests/ui/manual_split_once.fixed | 50 ++++++ tests/ui/manual_split_once.rs | 50 ++++++ tests/ui/manual_split_once.stderr | 82 ++++++++++ 14 files changed, 459 insertions(+), 26 deletions(-) create mode 100644 clippy_lints/src/methods/manual_split_once.rs create mode 100644 tests/ui/manual_split_once.fixed create mode 100644 tests/ui/manual_split_once.rs create mode 100644 tests/ui/manual_split_once.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b89170073b..b9e67d361c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2754,6 +2754,7 @@ Released 2018-09-13 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic +[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8372d681078..1fadaf4770a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -773,6 +773,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, methods::MANUAL_SATURATING_ARITHMETIC, + methods::MANUAL_SPLIT_ONCE, methods::MANUAL_STR_REPEAT, methods::MAP_COLLECT_RESULT_UNIT, methods::MAP_FLATTEN, @@ -1319,6 +1320,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_IDENTITY), @@ -1617,6 +1619,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::ITER_COUNT), LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MAP_IDENTITY), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), diff --git a/clippy_lints/src/methods/manual_split_once.rs b/clippy_lints/src/methods/manual_split_once.rs new file mode 100644 index 00000000000..e273186d051 --- /dev/null +++ b/clippy_lints/src/methods/manual_split_once.rs @@ -0,0 +1,213 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::{is_diag_item_method, match_def_path, paths}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_span::{symbol::sym, Span, SyntaxContext}; + +use super::MANUAL_SPLIT_ONCE; + +pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { + if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { + return; + } + + let ctxt = expr.span.ctxt(); + let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id)) { + Some(x) => x, + None => return, + }; + let (method_name, msg) = if method_name == "splitn" { + ("split_once", "manual implementation of `split_once`") + } else { + ("rsplit_once", "manual implementation of `rsplit_once`") + }; + + let mut app = Applicability::MachineApplicable; + let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; + let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; + + match usage.kind { + IterUsageKind::NextTuple => { + span_lint_and_sugg( + cx, + MANUAL_SPLIT_ONCE, + usage.span, + msg, + "try this", + format!("{}.{}({})", self_snip, method_name, pat_snip), + app, + ); + }, + IterUsageKind::Next => { + let self_deref = { + let adjust = cx.typeck_results().expr_adjustments(self_arg); + if adjust.is_empty() { + String::new() + } else if cx.typeck_results().expr_ty(self_arg).is_box() + || adjust + .iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box()) + { + format!("&{}", "*".repeat(adjust.len() - 1)) + } else { + "*".repeat(adjust.len() - 2) + } + }; + let sugg = if usage.unwrap_kind.is_some() { + format!( + "{}.{}({}).map_or({}{}, |x| x.0)", + &self_snip, method_name, pat_snip, self_deref, &self_snip + ) + } else { + format!( + "Some({}.{}({}).map_or({}{}, |x| x.0))", + &self_snip, method_name, pat_snip, self_deref, &self_snip + ) + }; + + span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); + }, + IterUsageKind::Second => { + let access_str = match usage.unwrap_kind { + Some(UnwrapKind::Unwrap) => ".unwrap().1", + Some(UnwrapKind::QuestionMark) => "?.1", + None => ".map(|x| x.1)", + }; + span_lint_and_sugg( + cx, + MANUAL_SPLIT_ONCE, + usage.span, + msg, + "try this", + format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str), + app, + ); + }, + } +} + +enum IterUsageKind { + Next, + Second, + NextTuple, +} + +enum UnwrapKind { + Unwrap, + QuestionMark, +} + +struct IterUsage { + kind: IterUsageKind, + unwrap_kind: Option, + span: Span, +} + +fn parse_iter_usage( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + mut iter: impl Iterator)>, +) -> Option { + let (kind, span) = match iter.next() { + Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { + let (name, args) = if let ExprKind::MethodCall(name, _, [_, args @ ..], _) = e.kind { + (name, args) + } else { + return None; + }; + let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; + let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; + + match (&*name.ident.as_str(), args) { + ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Next, e.span), + ("next_tuple", []) => { + if_chain! { + if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); + if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); + if cx.tcx.is_diagnostic_item(sym::option_type, adt_def.did); + if let ty::Tuple(subs) = subs.type_at(0).kind(); + if subs.len() == 2; + then { + return Some(IterUsage { kind: IterUsageKind::NextTuple, span: e.span, unwrap_kind: None }); + } else { + return None; + } + } + }, + ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + let span = if name.ident.as_str() == "nth" { + e.span + } else { + if_chain! { + if let Some((_, Node::Expr(next_expr))) = iter.next(); + if let ExprKind::MethodCall(next_name, _, [_], _) = next_expr.kind; + if next_name.ident.name == sym::next; + if next_expr.span.ctxt() == ctxt; + if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); + if cx.tcx.trait_of_item(next_id) == Some(iter_id); + then { + next_expr.span + } else { + return None; + } + } + }; + match idx { + 0 => (IterUsageKind::Next, span), + 1 => (IterUsageKind::Second, span), + _ => return None, + } + } else { + return None; + } + }, + _ => return None, + } + }, + _ => return None, + }; + + let (unwrap_kind, span) = if let Some((_, Node::Expr(e))) = iter.next() { + match e.kind { + ExprKind::Call( + Expr { + kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)), + .. + }, + _, + ) => { + let parent_span = e.span.parent().unwrap(); + if parent_span.ctxt() == ctxt { + (Some(UnwrapKind::QuestionMark), parent_span) + } else { + (None, span) + } + }, + _ if e.span.ctxt() != ctxt => (None, span), + ExprKind::MethodCall(name, _, [_], _) + if name.ident.name == sym::unwrap + && cx + .typeck_results() + .type_dependent_def_id(e.hir_id) + .map_or(false, |id| is_diag_item_method(cx, id, sym::option_type)) => + { + (Some(UnwrapKind::Unwrap), e.span) + }, + _ => (None, span), + } + } else { + (None, span) + }; + + Some(IterUsage { + kind, + unwrap_kind, + span, + }) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 91606ed3b2b..15ad0325006 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,6 +33,7 @@ mod iter_nth_zero; mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; +mod manual_split_once; mod manual_str_repeat; mod map_collect_result_unit; mod map_flatten; @@ -64,6 +65,7 @@ mod wrong_self_convention; 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, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; @@ -1771,6 +1773,31 @@ declare_clippy_lint! { "manual implementation of `str::repeat`" } +declare_clippy_lint! { + /// **What it does:** Checks for usages of `splitn(2, _)` + /// + /// **Why is this bad?** `split_once` is clearer. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let some_str = "name=value"; + /// let mut iter = some_str.splitn(2, '='); + /// let name = iter.next().unwrap(); + /// let value = iter.next().unwrap_or(""); + /// + /// // Good + /// let some_str = "name=value"; + /// let (name, value) = some_str.split_once('=').unwrap_or((some_str, "")); + /// ``` + pub MANUAL_SPLIT_ONCE, + complexity, + "replace `.splitn(2, pat)` with `.split_once(pat)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -1848,7 +1875,8 @@ impl_lint_pass!(Methods => [ IMPLICIT_CLONE, SUSPICIOUS_SPLITN, MANUAL_STR_REPEAT, - EXTEND_WITH_DRAIN + EXTEND_WITH_DRAIN, + MANUAL_SPLIT_ONCE ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2176,8 +2204,18 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, - ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => { - suspicious_splitn::check(cx, name, expr, recv, count_arg); + ("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); + if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) { + manual_split_once::check(cx, name, expr, recv, pat_arg); + } + } + }, + ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { + if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + suspicious_splitn::check(cx, name, expr, recv, count); + } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index a271df60572..1c546a15bf6 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -1,4 +1,3 @@ -use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_note; use if_chain::if_chain; use rustc_ast::LitKind; @@ -8,15 +7,8 @@ use rustc_span::source_map::Spanned; use super::SUSPICIOUS_SPLITN; -pub(super) fn check( - cx: &LateContext<'_>, - method_name: &str, - expr: &Expr<'_>, - self_arg: &Expr<'_>, - count_arg: &Expr<'_>, -) { +pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { if_chain! { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg); if count <= 1; if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(call_id); @@ -24,9 +16,9 @@ pub(super) fn check( if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id); then { // Ignore empty slice and string literals when used with a literal count. - if (matches!(self_arg.kind, ExprKind::Array([])) + if matches!(self_arg.kind, ExprKind::Array([])) || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) - ) && matches!(count_arg.kind, ExprKind::Lit(_)) + { return; } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 9ee2e302452..211ffdeca20 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -136,7 +136,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 71cfa196fc3..9302e5c21fa 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -21,7 +21,7 @@ fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) { "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}", &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { // extract just major + minor version and ignore patch versions - format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap()) + format!("rust-{}", n.rsplit_once('.').unwrap().1) }), lint )); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 4a9c4fd0276..14234d9c9cb 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -13,6 +13,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,53,0 { OR_PATTERNS } + 1,52,0 { STR_SPLIT_ONCE } 1,50,0 { BOOL_THEN } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index b0c3fe1e5a7..d7e46c2d3eb 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -68,6 +68,7 @@ pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; +pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal-lints")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; #[cfg(feature = "internal-lints")] diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 52f95ff34f5..503effbdad5 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -147,22 +147,23 @@ macro_rules! visitable_ref { } } }; - ([$t:ident], $f:ident) => { - impl Visitable<'tcx> for &'tcx [$t<'tcx>] { - fn visit>(self, visitor: &mut V) { - for x in self { - visitor.$f(x); - } - } - } - }; } visitable_ref!(Arm, visit_arm); visitable_ref!(Block, visit_block); visitable_ref!(Body, visit_body); visitable_ref!(Expr, visit_expr); visitable_ref!(Stmt, visit_stmt); -visitable_ref!([Stmt], visit_stmt); + +// impl<'tcx, I: IntoIterator> Visitable<'tcx> for I +// where +// I::Item: Visitable<'tcx>, +// { +// fn visit>(self, visitor: &mut V) { +// for x in self { +// x.visit(visitor); +// } +// } +// } /// Calls the given function for each break expression. pub fn visit_break_exprs<'tcx>( diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 0a82377a10e..6116acffe07 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -39,6 +39,7 @@ fn third_party_crates() -> String { "clippy_lints", "clippy_utils", "if_chain", + "itertools", "quote", "regex", "serde", diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed new file mode 100644 index 00000000000..3a0332939d4 --- /dev/null +++ b/tests/ui/manual_split_once.fixed @@ -0,0 +1,50 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_split_once)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let _ = Some("key=value".split_once('=').map_or("key=value", |x| x.0)); + let _ = "key=value".splitn(2, '=').nth(2); + let _ = "key=value".split_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".split_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".split_once('=').unwrap().1; + let _ = "key=value".split_once('=').unwrap().1; + let (_, _) = "key=value".split_once('=').unwrap(); + + let s = String::from("key=value"); + let _ = s.split_once('=').map_or(&*s, |x| x.0); + + let s = Box::::from("key=value"); + let _ = s.split_once('=').map_or(&*s, |x| x.0); + + let s = &"key=value"; + let _ = s.split_once('=').map_or(*s, |x| x.0); + + fn _f(s: &str) -> Option<&str> { + let _ = s.split_once("key=value").map_or(s, |x| x.0); + let _ = s.split_once("key=value")?.1; + let _ = s.split_once("key=value")?.1; + None + } + + // Don't lint, slices don't have `split_once` + let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); +} + +fn _msrv_1_51() { + #![clippy::msrv = "1.51"] + // `str::split_once` was stabilized in 1.16. Do not lint this + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); +} + +fn _msrv_1_52() { + #![clippy::msrv = "1.52"] + let _ = "key=value".split_once('=').unwrap().1; +} diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs new file mode 100644 index 00000000000..e6093b63fe8 --- /dev/null +++ b/tests/ui/manual_split_once.rs @@ -0,0 +1,50 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_split_once)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let _ = "key=value".splitn(2, '=').next(); + let _ = "key=value".splitn(2, '=').nth(2); + let _ = "key=value".splitn(2, '=').next().unwrap(); + let _ = "key=value".splitn(2, '=').nth(0).unwrap(); + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); + let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); + + let s = String::from("key=value"); + let _ = s.splitn(2, '=').next().unwrap(); + + let s = Box::::from("key=value"); + let _ = s.splitn(2, '=').nth(0).unwrap(); + + let s = &"key=value"; + let _ = s.splitn(2, '=').skip(0).next().unwrap(); + + fn _f(s: &str) -> Option<&str> { + let _ = s.splitn(2, "key=value").next()?; + let _ = s.splitn(2, "key=value").nth(1)?; + let _ = s.splitn(2, "key=value").skip(1).next()?; + None + } + + // Don't lint, slices don't have `split_once` + let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); +} + +fn _msrv_1_51() { + #![clippy::msrv = "1.51"] + // `str::split_once` was stabilized in 1.16. Do not lint this + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); +} + +fn _msrv_1_52() { + #![clippy::msrv = "1.52"] + let _ = "key=value".splitn(2, '=').nth(1).unwrap(); +} diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr new file mode 100644 index 00000000000..4f15196b469 --- /dev/null +++ b/tests/ui/manual_split_once.stderr @@ -0,0 +1,82 @@ +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:13:13 + | +LL | let _ = "key=value".splitn(2, '=').next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some("key=value".split_once('=').map_or("key=value", |x| x.0))` + | + = note: `-D clippy::manual-split-once` implied by `-D warnings` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:15:13 + | +LL | let _ = "key=value".splitn(2, '=').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').map_or("key=value", |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:16:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').map_or("key=value", |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:17:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:18:13 + | +LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:19:18 + | +LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=')` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:22:13 + | +LL | let _ = s.splitn(2, '=').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(&*s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:25:13 + | +LL | let _ = s.splitn(2, '=').nth(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(&*s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:28:13 + | +LL | let _ = s.splitn(2, '=').skip(0).next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(*s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:31:17 + | +LL | let _ = s.splitn(2, "key=value").next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value").map_or(s, |x| x.0)` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:32:17 + | +LL | let _ = s.splitn(2, "key=value").nth(1)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:33:17 + | +LL | let _ = s.splitn(2, "key=value").skip(1).next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:49:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + +error: aborting due to 13 previous errors + -- cgit 1.4.1-3-g733a5 From aab3267412bd23cae4fd58e860b6b9a36de42448 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 15 Aug 2021 16:27:59 -0400 Subject: Update docs for `manual_split_once` --- clippy_lints/src/methods/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 15ad0325006..b6438bce874 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1774,24 +1774,22 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usages of `splitn(2, _)` + /// **What it does:** Checks for usages of `str::splitn(2, _)` /// - /// **Why is this bad?** `split_once` is clearer. + /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient. /// /// **Known problems:** None. /// /// **Example:** /// - /// ```rust + /// ```rust,ignore /// // Bad - /// let some_str = "name=value"; - /// let mut iter = some_str.splitn(2, '='); - /// let name = iter.next().unwrap(); - /// let value = iter.next().unwrap_or(""); + /// let (key, value) = _.splitn(2, '=').next_tuple()?; + /// let value = _.splitn(2, '=').nth(1)?; /// /// // Good - /// let some_str = "name=value"; - /// let (name, value) = some_str.split_once('=').unwrap_or((some_str, "")); + /// let (key, value) = _.split_once('=')?; + /// let value = _.split_once('=')?.1; /// ``` pub MANUAL_SPLIT_ONCE, complexity, -- cgit 1.4.1-3-g733a5 From 62b46125cb66d1f9050711d012cd16c49c99217c Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 4 Sep 2021 18:21:49 +0200 Subject: Avoid slice indexing in Clippy (down with the ICEs) --- clippy_lints/src/blocks_in_if_conditions.rs | 4 ++-- clippy_lints/src/casts/cast_ptr_alignment.rs | 4 ++-- clippy_lints/src/floating_point_arithmetic.rs | 30 +++++++++++++-------------- clippy_lints/src/if_let_mutex.rs | 6 +++--- clippy_lints/src/if_let_some_result.rs | 4 ++-- clippy_lints/src/loops/needless_range_loop.rs | 4 ++-- clippy_lints/src/mem_forget.rs | 4 ++-- clippy_lints/src/methods/or_fun_call.rs | 4 ++-- clippy_lints/src/methods/utils.rs | 6 +++--- clippy_lints/src/misc.rs | 4 ++-- clippy_lints/src/mut_mutex_lock.rs | 4 ++-- clippy_lints/src/open_options.rs | 6 +++--- clippy_lints/src/ptr_offset_with_cast.rs | 8 +++---- clippy_lints/src/strings.rs | 8 +++---- clippy_lints/src/to_string_in_display.rs | 4 ++-- clippy_lints/src/undropped_manually_drops.rs | 4 ++-- clippy_lints/src/unused_io_amount.rs | 8 +++---- clippy_lints/src/utils/internal_lints.rs | 4 ++-- 18 files changed, 58 insertions(+), 58 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 51d95cc6f0b..47e5b0d583d 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -61,8 +61,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { // do not lint if the closure is called using an iterator (see #1141) if_chain! { if let Some(parent) = get_parent_expr(self.cx, expr); - if let ExprKind::MethodCall(_, _, args, _) = parent.kind; - let caller = self.cx.typeck_results().expr_ty(&args[0]); + if let ExprKind::MethodCall(_, _, [self_arg, ..], _) = &parent.kind; + let caller = self.cx.typeck_results().expr_ty(self_arg); if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(self.cx, caller, iter_id, &[]); then { diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 62a119d662b..5880859e719 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { cx.typeck_results().expr_ty(expr), ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind { + } else if let ExprKind::MethodCall(method_path, _, [self_arg, ..], _) = &expr.kind { if_chain! { if method_path.ident.name == sym!(cast); if let Some(generic_args) = method_path.args; @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !is_hir_ty_cfg_dependant(cx, cast_to); then { let (cast_from, cast_to) = - (cx.typeck_results().expr_ty(&args[0]), cx.typeck_results().expr_ty(expr)); + (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index a643b3eb8f1..eda611117ba 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -362,22 +362,22 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { if_chain! { if let ExprKind::MethodCall( PathSegment { ident: lmethod_name, .. }, - ref _lspan, - largs, + _lspan, + [largs_0, largs_1, ..], _ - ) = add_lhs.kind; + ) = &add_lhs.kind; if let ExprKind::MethodCall( PathSegment { ident: rmethod_name, .. }, - ref _rspan, - rargs, + _rspan, + [rargs_0, rargs_1, ..], _ - ) = add_rhs.kind; + ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), &largs[1]); - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), &rargs[1]); + if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1); + if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."))); + return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, ".."), Sugg::hir(cx, rargs_0, ".."))); } } } @@ -407,8 +407,8 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if cx.typeck_results().expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(path, _, method_args, _) = lhs.kind; - if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point(); + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &lhs.kind; + if cx.typeck_results().expr_ty(self_arg).is_floating_point(); if path.ident.name.as_str() == "exp"; then { span_lint_and_sugg( @@ -419,7 +419,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { "consider using", format!( "{}.exp_m1()", - Sugg::hir(cx, &method_args[0], "..") + Sugg::hir(cx, self_arg, "..") ), Applicability::MachineApplicable, ); @@ -617,8 +617,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind; if are_same_base_logs(cx, lhs, rhs); - if let ExprKind::MethodCall(_, _, largs, _) = lhs.kind; - if let ExprKind::MethodCall(_, _, rargs, _) = rhs.kind; + if let ExprKind::MethodCall(_, _, [largs_self, ..], _) = &lhs.kind; + if let ExprKind::MethodCall(_, _, [rargs_self, ..], _) = &rhs.kind; then { span_lint_and_sugg( cx, @@ -626,7 +626,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "log base can be expressed more clearly", "consider using", - format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),), + format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 7dad1c31150..ef72b88b3c7 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -138,12 +138,12 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind; + if let ExprKind::MethodCall(path, _span, [self_arg, ..], _) = &expr.kind; if path.ident.as_str() == "lock"; - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(self_arg); if is_type_diagnostic_item(cx, ty, sym!(mutex_type)); then { - Some(&args[0]) + Some(self_arg) } else { None } diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 33eba02dae0..adcd78ed0d4 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -46,10 +46,10 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr); - if let ExprKind::MethodCall(_, ok_span, result_types, _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) + if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::result_type); if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; then { diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index f17e76d9682..e8f3550283a 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -301,10 +301,10 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(meth, _, args, _) = expr.kind; + if let ExprKind::MethodCall(meth, _, [args_0, args_1, ..], _) = &expr.kind; if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); - if !self.check(&args[1], &args[0], expr); + if !self.check(args_1, args_0, expr); then { return } } diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 07202a59c4b..eb437dc47af 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -28,11 +28,11 @@ declare_lint_pass!(MemForget => [MEM_FORGET]); impl<'tcx> LateLintPass<'tcx> for MemForget { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Call(path_expr, args) = e.kind { + if let ExprKind::Call(path_expr, [ref first_arg, ..]) = e.kind { if let ExprKind::Path(ref qpath) = path_expr.kind { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() { if match_def_path(cx, def_id, &paths::MEM_FORGET) { - let forgot_ty = cx.typeck_results().expr_ty(&args[0]); + let forgot_ty = cx.typeck_results().expr_ty(first_arg); if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) { span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type"); diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index c1d22e5d72c..30ed1d665a9 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -96,9 +96,9 @@ pub(super) fn check<'tcx>( (&paths::RESULT, true, &["or", "unwrap_or"], "else"), ]; - if let hir::ExprKind::MethodCall(path, _, args, _) = &arg.kind { + if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &arg.kind { if path.ident.name == sym::len { - let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); match ty.kind() { ty::Slice(_) | ty::Array(_, _) | ty::Str => return, diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 0daea47816a..30d6665a920 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -24,9 +24,9 @@ pub(super) fn derefs_to_slice<'tcx>( } } - if let hir::ExprKind::MethodCall(path, _, args, _) = expr.kind { - if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { - Some(&args[0]) + if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) { + Some(self_arg) } else { None } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index c796abe9815..538fa4e1678 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -513,12 +513,12 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if_chain! { - if let ExprKind::MethodCall(method_name, _, expressions, _) = expr.kind; + if let ExprKind::MethodCall(method_name, _, [ref self_arg, ..], _) = expr.kind; if sym!(signum) == method_name.ident.name; // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) then { - return is_float(cx, &expressions[0]); + return is_float(cx, self_arg); } } false diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs index 85e870632a5..e9dcc7b227d 100644 --- a/clippy_lints/src/mut_mutex_lock.rs +++ b/clippy_lints/src/mut_mutex_lock.rs @@ -47,9 +47,9 @@ declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]); impl<'tcx> LateLintPass<'tcx> for MutMutexLock { fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) { if_chain! { - if let ExprKind::MethodCall(path, method_span, args, _) = &ex.kind; + if let ExprKind::MethodCall(path, method_span, [self_arg, ..], _) = &ex.kind; if path.ident.name == sym!(lock); - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind(); if is_type_diagnostic_item(cx, inner_ty, sym!(mutex_type)); then { diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 4064d94da2a..5752342cf62 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -31,11 +31,11 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); impl<'tcx> LateLintPass<'tcx> for OpenOptions { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(path, _, arguments, _) = e.kind { - let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &e.kind { + let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); - get_open_options(cx, &arguments[0], &mut options); + get_open_options(cx, self_arg, &mut options); check_open_options(cx, &options, e.span); } } diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index f1975056ddc..cfb5287c667 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -92,13 +92,13 @@ fn expr_as_ptr_offset_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(path_segment, _, args, _) = expr.kind { - if is_expr_ty_raw_ptr(cx, &args[0]) { + if let ExprKind::MethodCall(path_segment, _, [arg_0, arg_1, ..], _) = &expr.kind { + if is_expr_ty_raw_ptr(cx, arg_0) { if path_segment.ident.name == sym::offset { - return Some((&args[0], &args[1], Method::Offset)); + return Some((arg_0, arg_1, Method::Offset)); } if path_segment.ident.name == sym!(wrapping_offset) { - return Some((&args[0], &args[1], Method::WrappingOffset)); + return Some((arg_0, arg_1, Method::WrappingOffset)); } } } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 1a78a4968e5..13d8f954c44 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -345,9 +345,9 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]); impl LateLintPass<'_> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; if path.ident.name == sym!(to_string); - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); if *ty.kind() == ty::Str; then { @@ -394,9 +394,9 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]); impl LateLintPass<'_> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; if path.ident.name == sym!(to_string); - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(self_arg); if is_type_diagnostic_item(cx, ty, sym::string_type); then { span_lint_and_help( diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index b036ed9a3d2..b7414cec87c 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -92,11 +92,11 @@ impl LateLintPass<'_> for ToStringInDisplay { if_chain! { if self.in_display_impl; if let Some(self_hir_id) = self.self_hir_id; - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, [ref self_arg, ..], _) = expr.kind; if path.ident.name == sym!(to_string); if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if is_diag_trait_item(cx, expr_def_id, sym::ToString); - if path_to_local_id(&args[0], self_hir_id); + if path_to_local_id(self_arg, self_hir_id); then { span_lint( cx, diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index 47571e608c7..09570616593 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -37,8 +37,8 @@ declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]); impl LateLintPass<'tcx> for UndroppedManuallyDrops { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(args) = match_function_call(cx, expr, &paths::DROP) { - let ty = cx.typeck_results().expr_ty(&args[0]); + if let Some([arg_0, ..]) = match_function_call(cx, expr, &paths::DROP) { + let ty = cx.typeck_results().expr_ty(arg_0); if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop) { span_lint_and_help( cx, diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 82bc4a6d153..031b182bd2f 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -45,20 +45,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { match expr.kind { hir::ExprKind::Match(res, _, _) if is_try(cx, expr).is_some() => { - if let hir::ExprKind::Call(func, args) = res.kind { + if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind { if matches!( func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _)) ) { - check_map_error(cx, &args[0], expr); + check_map_error(cx, arg_0, expr); } } else { check_map_error(cx, res, expr); } }, - hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() { + hir::ExprKind::MethodCall(path, _, [ref arg_0, ..], _) => match &*path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { - check_map_error(cx, &args[0], expr); + check_map_error(cx, arg_0, expr); }, _ => (), }, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 42d51272279..756c33d70c2 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -504,10 +504,10 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { } if_chain! { - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; + if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(&*fn_name.as_str()); - let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); then { -- cgit 1.4.1-3-g733a5 From 4c1b6a28e4c7b932b077c03e7a0f100b791391d7 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 10 Sep 2021 12:20:39 -0400 Subject: Fix result order for `manual_split_once` when `rsplitn` is used --- clippy_lints/src/methods/manual_split_once.rs | 70 +++++++++++++-------------- tests/ui/manual_split_once.fixed | 6 +++ tests/ui/manual_split_once.rs | 6 +++ tests/ui/manual_split_once.stderr | 28 ++++++++++- 4 files changed, 72 insertions(+), 38 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/manual_split_once.rs b/clippy_lints/src/methods/manual_split_once.rs index e273186d051..8440f291859 100644 --- a/clippy_lints/src/methods/manual_split_once.rs +++ b/clippy_lints/src/methods/manual_split_once.rs @@ -17,32 +17,25 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se } let ctxt = expr.span.ctxt(); - let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id)) { + let (method_name, msg, reverse) = if method_name == "splitn" { + ("split_once", "manual implementation of `split_once`", false) + } else { + ("rsplit_once", "manual implementation of `rsplit_once`", true) + }; + let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) { Some(x) => x, None => return, }; - let (method_name, msg) = if method_name == "splitn" { - ("split_once", "manual implementation of `split_once`") - } else { - ("rsplit_once", "manual implementation of `rsplit_once`") - }; let mut app = Applicability::MachineApplicable; let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; - match usage.kind { + let sugg = match usage.kind { IterUsageKind::NextTuple => { - span_lint_and_sugg( - cx, - MANUAL_SPLIT_ONCE, - usage.span, - msg, - "try this", - format!("{}.{}({})", self_snip, method_name, pat_snip), - app, - ); + format!("{}.{}({})", self_snip, method_name, pat_snip) }, + IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip), IterUsageKind::Next => { let self_deref = { let adjust = cx.typeck_results().expr_adjustments(self_arg); @@ -58,7 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se "*".repeat(adjust.len() - 2) } }; - let sugg = if usage.unwrap_kind.is_some() { + if usage.unwrap_kind.is_some() { format!( "{}.{}({}).map_or({}{}, |x| x.0)", &self_snip, method_name, pat_snip, self_deref, &self_snip @@ -68,9 +61,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se "Some({}.{}({}).map_or({}{}, |x| x.0))", &self_snip, method_name, pat_snip, self_deref, &self_snip ) - }; - - span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); + } }, IterUsageKind::Second => { let access_str = match usage.unwrap_kind { @@ -78,23 +69,18 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se Some(UnwrapKind::QuestionMark) => "?.1", None => ".map(|x| x.1)", }; - span_lint_and_sugg( - cx, - MANUAL_SPLIT_ONCE, - usage.span, - msg, - "try this", - format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str), - app, - ); + format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str) }, - } + }; + + span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); } enum IterUsageKind { Next, Second, NextTuple, + RNextTuple, } enum UnwrapKind { @@ -108,10 +94,12 @@ struct IterUsage { span: Span, } +#[allow(clippy::too_many_lines)] fn parse_iter_usage( cx: &LateContext<'tcx>, ctxt: SyntaxContext, mut iter: impl Iterator)>, + reverse: bool, ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { @@ -124,20 +112,30 @@ fn parse_iter_usage( let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; match (&*name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Next, e.span), + ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if reverse { + (IterUsageKind::Second, e.span) + } else { + (IterUsageKind::Next, e.span) + } + }, ("next_tuple", []) => { - if_chain! { + return if_chain! { if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); if cx.tcx.is_diagnostic_item(sym::option_type, adt_def.did); if let ty::Tuple(subs) = subs.type_at(0).kind(); if subs.len() == 2; then { - return Some(IterUsage { kind: IterUsageKind::NextTuple, span: e.span, unwrap_kind: None }); + Some(IterUsage { + kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple }, + span: e.span, + unwrap_kind: None + }) } else { - return None; + None } - } + }; }, ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { @@ -158,7 +156,7 @@ fn parse_iter_usage( } } }; - match idx { + match if reverse { idx ^ 1 } else { idx } { 0 => (IterUsageKind::Next, span), 1 => (IterUsageKind::Second, span), _ => return None, diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed index 3a0332939d4..992baf1f185 100644 --- a/tests/ui/manual_split_once.fixed +++ b/tests/ui/manual_split_once.fixed @@ -36,6 +36,12 @@ fn main() { // Don't lint, slices don't have `split_once` let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); + + // `rsplitn` gives the results in the reverse order of `rsplit_once` + let _ = "key=value".rsplit_once('=').unwrap().1; + let _ = "key=value".rsplit_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".rsplit_once('=').map(|x| x.1); + let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); } fn _msrv_1_51() { diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index e6093b63fe8..4f92ab6b812 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -36,6 +36,12 @@ fn main() { // Don't lint, slices don't have `split_once` let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); + + // `rsplitn` gives the results in the reverse order of `rsplit_once` + let _ = "key=value".rsplitn(2, '=').next().unwrap(); + let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); + let _ = "key=value".rsplitn(2, '=').nth(0); + let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); } fn _msrv_1_51() { diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index 4f15196b469..7bea2303d92 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -72,11 +72,35 @@ error: manual implementation of `split_once` LL | let _ = s.splitn(2, "key=value").skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:41:13 + | +LL | let _ = "key=value".rsplitn(2, '=').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().1` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:42:13 + | +LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map_or("key=value", |x| x.0)` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:43:13 + | +LL | let _ = "key=value".rsplitn(2, '=').nth(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|x| x.1)` + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:44:18 + | +LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` + error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:49:13 + --> $DIR/manual_split_once.rs:55:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` -error: aborting due to 13 previous errors +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From b68325ecf6dfd87d2dda5c6b3f3d3b0bcc315d3e Mon Sep 17 00:00:00 2001 From: lengyijun Date: Fri, 17 Sep 2021 11:48:21 +0800 Subject: add #4546 test --- clippy_lints/src/methods/mod.rs | 2 ++ tests/ui/wrong_self_convention2.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e89b2d295b9..486208f0fad 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -264,6 +264,8 @@ declare_clippy_lint! { /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait /// (see e.g. the `std::string::ToString` trait). /// + /// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required. + /// /// Please find more info here: /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv /// diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index dd3e842c925..0d827c1feb3 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -87,3 +87,21 @@ mod issue3414 { } } } + +// don't trigger +mod issue4546 { + use std::pin::Pin; + + struct S; + impl S { + pub fn as_mut(self: Pin<&mut Self>) {} + + pub fn as_other_thingy(self: Pin<&Self>) {} + + pub fn is_other_thingy(self: Pin<&Self>) {} + + pub fn to_mut(self: Pin<&mut Self>) {} + + pub fn to_other_thingy(self: Pin<&Self>) {} + } +} -- cgit 1.4.1-3-g733a5 From 388a3d098358edd1f7b83f1f47f1e1e157bad067 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Mon, 4 Oct 2021 10:03:40 +0330 Subject: Implement equatable if let lint --- CHANGELOG.md | 1 + clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/casts/cast_precision_loss.rs | 2 +- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/equatable_if_let.rs | 100 +++++++++++++++++++++ clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/identity_op.rs | 14 +-- clippy_lints/src/integer_division.rs | 2 +- clippy_lints/src/len_zero.rs | 12 +-- clippy_lints/src/lib.mods.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.rs | 1 + clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/loops/needless_range_loop.rs | 2 +- clippy_lints/src/loops/never_loop.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 +- clippy_lints/src/methods/or_fun_call.rs | 14 +-- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/needless_bool.rs | 2 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 2 +- clippy_lints/src/non_send_fields_in_send_ty.rs | 2 +- clippy_lints/src/overflow_check_conditional.rs | 31 +++---- clippy_lints/src/redundant_pub_crate.rs | 36 ++++---- clippy_lints/src/repeat_once.rs | 2 +- clippy_lints/src/transmuting_null.rs | 4 +- clippy_lints/src/zero_div_zero.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/numeric_literal.rs | 4 +- clippy_utils/src/sugg.rs | 2 +- clippy_utils/src/usage.rs | 2 +- tests/ui/branches_sharing_code/shared_at_bottom.rs | 2 +- tests/ui/collapsible_else_if.fixed | 2 +- tests/ui/collapsible_else_if.rs | 2 +- tests/ui/collapsible_if.fixed | 2 +- tests/ui/collapsible_if.rs | 2 +- tests/ui/collapsible_match.rs | 7 +- tests/ui/collapsible_match.stderr | 40 ++++----- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/equatable_if_let.fixed | 69 ++++++++++++++ tests/ui/equatable_if_let.rs | 69 ++++++++++++++ tests/ui/equatable_if_let.stderr | 64 +++++++++++++ tests/ui/if_same_then_else2.rs | 1 + tests/ui/if_same_then_else2.stderr | 24 ++--- tests/ui/match_expr_like_matches_macro.fixed | 2 +- tests/ui/match_expr_like_matches_macro.rs | 2 +- tests/ui/match_overlapping_arm.rs | 2 +- tests/ui/match_ref_pats.rs | 1 + tests/ui/match_ref_pats.stderr | 16 ++-- tests/ui/needless_bool/fixable.fixed | 1 + tests/ui/needless_bool/fixable.rs | 1 + tests/ui/needless_bool/fixable.stderr | 24 ++--- tests/ui/needless_return.fixed | 7 +- tests/ui/needless_return.rs | 7 +- tests/ui/needless_return.stderr | 64 ++++++------- tests/ui/option_if_let_else.fixed | 2 +- tests/ui/option_if_let_else.rs | 2 +- .../ui/redundant_pattern_matching_drop_order.fixed | 2 +- tests/ui/redundant_pattern_matching_drop_order.rs | 2 +- tests/ui/redundant_pattern_matching_option.fixed | 1 + tests/ui/redundant_pattern_matching_option.rs | 1 + tests/ui/redundant_pattern_matching_option.stderr | 38 ++++---- tests/ui/redundant_pattern_matching_poll.fixed | 1 + tests/ui/redundant_pattern_matching_poll.rs | 1 + tests/ui/redundant_pattern_matching_poll.stderr | 36 ++++---- tests/ui/while_let_on_iterator.fixed | 8 +- tests/ui/while_let_on_iterator.rs | 8 +- tests/ui/while_let_on_iterator.stderr | 42 ++++----- 72 files changed, 572 insertions(+), 253 deletions(-) create mode 100644 clippy_lints/src/equatable_if_let.rs create mode 100644 tests/ui/equatable_if_let.fixed create mode 100644 tests/ui/equatable_if_let.rs create mode 100644 tests/ui/equatable_if_let.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4424f5061..7fdb300c977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2695,6 +2695,7 @@ Released 2018-09-13 [`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use [`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names [`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op +[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2ef7dcc1775..6f8b645dd70 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -563,7 +563,7 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip; // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - if let AttrStyle::Outer = attr.style; + if attr.style == AttrStyle::Outer; then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 63ac8fd2dd2..334e1646cd4 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca } let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { + let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) { 32 } else { 64 diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 8416b8440df..24ac5917dcb 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -393,7 +393,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { if_chain! { if let Some(header) = kind.header(); - if let Unsafety::Unsafe = header.unsafety; + if header.unsafety == Unsafety::Unsafe; then { self.has_unsafe = true; } @@ -408,7 +408,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { } if let ExprKind::Block(block, _) = expr.kind { - if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { self.has_unsafe = true; } } diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs new file mode 100644 index 00000000000..0c6ba91c943 --- /dev/null +++ b/clippy_lints/src/equatable_if_let.rs @@ -0,0 +1,100 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::implements_trait; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for pattern matchings that can be expressed using equality. + /// + /// ### Why is this bad? + /// + /// * It reads better and has less cognitive load because equality won't cause binding. + /// * It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely + /// criticized for increasing the cognitive load of reading the code. + /// * Equality is a simple bool expression and can be merged with `&&` and `||` and + /// reuse if blocks + /// + /// ### Example + /// ```rust,ignore + /// if let Some(2) = x { + /// do_thing(); + /// } + /// ``` + /// Should be written + /// ```rust,ignore + /// if x == Some(2) { + /// do_thing(); + /// } + /// ``` + pub EQUATABLE_IF_LET, + nursery, + "using pattern matching instead of equality" +} + +declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]); + +/// detects if pattern matches just one thing +fn unary_pattern(pat: &Pat<'_>) -> bool { + fn array_rec(pats: &[Pat<'_>]) -> bool { + pats.iter().all(unary_pattern) + } + match &pat.kind { + PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + false + }, + PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a), + PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), + PatKind::Path(_) | PatKind::Lit(_) => true, + } +} + +fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool { + if let Some(def_id) = cx.tcx.lang_items().eq_trait() { + implements_trait(cx, ty, def_id, &[other.into()]) + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for PatternEquality { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let ExprKind::Let(pat, exp, _) = expr.kind; + if unary_pattern(pat); + let exp_ty = cx.typeck_results().expr_ty(exp); + let pat_ty = cx.typeck_results().pat_ty(pat); + if is_structural_partial_eq(cx, exp_ty, pat_ty); + then { + + let mut applicability = Applicability::MachineApplicable; + let pat_str = match pat.kind { + PatKind::Struct(..) => format!( + "({})", + snippet_with_applicability(cx, pat.span, "..", &mut applicability), + ), + _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(), + }; + span_lint_and_sugg( + cx, + EQUATABLE_IF_LET, + expr.span, + "this pattern matching can be expressed using equality", + "try", + format!( + "{} == {}", + snippet_with_applicability(cx, exp.span, "..", &mut applicability), + pat_str, + ), + applicability, + ); + } + } + } +} diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 026d14d0ea2..d0944c37cf5 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for ErasingOp { } fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) { - if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) { + if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) { span_lint( cx, ERASING_OP, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 090be73af3b..75b1c882c23 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { for trait_item in items { if trait_item.id.hir_id() == hir_id { // be sure we have `self` parameter in this function - if let AssocItemKind::Fn { has_self: true } = trait_item.kind { + if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { trait_self_ty = Some( TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()) .self_ty() diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 9df92cc5b64..765a6c7585a 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if let Some(mut snippet) = snippet_opt(cx, callee.span) { if_chain! { if let ty::Closure(_, substs) = callee_ty.peel_refs().kind(); - if let ClosureKind::FnMut = substs.as_closure().kind(); + if substs.as_closure().kind() == ClosureKind::FnMut; if get_enclosing_loop_or_closure(cx.tcx, expr).is_some() || UsedAfterExprVisitor::is_found(cx, callee); diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 8714ce90164..1b56dd4b081 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { match typ.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let sig = typ.fn_sig(self.cx.tcx); - if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() { + if self.cx.tcx.erase_late_bound_regions(sig).output().kind() == &ty::Never { self.report_diverging_sub_expr(e); } }, diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 5feb0ce8dec..73bdd67ff5d 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,5 +1,4 @@ use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -62,16 +61,9 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp { fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool { // `1 << 0` is a common pattern in bit manipulation code - if_chain! { - if let BinOpKind::Shl = cmp.node; - if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), right); - if let Some(Constant::Int(1)) = constant_simple(cx, cx.typeck_results(), left); - then { - return true; - } - } - - false + cmp.node == BinOpKind::Shl + && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0)) + && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)) } #[allow(clippy::cast_possible_wrap)] diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index a0e6f12b812..c962e814fa5 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for IntegerDivision { fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { if_chain! { if let hir::ExprKind::Binary(binop, left, right) = &expr.kind; - if let hir::BinOpKind::Div = &binop.node; + if binop.node == hir::BinOpKind::Div; then { let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right)); return left_ty.is_integral() && right_ty.is_integral(); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index a519ad90df5..1811f739421 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -455,14 +455,10 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if let ty::AssocKind::Fn = item.kind { - if item.ident.name.as_str() == "is_empty" { - let sig = cx.tcx.fn_sig(item.def_id); - let ty = sig.skip_binder(); - ty.inputs().len() == 1 - } else { - false - } + if item.kind == ty::AssocKind::Fn && item.ident.name.as_str() == "is_empty" { + let sig = cx.tcx.fn_sig(item.def_id); + let ty = sig.skip_binder(); + ty.inputs().len() == 1 } else { false } diff --git a/clippy_lints/src/lib.mods.rs b/clippy_lints/src/lib.mods.rs index 7fd84783c22..8e899553e69 100644 --- a/clippy_lints/src/lib.mods.rs +++ b/clippy_lints/src/lib.mods.rs @@ -49,6 +49,7 @@ mod entry; mod enum_clike; mod enum_variants; mod eq_op; +mod equatable_if_let; mod erasing_op; mod escape; mod eta_reduction; diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 28d54246fbb..2ba2b3da55c 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -116,6 +116,7 @@ store.register_lints(&[ enum_variants::MODULE_NAME_REPETITIONS, eq_op::EQ_OP, eq_op::OP_REF, + equatable_if_let::EQUATABLE_IF_LET, erasing_op::ERASING_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 32606e570d8..96e0b421094 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -8,6 +8,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(copies::BRANCHES_SHARING_CODE), LintId::of(disallowed_method::DISALLOWED_METHOD), LintId::of(disallowed_type::DISALLOWED_TYPE), + LintId::of(equatable_if_let::EQUATABLE_IF_LET), LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c3be6db6ffa..04128c8a0cc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -485,6 +485,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); + store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 358d53e8859..aedf0844937 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -92,7 +92,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { - if let ty::BorrowKind::MutBorrow = bk { + if bk == ty::BorrowKind::MutBorrow { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 7157b801185..172d9fc39a2 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>( let mut take_expr = end; if let ExprKind::Binary(ref op, left, right) = end.kind { - if let BinOpKind::Add = op.node { + if op.node == BinOpKind::Add { let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left); let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right); diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 41956650c9f..c0fde5e5166 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { NeverLoopResult::AlwaysBreak => { span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| { if_chain! { - if let LoopSource::ForLoop = source; + if source == LoopSource::ForLoop; if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1); if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match); then { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 8e1385fb83a..b632af455f8 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { ) { if_chain! { if let Some(header) = kind.header(); - if let IsAsync::NotAsync = header.asyncness; + if header.asyncness == IsAsync::NotAsync; // Check that this function returns `impl Future` if let FnRetTy::Return(ret_ty) = decl.output; if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty); @@ -178,7 +178,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) if args.len() == 1; if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0]; let closure_body = cx.tcx.hir().body(body_id); - if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind; + if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); then { return Some(closure_body); } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 30ed1d665a9..a4d3f0bfb6c 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -178,15 +178,15 @@ pub(super) fn check<'tcx>( hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); }, - hir::ExprKind::Block(block, _) => { - if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { - if let Some(block_expr) = block.expr { - if let hir::ExprKind::MethodCall(..) = block_expr.kind { - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); - } + hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => + { + if let Some(block_expr) = block.expr { + if let hir::ExprKind::MethodCall(..) = block_expr.kind { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); } } - }, + } _ => (), } } diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 2d14943b56c..f45e68233a1 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for ModuloArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match &expr.kind { ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { - if let BinOpKind::Rem = op.node { + if op.node == BinOpKind::Rem { let lhs_operand = analyze_operand(lhs, cx, expr); let rhs_operand = analyze_operand(rhs, cx, expr); if_chain! { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index c9dd94400ef..91944653500 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -248,7 +248,7 @@ fn check_comparison<'a, 'tcx>( if l_ty.is_bool() && r_ty.is_bool() { let mut applicability = Applicability::MachineApplicable; - if let BinOpKind::Eq = op.node { + if op.node == BinOpKind::Eq { let expression_info = one_side_is_unary_not(left_side, right_side); if expression_info.one_side_is_unary_not { span_lint_and_sugg( diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index fa36d8fb1b3..1b15d29439f 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply { fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { if_chain! { if let ExprKind::Lit(ref l) = lit.kind; - if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)); + if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if cx.typeck_results().expr_ty(exp).is_integral(); then { span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`"); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 0ad616a39d2..0ac27f1cba2 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { }) = item.kind { for assoc_item in items { - if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind { + if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) { let impl_item = cx.tcx.hir().impl_item(assoc_item.id); if in_external_macro(cx.sess(), impl_item.span) { return; diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 0dbf296c714..0973e3a1768 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { if let Some(trait_ref) = &hir_impl.of_trait; if let Some(trait_id) = trait_ref.trait_def_id(); if send_trait == trait_id; - if let ImplPolarity::Positive = hir_impl.polarity; + if hir_impl.polarity == ImplPolarity::Positive; if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id); if let self_ty = ty_trait_ref.self_ty(); if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind(); diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 34755afdb72..0f9e5ada3a8 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -26,6 +26,9 @@ declare_clippy_lint! { declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); +const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust"; +const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust"; + impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -40,17 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); then { - if let BinOpKind::Lt = op.node { - if let BinOpKind::Add = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C overflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); } - if let BinOpKind::Gt = op.node { - if let BinOpKind::Sub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C underflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } @@ -65,17 +62,11 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); then { - if let BinOpKind::Gt = op.node { - if let BinOpKind::Add = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C overflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); } - if let BinOpKind::Lt = op.node { - if let BinOpKind::Sub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C underflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index ed2e1f90fa5..919d4e11e5a 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -41,25 +41,23 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]); impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let VisibilityKind::Crate { .. } = item.vis.node { - if !cx.access_levels.is_exported(item.def_id) { - if let Some(false) = self.is_exported.last() { - let span = item.span.with_hi(item.ident.span.hi()); - let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id()); - span_lint_and_then( - cx, - REDUNDANT_PUB_CRATE, - span, - &format!("pub(crate) {} inside private module", descr), - |diag| { - diag.span_suggestion( - item.vis.span, - "consider using", - "pub".to_string(), - Applicability::MachineApplicable, - ); - }, - ); - } + if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) { + let span = item.span.with_hi(item.ident.span.hi()); + let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id()); + span_lint_and_then( + cx, + REDUNDANT_PUB_CRATE, + span, + &format!("pub(crate) {} inside private module", descr), + |diag| { + diag.span_suggestion( + item.vis.span, + "consider using", + "pub".to_string(), + Applicability::MachineApplicable, + ); + }, + ); } } diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 54b9c8b3275..710de773e9c 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { if_chain! { if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind; if path.ident.name == sym!(repeat); - if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(count); + if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1)); if !in_macro(receiver.span); then { let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index a67fa792205..ef80663d1da 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -49,8 +49,8 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { let mut const_eval_context = constant_context(cx, cx.typeck_results()); if_chain! { if let ExprKind::Path(ref _qpath) = arg.kind; - let x = const_eval_context.expr(arg); - if let Some(Constant::RawPtr(0)) = x; + if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); + if x == 0; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index b29ced28ac4..e0746ce4d81 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -32,7 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { // check for instances of 0.0/0.0 if_chain! { if let ExprKind::Binary(ref op, left, right) = expr.kind; - if let BinOpKind::Div = op.node; + if op.node == BinOpKind::Div; // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 231b5b80d18..00cf8a4d077 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1508,7 +1508,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc if let ExprKind::Match(_, arms, ref source) = expr.kind { // desugared from a `?` operator - if let MatchSource::TryDesugar = *source { + if *source == MatchSource::TryDesugar { return Some(expr); } diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index 98f65039b7d..7ad21044d7d 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -74,7 +74,7 @@ impl<'a> NumericLiteral<'a> { }; // Grab part of the literal after prefix, if present. - let (prefix, mut sans_prefix) = if let Radix::Decimal = radix { + let (prefix, mut sans_prefix) = if radix == Radix::Decimal { (None, lit) } else { let (p, s) = lit.split_at(2); @@ -179,7 +179,7 @@ impl<'a> NumericLiteral<'a> { // The exponent may have a sign, output it early, otherwise it will be // treated as a digit - if let Some('-') = digits.clone().next() { + if digits.clone().next() == Some('-') { let _ = digits.next(); output.push('-'); } diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index ab05a0b4238..5b0efb1fd71 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -311,7 +311,7 @@ impl<'a> Sugg<'a> { /// Return `true` if `sugg` is enclosed in parenthesis. fn has_enclosing_paren(sugg: impl AsRef) -> bool { let mut chars = sugg.as_ref().chars(); - if let Some('(') = chars.next() { + if chars.next() == Some('(') { let mut depth = 1; for c in &mut chars { if c == '(' { diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 098ec175fe2..34206b5ae2b 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -65,7 +65,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { - if let ty::BorrowKind::MutBorrow = bk { + if bk == ty::BorrowKind::MutBorrow { self.update(cmt); } } diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.rs b/tests/ui/branches_sharing_code/shared_at_bottom.rs index ce2040bdeb8..12f550d9c9a 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(dead_code, clippy::equatable_if_let)] #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] // This tests the branches_sharing_code lint at the end of blocks diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index c69a46f0a77..bb6c4c0703d 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 1359c7eb627..6d4f688db8c 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index e4c088bf6f0..5b0e4a473c4 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index d6cf01c8319..cd231a5d7ab 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 4ce365cc764..603ae7dc9eb 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -1,5 +1,10 @@ #![warn(clippy::collapsible_match)] -#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] +#![allow( + clippy::needless_return, + clippy::no_effect, + clippy::single_match, + clippy::equatable_if_let +)] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { // match without block diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index c119570e8ab..5f18b693502 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:7:20 + --> $DIR/collapsible_match.rs:12:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ LL | | }, | = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:7:12 + --> $DIR/collapsible_match.rs:12:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -18,7 +18,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:16:20 + --> $DIR/collapsible_match.rs:21:20 | LL | Ok(val) => match val { | ____________________^ @@ -28,7 +28,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:16:12 + --> $DIR/collapsible_match.rs:21:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -36,7 +36,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:25:9 + --> $DIR/collapsible_match.rs:30:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -44,7 +44,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:24:15 + --> $DIR/collapsible_match.rs:29:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -52,7 +52,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:32:9 + --> $DIR/collapsible_match.rs:37:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -62,7 +62,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:31:15 + --> $DIR/collapsible_match.rs:36:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -70,7 +70,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:43:9 + --> $DIR/collapsible_match.rs:48:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -79,7 +79,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:42:15 + --> $DIR/collapsible_match.rs:47:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -88,7 +88,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:52:13 + --> $DIR/collapsible_match.rs:57:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -96,7 +96,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:51:12 + --> $DIR/collapsible_match.rs:56:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -104,7 +104,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:61:9 + --> $DIR/collapsible_match.rs:66:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -113,7 +113,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:60:15 + --> $DIR/collapsible_match.rs:65:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -122,7 +122,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:72:13 + --> $DIR/collapsible_match.rs:77:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -132,7 +132,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:71:12 + --> $DIR/collapsible_match.rs:76:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -140,7 +140,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:83:20 + --> $DIR/collapsible_match.rs:88:20 | LL | Ok(val) => match val { | ____________________^ @@ -150,7 +150,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:83:12 + --> $DIR/collapsible_match.rs:88:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -158,7 +158,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:92:22 + --> $DIR/collapsible_match.rs:97:22 | LL | Some(val) => match val { | ______________________^ @@ -168,7 +168,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:92:14 + --> $DIR/collapsible_match.rs:97:14 | LL | Some(val) => match val { | ^^^ replace this binding diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 7d62e315da2..02c49aa0d7c 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::blacklisted_name, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed new file mode 100644 index 00000000000..ba72cc237b4 --- /dev/null +++ b/tests/ui/equatable_if_let.fixed @@ -0,0 +1,69 @@ +// run-rustfix + +#![allow(unused_variables, dead_code)] +#![warn(clippy::equatable_if_let)] + +use std::cmp::Ordering; + +#[derive(PartialEq)] +enum Enum { + TupleVariant(i32, u64), + RecordVariant { a: i64, b: u32 }, + UnitVariant, + Recursive(Struct), +} + +#[derive(PartialEq)] +struct Struct { + a: i32, + b: bool, +} + +enum NotPartialEq { + A, + B, +} + +enum NotStructuralEq { + A, + B, +} + +impl PartialEq for NotStructuralEq { + fn eq(&self, _: &NotStructuralEq) -> bool { + false + } +} + +fn main() { + let a = 2; + let b = 3; + let c = Some(2); + let d = Struct { a: 2, b: false }; + let e = Enum::UnitVariant; + let f = NotPartialEq::A; + let g = NotStructuralEq::A; + + // true + + if a == 2 {} + if a.cmp(&b) == Ordering::Greater {} + if c == Some(2) {} + if d == (Struct { a: 2, b: false }) {} + if e == Enum::TupleVariant(32, 64) {} + if e == (Enum::RecordVariant { a: 64, b: 32 }) {} + if e == Enum::UnitVariant {} + if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {} + + // false + + if let 2 | 3 = a {} + if let x @ 2 = a {} + if let Some(3 | 4) = c {} + if let Struct { a, b: false } = d {} + if let Struct { a: 2, b: x } = d {} + if let NotPartialEq::A = f {} + if g == NotStructuralEq::A {} + if let Some(NotPartialEq::A) = Some(f) {} + if Some(g) == Some(NotStructuralEq::A) {} +} diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs new file mode 100644 index 00000000000..12526ca193d --- /dev/null +++ b/tests/ui/equatable_if_let.rs @@ -0,0 +1,69 @@ +// run-rustfix + +#![allow(unused_variables, dead_code)] +#![warn(clippy::equatable_if_let)] + +use std::cmp::Ordering; + +#[derive(PartialEq)] +enum Enum { + TupleVariant(i32, u64), + RecordVariant { a: i64, b: u32 }, + UnitVariant, + Recursive(Struct), +} + +#[derive(PartialEq)] +struct Struct { + a: i32, + b: bool, +} + +enum NotPartialEq { + A, + B, +} + +enum NotStructuralEq { + A, + B, +} + +impl PartialEq for NotStructuralEq { + fn eq(&self, _: &NotStructuralEq) -> bool { + false + } +} + +fn main() { + let a = 2; + let b = 3; + let c = Some(2); + let d = Struct { a: 2, b: false }; + let e = Enum::UnitVariant; + let f = NotPartialEq::A; + let g = NotStructuralEq::A; + + // true + + if let 2 = a {} + if let Ordering::Greater = a.cmp(&b) {} + if let Some(2) = c {} + if let Struct { a: 2, b: false } = d {} + if let Enum::TupleVariant(32, 64) = e {} + if let Enum::RecordVariant { a: 64, b: 32 } = e {} + if let Enum::UnitVariant = e {} + if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + + // false + + if let 2 | 3 = a {} + if let x @ 2 = a {} + if let Some(3 | 4) = c {} + if let Struct { a, b: false } = d {} + if let Struct { a: 2, b: x } = d {} + if let NotPartialEq::A = f {} + if let NotStructuralEq::A = g {} + if let Some(NotPartialEq::A) = Some(f) {} + if let Some(NotStructuralEq::A) = Some(g) {} +} diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr new file mode 100644 index 00000000000..79ef919384d --- /dev/null +++ b/tests/ui/equatable_if_let.stderr @@ -0,0 +1,64 @@ +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:49:8 + | +LL | if let 2 = a {} + | ^^^^^^^^^ help: try: `a == 2` + | + = note: `-D clippy::equatable-if-let` implied by `-D warnings` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:50:8 + | +LL | if let Ordering::Greater = a.cmp(&b) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:51:8 + | +LL | if let Some(2) = c {} + | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:52:8 + | +LL | if let Struct { a: 2, b: false } = d {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:53:8 + | +LL | if let Enum::TupleVariant(32, 64) = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:54:8 + | +LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:55:8 + | +LL | if let Enum::UnitVariant = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:56:8 + | +LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:66:8 + | +LL | if let NotStructuralEq::A = g {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:68:8 + | +LL | if let Some(NotStructuralEq::A) = Some(g) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index e4dc5b647df..69189d9e0c0 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -2,6 +2,7 @@ #![allow( clippy::blacklisted_name, clippy::collapsible_else_if, + clippy::equatable_if_let, clippy::collapsible_if, clippy::ifs_same_cond, clippy::needless_return, diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index 6524be0af85..cac788f859d 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:13:13 + --> $DIR/if_same_then_else2.rs:14:13 | LL | if true { | _____________^ @@ -13,7 +13,7 @@ LL | | } else { | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/if_same_then_else2.rs:22:12 + --> $DIR/if_same_then_else2.rs:23:12 | LL | } else { | ____________^ @@ -26,7 +26,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:34:13 + --> $DIR/if_same_then_else2.rs:35:13 | LL | if true { | _____________^ @@ -35,7 +35,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:36:12 + --> $DIR/if_same_then_else2.rs:37:12 | LL | } else { | ____________^ @@ -45,7 +45,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:41:13 + --> $DIR/if_same_then_else2.rs:42:13 | LL | if true { | _____________^ @@ -54,7 +54,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:43:12 + --> $DIR/if_same_then_else2.rs:44:12 | LL | } else { | ____________^ @@ -64,7 +64,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:91:21 + --> $DIR/if_same_then_else2.rs:92:21 | LL | let _ = if true { | _____________________^ @@ -73,7 +73,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:93:12 + --> $DIR/if_same_then_else2.rs:94:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:98:13 + --> $DIR/if_same_then_else2.rs:99:13 | LL | if true { | _____________^ @@ -92,7 +92,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:100:12 + --> $DIR/if_same_then_else2.rs:101:12 | LL | } else { | ____________^ @@ -102,7 +102,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:122:20 + --> $DIR/if_same_then_else2.rs:123:20 | LL | } else if true { | ____________________^ @@ -112,7 +112,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:125:12 + --> $DIR/if_same_then_else2.rs:126:12 | LL | } else { | ____________^ diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed index 319299862a7..c611f76bf96 100644 --- a/tests/ui/match_expr_like_matches_macro.fixed +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_like_matches_macro)] -#![allow(unreachable_patterns, dead_code)] +#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)] fn main() { let x = Some(5); diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs index 2ef6cf42387..2deeb84e741 100644 --- a/tests/ui/match_expr_like_matches_macro.rs +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_like_matches_macro)] -#![allow(unreachable_patterns, dead_code)] +#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)] fn main() { let x = Some(5); diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index c84e31ea482..846d665d1d8 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -2,7 +2,7 @@ #![feature(half_open_range_patterns)] #![warn(clippy::match_overlapping_arm)] #![allow(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] /// Tests for match_overlapping_arm diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 5de43733ad3..6cbb4d32b0d 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,4 +1,5 @@ #![warn(clippy::match_ref_pats)] +#![allow(clippy::equatable_if_let)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index a57a338b276..072aff445e9 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:6:9 + --> $DIR/match_ref_pats.rs:7:9 | LL | / match v { LL | | &Some(v) => println!("{:?}", v), @@ -16,7 +16,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:17:5 + --> $DIR/match_ref_pats.rs:18:5 | LL | / match tup { LL | | &(v, 1) => println!("{}", v), @@ -31,7 +31,7 @@ LL ~ (v, 1) => println!("{}", v), | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:23:5 + --> $DIR/match_ref_pats.rs:24:5 | LL | / match &w { LL | | &Some(v) => println!("{:?}", v), @@ -47,7 +47,7 @@ LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:35:12 + --> $DIR/match_ref_pats.rs:36:12 | LL | if let &None = a { | -------^^^^^---- help: try this: `if a.is_none()` @@ -55,7 +55,7 @@ LL | if let &None = a { = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:35:5 + --> $DIR/match_ref_pats.rs:36:5 | LL | / if let &None = a { LL | | println!("none"); @@ -68,13 +68,13 @@ LL | if let None = *a { | ~~~~ ~~ error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:40:12 + --> $DIR/match_ref_pats.rs:41:12 | LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:40:5 + --> $DIR/match_ref_pats.rs:41:5 | LL | / if let &None = &b { LL | | println!("none"); @@ -87,7 +87,7 @@ LL | if let None = b { | ~~~~ ~ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:67:9 + --> $DIR/match_ref_pats.rs:68:9 | LL | / match foo_variant!(0) { LL | | &Foo::A => println!("A"), diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 639eac8b8b3..a2e3988daff 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -6,6 +6,7 @@ dead_code, clippy::no_effect, clippy::if_same_then_else, + clippy::equatable_if_let, clippy::needless_return, clippy::self_named_constructors )] diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index a3ce086a1c9..75805e85789 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -6,6 +6,7 @@ dead_code, clippy::no_effect, clippy::if_same_then_else, + clippy::equatable_if_let, clippy::needless_return, clippy::self_named_constructors )] diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr index 8026d643c44..1fa12add167 100644 --- a/tests/ui/needless_bool/fixable.stderr +++ b/tests/ui/needless_bool/fixable.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:40:5 + --> $DIR/fixable.rs:41:5 | LL | / if x { LL | | true @@ -11,7 +11,7 @@ LL | | }; = note: `-D clippy::needless-bool` implied by `-D warnings` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:45:5 + --> $DIR/fixable.rs:46:5 | LL | / if x { LL | | false @@ -21,7 +21,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:50:5 + --> $DIR/fixable.rs:51:5 | LL | / if x && y { LL | | false @@ -31,7 +31,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:70:5 + --> $DIR/fixable.rs:71:5 | LL | / if x { LL | | return true; @@ -41,7 +41,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:78:5 + --> $DIR/fixable.rs:79:5 | LL | / if x { LL | | return false; @@ -51,7 +51,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:86:5 + --> $DIR/fixable.rs:87:5 | LL | / if x && y { LL | | return true; @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:94:5 + --> $DIR/fixable.rs:95:5 | LL | / if x && y { LL | | return false; @@ -71,7 +71,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:102:8 + --> $DIR/fixable.rs:103:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -79,25 +79,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:106:8 + --> $DIR/fixable.rs:107:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:116:8 + --> $DIR/fixable.rs:117:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:117:8 + --> $DIR/fixable.rs:118:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:126:12 + --> $DIR/fixable.rs:127:12 | LL | } else if returns_bool() { | ____________^ diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 37efa6274df..9c999e12b4c 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -3,7 +3,12 @@ #![feature(let_else)] #![allow(unused)] -#![allow(clippy::if_same_then_else, clippy::single_match, clippy::needless_bool)] +#![allow( + clippy::if_same_then_else, + clippy::single_match, + clippy::needless_bool, + clippy::equatable_if_let +)] #![warn(clippy::needless_return)] macro_rules! the_answer { diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index cbf384ac9e4..da7dcf4f0a9 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -3,7 +3,12 @@ #![feature(let_else)] #![allow(unused)] -#![allow(clippy::if_same_then_else, clippy::single_match, clippy::needless_bool)] +#![allow( + clippy::if_same_then_else, + clippy::single_match, + clippy::needless_bool, + clippy::equatable_if_let +)] #![warn(clippy::needless_return)] macro_rules! the_answer { diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 7ce7028bbae..2e802cff1e6 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:20:5 + --> $DIR/needless_return.rs:25:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` @@ -7,187 +7,187 @@ LL | return true; = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded `return` statement - --> $DIR/needless_return.rs:24:5 + --> $DIR/needless_return.rs:29:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:29:9 + --> $DIR/needless_return.rs:34:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:31:9 + --> $DIR/needless_return.rs:36:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:37:17 + --> $DIR/needless_return.rs:42:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:39:13 + --> $DIR/needless_return.rs:44:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:46:9 + --> $DIR/needless_return.rs:51:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:48:16 + --> $DIR/needless_return.rs:53:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:56:5 + --> $DIR/needless_return.rs:61:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:61:9 + --> $DIR/needless_return.rs:66:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:63:9 + --> $DIR/needless_return.rs:68:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:70:14 + --> $DIR/needless_return.rs:75:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:85:9 + --> $DIR/needless_return.rs:90:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:87:9 + --> $DIR/needless_return.rs:92:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:108:32 + --> $DIR/needless_return.rs:113:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:113:13 + --> $DIR/needless_return.rs:118:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:115:20 + --> $DIR/needless_return.rs:120:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:121:32 + --> $DIR/needless_return.rs:126:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:130:5 + --> $DIR/needless_return.rs:135:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:134:5 + --> $DIR/needless_return.rs:139:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:139:9 + --> $DIR/needless_return.rs:144:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:141:9 + --> $DIR/needless_return.rs:146:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:147:17 + --> $DIR/needless_return.rs:152:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:149:13 + --> $DIR/needless_return.rs:154:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:156:9 + --> $DIR/needless_return.rs:161:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:158:16 + --> $DIR/needless_return.rs:163:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:166:5 + --> $DIR/needless_return.rs:171:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:171:9 + --> $DIR/needless_return.rs:176:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:173:9 + --> $DIR/needless_return.rs:178:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:180:14 + --> $DIR/needless_return.rs:185:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:195:9 + --> $DIR/needless_return.rs:200:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:197:9 + --> $DIR/needless_return.rs:202:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index d1815d0aec3..a3ebe5d0703 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -2,7 +2,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref)] +#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index a15627338cb..b11df3db60f 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -2,7 +2,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref)] +#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { diff --git a/tests/ui/redundant_pattern_matching_drop_order.fixed b/tests/ui/redundant_pattern_matching_drop_order.fixed index 794ed542435..ce3229f1759 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -2,7 +2,7 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] use std::task::Poll::{Pending, Ready}; fn main() { diff --git a/tests/ui/redundant_pattern_matching_drop_order.rs b/tests/ui/redundant_pattern_matching_drop_order.rs index b9c82d86f61..29b8543cf47 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/tests/ui/redundant_pattern_matching_drop_order.rs @@ -2,7 +2,7 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] use std::task::Poll::{Pending, Ready}; fn main() { diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 99714477266..813e268a60c 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 8309847e181..82a98468943 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 613a30d4a48..3a58e5ad7be 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:13:12 + --> $DIR/redundant_pattern_matching_option.rs:14:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` @@ -7,43 +7,43 @@ LL | if let None = None::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:15:12 + --> $DIR/redundant_pattern_matching_option.rs:16:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:17:12 + --> $DIR/redundant_pattern_matching_option.rs:18:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:23:15 + --> $DIR/redundant_pattern_matching_option.rs:24:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:25:15 + --> $DIR/redundant_pattern_matching_option.rs:26:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:27:15 + --> $DIR/redundant_pattern_matching_option.rs:28:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:30:15 + --> $DIR/redundant_pattern_matching_option.rs:31:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:38:5 + --> $DIR/redundant_pattern_matching_option.rs:39:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:43:5 + --> $DIR/redundant_pattern_matching_option.rs:44:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:48:13 + --> $DIR/redundant_pattern_matching_option.rs:49:13 | LL | let _ = match None::<()> { | _____________^ @@ -71,49 +71,49 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:54:20 + --> $DIR/redundant_pattern_matching_option.rs:55:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:58:20 + --> $DIR/redundant_pattern_matching_option.rs:59:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:60:19 + --> $DIR/redundant_pattern_matching_option.rs:61:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:79:12 + --> $DIR/redundant_pattern_matching_option.rs:80:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:81:12 + --> $DIR/redundant_pattern_matching_option.rs:82:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:83:15 + --> $DIR/redundant_pattern_matching_option.rs:84:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:85:15 + --> $DIR/redundant_pattern_matching_option.rs:86:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:87:5 + --> $DIR/redundant_pattern_matching_option.rs:88:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:92:5 + --> $DIR/redundant_pattern_matching_option.rs:93:5 | LL | / match None::<()> { LL | | Some(_) => false, diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index c2977453804..3645f2c4bfd 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index 665c8c41750..866c71b7cfa 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index 5ecf024a733..1b480f3157f 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:15:12 + --> $DIR/redundant_pattern_matching_poll.rs:16:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` @@ -7,37 +7,37 @@ LL | if let Pending = Pending::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:17:12 + --> $DIR/redundant_pattern_matching_poll.rs:18:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:19:12 + --> $DIR/redundant_pattern_matching_poll.rs:20:12 | LL | if let Ready(_) = Ready(42) { | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:25:15 + --> $DIR/redundant_pattern_matching_poll.rs:26:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:27:15 + --> $DIR/redundant_pattern_matching_poll.rs:28:15 | LL | while let Pending = Ready(42) {} | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:29:15 + --> $DIR/redundant_pattern_matching_poll.rs:30:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:35:5 + --> $DIR/redundant_pattern_matching_poll.rs:36:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -46,7 +46,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:40:5 + --> $DIR/redundant_pattern_matching_poll.rs:41:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, @@ -55,7 +55,7 @@ LL | | }; | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:45:13 + --> $DIR/redundant_pattern_matching_poll.rs:46:13 | LL | let _ = match Pending::<()> { | _____________^ @@ -65,49 +65,49 @@ LL | | }; | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:51:20 + --> $DIR/redundant_pattern_matching_poll.rs:52:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try this: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:55:20 + --> $DIR/redundant_pattern_matching_poll.rs:56:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:57:19 + --> $DIR/redundant_pattern_matching_poll.rs:58:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:73:12 + --> $DIR/redundant_pattern_matching_poll.rs:74:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:75:12 + --> $DIR/redundant_pattern_matching_poll.rs:76:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:77:15 + --> $DIR/redundant_pattern_matching_poll.rs:78:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:79:15 + --> $DIR/redundant_pattern_matching_poll.rs:80:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:81:5 + --> $DIR/redundant_pattern_matching_poll.rs:82:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -116,7 +116,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:86:5 + --> $DIR/redundant_pattern_matching_poll.rs:87:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index f5a34190902..1e74ad2de65 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] +#![allow( + clippy::never_loop, + unreachable_code, + unused_mut, + dead_code, + clippy::equatable_if_let +)] fn base() { let mut iter = 1..20; diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 72f34257d1f..69cb636cee8 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] +#![allow( + clippy::never_loop, + unreachable_code, + unused_mut, + dead_code, + clippy::equatable_if_let +)] fn base() { let mut iter = 1..20; diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 5e2fce4491a..1a11ba26eef 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:8:5 + --> $DIR/while_let_on_iterator.rs:14:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -7,85 +7,85 @@ LL | while let Option::Some(x) = iter.next() { = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:13:5 + --> $DIR/while_let_on_iterator.rs:19:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:18:5 + --> $DIR/while_let_on_iterator.rs:24:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:94:9 + --> $DIR/while_let_on_iterator.rs:100:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:101:9 + --> $DIR/while_let_on_iterator.rs:107:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:114:9 + --> $DIR/while_let_on_iterator.rs:120:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:134:9 + --> $DIR/while_let_on_iterator.rs:140:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:191:9 + --> $DIR/while_let_on_iterator.rs:197:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:202:5 + --> $DIR/while_let_on_iterator.rs:208:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:204:9 + --> $DIR/while_let_on_iterator.rs:210:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:213:9 + --> $DIR/while_let_on_iterator.rs:219:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:222:9 + --> $DIR/while_let_on_iterator.rs:228:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:239:9 + --> $DIR/while_let_on_iterator.rs:245:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:254:13 + --> $DIR/while_let_on_iterator.rs:260:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: manual `!RangeInclusive::contains` implementation - --> $DIR/while_let_on_iterator.rs:255:20 + --> $DIR/while_let_on_iterator.rs:261:20 | LL | if i < 3 || i > 7 { | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` @@ -93,37 +93,37 @@ LL | if i < 3 || i > 7 { = note: `-D clippy::manual-range-contains` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:286:13 + --> $DIR/while_let_on_iterator.rs:292:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:315:5 + --> $DIR/while_let_on_iterator.rs:321:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:327:9 + --> $DIR/while_let_on_iterator.rs:333:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:341:5 + --> $DIR/while_let_on_iterator.rs:347:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:352:5 + --> $DIR/while_let_on_iterator.rs:358:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:371:5 + --> $DIR/while_let_on_iterator.rs:377:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` -- cgit 1.4.1-3-g733a5 From 7c82e78f308b35b40f424527b6d7961a81280529 Mon Sep 17 00:00:00 2001 From: Matthias Kaak Date: Tue, 5 Oct 2021 19:03:13 +0000 Subject: improved help message for `suspicious_map` --- clippy_lints/src/methods/suspicious_map.rs | 2 +- tests/ui/suspicious_map.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 0fd0668c734..18ded291915 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -28,7 +28,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi expr.span, "this call to `map()` won't have an effect on the call to `count()`", None, - "make sure you did not confuse `map` with `filter` or `for_each`", + "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`", ); } } diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr index 8c3f36584a5..3ffcd1a9031 100644 --- a/tests/ui/suspicious_map.stderr +++ b/tests/ui/suspicious_map.stderr @@ -5,7 +5,7 @@ LL | let _ = (0..3).map(|x| x + 2).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-map` implied by `-D warnings` - = help: make sure you did not confuse `map` with `filter` or `for_each` + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` error: this call to `map()` won't have an effect on the call to `count()` --> $DIR/suspicious_map.rs:7:13 @@ -13,7 +13,7 @@ error: this call to `map()` won't have an effect on the call to `count()` LL | let _ = (0..3).map(f).count(); | ^^^^^^^^^^^^^^^^^^^^^ | - = help: make sure you did not confuse `map` with `filter` or `for_each` + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 320ecb1f0b4e41427ef7af049ce44c815bdd7664 Mon Sep 17 00:00:00 2001 From: Matthias Kaak Date: Tue, 5 Oct 2021 19:40:15 +0000 Subject: Mentioned `inspect` in lint description of `suspicious_map` --- clippy_lints/src/methods/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2025056ac94..b26d11c0d6b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1284,8 +1284,9 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// It looks suspicious. Maybe `map` was confused with `filter`. - /// If the `map` call is intentional, this should be rewritten. Or, if you intend to - /// drive the iterator to completion, you can just use `for_each` instead. + /// If the `map` call is intentional, this should be rewritten + /// using `inspect`. Or, if you intend to drive the iterator to + /// completion, you can just use `for_each` instead. /// /// ### Example /// ```rust -- cgit 1.4.1-3-g733a5 From 452181c69d2a106d9d5a1262b69e68a765c4b3e3 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Fri, 17 Sep 2021 02:55:26 -0400 Subject: Implement uninit_vec lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_correctness.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/uninit_assumed_init.rs | 14 +- clippy_lints/src/uninit_vec.rs | 174 ++++++++++++++++++++++++ clippy_utils/src/lib.rs | 10 ++ clippy_utils/src/paths.rs | 3 + tests/ui/uninit_vec.rs | 32 +++++ tests/ui/uninit_vec.stderr | 51 +++++++ 11 files changed, 278 insertions(+), 12 deletions(-) create mode 100644 clippy_lints/src/uninit_vec.rs create mode 100644 tests/ui/uninit_vec.rs create mode 100644 tests/ui/uninit_vec.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 13067e4e92a..2c69432f31c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3038,6 +3038,7 @@ Released 2018-09-13 [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init +[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 3e6e0244754..f0ef0befea0 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -278,6 +278,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(types::VEC_BOX), LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(uninit_vec::UNINIT_VEC), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_ARG), LintId::of(unit_types::UNIT_CMP), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index e0ef7b3b8af..8eb662195e2 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -63,6 +63,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(transmuting_null::TRANSMUTING_NULL), LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(uninit_vec::UNINIT_VEC), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_CMP), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 3c4b720671a..401c5b78b38 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -470,6 +470,7 @@ store.register_lints(&[ unicode::INVISIBLE_CHARACTERS, unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, + uninit_vec::UNINIT_VEC, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e1bcbbd0ed..829d5acdfde 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -361,6 +361,7 @@ mod types; mod undocumented_unsafe_blocks; mod undropped_manually_drops; mod unicode; +mod uninit_vec; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -518,6 +519,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch)); store.register_late_pass(|| Box::new(unicode::Unicode)); + store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 1a5894e48d1..dbd91fb6d9d 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_path_def_path, match_def_path, paths}; +use clippy_utils::{is_expr_path_def_path, is_uninit_ty_valid, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; use super::UNINIT_ASSUMED_INIT; @@ -13,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); - if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); + if !is_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( cx, @@ -24,12 +23,3 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr } } } - -fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component), - ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), - ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), - _ => false, - } -} diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs new file mode 100644 index 00000000000..ff302289a1f --- /dev/null +++ b/clippy_lints/src/uninit_vec.rs @@ -0,0 +1,174 @@ +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq}; +use rustc_hir::def::Res; +use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the creation of uninitialized `Vec` by calling `set_len()` + /// immediately after `with_capacity()` or `reserve()`. + /// + /// ### Why is this bad? + /// It creates `Vec` that contains uninitialized data, which leads to an + /// undefined behavior with most safe operations. + /// Notably, using uninitialized `Vec` with generic `Read` is unsound. + /// + /// ### Example + /// ```rust,ignore + /// let mut vec: Vec = Vec::with_capacity(1000); + /// unsafe { vec.set_len(1000); } + /// reader.read(&mut vec); // undefined behavior! + /// ``` + /// Use an initialized buffer: + /// ```rust,ignore + /// let mut vec: Vec = vec![0; 1000]; + /// reader.read(&mut vec); + /// ``` + /// Or, wrap the content in `MaybeUninit`: + /// ```rust,ignore + /// let mut vec: Vec> = Vec::with_capacity(1000); + /// unsafe { vec.set_len(1000); } + /// ``` + pub UNINIT_VEC, + correctness, + "Vec with uninitialized data" +} + +declare_lint_pass!(UninitVec => [UNINIT_VEC]); + +impl<'tcx> LateLintPass<'tcx> for UninitVec { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + for w in block.stmts.windows(2) { + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { + handle_pair(cx, &w[0], expr); + } + } + + if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { + handle_pair(cx, stmt, expr); + } + } +} + +fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) { + if_chain! { + if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first); + if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second); + if vec.eq_expr(cx, set_len_self); + if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); + if let ty::Adt(_, substs) = vec_ty.kind(); + // Check T of Vec + if !is_uninit_ty_valid(cx, substs.type_at(0)); + then { + span_lint_and_note( + cx, + UNINIT_VEC, + call_span, + "calling `set_len()` immediately after reserving a buffer creates uninitialized values", + Some(first.span), + "the buffer is reserved here" + ); + } + } +} + +#[derive(Clone, Copy, Debug)] +enum LocalOrExpr<'tcx> { + Local(HirId), + Expr(&'tcx Expr<'tcx>), +} + +impl<'tcx> LocalOrExpr<'tcx> { + fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + match self { + LocalOrExpr::Local(hir_id) => path_to_local_id(expr, hir_id), + LocalOrExpr::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr), + } + } +} + +/// Returns the target vec of Vec::with_capacity() or Vec::reserve() +fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stmt<'_>) -> Option> { + match stmt.kind { + StmtKind::Local(local) => { + // let mut x = Vec::with_capacity() + if_chain! { + if let Some(init_expr) = local.init; + if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; + if is_with_capacity(cx, init_expr); + then { + Some(LocalOrExpr::Local(hir_id)) + } else { + None + } + } + }, + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { + match expr.kind { + ExprKind::Assign(lhs, rhs, _span) if is_with_capacity(cx, rhs) => { + // self.vec = Vec::with_capacity() + Some(LocalOrExpr::Expr(lhs)) + }, + ExprKind::MethodCall(_, _, [vec_expr, _], _) => { + // self.vec.reserve() + if_chain! { + if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if match_def_path(cx, id, &paths::VEC_RESERVE); + then { + Some(LocalOrExpr::Expr(vec_expr)) + } else { + None + } + } + }, + _ => None, + } + }, + _ => None, + } +} + +fn is_with_capacity(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> bool { + if_chain! { + if let ExprKind::Call(path_expr, _) = &expr.kind; + if let ExprKind::Path(qpath) = &path_expr.kind; + if let Res::Def(_, def_id) = cx.qpath_res(qpath, path_expr.hir_id); + then { + match_def_path(cx, def_id, &paths::VEC_WITH_CAPACITY) + } else { + false + } + } +} + +/// Returns self if the expression is Vec::set_len() +fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> { + // peel unsafe blocks in `unsafe { vec.set_len() }` + let expr = peel_hir_expr_while(expr, |e| { + if let ExprKind::Block(block, _) = e.kind { + match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) { + (None, Some(expr)) => Some(expr), + (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), None) => Some(expr), + _ => None, + } + } else { + None + } + }); + match expr.kind { + ExprKind::MethodCall(_, _, [vec_expr, _], _) => { + cx.typeck_results().type_dependent_def_id(expr.hir_id).and_then(|id| { + if match_def_path(cx, id, &paths::VEC_SET_LEN) { + Some((vec_expr, expr.span)) + } else { + None + } + }) + }, + _ => None, + } +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 09eee78f0d1..00d2098a021 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1470,6 +1470,16 @@ pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { false } +/// Checks if a given type looks safe to be uninitialized. +pub fn is_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + match ty.kind() { + rustc_ty::Array(component, _) => is_uninit_ty_valid(cx, component), + rustc_ty::Tuple(types) => types.types().all(|ty| is_uninit_ty_valid(cx, ty)), + rustc_ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), + _ => false, + } +} + pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator> { (0..decl.inputs.len()).map(move |i| &body.params[i]) } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e43c5756021..dffe30910dd 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -183,5 +183,8 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; +pub const VEC_RESERVE: [&str; 4] = ["alloc", "vec", "Vec", "reserve"]; +pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; +pub const VEC_SET_LEN: [&str; 4] = ["alloc", "vec", "Vec", "set_len"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs new file mode 100644 index 00000000000..5e67288405a --- /dev/null +++ b/tests/ui/uninit_vec.rs @@ -0,0 +1,32 @@ +#![warn(clippy::uninit_vec)] + +use std::mem::MaybeUninit; + +fn main() { + // with_capacity() -> set_len() should be detected + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(200); + } + + // reserve() -> set_len() should be detected + vec.reserve(1000); + unsafe { + vec.set_len(200); + } + + // test when both calls are enclosed in the same unsafe block + unsafe { + let mut vec: Vec = Vec::with_capacity(1000); + vec.set_len(200); + + vec.reserve(1000); + vec.set_len(200); + } + + // MaybeUninit-wrapped types should not be detected + let mut vec: Vec> = Vec::with_capacity(1000); + unsafe { + vec.set_len(200); + } +} diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr new file mode 100644 index 00000000000..1d7807fcf7d --- /dev/null +++ b/tests/ui/uninit_vec.stderr @@ -0,0 +1,51 @@ +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:9:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::uninit-vec` implied by `-D warnings` +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:7:5 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:15:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:13:5 + | +LL | vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^ + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:21:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:20:9 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:24:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:23:9 + | +LL | vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 759200b6991b5dac5fdb12bc6c366b16850add00 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Fri, 17 Sep 2021 14:42:32 -0400 Subject: Handle PR feedbacks first round --- clippy_lints/src/methods/uninit_assumed_init.rs | 4 +-- clippy_lints/src/uninit_vec.rs | 41 ++++++++++++++----------- clippy_utils/src/lib.rs | 10 ------ clippy_utils/src/paths.rs | 1 - clippy_utils/src/ty.rs | 10 ++++++ tests/ui/uninit_vec.rs | 8 ++++- 6 files changed, 42 insertions(+), 32 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index dbd91fb6d9d..ce89189bce9 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_path_def_path, is_uninit_ty_valid, paths}; +use clippy_utils::{is_expr_path_def_path, paths, ty::is_uninit_value_valid_for_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); - if !is_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); + if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( cx, diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 8b1254b60f9..37084f57043 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,11 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{ + match_def_path, path_to_local_id, paths, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq, +}; use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -44,32 +47,36 @@ impl<'tcx> LateLintPass<'tcx> for UninitVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { for w in block.stmts.windows(2) { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { - handle_pair(cx, &w[0], expr); + handle_uninit_vec_pair(cx, &w[0], expr); } } if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { - handle_pair(cx, stmt, expr); + handle_uninit_vec_pair(cx, stmt, expr); } } } -fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) { +fn handle_uninit_vec_pair( + cx: &LateContext<'tcx>, + maybe_with_capacity_or_reserve: &'tcx Stmt<'tcx>, + maybe_set_len: &'tcx Expr<'tcx>, +) { if_chain! { - if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first); - if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second); + if let Some(vec) = extract_with_capacity_or_reserve_target(cx, maybe_with_capacity_or_reserve); + if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len); if vec.eq_expr(cx, set_len_self); if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); if let ty::Adt(_, substs) = vec_ty.kind(); // Check T of Vec - if !is_uninit_ty_valid(cx, substs.type_at(0)); + if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); then { span_lint_and_note( cx, UNINIT_VEC, call_span, "calling `set_len()` immediately after reserving a buffer creates uninitialized values", - Some(first.span), + Some(maybe_with_capacity_or_reserve.span), "the buffer is reserved here" ); } @@ -113,16 +120,14 @@ fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stm // self.vec = Vec::with_capacity() Some(LocalOrExpr::Expr(lhs)) }, - ExprKind::MethodCall(_, _, [vec_expr, _], _) => { + ExprKind::MethodCall(path, _, [self_expr, _], _) => { // self.vec.reserve() - if_chain! { - if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, id, &paths::VEC_RESERVE); - then { - Some(LocalOrExpr::Expr(vec_expr)) - } else { - None - } + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::vec_type) + && path.ident.name.as_str() == "reserve" + { + Some(LocalOrExpr::Expr(self_expr)) + } else { + None } }, _ => None, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 00d2098a021..09eee78f0d1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1470,16 +1470,6 @@ pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { false } -/// Checks if a given type looks safe to be uninitialized. -pub fn is_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match ty.kind() { - rustc_ty::Array(component, _) => is_uninit_ty_valid(cx, component), - rustc_ty::Tuple(types) => types.types().all(|ty| is_uninit_ty_valid(cx, ty)), - rustc_ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), - _ => false, - } -} - pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator> { (0..decl.inputs.len()).map(move |i| &body.params[i]) } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index dffe30910dd..63ec10a3178 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -183,7 +183,6 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; -pub const VEC_RESERVE: [&str; 4] = ["alloc", "vec", "Vec", "reserve"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const VEC_SET_LEN: [&str; 4] = ["alloc", "vec", "Vec", "set_len"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 6ebe1a0028a..ca64ac7de3e 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -367,3 +367,13 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { _ => a == b, } } + +/// Checks if a given type looks safe to be uninitialized. +pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), + ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), + ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did), + _ => false, + } +} diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 5e67288405a..34b9e07ef1d 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -25,8 +25,14 @@ fn main() { } // MaybeUninit-wrapped types should not be detected - let mut vec: Vec> = Vec::with_capacity(1000); unsafe { + let mut vec: Vec> = Vec::with_capacity(1000); + vec.set_len(200); + + let mut vec: Vec<(MaybeUninit, MaybeUninit)> = Vec::with_capacity(1000); + vec.set_len(200); + + let mut vec: Vec<(MaybeUninit, [MaybeUninit; 2])> = Vec::with_capacity(1000); vec.set_len(200); } } -- cgit 1.4.1-3-g733a5 From 5adf17cb43d62e7e02c13f32def548b724bf2148 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Oct 2021 09:42:42 +0200 Subject: Bring `manual_split_once` docs in line with other lint docs --- clippy_lints/src/methods/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b26d11c0d6b..26c29fbb289 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1777,14 +1777,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usages of `str::splitn(2, _)` - /// - /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient. - /// - /// **Known problems:** None. + /// ### What it does + /// Checks for usages of `str::splitn(2, _)` /// - /// **Example:** + /// ### Why is this bad? + /// `split_once` is both clearer in intent and slightly more efficient. /// + /// ### Example /// ```rust,ignore /// // Bad /// let (key, value) = _.splitn(2, '=').next_tuple()?; -- cgit 1.4.1-3-g733a5 From 20fb7f291604267447ef95ee437f9bc8699879d1 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 24 Oct 2021 12:52:38 -0500 Subject: Update rustfmt --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/entry.rs | 13 ++++++++----- clippy_lints/src/eta_reduction.rs | 17 ++++++++++------- clippy_lints/src/int_plus_one.rs | 4 ++-- clippy_lints/src/loops/utils.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 4 ++-- clippy_lints/src/methods/or_fun_call.rs | 2 +- clippy_lints/src/module_style.rs | 2 +- clippy_lints/src/needless_borrow.rs | 20 ++++++++++++-------- clippy_utils/src/higher.rs | 4 ++-- clippy_utils/src/lib.rs | 25 ++++++++++++++----------- 11 files changed, 54 insertions(+), 41 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7825e5f6ed5..ce59311c4aa 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { target_mut, }, )); - } + }, _ => (), } }, diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index ac6824672f6..57fd24bd4f0 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map ExprKind::MethodCall( _, _, - [map, Expr { - kind: ExprKind::AddrOf(_, _, key), - span: key_span, - .. - }], + [ + map, + Expr { + kind: ExprKind::AddrOf(_, _, key), + span: key_span, + .. + }, + ], _, ) if key_span.ctxt() == expr.span.ctxt() => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 765a6c7585a..9247343b52a 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_ } match *cx.typeck_results().expr_adjustments(arg) { [] => true, - [Adjustment { - kind: Adjust::Deref(None), - .. - }, Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), - .. - }] => { + [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), + .. + }, + ] => { // re-borrow with the same mutability is allowed let ty = cx.typeck_results().expr_ty(arg); matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into()) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 49b69dd072a..6850e0c3476 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -89,7 +89,7 @@ impl IntPlusOne { }, _ => None, } - } + }, // case where `x + 1 <= ...` or `1 + x <= ...` (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => @@ -104,7 +104,7 @@ impl IntPlusOne { }, _ => None, } - } + }, // case where `... >= y - 1` or `... >= -1 + y` (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 2f7360210ba..f9f515cc40a 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -338,7 +338,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(), meth_name, ) - } + }, _ => format!( "{}.into_iter()", sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 1a32af5dc7a..b4dacb2580c 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -85,7 +85,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => { return; - } + }, ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) @@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, ) => { return; - } + }, _ => false, }; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b5bbbb09092..fe9ffde0d33 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -186,7 +186,7 @@ pub(super) fn check<'tcx>( check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); } } - } + }, _ => (), } } diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index f351d0098b7..d41b5474564 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -106,7 +106,7 @@ impl EarlyLintPass for ModStyle { } process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders); check_self_named_mod_exists(cx, path, file); - } + }, _ => {}, } } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 1b2495d764d..f1be90c44f9 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -107,14 +107,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { - if let [Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Borrow(_), - .. - }] = *adj3 + if let [ + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Borrow(_), + .. + }, + ] = *adj3 { let help_msg_ty = if matches!(mutability, Mutability::Not) { format!("&{}", ty) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 60c4cb361aa..7cbd43e6266 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -770,13 +770,13 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - } return Some(VecInitKind::WithExprCapacity(arg.hir_id)); } - } + }, ExprKind::Path(QPath::Resolved(_, path)) if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => { return Some(VecInitKind::Default); - } + }, _ => (), } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index aeb8c12ae8b..bcc38c72256 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -844,10 +844,13 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind let mut capture_expr_ty = e; for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) { - if let [Adjustment { - kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), - target, - }, ref adjust @ ..] = *cx + if let [ + Adjustment { + kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), + target, + }, + ref adjust @ .., + ] = *cx .typeck_results() .adjustments() .get(child_id) @@ -1232,9 +1235,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti for (_, node) in tcx.hir().parent_iter(expr.hir_id) { match node { Node::Expr( - e - @ - Expr { + e @ Expr { kind: ExprKind::Loop(..) | ExprKind::Closure(..), .. }, @@ -1692,10 +1693,12 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool { pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Call( _, - &[Expr { - kind: ExprKind::Closure(_, _, body, _, _), - .. - }], + &[ + Expr { + kind: ExprKind::Closure(_, _, body, _, _), + .. + }, + ], ) = body.value.kind { if let ExprKind::Block( -- cgit 1.4.1-3-g733a5 From 14d54f0f6eb3b03cb5d719949a25404a8fe563d9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 29 Oct 2021 11:14:22 -0500 Subject: Use Span::from_expansion instead of in_macro --- clippy_lints/src/booleans.rs | 28 ++++++++++---------- clippy_lints/src/copies.rs | 6 ++--- clippy_lints/src/default.rs | 6 ++--- clippy_lints/src/dereference.rs | 4 +-- clippy_lints/src/derivable_impls.rs | 4 +-- clippy_lints/src/eq_op.rs | 6 ++--- clippy_lints/src/excessive_bools.rs | 3 +-- clippy_lints/src/implicit_saturating_sub.rs | 4 +-- .../src/inconsistent_struct_constructor.rs | 3 +-- clippy_lints/src/inherent_impl.rs | 8 +++--- clippy_lints/src/lifetimes.rs | 4 +-- clippy_lints/src/literal_representation.rs | 7 ++--- clippy_lints/src/macro_use.rs | 6 ++++- clippy_lints/src/matches.rs | 19 ++++++-------- clippy_lints/src/mem_replace.rs | 4 +-- clippy_lints/src/methods/bind_instead_of_map.rs | 4 +-- clippy_lints/src/methods/mod.rs | 4 +-- clippy_lints/src/needless_arbitrary_self_type.rs | 7 +++-- clippy_lints/src/needless_bitwise_bool.rs | 3 +-- clippy_lints/src/needless_borrow.rs | 12 ++++----- clippy_lints/src/needless_option_as_deref.rs | 3 +-- clippy_lints/src/nonstandard_macro_braces.rs | 30 ++++++++-------------- clippy_lints/src/option_if_let_else.rs | 4 +-- clippy_lints/src/ptr_eq.rs | 3 +-- clippy_lints/src/redundant_slicing.rs | 4 +-- clippy_lints/src/reference.rs | 3 +-- clippy_lints/src/repeat_once.rs | 3 +-- clippy_lints/src/returns.rs | 5 ++-- clippy_lints/src/single_component_path_imports.rs | 3 +-- clippy_lints/src/strlen_on_c_strings.rs | 3 +-- clippy_lints/src/trait_bounds.rs | 10 ++++---- clippy_lints/src/try_err.rs | 20 +++++---------- clippy_lints/src/undocumented_unsafe_blocks.rs | 4 +-- clippy_lints/src/unnecessary_wraps.rs | 4 +-- clippy_lints/src/use_self.rs | 10 ++++---- clippy_lints/src/wildcard_imports.rs | 4 +-- clippy_utils/src/lib.rs | 6 ----- clippy_utils/src/usage.rs | 2 +- tests/ui-internal/if_chain_style.rs | 2 +- tests/ui/manual_assert.edition2018.fixed | 2 ++ tests/ui/manual_assert.edition2018.stderr | 14 +++++----- tests/ui/manual_assert.edition2021.fixed | 2 ++ tests/ui/manual_assert.edition2021.stderr | 14 +++++----- tests/ui/manual_assert.fixed | 2 ++ tests/ui/manual_assert.rs | 2 ++ 45 files changed, 137 insertions(+), 164 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 8282800c819..a1e6b7224ff 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{eq_expr_value, get_trait_def_id, in_macro, paths}; +use clippy_utils::{eq_expr_value, get_trait_def_id, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -453,22 +453,20 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if in_macro(e.span) { - return; - } - match &e.kind { - ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { - self.bool_expr(e); - }, - ExprKind::Unary(UnOp::Not, inner) => { - if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { + if !e.span.from_expansion() { + match &e.kind { + ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { self.bool_expr(e); - } else { - walk_expr(self, e); - } - }, - _ => walk_expr(self, e), + }, + ExprKind::Unary(UnOp::Not, inner) => { + if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { + self.bool_expr(e); + } + }, + _ => {}, + } } + walk_expr(self, e); } fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 8abf10c0d1c..f57da62da5f 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; use clippy_utils::{ - both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, in_macro, is_else_clause, - is_lint_allowed, search_same, ContainsName, SpanlessEq, SpanlessHash, + both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, is_else_clause, is_lint_allowed, + search_same, ContainsName, SpanlessEq, SpanlessHash, }; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; @@ -623,7 +623,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool { // Do not lint if any expr originates from a macro - if in_macro(lhs.span) || in_macro(rhs.span) { + if lhs.span.from_expansion() || rhs.span.from_expansion() { return false; } // Do not spawn warning if `IFS_SAME_COND` already produced it. diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index cde27d3ad2a..54647ba823e 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths}; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -78,7 +78,7 @@ impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]); impl LateLintPass<'_> for Default { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if !in_macro(expr.span); + if !expr.span.from_expansion(); // Avoid cases already linted by `field_reassign_with_default` if !self.reassigned_linted.contains(&expr.span); if let ExprKind::Call(path, ..) = expr.kind; @@ -125,7 +125,7 @@ impl LateLintPass<'_> for Default { if let StmtKind::Local(local) = stmt.kind; if let Some(expr) = local.init; if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); - if !in_macro(expr.span); + if !expr.span.from_expansion(); // only take bindings to identifiers if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind; // only when assigning `... = Default::default()` diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index ce59311c4aa..975353add08 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::peel_mid_ty_refs; -use clippy_utils::{get_parent_node, in_macro, is_lint_allowed}; +use clippy_utils::{get_parent_node, is_lint_allowed}; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp}; @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { } // Stop processing sub expressions when a macro call is seen - if in_macro(expr.span) { + if expr.span.from_expansion() { if let Some((state, data)) = self.state.take() { report(cx, expr, state, data); } diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index fdef0abe970..01ec306e5e1 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks}; +use clippy_utils::{is_automatically_derived, is_default_equivalent, remove_blocks}; use rustc_hir::{ def::{DefKind, Res}, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { }) = item.kind; if let attrs = cx.tcx.hir().attrs(item.hir_id()); if !is_automatically_derived(attrs); - if !in_macro(item.span); + if !item.span.from_expansion(); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Default, def_id); if let impl_item_hir = child.id.hir_id(); diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 655560afd42..c034c849b55 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,9 +1,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{ - ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function, -}; +use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; @@ -102,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } let macro_with_not_op = |expr_kind: &ExprKind<'_>| { if let ExprKind::Unary(_, expr) = *expr_kind { - in_macro(expr.span) + expr.span.from_expansion() } else { false } diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 476e6d23f12..06171702f75 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::in_macro; use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -135,7 +134,7 @@ fn is_bool_ty(ty: &Ty) -> bool { impl EarlyLintPass for ExcessiveBools { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if in_macro(item.span) { + if item.span.from_expansion() { return; } match &item.kind { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index a4f60ded3a6..ecbbbc5bc64 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; -use clippy_utils::{in_macro, SpanlessEq}; +use clippy_utils::SpanlessEq; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -39,7 +39,7 @@ declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]); impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if in_macro(expr.span) { + if expr.span.from_expansion() { return; } if_chain! { diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 1f8240a1f63..52c92b3b122 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; @@ -66,7 +65,7 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU impl LateLintPass<'_> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { - if !in_macro(expr.span); + if !expr.span.from_expansion(); if let ExprKind::Struct(qpath, fields, base) = expr.kind; let ty = cx.typeck_results().expr_ty(expr); if let Some(adt_def) = ty.ty_adt_def(); diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 0d23bec27a3..bd0b2964309 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,7 +1,7 @@ //! lint on inherent implementations use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::{in_macro, is_lint_allowed}; +use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -123,8 +123,10 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option { .. }) = cx.tcx.hir().get(id) { - (!in_macro(span) && impl_item.generics.params.is_empty() && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id)) - .then(|| span) + (!span.from_expansion() + && impl_item.generics.params.is_empty() + && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id)) + .then(|| span) } else { None } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index cb0b96e0652..6565d5a6d70 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{in_macro, trait_ref_of_method}; +use clippy_utils::trait_ref_of_method; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::intravisit::{ walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, @@ -128,7 +128,7 @@ fn check_fn_inner<'tcx>( span: Span, report_extra_lifetimes: bool, ) { - if in_macro(span) || has_where_lifetimes(cx, &generics.where_clause) { + if span.from_expansion() || has_where_lifetimes(cx, &generics.where_clause) { return; } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 0e5121ca3d7..0e36ab085a3 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -2,11 +2,8 @@ //! floating-point literal expressions. use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::numeric_literal::{NumericLiteral, Radix}; use clippy_utils::source::snippet_opt; -use clippy_utils::{ - in_macro, - numeric_literal::{NumericLiteral, Radix}, -}; use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; @@ -283,7 +280,7 @@ impl LiteralDigitGrouping { | WarningType::InconsistentDigitGrouping | WarningType::UnusualByteGroupings | WarningType::LargeDigitGroups => { - !in_macro(lit.span) + !lit.span.from_expansion() } WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => { true diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 99ac4680720..bccdc3be5e9 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; @@ -9,6 +8,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::hygiene::ExpnKind; use rustc_span::{edition::Edition, sym, Span}; declare_clippy_lint! { @@ -213,3 +213,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } } } + +fn in_macro(span: Span) -> bool { + span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) +} diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index eb311983b29..f9030564588 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -8,9 +8,9 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use clippy_utils::visitors::is_local_used; use clippy_utils::{ - get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, - meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, - remove_blocks, strip_pat_refs, + get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs, + path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, + strip_pat_refs, }; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use core::array; @@ -26,7 +26,6 @@ use rustc_hir::{ }; use rustc_hir::{HirIdMap, HirIdSet}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS, VariantDef}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -602,7 +601,7 @@ impl_lint_pass!(Matches => [ impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { + if expr.span.from_expansion() { return; } @@ -641,8 +640,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { if_chain! { - if !in_external_macro(cx.sess(), local.span); - if !in_macro(local.span); + if !local.span.from_expansion(); if let Some(expr) = local.init; if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind; if arms.len() == 1 && arms[0].guard.is_none(); @@ -677,8 +675,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if_chain! { - if !in_external_macro(cx.sess(), pat.span); - if !in_macro(pat.span); + if !pat.span.from_expansion(); if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); let ty = cx.tcx.type_of(def_id); @@ -705,7 +702,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { #[rustfmt::skip] fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() { - if in_macro(expr.span) { + if expr.span.from_expansion() { // Don't lint match expressions present in // macro_rules! block return; @@ -1448,7 +1445,7 @@ fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option { #[allow(clippy::too_many_lines)] fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) { - if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) { + if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) { return; } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 1e6057a8fe9..cf721fc65db 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{in_macro, is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::{is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; @@ -213,7 +213,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< expr_span, "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", |diag| { - if !in_macro(expr_span) { + if !expr_span.from_expansion() { let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, "")); diag.span_suggestion( diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index da428a7b487..b7690cf9222 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,7 +1,7 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; -use clippy_utils::{in_macro, remove_blocks, visitors::find_all_ret_expressions}; +use clippy_utils::{remove_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -106,7 +106,7 @@ pub(crate) trait BindInsteadOfMap { let mut suggs = Vec::new(); let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| { if_chain! { - if !in_macro(ret_expr.span); + if !ret_expr.span.from_expansion(); if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind; if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind; if Self::is_variant(cx, path.res); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 26c29fbb289..6c4272f9e65 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -68,7 +68,7 @@ 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, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; +use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -1900,7 +1900,7 @@ macro_rules! method_call { impl<'tcx> LateLintPass<'tcx> for Methods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if in_macro(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 9a3d9383cd9..c8a8750c2ff 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use if_chain::if_chain; use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; @@ -78,7 +77,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod let self_param = match (binding_mode, mutbl) { (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(), (Mode::Ref(Some(lifetime)), Mutability::Mut) => { - if in_macro(lifetime.ident.span) { + if lifetime.ident.span.from_expansion() { applicability = Applicability::HasPlaceholders; "&'_ mut self".to_string() } else { @@ -87,7 +86,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod }, (Mode::Ref(None), Mutability::Not) => "&self".to_string(), (Mode::Ref(Some(lifetime)), Mutability::Not) => { - if in_macro(lifetime.ident.span) { + if lifetime.ident.span.from_expansion() { applicability = Applicability::HasPlaceholders; "&'_ self".to_string() } else { @@ -114,7 +113,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod impl EarlyLintPass for NeedlessArbitrarySelfType { fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) { // Bail out if the parameter it's not a receiver or was not written by the user - if !p.is_self() || in_macro(p.span) { + if !p.is_self() || p.span.from_expansion() { return; } diff --git a/clippy_lints/src/needless_bitwise_bool.rs b/clippy_lints/src/needless_bitwise_bool.rs index 203da29cb91..ad981599473 100644 --- a/clippy_lints/src/needless_bitwise_bool.rs +++ b/clippy_lints/src/needless_bitwise_bool.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::in_macro; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; @@ -41,7 +40,7 @@ declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]); fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); if_chain! { - if !in_macro(expr.span); + if !expr.span.from_expansion(); if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind()); if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr; if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind; diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index f1be90c44f9..085be6650cc 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context}; -use clippy_utils::{get_parent_expr, in_macro, path_to_local}; +use clippy_utils::{get_parent_expr, path_to_local}; use if_chain::if_chain; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_data_structures::fx::FxIndexMap; @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) { // This binding id has been seen before. Add this pattern to the list of changes. if let Some(prev_pat) = opt_prev_pat { - if in_macro(pat.span) { + if pat.span.from_expansion() { // Doesn't match the context of the previous pattern. Can't lint here. *opt_prev_pat = None; } else { @@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } if_chain! { - if !in_macro(pat.span); + if !pat.span.from_expansion(); if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind(); // only lint immutable refs, because borrowed `&mut T` cannot be moved out if let ty::Ref(_, _, Mutability::Not) = *tam.kind(); @@ -248,12 +248,12 @@ impl NeedlessBorrow { span, kind: ExprKind::Unary(UnOp::Deref, _), .. - }) if !in_macro(span) => { + }) if !span.from_expansion() => { // Remove explicit deref. let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0; pat.replacements.push((span, snip.into())); }, - Some(parent) if !in_macro(parent.span) => { + Some(parent) if !parent.span.from_expansion() => { // Double reference might be needed at this point. if parent.precedence().order() == PREC_POSTFIX { // Parentheses would be needed here, don't lint. @@ -264,7 +264,7 @@ impl NeedlessBorrow { pat.replacements.push((e.span, format!("&{}", snip))); } }, - _ if !in_macro(e.span) => { + _ if !e.span.from_expansion() => { // Double reference might be needed at this point. pat.always_deref = false; let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); diff --git a/clippy_lints/src/needless_option_as_deref.rs b/clippy_lints/src/needless_option_as_deref.rs index fbdaaf51f74..e88e98e6081 100644 --- a/clippy_lints/src/needless_option_as_deref.rs +++ b/clippy_lints/src/needless_option_as_deref.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -38,7 +37,7 @@ declare_lint_pass!(OptionNeedlessDeref=> [ impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() || in_macro(expr.span) { + if expr.span.from_expansion() { return; } let typeck = cx.typeck_results(); diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index ca660a9250d..bab15217d52 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -3,14 +3,16 @@ use std::{ hash::{Hash, Hasher}, }; -use clippy_utils::{diagnostics::span_lint_and_help, in_macro, is_direct_expn_of, source::snippet_opt}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::hygiene::{ExpnKind, MacroKind}; +use rustc_span::{Span, Symbol}; use serde::{de, Deserialize}; declare_clippy_lint! { @@ -37,7 +39,7 @@ declare_clippy_lint! { const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")]; /// The (name, (open brace, close brace), source snippet) -type MacroInfo<'a> = (&'a str, &'a (String, String), String); +type MacroInfo<'a> = (Symbol, &'a (String, String), String); #[derive(Clone, Debug, Default)] pub struct MacroBraces { @@ -93,17 +95,16 @@ impl EarlyLintPass for MacroBraces { fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a MacroBraces) -> Option> { let unnested_or_local = || { - let nested = in_macro(span.ctxt().outer_expn_data().call_site); - !nested + !span.ctxt().outer_expn_data().call_site.from_expansion() || span .macro_backtrace() .last() .map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local)) }; if_chain! { - // Make sure we are only one level deep otherwise there are to many FP's - if in_macro(span); - if let Some((name, braces)) = find_matching_macro(span, &mac_braces.macro_braces); + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind; + let name = &*mac_name.as_str(); + if let Some(braces) = mac_braces.macro_braces.get(name); if let Some(snip) = snippet_opt(cx, span.ctxt().outer_expn_data().call_site); // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 @@ -114,14 +115,14 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac if !c.starts_with(&format!("{}!{}", name, braces.0)); if !mac_braces.done.contains(&span.ctxt().outer_expn_data().call_site); then { - Some((name, braces, snip)) + Some((mac_name, braces, snip)) } else { None } } } -fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: &str, span: Span) { +fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: Symbol, span: Span) { let with_space = &format!("! {}", braces.0); let without_space = &format!("!{}", braces.0); let mut help = snip; @@ -144,15 +145,6 @@ fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), nam ); } -fn find_matching_macro( - span: Span, - braces: &FxHashMap, -) -> Option<(&String, &(String, String))> { - braces - .iter() - .find(|(macro_name, _)| is_direct_expn_of(span, macro_name).is_some()) -} - fn macro_braces(conf: FxHashSet) -> FxHashMap { let mut braces = vec![ macro_matcher!( diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index cbe1c5d44d5..ed5583799fe 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -3,7 +3,7 @@ use clippy_utils::higher; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - can_move_expr_to_closure, eager_or_lazy, in_constant, in_macro, is_else_clause, is_lang_ctor, peel_hir_expr_while, + can_move_expr_to_closure, eager_or_lazy, in_constant, is_else_clause, is_lang_ctor, peel_hir_expr_while, CaptureKind, }; use if_chain::if_chain; @@ -126,7 +126,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo /// this construct is found, or None if this construct is not found. fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if_chain! { - if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly + if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly if !in_constant(cx, expr.hir_id); if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr); diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 3258c9fb3fe..2df34d6d9b9 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_errors::Applicability; @@ -41,7 +40,7 @@ static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; impl LateLintPass<'_> for PtrEq { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_macro(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 290348c4509..0c460150087 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{get_parent_expr, in_macro}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; @@ -43,7 +43,7 @@ declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]); impl LateLintPass<'_> for RedundantSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_macro(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 77b6e60d893..70dff5ad313 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; @@ -50,7 +49,7 @@ impl EarlyLintPass for DerefAddrOf { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; - if !in_macro(addrof_target.span); + if !addrof_target.span.from_expansion(); then { let mut applicability = Applicability::MachineApplicable; let sugg = if e.span.from_expansion() { diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index cf94c0e97d9..e5e55ee7505 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -1,6 +1,5 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; @@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind; if path.ident.name == sym!(repeat); if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1)); - if !in_macro(receiver.span); + if !receiver.span.from_expansion(); then { let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); if ty.is_str() { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index ae85b7087e7..e2b1a33746e 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; -use clippy_utils::{fn_def_id, in_macro, path_to_local_id}; +use clippy_utils::{fn_def_id, path_to_local_id}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; @@ -90,8 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { if !last_statement_borrows(cx, initexpr); if !in_external_macro(cx.sess(), initexpr.span); if !in_external_macro(cx.sess(), retexpr.span); - if !in_external_macro(cx.sess(), local.span); - if !in_macro(local.span); + if !local.span.from_expansion(); then { span_lint_and_then( cx, diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index f6487b8c46b..87aa02b6585 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::in_macro; use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -110,7 +109,7 @@ fn track_uses( single_use_usages: &mut Vec<(Symbol, Span, bool)>, macros: &mut Vec, ) { - if in_macro(item.span) || item.vis.kind.is_pub() { + if item.span.from_expansion() || item.vis.kind.is_pub() { return; } diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 516fa3d95b4..8bf40ec5312 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::in_macro; use clippy_utils::paths; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{is_type_diagnostic_item, is_type_ref_to_diagnostic_item}; @@ -40,7 +39,7 @@ declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]); impl LateLintPass<'tcx> for StrlenOnCStrings { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if in_macro(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 79367c4230c..73bdcae9e39 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, SpanlessHash}; +use clippy_utils::SpanlessHash; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; @@ -93,7 +93,7 @@ fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span) impl TraitBounds { fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if in_macro(gen.span) { + if gen.span.from_expansion() { return; } let hash = |ty| -> u64 { @@ -107,7 +107,7 @@ impl TraitBounds { if_chain! { if let WherePredicate::BoundPredicate(ref p) = bound; if p.bounds.len() as u64 <= self.max_trait_bounds; - if !in_macro(p.span); + if !p.span.from_expansion(); let h = hash(p.bounded_ty); if let Some(ref v) = map.insert(h, p.bounds.iter().collect::>()); @@ -151,7 +151,7 @@ impl TraitBounds { } fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if in_macro(gen.span) || gen.params.is_empty() || gen.where_clause.predicates.is_empty() { + if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() { return; } @@ -170,7 +170,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { for predicate in gen.where_clause.predicates { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; - if !in_macro(bound_predicate.span); + if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(segment) = segments.first(); if let Some(trait_resolutions_direct) = map.get(&segment.ident); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index e9ec120a7f9..cc450b1e599 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, get_parent_expr, in_macro, is_lang_ctor, match_def_path, paths}; +use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; +use rustc_span::{hygiene, sym}; declare_clippy_lint! { /// ### What it does @@ -93,15 +93,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { }; let expr_err_ty = cx.typeck_results().expr_ty(err_arg); - let differing_contexts = differing_macro_contexts(expr.span, err_arg.span); - - let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts { - snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_") - } else if err_arg.span.from_expansion() && !in_macro(expr.span) { - snippet_with_macro_callsite(cx, err_arg.span, "_") - } else { - snippet(cx, err_arg.span, "_") - }; + let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt()); + let mut applicability = Applicability::MachineApplicable; + let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability); let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) { "" // already returns } else { @@ -120,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { "returning an `Err(_)` with the `?` operator", "try this", suggestion, - Applicability::MachineApplicable + applicability, ); } } diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 11aef50991b..99b33e5433f 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::is_lint_allowed; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; -use clippy_utils::{in_macro, is_lint_allowed}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource}; @@ -134,7 +134,7 @@ impl UndocumentedUnsafeBlocks { let enclosing_scope_span = map.opt_span(enclosing_hir_id)?; - let between_span = if in_macro(block_span) { + let between_span = if block_span.from_expansion() { self.macro_expansion = true; enclosing_scope_span.with_hi(block_span.hi()) } else { diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index c940cf077d1..fcfa8403177 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{contains_return, in_macro, is_lang_ctor, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::{contains_return, is_lang_ctor, return_ty, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { let mut suggs = Vec::new(); let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| { if_chain! { - if !in_macro(ret_expr.span); + if !ret_expr.span.from_expansion(); // Check if a function call. if let ExprKind::Call(func, [arg]) = ret_expr.kind; // Check if OPTION_SOME or RESULT_OK, depending on return type. diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 9ae50e47ca4..09aad296f03 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::same_type_and_consts; -use clippy_utils::{in_macro, meets_msrv, msrvs}; +use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { if_chain! { - if !in_macro(hir_ty.span); + if !hir_ty.span.from_expansion(); if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, @@ -214,8 +214,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { }; if same_type_and_consts(ty, cx.tcx.type_of(impl_id)); let hir = cx.tcx.hir(); - let id = hir.get_parent_node(hir_ty.hir_id); - if !hir.opt_span(id).map_or(false, in_macro); + // prevents false positive on `#[derive(serde::Deserialize)]` + if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion(); then { span_lint(cx, hir_ty.span); } @@ -224,7 +224,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if !in_macro(expr.span); + if !expr.span.from_expansion(); if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id); diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index bafb9d3e3b1..2f3e525fdcf 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_test_module_or_function; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, is_test_module_or_function}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ @@ -196,7 +196,7 @@ impl LateLintPass<'_> for WildcardImports { impl WildcardImports { fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { - in_macro(item.span) + item.span.from_expansion() || is_prelude_import(segments) || (is_super_only_import(segments) && self.test_modules_deep > 0) } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 086fbc9d3dd..7799fd527cc 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -250,12 +250,6 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem false } -/// Returns `true` if this `span` was expanded by any macro. -#[must_use] -pub fn in_macro(span: Span) -> bool { - span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) -} - pub fn is_unit_expr(expr: &Expr<'_>) -> bool { matches!( expr.kind, diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 34206b5ae2b..07883fdc454 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -179,7 +179,7 @@ impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { // desugaring, as this will detect a break if there's a while loop // or a for loop inside the expression. _ => { - if utils::in_macro(ex.span) { + if ex.span.from_expansion() { self.seen_return_break_continue = true; } else { rustc_hir::intravisit::walk_expr(self, ex); diff --git a/tests/ui-internal/if_chain_style.rs b/tests/ui-internal/if_chain_style.rs index 8e871707aa8..e064fd188c8 100644 --- a/tests/ui-internal/if_chain_style.rs +++ b/tests/ui-internal/if_chain_style.rs @@ -1,5 +1,5 @@ #![warn(clippy::if_chain_style)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::nonminimal_bool)] extern crate if_chain; diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 11fe06c5724..6c2a25c37d8 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -2,7 +2,9 @@ // [edition2018] edition:2018 // [edition2021] edition:2021 // run-rustfix + #![warn(clippy::manual_assert)] +#![allow(clippy::nonminimal_bool)] fn main() { let a = vec![1, 2, 3]; diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index 03c03472f90..77511631e44 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:22:5 + --> $DIR/manual_assert.rs:24:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-assert` implied by `-D warnings` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:25:5 + --> $DIR/manual_assert.rs:27:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:42:5 + --> $DIR/manual_assert.rs:44:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:45:5 + --> $DIR/manual_assert.rs:47:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:48:5 + --> $DIR/manual_assert.rs:50:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:51:5 + --> $DIR/manual_assert.rs:53:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -49,7 +49,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:54:5 + --> $DIR/manual_assert.rs:56:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 11fe06c5724..6c2a25c37d8 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -2,7 +2,9 @@ // [edition2018] edition:2018 // [edition2021] edition:2021 // run-rustfix + #![warn(clippy::manual_assert)] +#![allow(clippy::nonminimal_bool)] fn main() { let a = vec![1, 2, 3]; diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index 03c03472f90..77511631e44 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:22:5 + --> $DIR/manual_assert.rs:24:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-assert` implied by `-D warnings` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:25:5 + --> $DIR/manual_assert.rs:27:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:42:5 + --> $DIR/manual_assert.rs:44:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:45:5 + --> $DIR/manual_assert.rs:47:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:48:5 + --> $DIR/manual_assert.rs:50:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:51:5 + --> $DIR/manual_assert.rs:53:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -49,7 +49,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:54:5 + --> $DIR/manual_assert.rs:56:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); diff --git a/tests/ui/manual_assert.fixed b/tests/ui/manual_assert.fixed index 11fe06c5724..6c2a25c37d8 100644 --- a/tests/ui/manual_assert.fixed +++ b/tests/ui/manual_assert.fixed @@ -2,7 +2,9 @@ // [edition2018] edition:2018 // [edition2021] edition:2021 // run-rustfix + #![warn(clippy::manual_assert)] +#![allow(clippy::nonminimal_bool)] fn main() { let a = vec![1, 2, 3]; diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 8713426fc88..d3e0897488f 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -2,7 +2,9 @@ // [edition2018] edition:2018 // [edition2021] edition:2021 // run-rustfix + #![warn(clippy::manual_assert)] +#![allow(clippy::nonminimal_bool)] fn main() { let a = vec![1, 2, 3]; -- cgit 1.4.1-3-g733a5 From d647696c1f167802c9bb9ffe2c98459b152d563c Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 21 Oct 2021 21:06:26 +0200 Subject: Added `clippy::version` attribute to all normal lints So, some context for this, well, more a story. I'm not used to scripting, I've never really scripted anything, even if it's a valuable skill. I just never really needed it. Now, `@flip1995` correctly suggested using a script for this in `rust-clippy#7813`... And I decided to write a script using nushell because why not? This was a mistake... I spend way more time on this than I would like to admit. It has definitely been more than 4 hours. It shouldn't take that long, but me being new to scripting and nushell just wasn't a good mixture... Anyway, here is the script that creates another script which adds the versions. Fun... Just execute this on the `gh-pages` branch and the resulting `replacer.sh` in `clippy_lints` and it should all work. ```nu mv v0.0.212 rust-1.00.0; mv beta rust-1.57.0; mv master rust-1.58.0; let paths = (open ./rust-1.58.0/lints.json | select id id_span | flatten | select id path); let versions = ( ls | where name =~ "rust-" | select name | format {name}/lints.json | each { open $it | select id | insert version $it | str substring "5,11" version} | group-by id | rotate counter-clockwise id version | update version {get version | first 1} | flatten | select id version); $paths | each { |row| let version = ($versions | where id == ($row.id) | format {version}) let idu = ($row.id | str upcase) $"sed -i '0,/($idu),/{s/pub ($idu),/#[clippy::version = "($version)"]\n pub ($idu),/}' ($row.path)" } | str collect ";" | str find-replace --all '1.00.0' 'pre 1.29.0' | save "replacer.sh"; ``` And this still has some problems, but at this point I just want to be done -.- --- clippy_lints/src/absurd_extreme_comparisons.rs | 1 + clippy_lints/src/approx_const.rs | 1 + clippy_lints/src/arithmetic.rs | 2 + clippy_lints/src/as_conversions.rs | 1 + clippy_lints/src/asm_syntax.rs | 2 + clippy_lints/src/assertions_on_constants.rs | 1 + clippy_lints/src/assign_ops.rs | 2 + clippy_lints/src/async_yields_async.rs | 1 + clippy_lints/src/attrs.rs | 7 +++ clippy_lints/src/await_holding_invalid.rs | 2 + clippy_lints/src/bit_mask.rs | 3 ++ clippy_lints/src/blacklisted_name.rs | 1 + clippy_lints/src/blocks_in_if_conditions.rs | 1 + clippy_lints/src/bool_assert_comparison.rs | 1 + clippy_lints/src/booleans.rs | 2 + clippy_lints/src/bytecount.rs | 1 + clippy_lints/src/cargo_common_metadata.rs | 1 + .../case_sensitive_file_extension_comparisons.rs | 1 + clippy_lints/src/casts/mod.rs | 13 +++++ clippy_lints/src/checked_conversions.rs | 1 + clippy_lints/src/cognitive_complexity.rs | 1 + clippy_lints/src/collapsible_if.rs | 2 + clippy_lints/src/collapsible_match.rs | 1 + clippy_lints/src/comparison_chain.rs | 1 + clippy_lints/src/copies.rs | 4 ++ clippy_lints/src/copy_iterator.rs | 1 + clippy_lints/src/create_dir.rs | 1 + clippy_lints/src/dbg_macro.rs | 1 + clippy_lints/src/default.rs | 2 + clippy_lints/src/default_numeric_fallback.rs | 1 + clippy_lints/src/dereference.rs | 1 + clippy_lints/src/derivable_impls.rs | 1 + clippy_lints/src/derive.rs | 4 ++ clippy_lints/src/disallowed_method.rs | 1 + clippy_lints/src/disallowed_script_idents.rs | 1 + clippy_lints/src/disallowed_type.rs | 1 + clippy_lints/src/doc.rs | 5 ++ clippy_lints/src/double_comparison.rs | 1 + clippy_lints/src/double_parens.rs | 1 + clippy_lints/src/drop_forget_ref.rs | 4 ++ clippy_lints/src/duration_subsec.rs | 1 + clippy_lints/src/else_if_without_else.rs | 1 + clippy_lints/src/empty_enum.rs | 1 + clippy_lints/src/entry.rs | 1 + clippy_lints/src/enum_clike.rs | 1 + clippy_lints/src/enum_variants.rs | 3 ++ clippy_lints/src/eq_op.rs | 2 + clippy_lints/src/equatable_if_let.rs | 1 + clippy_lints/src/erasing_op.rs | 1 + clippy_lints/src/escape.rs | 1 + clippy_lints/src/eta_reduction.rs | 2 + clippy_lints/src/eval_order_dependence.rs | 2 + clippy_lints/src/excessive_bools.rs | 2 + clippy_lints/src/exhaustive_items.rs | 2 + clippy_lints/src/exit.rs | 1 + clippy_lints/src/explicit_write.rs | 1 + clippy_lints/src/fallible_impl_from.rs | 1 + clippy_lints/src/feature_name.rs | 2 + clippy_lints/src/float_equality_without_abs.rs | 1 + clippy_lints/src/float_literal.rs | 2 + clippy_lints/src/floating_point_arithmetic.rs | 2 + clippy_lints/src/format.rs | 1 + clippy_lints/src/format_args.rs | 2 + clippy_lints/src/formatting.rs | 4 ++ clippy_lints/src/from_over_into.rs | 1 + clippy_lints/src/from_str_radix_10.rs | 1 + clippy_lints/src/functions/mod.rs | 7 +++ clippy_lints/src/future_not_send.rs | 1 + clippy_lints/src/get_last_with_len.rs | 1 + clippy_lints/src/identity_op.rs | 1 + clippy_lints/src/if_let_mutex.rs | 1 + clippy_lints/src/if_not_else.rs | 1 + clippy_lints/src/if_then_some_else_none.rs | 1 + clippy_lints/src/implicit_hasher.rs | 1 + clippy_lints/src/implicit_return.rs | 1 + clippy_lints/src/implicit_saturating_sub.rs | 1 + .../src/inconsistent_struct_constructor.rs | 1 + clippy_lints/src/indexing_slicing.rs | 2 + clippy_lints/src/infinite_iter.rs | 2 + clippy_lints/src/inherent_impl.rs | 1 + clippy_lints/src/inherent_to_string.rs | 2 + clippy_lints/src/inline_fn_without_body.rs | 1 + clippy_lints/src/int_plus_one.rs | 1 + clippy_lints/src/integer_division.rs | 1 + clippy_lints/src/invalid_upcast_comparisons.rs | 1 + clippy_lints/src/items_after_statements.rs | 1 + clippy_lints/src/iter_not_returning_iterator.rs | 1 + clippy_lints/src/large_const_arrays.rs | 1 + clippy_lints/src/large_enum_variant.rs | 1 + clippy_lints/src/large_stack_arrays.rs | 1 + clippy_lints/src/len_zero.rs | 3 ++ clippy_lints/src/let_if_seq.rs | 1 + clippy_lints/src/let_underscore.rs | 3 ++ clippy_lints/src/lifetimes.rs | 2 + clippy_lints/src/literal_representation.rs | 6 +++ clippy_lints/src/loops/mod.rs | 18 +++++++ clippy_lints/src/macro_use.rs | 1 + clippy_lints/src/main_recursion.rs | 1 + clippy_lints/src/manual_assert.rs | 1 + clippy_lints/src/manual_async_fn.rs | 1 + clippy_lints/src/manual_map.rs | 1 + clippy_lints/src/manual_non_exhaustive.rs | 1 + clippy_lints/src/manual_ok_or.rs | 1 + clippy_lints/src/manual_strip.rs | 1 + clippy_lints/src/manual_unwrap_or.rs | 1 + clippy_lints/src/map_clone.rs | 1 + clippy_lints/src/map_err_ignore.rs | 1 + clippy_lints/src/map_unit_fn.rs | 2 + clippy_lints/src/match_on_vec_items.rs | 1 + clippy_lints/src/match_result_ok.rs | 1 + clippy_lints/src/match_str_case_mismatch.rs | 1 + clippy_lints/src/matches.rs | 16 ++++++ clippy_lints/src/mem_forget.rs | 1 + clippy_lints/src/mem_replace.rs | 3 ++ clippy_lints/src/methods/mod.rs | 63 ++++++++++++++++++++++ clippy_lints/src/minmax.rs | 1 + clippy_lints/src/misc.rs | 9 ++++ clippy_lints/src/misc_early/mod.rs | 9 ++++ clippy_lints/src/missing_const_for_fn.rs | 1 + clippy_lints/src/missing_doc.rs | 1 + clippy_lints/src/missing_enforced_import_rename.rs | 1 + clippy_lints/src/missing_inline.rs | 1 + clippy_lints/src/module_style.rs | 2 + clippy_lints/src/modulo_arithmetic.rs | 1 + clippy_lints/src/multiple_crate_versions.rs | 1 + clippy_lints/src/mut_key.rs | 1 + clippy_lints/src/mut_mut.rs | 1 + clippy_lints/src/mut_mutex_lock.rs | 1 + clippy_lints/src/mut_reference.rs | 1 + clippy_lints/src/mutable_debug_assertion.rs | 1 + clippy_lints/src/mutex_atomic.rs | 2 + clippy_lints/src/needless_arbitrary_self_type.rs | 1 + clippy_lints/src/needless_bitwise_bool.rs | 1 + clippy_lints/src/needless_bool.rs | 2 + clippy_lints/src/needless_borrow.rs | 2 + clippy_lints/src/needless_borrowed_ref.rs | 1 + clippy_lints/src/needless_continue.rs | 1 + clippy_lints/src/needless_for_each.rs | 1 + clippy_lints/src/needless_option_as_deref.rs | 1 + clippy_lints/src/needless_pass_by_value.rs | 1 + clippy_lints/src/needless_question_mark.rs | 1 + clippy_lints/src/needless_update.rs | 1 + clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 1 + clippy_lints/src/neg_multiply.rs | 1 + clippy_lints/src/new_without_default.rs | 1 + clippy_lints/src/no_effect.rs | 3 ++ clippy_lints/src/non_copy_const.rs | 2 + clippy_lints/src/non_expressive_names.rs | 3 ++ clippy_lints/src/non_octal_unix_permissions.rs | 1 + clippy_lints/src/non_send_fields_in_send_ty.rs | 1 + clippy_lints/src/nonstandard_macro_braces.rs | 1 + clippy_lints/src/open_options.rs | 1 + clippy_lints/src/option_env_unwrap.rs | 1 + clippy_lints/src/option_if_let_else.rs | 1 + clippy_lints/src/overflow_check_conditional.rs | 1 + clippy_lints/src/panic_in_result_fn.rs | 1 + clippy_lints/src/panic_unimplemented.rs | 4 ++ clippy_lints/src/partialeq_ne_impl.rs | 1 + clippy_lints/src/pass_by_ref_or_value.rs | 2 + clippy_lints/src/path_buf_push_overwrite.rs | 1 + clippy_lints/src/pattern_type_mismatch.rs | 1 + clippy_lints/src/precedence.rs | 1 + clippy_lints/src/ptr.rs | 4 ++ clippy_lints/src/ptr_eq.rs | 1 + clippy_lints/src/ptr_offset_with_cast.rs | 1 + clippy_lints/src/question_mark.rs | 1 + clippy_lints/src/ranges.rs | 5 ++ clippy_lints/src/redundant_clone.rs | 1 + clippy_lints/src/redundant_closure_call.rs | 1 + clippy_lints/src/redundant_else.rs | 1 + clippy_lints/src/redundant_field_names.rs | 1 + clippy_lints/src/redundant_pub_crate.rs | 1 + clippy_lints/src/redundant_slicing.rs | 1 + clippy_lints/src/redundant_static_lifetimes.rs | 1 + clippy_lints/src/ref_option_ref.rs | 1 + clippy_lints/src/reference.rs | 2 + clippy_lints/src/regex.rs | 2 + clippy_lints/src/repeat_once.rs | 1 + clippy_lints/src/returns.rs | 2 + clippy_lints/src/same_name_method.rs | 1 + clippy_lints/src/self_assignment.rs | 1 + clippy_lints/src/self_named_constructors.rs | 1 + clippy_lints/src/semicolon_if_nothing_returned.rs | 1 + clippy_lints/src/serde_api.rs | 1 + clippy_lints/src/shadow.rs | 3 ++ clippy_lints/src/single_component_path_imports.rs | 1 + clippy_lints/src/size_of_in_element_count.rs | 1 + clippy_lints/src/slow_vector_initialization.rs | 1 + clippy_lints/src/stable_sort_primitive.rs | 1 + clippy_lints/src/strings.rs | 7 +++ clippy_lints/src/strlen_on_c_strings.rs | 1 + clippy_lints/src/suspicious_operation_groupings.rs | 1 + clippy_lints/src/suspicious_trait_impl.rs | 2 + clippy_lints/src/swap.rs | 2 + clippy_lints/src/tabs_in_doc_comments.rs | 1 + clippy_lints/src/temporary_assignment.rs | 1 + clippy_lints/src/to_digit_is_some.rs | 1 + clippy_lints/src/to_string_in_display.rs | 1 + clippy_lints/src/trailing_empty_array.rs | 1 + clippy_lints/src/trait_bounds.rs | 2 + clippy_lints/src/transmute/mod.rs | 13 +++++ clippy_lints/src/transmuting_null.rs | 1 + clippy_lints/src/try_err.rs | 1 + clippy_lints/src/types/mod.rs | 9 ++++ clippy_lints/src/undocumented_unsafe_blocks.rs | 1 + clippy_lints/src/undropped_manually_drops.rs | 1 + clippy_lints/src/unicode.rs | 3 ++ clippy_lints/src/uninit_vec.rs | 1 + clippy_lints/src/unit_hash.rs | 1 + clippy_lints/src/unit_return_expecting_ord.rs | 1 + clippy_lints/src/unit_types/mod.rs | 3 ++ clippy_lints/src/unnamed_address.rs | 2 + clippy_lints/src/unnecessary_self_imports.rs | 1 + clippy_lints/src/unnecessary_sort_by.rs | 1 + clippy_lints/src/unnecessary_wraps.rs | 1 + clippy_lints/src/unnested_or_patterns.rs | 1 + clippy_lints/src/unsafe_removed_from_name.rs | 1 + clippy_lints/src/unused_async.rs | 1 + clippy_lints/src/unused_io_amount.rs | 1 + clippy_lints/src/unused_self.rs | 1 + clippy_lints/src/unused_unit.rs | 1 + clippy_lints/src/unwrap.rs | 2 + clippy_lints/src/unwrap_in_result.rs | 1 + clippy_lints/src/upper_case_acronyms.rs | 1 + clippy_lints/src/use_self.rs | 1 + clippy_lints/src/useless_conversion.rs | 1 + clippy_lints/src/vec.rs | 1 + clippy_lints/src/vec_init_then_push.rs | 1 + clippy_lints/src/vec_resize_to_zero.rs | 1 + clippy_lints/src/verbose_file_reads.rs | 1 + clippy_lints/src/wildcard_dependencies.rs | 1 + clippy_lints/src/wildcard_imports.rs | 2 + clippy_lints/src/write.rs | 9 ++++ clippy_lints/src/zero_div_zero.rs | 1 + clippy_lints/src/zero_sized_map_values.rs | 1 + 235 files changed, 490 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/absurd_extreme_comparisons.rs b/clippy_lints/src/absurd_extreme_comparisons.rs index 1483f3f9185..7665aa8380b 100644 --- a/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/absurd_extreme_comparisons.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// if vec.len() <= 0 {} /// if 100 > i32::MAX {} /// ``` + #[clippy::version = "pre 1.29.0"] pub ABSURD_EXTREME_COMPARISONS, correctness, "a comparison with a maximum or minimum value that is always true or false" diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index fb54ac1ec51..12435eefbc4 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// let x = std::f32::consts::PI; /// let y = std::f64::consts::FRAC_1_PI; /// ``` + #[clippy::version = "pre 1.29.0"] pub APPROX_CONSTANT, correctness, "the approximate of a known float constant (in `std::fXX::consts`)" diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 36fe7b7a867..e0c1d6ab6e1 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -25,6 +25,7 @@ declare_clippy_lint! { /// # let a = 0; /// a + 1; /// ``` + #[clippy::version = "pre 1.29.0"] pub INTEGER_ARITHMETIC, restriction, "any integer arithmetic expression which could overflow or panic" @@ -43,6 +44,7 @@ declare_clippy_lint! { /// # let a = 0.0; /// a + 1.0; /// ``` + #[clippy::version = "pre 1.29.0"] pub FLOAT_ARITHMETIC, restriction, "any floating-point arithmetic statement" diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 0be460d67a7..53704da1046 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// f(a.try_into().expect("Unexpected u16 overflow in f")); /// ``` /// + #[clippy::version = "1.41.0"] pub AS_CONVERSIONS, restriction, "using a potentially dangerous silent `as` conversion" diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 825832eb79d..0322698f029 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -75,6 +75,7 @@ declare_clippy_lint! { /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); /// # } /// ``` + #[clippy::version = "1.49.0"] pub INLINE_ASM_X86_INTEL_SYNTAX, restriction, "prefer AT&T x86 assembly syntax" @@ -111,6 +112,7 @@ declare_clippy_lint! { /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); /// # } /// ``` + #[clippy::version = "1.49.0"] pub INLINE_ASM_X86_ATT_SYNTAX, restriction, "prefer Intel x86 assembly syntax" diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index d834a1d317a..521fc84ee9c 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// const B: bool = false; /// assert!(B) /// ``` + #[clippy::version = "1.34.0"] pub ASSERTIONS_ON_CONSTANTS, style, "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`" diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 2097a1feff9..e16f4369da9 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// // Good /// a += b; /// ``` + #[clippy::version = "pre 1.29.0"] pub ASSIGN_OP_PATTERN, style, "assigning the result of an operation on a variable to that same variable" @@ -60,6 +61,7 @@ declare_clippy_lint! { /// // ... /// a += a + b; /// ``` + #[clippy::version = "pre 1.29.0"] pub MISREFACTORED_ASSIGN_OP, suspicious, "having a variable on both sides of an assign op" diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 182736a5a20..0619490e73c 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// }; /// } /// ``` + #[clippy::version = "1.48.0"] pub ASYNC_YIELDS_ASYNC, correctness, "async blocks that return a type that can be awaited" diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 9c5db18336f..1edb7c950e7 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -66,6 +66,7 @@ declare_clippy_lint! { /// #[inline(always)] /// fn not_quite_hot_code(..) { ... } /// ``` + #[clippy::version = "pre 1.29.0"] pub INLINE_ALWAYS, pedantic, "use of `#[inline(always)]`" @@ -100,6 +101,7 @@ declare_clippy_lint! { /// #[macro_use] /// extern crate baz; /// ``` + #[clippy::version = "pre 1.29.0"] pub USELESS_ATTRIBUTE, correctness, "use of lint attributes on `extern crate` items" @@ -119,6 +121,7 @@ declare_clippy_lint! { /// #[deprecated(since = "forever")] /// fn something_else() { /* ... */ } /// ``` + #[clippy::version = "pre 1.29.0"] pub DEPRECATED_SEMVER, correctness, "use of `#[deprecated(since = \"x\")]` where x is not semver" @@ -156,6 +159,7 @@ declare_clippy_lint! { /// #[allow(dead_code)] /// fn this_is_fine_too() { } /// ``` + #[clippy::version = "pre 1.29.0"] pub EMPTY_LINE_AFTER_OUTER_ATTR, nursery, "empty line after outer attribute" @@ -179,6 +183,7 @@ declare_clippy_lint! { /// ```rust /// #![deny(clippy::as_conversions)] /// ``` + #[clippy::version = "1.47.0"] pub BLANKET_CLIPPY_RESTRICTION_LINTS, suspicious, "enabling the complete restriction group" @@ -210,6 +215,7 @@ declare_clippy_lint! { /// #[rustfmt::skip] /// fn main() { } /// ``` + #[clippy::version = "1.32.0"] pub DEPRECATED_CFG_ATTR, complexity, "usage of `cfg_attr(rustfmt)` instead of tool attributes" @@ -242,6 +248,7 @@ declare_clippy_lint! { /// fn conditional() { } /// ``` /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. + #[clippy::version = "1.45.0"] pub MISMATCHED_TARGET_OS, correctness, "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 28615b9217c..1cc3418d474 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -47,6 +47,7 @@ declare_clippy_lint! { /// bar.await; /// } /// ``` + #[clippy::version = "1.45.0"] pub AWAIT_HOLDING_LOCK, pedantic, "Inside an async function, holding a MutexGuard while calling await" @@ -88,6 +89,7 @@ declare_clippy_lint! { /// bar.await; /// } /// ``` + #[clippy::version = "1.49.0"] pub AWAIT_HOLDING_REFCELL_REF, pedantic, "Inside an async function, holding a RefCell ref while calling await" diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 11346e7c96a..0977cf22b2c 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// # let x = 1; /// if (x & 1 == 2) { } /// ``` + #[clippy::version = "pre 1.29.0"] pub BAD_BIT_MASK, correctness, "expressions of the form `_ & mask == select` that will only ever return `true` or `false`" @@ -73,6 +74,7 @@ declare_clippy_lint! { /// # let x = 1; /// if (x | 1 > 3) { } /// ``` + #[clippy::version = "pre 1.29.0"] pub INEFFECTIVE_BIT_MASK, correctness, "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`" @@ -95,6 +97,7 @@ declare_clippy_lint! { /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` + #[clippy::version = "pre 1.29.0"] pub VERBOSE_BIT_MASK, pedantic, "expressions where a bit mask is less readable than the corresponding method call" diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 916c78c982a..1600fb25d89 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -17,6 +17,7 @@ declare_clippy_lint! { /// ```rust /// let foo = 3.14; /// ``` + #[clippy::version = "pre 1.29.0"] pub BLACKLISTED_NAME, style, "usage of a blacklisted/placeholder name" diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 47e5b0d583d..b59f49357df 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// let res = { let x = somefunc(); x }; /// if res { /* ... */ } /// ``` + #[clippy::version = "1.45.0"] pub BLOCKS_IN_IF_CONDITIONS, style, "useless or complex blocks that can be eliminated in conditions" diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index cdc192a47e4..a59abc66306 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// // Good /// assert!(!"a".is_empty()); /// ``` + #[clippy::version = "1.53.0"] pub BOOL_ASSERT_COMPARISON, style, "Using a boolean as comparison value in an assert_* macro when there is no need" diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a1e6b7224ff..51835ee7488 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// if a && true // should be: if a /// if !(a == b) // should be: if a != b /// ``` + #[clippy::version = "pre 1.29.0"] pub NONMINIMAL_BOOL, complexity, "boolean expressions that can be written more concisely" @@ -52,6 +53,7 @@ declare_clippy_lint! { /// if a && b || a { ... } /// ``` /// The `b` is unnecessary, the expression is equivalent to `if a`. + #[clippy::version = "pre 1.29.0"] pub LOGIC_BUG, correctness, "boolean expressions that contain terminals which can be eliminated" diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index a07cd5e5f4e..a938ada9d2a 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// # let vec = vec![1_u8]; /// &vec.iter().filter(|x| **x == 0u8).count(); // use bytecount::count instead /// ``` + #[clippy::version = "pre 1.29.0"] pub NAIVE_BYTECOUNT, pedantic, "use of naive `.filter(|&x| x == y).count()` to count byte values" diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index ff619c59b6e..23f79fdc682 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -42,6 +42,7 @@ declare_clippy_lint! { /// keywords = ["clippy", "lint", "plugin"] /// categories = ["development-tools", "development-tools::cargo-plugins"] /// ``` + #[clippy::version = "1.32.0"] pub CARGO_COMMON_METADATA, cargo, "common metadata is defined in `Cargo.toml`" diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index c876553c165..3f286dd9e2f 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// filename.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rs")) == Some(true) /// } /// ``` + #[clippy::version = "1.51.0"] pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, pedantic, "Checks for calls to ends_with with case-sensitive file extensions" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 233abd17894..c674327486c 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// let x = u64::MAX; /// x as f64; /// ``` + #[clippy::version = "pre 1.29.0"] pub CAST_PRECISION_LOSS, pedantic, "casts that cause loss of precision, e.g., `x as f32` where `x: u64`" @@ -61,6 +62,7 @@ declare_clippy_lint! { /// let y: i8 = -1; /// y as u128; // will return 18446744073709551615 /// ``` + #[clippy::version = "pre 1.29.0"] pub CAST_SIGN_LOSS, pedantic, "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`" @@ -83,6 +85,7 @@ declare_clippy_lint! { /// x as u8 /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub CAST_POSSIBLE_TRUNCATION, pedantic, "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`" @@ -106,6 +109,7 @@ declare_clippy_lint! { /// ```rust /// u32::MAX as i32; // will yield a value of `-1` /// ``` + #[clippy::version = "pre 1.29.0"] pub CAST_POSSIBLE_WRAP, pedantic, "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`" @@ -138,6 +142,7 @@ declare_clippy_lint! { /// u64::from(x) /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub CAST_LOSSLESS, pedantic, "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`" @@ -163,6 +168,7 @@ declare_clippy_lint! { /// let _ = 2_i32; /// let _ = 0.5_f32; /// ``` + #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_CAST, complexity, "cast to the same type, e.g., `x as i32` where `x: i32`" @@ -190,6 +196,7 @@ declare_clippy_lint! { /// (&1u8 as *const u8).cast::(); /// (&mut 1u8 as *mut u8).cast::(); /// ``` + #[clippy::version = "pre 1.29.0"] pub CAST_PTR_ALIGNMENT, pedantic, "cast from a pointer to a more-strictly-aligned pointer" @@ -217,6 +224,7 @@ declare_clippy_lint! { /// fn fun2() -> i32 { 1 } /// let a = fun2 as usize; /// ``` + #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, style, "casting a function pointer to a numeric type other than usize" @@ -247,6 +255,7 @@ declare_clippy_lint! { /// let fn_ptr = fn2 as usize; /// let fn_ptr_truncated = fn_ptr as i32; /// ``` + #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION, style, "casting a function pointer to a numeric type not wide enough to store the address" @@ -283,6 +292,7 @@ declare_clippy_lint! { /// } /// let _ = fn3 as fn() -> u16; /// ``` + #[clippy::version = "1.58.0"] pub FN_TO_NUMERIC_CAST_ANY, restriction, "casting a function pointer to any integer type" @@ -317,6 +327,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.33.0"] pub CAST_REF_TO_MUT, correctness, "a cast of reference to a mutable pointer" @@ -344,6 +355,7 @@ declare_clippy_lint! { /// ```rust,ignore /// b'x' /// ``` + #[clippy::version = "pre 1.29.0"] pub CHAR_LIT_AS_U8, complexity, "casting a character literal to `u8` truncates" @@ -372,6 +384,7 @@ declare_clippy_lint! { /// let _ = ptr.cast::(); /// let _ = mut_ptr.cast::(); /// ``` + #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 842bbf006cc..ffe6340bd77 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// i32::try_from(foo).is_ok() /// # ; /// ``` + #[clippy::version = "1.37.0"] pub CHECKED_CONVERSIONS, pedantic, "`try_from` could replace manual bounds checking when casting" diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 1ccb8c5d880..84a2373efe1 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// /// ### Example /// No. You'll see it when you get the warning. + #[clippy::version = "1.35.0"] pub COGNITIVE_COMPLEXITY, nursery, "functions that should be split up into multiple functions" diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 4aa87980715..f03f34e5a4b 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -47,6 +47,7 @@ declare_clippy_lint! { /// … /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub COLLAPSIBLE_IF, style, "nested `if`s that can be collapsed (e.g., `if x { if y { ... } }`" @@ -82,6 +83,7 @@ declare_clippy_lint! { /// … /// } /// ``` + #[clippy::version = "1.51.0"] pub COLLAPSIBLE_ELSE_IF, style, "nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)" diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs index a4693fa213b..626f9971f01 100644 --- a/clippy_lints/src/collapsible_match.rs +++ b/clippy_lints/src/collapsible_match.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// }; /// } /// ``` + #[clippy::version = "1.50.0"] pub COLLAPSIBLE_MATCH, style, "Nested `match` or `if let` expressions where the patterns may be \"collapsed\" together." diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 597a3c67024..399d11472b0 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -49,6 +49,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.40.0"] pub COMPARISON_CHAIN, style, "`if`s that can be rewritten with `match` and `cmp`" diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f57da62da5f..d07bc23235b 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// … /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub IFS_SAME_COND, correctness, "consecutive `if`s with the same condition" @@ -88,6 +89,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.41.0"] pub SAME_FUNCTIONS_IN_IF_CONDITION, pedantic, "consecutive `if`s with the same function call" @@ -109,6 +111,7 @@ declare_clippy_lint! { /// 42 /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub IF_SAME_THEN_ELSE, correctness, "`if` with the same `then` and `else` blocks" @@ -147,6 +150,7 @@ declare_clippy_lint! { /// 42 /// }; /// ``` + #[clippy::version = "1.53.0"] pub BRANCHES_SHARING_CODE, nursery, "`if` statement with shared code in all blocks" diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index c2e9e8b3ab7..026683f6006 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// let a: Vec<_> = my_iterator.take(1).collect(); /// let b: Vec<_> = my_iterator.collect(); /// ``` + #[clippy::version = "1.30.0"] pub COPY_ITERATOR, pedantic, "implementing `Iterator` on a `Copy` type" diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index e4ee2772483..6bc4054a5ab 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// ```rust /// std::fs::create_dir_all("foo"); /// ``` + #[clippy::version = "1.48.0"] pub CREATE_DIR, restriction, "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`" diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index bab4a696f83..1aae4c81c73 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// // Good /// true /// ``` + #[clippy::version = "1.34.0"] pub DBG_MACRO, restriction, "`dbg!` macro is intended as a debugging tool" diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 54647ba823e..a0b137efe22 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// // Good /// let s = String::default(); /// ``` + #[clippy::version = "pre 1.29.0"] pub DEFAULT_TRAIT_ACCESS, pedantic, "checks for literal calls to `Default::default()`" @@ -62,6 +63,7 @@ declare_clippy_lint! { /// .. Default::default() /// }; /// ``` + #[clippy::version = "1.49.0"] pub FIELD_REASSIGN_WITH_DEFAULT, style, "binding initialized with Default should have its fields set in the initializer" diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 3f1b7ea6214..3573ea5f026 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -46,6 +46,7 @@ declare_clippy_lint! { /// let i = 10i32; /// let f = 1.23f64; /// ``` + #[clippy::version = "1.52.0"] pub DEFAULT_NUMERIC_FALLBACK, restriction, "usage of unconstrained numeric literals which may cause default numeric fallback." diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 975353add08..bbaae94d3dd 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let _ = d.unwrap().deref(); /// ``` + #[clippy::version = "1.44.0"] pub EXPLICIT_DEREF_METHODS, pedantic, "Explicit use of deref or deref_mut method while not in a method chain." diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 01ec306e5e1..d0fab2b48fb 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -46,6 +46,7 @@ declare_clippy_lint! { /// has exactly equal bounds, and therefore this lint is disabled for types with /// generic parameters. /// + #[clippy::version = "1.57.0"] pub DERIVABLE_IMPLS, complexity, "manual implementation of the `Default` trait which is equal to a derive" diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 24ac5917dcb..4b232a26e5d 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// ... /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub DERIVE_HASH_XOR_EQ, correctness, "deriving `Hash` but implementing `PartialEq` explicitly" @@ -88,6 +89,7 @@ declare_clippy_lint! { /// #[derive(Ord, PartialOrd, PartialEq, Eq)] /// struct Foo; /// ``` + #[clippy::version = "1.47.0"] pub DERIVE_ORD_XOR_PARTIAL_ORD, correctness, "deriving `Ord` but implementing `PartialOrd` explicitly" @@ -114,6 +116,7 @@ declare_clippy_lint! { /// // .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub EXPL_IMPL_CLONE_ON_COPY, pedantic, "implementing `Clone` explicitly on `Copy` types" @@ -147,6 +150,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.45.0"] pub UNSAFE_DERIVE_DESERIALIZE, pedantic, "deriving `serde::Deserialize` on a type that has methods using `unsafe`" diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs index 22d726cdcb7..c2217353b32 100644 --- a/clippy_lints/src/disallowed_method.rs +++ b/clippy_lints/src/disallowed_method.rs @@ -47,6 +47,7 @@ declare_clippy_lint! { /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` + #[clippy::version = "1.49.0"] pub DISALLOWED_METHOD, nursery, "use of a disallowed method call" diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 6d38d30cd0b..3c3f3631849 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// let zähler = 10; // OK, it's still latin. /// let カウンタ = 10; // Will spawn the lint. /// ``` + #[clippy::version = "1.55.0"] pub DISALLOWED_SCRIPT_IDENTS, restriction, "usage of non-allowed Unicode scripts" diff --git a/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs index 48f781516f4..7e784ca2244 100644 --- a/clippy_lints/src/disallowed_type.rs +++ b/clippy_lints/src/disallowed_type.rs @@ -42,6 +42,7 @@ declare_clippy_lint! { /// // A similar type that is allowed by the config /// use std::collections::HashMap; /// ``` + #[clippy::version = "1.55.0"] pub DISALLOWED_TYPE, nursery, "use of a disallowed type" diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 87ad5178ff0..249cf260309 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -67,6 +67,7 @@ declare_clippy_lint! { /// /// [SmallVec]: SmallVec /// fn main() {} /// ``` + #[clippy::version = "pre 1.29.0"] pub DOC_MARKDOWN, pedantic, "presence of `_`, `::` or camel-case outside backticks in documentation" @@ -101,6 +102,7 @@ declare_clippy_lint! { /// unimplemented!(); /// } /// ``` + #[clippy::version = "1.39.0"] pub MISSING_SAFETY_DOC, style, "`pub unsafe fn` without `# Safety` docs" @@ -129,6 +131,7 @@ declare_clippy_lint! { /// unimplemented!(); /// } /// ``` + #[clippy::version = "1.41.0"] pub MISSING_ERRORS_DOC, pedantic, "`pub fn` returns `Result` without `# Errors` in doc comment" @@ -159,6 +162,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.52.0"] pub MISSING_PANICS_DOC, pedantic, "`pub fn` may panic without `# Panics` in doc comment" @@ -187,6 +191,7 @@ declare_clippy_lint! { /// unimplemented!(); /// } /// `````` + #[clippy::version = "1.40.0"] pub NEEDLESS_DOCTEST_MAIN, style, "presence of `fn main() {` in code examples" diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 6520bb91faf..176092e5b28 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// # let y = 2; /// if x <= y {} /// ``` + #[clippy::version = "pre 1.29.0"] pub DOUBLE_COMPARISONS, complexity, "unnecessary double comparisons that can be simplified" diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index d0d87b6df9a..e10f740d24a 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// // Good /// foo(0); /// ``` + #[clippy::version = "pre 1.29.0"] pub DOUBLE_PARENS, complexity, "Warn on unnecessary double parentheses" diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 0f3dc866afb..a8f8e3d8a42 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -25,6 +25,7 @@ declare_clippy_lint! { /// // still locked /// operation_that_requires_mutex_to_be_unlocked(); /// ``` + #[clippy::version = "pre 1.29.0"] pub DROP_REF, correctness, "calls to `std::mem::drop` with a reference instead of an owned value" @@ -46,6 +47,7 @@ declare_clippy_lint! { /// let x = Box::new(1); /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped /// ``` + #[clippy::version = "pre 1.29.0"] pub FORGET_REF, correctness, "calls to `std::mem::forget` with a reference instead of an owned value" @@ -67,6 +69,7 @@ declare_clippy_lint! { /// std::mem::drop(x) // A copy of x is passed to the function, leaving the /// // original unaffected /// ``` + #[clippy::version = "pre 1.29.0"] pub DROP_COPY, correctness, "calls to `std::mem::drop` with a value that implements Copy" @@ -94,6 +97,7 @@ declare_clippy_lint! { /// std::mem::forget(x) // A copy of x is passed to the function, leaving the /// // original unaffected /// ``` + #[clippy::version = "pre 1.29.0"] pub FORGET_COPY, correctness, "calls to `std::mem::forget` with a value that implements Copy" diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 3774de62521..3070d105014 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// let _micros = dur.subsec_micros(); /// let _millis = dur.subsec_millis(); /// ``` + #[clippy::version = "pre 1.29.0"] pub DURATION_SUBSEC, complexity, "checks for calculation of subsecond microseconds or milliseconds" diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index b64246515f3..92c56c762aa 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// // We don't care about zero. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub ELSE_IF_WITHOUT_ELSE, restriction, "`if` expression with an `else if`, but without a final `else` branch" diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 3453c2da278..af9e65e6361 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// /// struct Test(!); /// ``` + #[clippy::version = "pre 1.29.0"] pub EMPTY_ENUM, pedantic, "enum with no variants" diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 57fd24bd4f0..3d92eb16870 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -54,6 +54,7 @@ declare_clippy_lint! { /// # let v = 1; /// map.entry(k).or_insert(v); /// ``` + #[clippy::version = "pre 1.29.0"] pub MAP_ENTRY, perf, "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`" diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index a2c3c7a7b49..3b6661c817b 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// Y = 0, /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub ENUM_CLIKE_UNPORTABLE_VARIANT, correctness, "C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`" diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 404b67c8f29..fc3a35efaf8 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// Battenberg, /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub ENUM_VARIANT_NAMES, style, "enums where all variants share a prefix/postfix" @@ -59,6 +60,7 @@ declare_clippy_lint! { /// struct BlackForest; /// } /// ``` + #[clippy::version = "1.33.0"] pub MODULE_NAME_REPETITIONS, pedantic, "type names prefixed/postfixed with their containing module's name" @@ -89,6 +91,7 @@ declare_clippy_lint! { /// ... /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MODULE_INCEPTION, style, "modules that have the same name as their parent module" diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index c034c849b55..10123460527 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// # let b = 4; /// assert_eq!(a, a); /// ``` + #[clippy::version = "pre 1.29.0"] pub EQ_OP, correctness, "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)" @@ -59,6 +60,7 @@ declare_clippy_lint! { /// // Good /// x == *y /// ``` + #[clippy::version = "pre 1.29.0"] pub OP_REF, style, "taking a reference to satisfy the type constraints on `==`" diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index e8b1d6f6eda..8905cc0de45 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// do_thing(); /// } /// ``` + #[clippy::version = "1.57.0"] pub EQUATABLE_IF_LET, nursery, "using pattern matching instead of equality" diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index d0944c37cf5..d49cec26be5 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -21,6 +21,7 @@ declare_clippy_lint! { /// 0 * x; /// x & 0; /// ``` + #[clippy::version = "pre 1.29.0"] pub ERASING_OP, correctness, "using erasing operations, e.g., `x * 0` or `y & 0`" diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 75b1c882c23..bc5d2f6278d 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// foo(x); /// println!("{}", x); /// ``` + #[clippy::version = "pre 1.29.0"] pub BOXED_LOCAL, perf, "using `Box` where unnecessary" diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 8def6529b3b..5a4b4247104 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// ``` /// where `foo(_)` is a plain function that takes the exact argument type of /// `x`. + #[clippy::version = "pre 1.29.0"] pub REDUNDANT_CLOSURE, style, "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)" @@ -60,6 +61,7 @@ declare_clippy_lint! { /// ```rust,ignore /// Some('a').map(char::to_uppercase); /// ``` + #[clippy::version = "1.35.0"] pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS, pedantic, "redundant closures for method calls" diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 1b56dd4b081..cdac9f3e6e1 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// }; /// let a = tmp + x; /// ``` + #[clippy::version = "pre 1.29.0"] pub EVAL_ORDER_DEPENDENCE, suspicious, "whether a variable read occurs before a write depends on sub-expression evaluation order" @@ -67,6 +68,7 @@ declare_clippy_lint! { /// let x = (a, b, c, panic!()); /// // can simply be replaced by `panic!()` /// ``` + #[clippy::version = "pre 1.29.0"] pub DIVERGING_SUB_EXPRESSION, complexity, "whether an expression contains a diverging sub expression" diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 06171702f75..5435e15de7b 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -37,6 +37,7 @@ declare_clippy_lint! { /// Finished, /// } /// ``` + #[clippy::version = "1.43.0"] pub STRUCT_EXCESSIVE_BOOLS, pedantic, "using too many bools in a struct" @@ -75,6 +76,7 @@ declare_clippy_lint! { /// /// fn f(shape: Shape, temperature: Temperature) { ... } /// ``` + #[clippy::version = "1.43.0"] pub FN_PARAMS_EXCESSIVE_BOOLS, pedantic, "using too many bools in function parameters" diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index bb4684ce38b..b0f50b5c144 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// Baz /// } /// ``` + #[clippy::version = "1.51.0"] pub EXHAUSTIVE_ENUMS, restriction, "detects exported enums that have not been marked #[non_exhaustive]" @@ -60,6 +61,7 @@ declare_clippy_lint! { /// baz: String, /// } /// ``` + #[clippy::version = "1.51.0"] pub EXHAUSTIVE_STRUCTS, restriction, "detects exported structs that have not been marked #[non_exhaustive]" diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 9cd5b2d9f44..d64cc61916c 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -18,6 +18,7 @@ declare_clippy_lint! { /// ```ignore /// std::process::exit(0) /// ``` + #[clippy::version = "1.41.0"] pub EXIT, restriction, "`std::process::exit` is called, terminating the program" diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 4f46ef906f4..6b327b9ce17 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// // this would be clearer as `eprintln!("foo: {:?}", bar);` /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); /// ``` + #[clippy::version = "pre 1.29.0"] pub EXPLICIT_WRITE, complexity, "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work" diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 70337f5bbeb..05d300058cf 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -44,6 +44,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub FALLIBLE_IMPL_FROM, nursery, "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`" diff --git a/clippy_lints/src/feature_name.rs b/clippy_lints/src/feature_name.rs index f534327f7a0..dc6bef52ddd 100644 --- a/clippy_lints/src/feature_name.rs +++ b/clippy_lints/src/feature_name.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// ghi = [] /// ``` /// + #[clippy::version = "1.57.0"] pub REDUNDANT_FEATURE_NAMES, cargo, "usage of a redundant feature name" @@ -60,6 +61,7 @@ declare_clippy_lint! { /// def = [] /// /// ``` + #[clippy::version = "1.57.0"] pub NEGATIVE_FEATURE_NAMES, cargo, "usage of a negative feature name" diff --git a/clippy_lints/src/float_equality_without_abs.rs b/clippy_lints/src/float_equality_without_abs.rs index c33d80b8e8e..ca8886228de 100644 --- a/clippy_lints/src/float_equality_without_abs.rs +++ b/clippy_lints/src/float_equality_without_abs.rs @@ -37,6 +37,7 @@ declare_clippy_lint! { /// (a - b).abs() < f32::EPSILON /// } /// ``` + #[clippy::version = "1.48.0"] pub FLOAT_EQUALITY_WITHOUT_ABS, suspicious, "float equality check without `.abs()`" diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 1e8a5bd7d34..d30dede833c 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// let v: f64 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789_9 /// ``` + #[clippy::version = "pre 1.29.0"] pub EXCESSIVE_PRECISION, style, "excessive precision for float literal" @@ -50,6 +51,7 @@ declare_clippy_lint! { /// let _: f32 = 16_777_216.0; /// let _: f64 = 16_777_217.0; /// ``` + #[clippy::version = "1.43.0"] pub LOSSY_FLOAT_LITERAL, restriction, "lossy whole number float literals" diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index eda611117ba..914723a4802 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -43,6 +43,7 @@ declare_clippy_lint! { /// let _ = a.ln_1p(); /// let _ = a.exp_m1(); /// ``` + #[clippy::version = "1.43.0"] pub IMPRECISE_FLOPS, nursery, "usage of imprecise floating point operations" @@ -99,6 +100,7 @@ declare_clippy_lint! { /// let _ = a.abs(); /// let _ = -a.abs(); /// ``` + #[clippy::version = "1.43.0"] pub SUBOPTIMAL_FLOPS, nursery, "usage of sub-optimal floating point operations" diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 7169ac9ad6c..3f043e5f2f1 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// // Good /// foo.to_owned(); /// ``` + #[clippy::version = "pre 1.29.0"] pub USELESS_FORMAT, complexity, "useless use of `format!`" diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index bb30accf145..f0e1a67dcdd 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` + #[clippy::version = "1.58.0"] pub FORMAT_IN_FORMAT_ARGS, perf, "`format!` used in a macro that does formatting" @@ -56,6 +57,7 @@ declare_clippy_lint! { /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` + #[clippy::version = "1.58.0"] pub TO_STRING_IN_FORMAT_ARGS, perf, "`to_string` applied to a type that implements `Display` in format args" diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index b4f186525c5..3e85c8a9c80 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -21,6 +21,7 @@ declare_clippy_lint! { /// ```rust,ignore /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`? /// ``` + #[clippy::version = "pre 1.29.0"] pub SUSPICIOUS_ASSIGNMENT_FORMATTING, suspicious, "suspicious formatting of `*=`, `-=` or `!=`" @@ -43,6 +44,7 @@ declare_clippy_lint! { /// if foo &&! bar { // this should be `foo && !bar` but looks like a different operator /// } /// ``` + #[clippy::version = "1.40.0"] pub SUSPICIOUS_UNARY_OP_FORMATTING, suspicious, "suspicious formatting of unary `-` or `!` on the RHS of a BinOp" @@ -79,6 +81,7 @@ declare_clippy_lint! { /// if bar { // this is the `else` block of the previous `if`, but should it be? /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub SUSPICIOUS_ELSE_FORMATTING, suspicious, "suspicious formatting of `else`" @@ -99,6 +102,7 @@ declare_clippy_lint! { /// -4, -5, -6 /// ]; /// ``` + #[clippy::version = "pre 1.29.0"] pub POSSIBLE_MISSING_COMMA, correctness, "possible missing comma in array" diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 347c6eb12cb..866ff216f84 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.51.0"] pub FROM_OVER_INTO, style, "Warns on implementations of `Into<..>` to use `From<..>`" diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 98ce3db025c..73e800073b0 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// let input: &str = get_input(); /// let num: u16 = input.parse()?; /// ``` + #[clippy::version = "1.52.0"] pub FROM_STR_RADIX_10, style, "from_str_radix with radix 10" diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index d7c5ec9ba35..ad031cbc09d 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// // .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub TOO_MANY_ARGUMENTS, complexity, "functions with too many arguments" @@ -49,6 +50,7 @@ declare_clippy_lint! { /// println!(""); /// } /// ``` + #[clippy::version = "1.34.0"] pub TOO_MANY_LINES, pedantic, "functions with too many lines" @@ -84,6 +86,7 @@ declare_clippy_lint! { /// println!("{}", unsafe { *x }); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NOT_UNSAFE_PTR_ARG_DEREF, correctness, "public functions dereferencing raw pointer arguments but not marked `unsafe`" @@ -103,6 +106,7 @@ declare_clippy_lint! { /// #[must_use] /// fn useless() { } /// ``` + #[clippy::version = "1.40.0"] pub MUST_USE_UNIT, style, "`#[must_use]` attribute on a unit-returning function / method" @@ -126,6 +130,7 @@ declare_clippy_lint! { /// unimplemented!(); /// } /// ``` + #[clippy::version = "1.40.0"] pub DOUBLE_MUST_USE, style, "`#[must_use]` attribute on a `#[must_use]`-returning function / method" @@ -155,6 +160,7 @@ declare_clippy_lint! { /// // this could be annotated with `#[must_use]`. /// fn id(t: T) -> T { t } /// ``` + #[clippy::version = "1.40.0"] pub MUST_USE_CANDIDATE, pedantic, "function or method that could take a `#[must_use]` attribute" @@ -204,6 +210,7 @@ declare_clippy_lint! { /// /// Note that there are crates that simplify creating the error type, e.g. /// [`thiserror`](https://docs.rs/thiserror). + #[clippy::version = "1.49.0"] pub RESULT_UNIT_ERR, style, "public function returning `Result` with an `Err` type of `()`" diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index e18442515b8..03af498eae3 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// ```rust /// async fn is_send(bytes: std::sync::Arc<[u8]>) {} /// ``` + #[clippy::version = "1.44.0"] pub FUTURE_NOT_SEND, nursery, "public Futures must be Send" diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index f3929b0f1e6..edca701869e 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// let x = vec![2, 3, 5]; /// let last_element = x.last(); /// ``` + #[clippy::version = "1.37.0"] pub GET_LAST_WITH_LEN, complexity, "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler" diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 414f465c494..b4e7bbc7671 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -22,6 +22,7 @@ declare_clippy_lint! { /// # let x = 1; /// x / 1 + 0 * 1 - 0 | 0; /// ``` + #[clippy::version = "pre 1.29.0"] pub IDENTITY_OP, complexity, "using identity operations, e.g., `x + 0` or `y / 1`" diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index a4118bf54b6..e20741d2407 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// use_locked(locked); /// } /// ``` + #[clippy::version = "1.45.0"] pub IF_LET_MUTEX, correctness, "locking a `Mutex` in an `if let` block can cause deadlocks" diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index ac938156237..3d59b783337 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// a() /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub IF_NOT_ELSE, pedantic, "`if` branches that could be swapped so no negation operation is necessary on the condition" diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index a2dac57454f..d95f5d41071 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// 42 /// }); /// ``` + #[clippy::version = "1.53.0"] pub IF_THEN_SOME_ELSE_NONE, restriction, "Finds if-else that could be written using `bool::then`" diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 81eb51e6f7c..6358228dd47 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -54,6 +54,7 @@ declare_clippy_lint! { /// /// pub fn foo(map: &mut HashMap) { } /// ``` + #[clippy::version = "pre 1.29.0"] pub IMPLICIT_HASHER, pedantic, "missing generalization over different hashers" diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 6d7c71d4082..07caeada80d 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// return x; /// } /// ``` + #[clippy::version = "1.33.0"] pub IMPLICIT_RETURN, restriction, "use a return statement like `return expr` instead of an expression" diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index ecbbbc5bc64..4088c54623d 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// // Good /// i = i.saturating_sub(1); /// ``` + #[clippy::version = "1.44.0"] pub IMPLICIT_SATURATING_SUB, pedantic, "Perform saturating subtraction instead of implicitly checking lower bound of data type" diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 52c92b3b122..1debdef9d86 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -55,6 +55,7 @@ declare_clippy_lint! { /// # let y = 2; /// Foo { x, y }; /// ``` + #[clippy::version = "1.52.0"] pub INCONSISTENT_STRUCT_CONSTRUCTOR, pedantic, "the order of the field init shorthand is inconsistent with the order in the struct definition" diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index f52f090d387..9ead4bb27a5 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// x[0]; /// x[3]; /// ``` + #[clippy::version = "pre 1.29.0"] pub OUT_OF_BOUNDS_INDEXING, correctness, "out of bounds constant indexing" @@ -85,6 +86,7 @@ declare_clippy_lint! { /// y.get(10..); /// y.get(..100); /// ``` + #[clippy::version = "pre 1.29.0"] pub INDEXING_SLICING, restriction, "indexing/slicing usage" diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 68c1fa35fcc..c7db47a552b 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// /// iter::repeat(1_u8).collect::>(); /// ``` + #[clippy::version = "pre 1.29.0"] pub INFINITE_ITER, correctness, "infinite iteration" @@ -42,6 +43,7 @@ declare_clippy_lint! { /// let infinite_iter = 0..; /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); /// ``` + #[clippy::version = "pre 1.29.0"] pub MAYBE_INFINITE_ITER, pedantic, "possible infinite iteration" diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index bd0b2964309..254d3f8a4d0 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// fn other() {} /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MULTIPLE_INHERENT_IMPL, restriction, "Multiple inherent impl that could be grouped" diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 61dd0eb4af7..60d234cd6f0 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.38.0"] pub INHERENT_TO_STRING, style, "type implements inherent method `to_string()`, but should instead implement the `Display` trait" @@ -88,6 +89,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.38.0"] pub INHERENT_TO_STRING_SHADOW_DISPLAY, correctness, "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait" diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 3e3df903f17..df69d3dcc51 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -24,6 +24,7 @@ declare_clippy_lint! { /// fn name(&self) -> &'static str; /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub INLINE_FN_WITHOUT_BODY, correctness, "use of `#[inline]` on trait methods without bodies" diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 6850e0c3476..3716d36ad88 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// # let y = 1; /// if x > y {} /// ``` + #[clippy::version = "pre 1.29.0"] pub INT_PLUS_ONE, complexity, "instead of using `x >= y + 1`, use `x > y`" diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index c962e814fa5..fa786205678 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// let x = 3f32 / 2f32; /// println!("{}", x); /// ``` + #[clippy::version = "1.37.0"] pub INTEGER_DIVISION, restriction, "integer division may cause loss of precision" diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 82438d85c7a..36e03e50a8e 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// let x: u8 = 1; /// (x as u32) > 300; /// ``` + #[clippy::version = "pre 1.29.0"] pub INVALID_UPCAST_COMPARISONS, pedantic, "a comparison involving an upcast which is always true or false" diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 3736d237642..b118d3c8b87 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -45,6 +45,7 @@ declare_clippy_lint! { /// foo(); // prints "foo" /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub ITEMS_AFTER_STATEMENTS, pedantic, "blocks where an item comes after a statement" diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 6c779348ca2..968bbc524b2 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.57.0"] pub ITER_NOT_RETURNING_ITERATOR, pedantic, "methods named `iter` or `iter_mut` that do not return an `Iterator`" diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index fe6814e35d0..80260e4cd83 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// // Good /// pub static a = [0u32; 1_000_000]; /// ``` + #[clippy::version = "1.44.0"] pub LARGE_CONST_ARRAYS, perf, "large non-scalar const array may cause performance overhead" diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 392166237be..0191713f60d 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// B(Box<[i32; 8000]>), /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub LARGE_ENUM_VARIANT, perf, "large size difference between variants on an enum" diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index bbb6c1f902c..1cc2c28c04a 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -19,6 +19,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let a = [0u32; 1_000_000]; /// ``` + #[clippy::version = "1.41.0"] pub LARGE_STACK_ARRAYS, pedantic, "allocating large arrays on stack may cause stack overflow" diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index f336fb9d42f..09cd0d22d8b 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -46,6 +46,7 @@ declare_clippy_lint! { /// .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub LEN_ZERO, style, "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead" @@ -71,6 +72,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub LEN_WITHOUT_IS_EMPTY, style, "traits or impls with a public `len` method but no corresponding `is_empty` method" @@ -108,6 +110,7 @@ declare_clippy_lint! { /// .. /// } /// ``` + #[clippy::version = "1.49.0"] pub COMPARISON_TO_EMPTY, style, "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead" diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 7f2c7b707f0..db09d00d730 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -48,6 +48,7 @@ declare_clippy_lint! { /// None /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub USELESS_LET_IF_SEQ, nursery, "unidiomatic `let mut` declaration followed by initialization in `if`" diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 9efd7aba7e8..557051fb8d2 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// // is_ok() is marked #[must_use] /// let _ = f().is_ok(); /// ``` + #[clippy::version = "1.42.0"] pub LET_UNDERSCORE_MUST_USE, restriction, "non-binding let on a `#[must_use]` expression" @@ -53,6 +54,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let _lock = mutex.lock(); /// ``` + #[clippy::version = "1.43.0"] pub LET_UNDERSCORE_LOCK, correctness, "non-binding let on a synchronization lock" @@ -94,6 +96,7 @@ declare_clippy_lint! { /// // dropped at end of scope /// } /// ``` + #[clippy::version = "1.50.0"] pub LET_UNDERSCORE_DROP, pedantic, "non-binding let on a type that implements `Drop`" diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 6565d5a6d70..fad3343d128 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -45,6 +45,7 @@ declare_clippy_lint! { /// x /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_LIFETIMES, complexity, "using explicit lifetimes for references in function arguments when elision rules \ @@ -73,6 +74,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub EXTRA_UNUSED_LIFETIMES, complexity, "unused lifetimes in function definitions" diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 0e36ab085a3..130543bbbee 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// // Good /// let x: u64 = 61_864_918_973_511; /// ``` + #[clippy::version = "pre 1.29.0"] pub UNREADABLE_LITERAL, pedantic, "long literal without underscores" @@ -53,6 +54,7 @@ declare_clippy_lint! { /// // Good /// 2_i32; /// ``` + #[clippy::version = "1.30.0"] pub MISTYPED_LITERAL_SUFFIXES, correctness, "mistyped literal suffix" @@ -75,6 +77,7 @@ declare_clippy_lint! { /// // Good /// let x: u64 = 61_864_918_973_511; /// ``` + #[clippy::version = "pre 1.29.0"] pub INCONSISTENT_DIGIT_GROUPING, style, "integer literals with digits grouped inconsistently" @@ -93,6 +96,7 @@ declare_clippy_lint! { /// let x: u32 = 0xFFF_FFF; /// let y: u8 = 0b01_011_101; /// ``` + #[clippy::version = "1.49.0"] pub UNUSUAL_BYTE_GROUPINGS, style, "binary or hex literals that aren't grouped by four" @@ -111,6 +115,7 @@ declare_clippy_lint! { /// ```rust /// let x: u64 = 6186491_8973511; /// ``` + #[clippy::version = "pre 1.29.0"] pub LARGE_DIGIT_GROUPS, pedantic, "grouping digits into groups that are too large" @@ -128,6 +133,7 @@ declare_clippy_lint! { /// `255` => `0xFF` /// `65_535` => `0xFFFF` /// `4_042_322_160` => `0xF0F0_F0F0` + #[clippy::version = "pre 1.29.0"] pub DECIMAL_LITERAL_REPRESENTATION, restriction, "using decimal representation when hexadecimal would be better" diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 5df1b796401..ccec648fa78 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -47,6 +47,7 @@ declare_clippy_lint! { /// # let mut dst = vec![0; 65]; /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]); /// ``` + #[clippy::version = "pre 1.29.0"] pub MANUAL_MEMCPY, perf, "manually copying items between slices" @@ -75,6 +76,7 @@ declare_clippy_lint! { /// println!("{}", i); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_RANGE_LOOP, style, "for-looping over a range of indices where an iterator over items would do" @@ -107,6 +109,7 @@ declare_clippy_lint! { /// // .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub EXPLICIT_ITER_LOOP, pedantic, "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" @@ -135,6 +138,7 @@ declare_clippy_lint! { /// // .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub EXPLICIT_INTO_ITER_LOOP, pedantic, "for-looping over `_.into_iter()` when `_` would do" @@ -158,6 +162,7 @@ declare_clippy_lint! { /// .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub ITER_NEXT_LOOP, correctness, "for-looping over `_.next()` which is probably not intended" @@ -201,6 +206,7 @@ declare_clippy_lint! { /// // .. /// } /// ``` + #[clippy::version = "1.45.0"] pub FOR_LOOPS_OVER_FALLIBLES, suspicious, "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`" @@ -233,6 +239,7 @@ declare_clippy_lint! { /// // .. do something with x /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub WHILE_LET_LOOP, complexity, "`loop { if let { ... } else break }`, which can be written as a `while let` loop" @@ -254,6 +261,7 @@ declare_clippy_lint! { /// // should be /// let len = iterator.count(); /// ``` + #[clippy::version = "1.30.0"] pub NEEDLESS_COLLECT, perf, "collecting an iterator when collect is not needed" @@ -284,6 +292,7 @@ declare_clippy_lint! { /// # fn bar(bar: usize, baz: usize) {} /// for (i, item) in v.iter().enumerate() { bar(i, *item); } /// ``` + #[clippy::version = "pre 1.29.0"] pub EXPLICIT_COUNTER_LOOP, complexity, "for-looping with an explicit counter when `_.enumerate()` would do" @@ -317,6 +326,7 @@ declare_clippy_lint! { /// ```no_run /// loop {} /// ``` + #[clippy::version = "pre 1.29.0"] pub EMPTY_LOOP, suspicious, "empty `loop {}`, which should block or sleep" @@ -336,6 +346,7 @@ declare_clippy_lint! { /// .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub WHILE_LET_ON_ITERATOR, style, "using a `while let` loop instead of a for loop on an iterator" @@ -364,6 +375,7 @@ declare_clippy_lint! { /// .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub FOR_KV_MAP, style, "looping on a map using `iter` when `keys` or `values` would do" @@ -385,6 +397,7 @@ declare_clippy_lint! { /// break; /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEVER_LOOP, correctness, "any loop that will always `break` or `return`" @@ -420,6 +433,7 @@ declare_clippy_lint! { /// println!("{}", i); // prints numbers from 0 to 42, not 0 to 21 /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MUT_RANGE_BOUND, suspicious, "for loop over a range where one of the bounds is a mutable variable" @@ -446,6 +460,7 @@ declare_clippy_lint! { /// println!("let me loop forever!"); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub WHILE_IMMUTABLE_CONDITION, correctness, "variables used within while expression are not mutated in the body" @@ -480,6 +495,7 @@ declare_clippy_lint! { /// let mut vec: Vec = vec![item1; 20]; /// vec.resize(20 + 30, item2); /// ``` + #[clippy::version = "1.47.0"] pub SAME_ITEM_PUSH, style, "the same item is pushed inside of a for loop" @@ -506,6 +522,7 @@ declare_clippy_lint! { /// let item = &item1; /// println!("{}", item); /// ``` + #[clippy::version = "1.49.0"] pub SINGLE_ELEMENT_LOOP, complexity, "there is no reason to have a single element loop" @@ -537,6 +554,7 @@ declare_clippy_lint! { /// println!("{}", n); /// } /// ``` + #[clippy::version = "1.52.0"] pub MANUAL_FLATTEN, complexity, "for loops over `Option`s or `Result`s with a single expression can be simplified" diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index bccdc3be5e9..262a26951c6 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -24,6 +24,7 @@ declare_clippy_lint! { /// #[macro_use] /// use some_macro; /// ``` + #[clippy::version = "1.44.0"] pub MACRO_USE_IMPORTS, pedantic, "#[macro_use] is no longer needed" diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 23b3ba2296e..fad8fa467d4 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// main(); /// } /// ``` + #[clippy::version = "1.38.0"] pub MAIN_RECURSION, style, "recursion using the entrypoint" diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index e55aa3f1850..ed3166086f7 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// let sad_people: Vec<&str> = vec![]; /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` + #[clippy::version = "1.57.0"] pub MANUAL_ASSERT, pedantic, "`panic!` and only a `panic!` in `if`-then statement" diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index b632af455f8..86819752f90 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// ```rust /// async fn foo() -> i32 { 42 } /// ``` + #[clippy::version = "1.45.0"] pub MANUAL_ASYNC_FN, style, "manual implementations of `async` functions can be simplified using the dedicated syntax" diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 96df3d0a490..cf5dabd9462 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// ```rust /// Some(0).map(|x| x + 1); /// ``` + #[clippy::version = "1.52.0"] pub MANUAL_MAP, style, "reimplementation of `map`" diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 335ea001ee4..63a72d4fdde 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -52,6 +52,7 @@ declare_clippy_lint! { /// #[non_exhaustive] /// struct T(pub i32, pub i32); /// ``` + #[clippy::version = "1.45.0"] pub MANUAL_NON_EXHAUSTIVE, style, "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index cf641d0ce86..b60e2dc366b 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// let foo: Option = None; /// foo.ok_or("error"); /// ``` + #[clippy::version = "1.49.0"] pub MANUAL_OK_OR, pedantic, "finds patterns that can be encoded more concisely with `Option::ok_or`" diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 4e040508b6b..f8e28f1671f 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -42,6 +42,7 @@ declare_clippy_lint! { /// assert_eq!(end.to_uppercase(), "WORLD!"); /// } /// ``` + #[clippy::version = "1.48.0"] pub MANUAL_STRIP, complexity, "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing" diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 42478e3416e..aac3c6e0de2 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// let foo: Option = None; /// foo.unwrap_or(1); /// ``` + #[clippy::version = "1.49.0"] pub MANUAL_UNWRAP_OR, complexity, "finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`" diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 7db5c7e52ea..c2b78e21861 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -37,6 +37,7 @@ declare_clippy_lint! { /// let y = x.iter(); /// let z = y.cloned(); /// ``` + #[clippy::version = "pre 1.29.0"] pub MAP_CLONE, style, "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 82d3732326e..61f21d532c5 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -97,6 +97,7 @@ declare_clippy_lint! { /// }) /// } /// ``` + #[clippy::version = "1.48.0"] pub MAP_ERR_IGNORE, restriction, "`map_err` should not ignore the original error" diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 40de9ffcd4e..a84de3e079b 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -47,6 +47,7 @@ declare_clippy_lint! { /// log_err_msg(format_msg(msg)); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub OPTION_MAP_UNIT_FN, complexity, "using `option.map(f)`, where `f` is a function or closure that returns `()`" @@ -87,6 +88,7 @@ declare_clippy_lint! { /// log_err_msg(format_msg(msg)); /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub RESULT_MAP_UNIT_FN, complexity, "using `result.map(f)`, where `f` is a function or closure that returns `()`" diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 552c9a58897..583b577ffe2 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// _ => {}, /// } /// ``` + #[clippy::version = "1.45.0"] pub MATCH_ON_VEC_ITEMS, pedantic, "matching on vector elements can panic" diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index ecf6ad316a4..b1839f00aae 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// vec.push(value) /// } /// ``` + #[clippy::version = "1.57.0"] pub MATCH_RESULT_OK, style, "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead" diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs index f501593c518..3316ebf4051 100644 --- a/clippy_lints/src/match_str_case_mismatch.rs +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// _ => {}, /// } /// ``` + #[clippy::version = "1.58.0"] pub MATCH_STR_CASE_MISMATCH, correctness, "creation of a case altering match expression with non-compliant arms" diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index e4e533fa71a..74765a1a1de 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -57,6 +57,7 @@ declare_clippy_lint! { /// bar(foo); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub SINGLE_MATCH, style, "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`" @@ -98,6 +99,7 @@ declare_clippy_lint! { /// bar(&other_ref); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub SINGLE_MATCH_ELSE, pedantic, "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern" @@ -129,6 +131,7 @@ declare_clippy_lint! { /// _ => frob(x), /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MATCH_REF_PATS, style, "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression" @@ -163,6 +166,7 @@ declare_clippy_lint! { /// bar(); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MATCH_BOOL, pedantic, "a `match` on a boolean expression instead of an `if..else` block" @@ -185,6 +189,7 @@ declare_clippy_lint! { /// _ => (), /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MATCH_OVERLAPPING_ARM, style, "a `match` with overlapping arms" @@ -207,6 +212,7 @@ declare_clippy_lint! { /// Err(_) => panic!("err"), /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MATCH_WILD_ERR_ARM, pedantic, "a `match` with `Err(_)` arm and take drastic actions" @@ -233,6 +239,7 @@ declare_clippy_lint! { /// // Good /// let r: Option<&()> = x.as_ref(); /// ``` + #[clippy::version = "pre 1.29.0"] pub MATCH_AS_REF, complexity, "a `match` on an Option value instead of using `as_ref()` or `as_mut`" @@ -265,6 +272,7 @@ declare_clippy_lint! { /// Foo::B(_) => {}, /// } /// ``` + #[clippy::version = "1.34.0"] pub WILDCARD_ENUM_MATCH_ARM, restriction, "a wildcard enum match arm using `_`" @@ -299,6 +307,7 @@ declare_clippy_lint! { /// Foo::C => {}, /// } /// ``` + #[clippy::version = "1.45.0"] pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS, pedantic, "a wildcard enum match for a single variant" @@ -326,6 +335,7 @@ declare_clippy_lint! { /// _ => {}, /// } /// ``` + #[clippy::version = "1.42.0"] pub WILDCARD_IN_OR_PATTERNS, complexity, "a wildcard pattern used with others patterns in same match arm" @@ -361,6 +371,7 @@ declare_clippy_lint! { /// let wrapper = Wrapper::Data(42); /// let Wrapper::Data(data) = wrapper; /// ``` + #[clippy::version = "pre 1.29.0"] pub INFALLIBLE_DESTRUCTURING_MATCH, style, "a `match` statement with a single infallible arm instead of a `let`" @@ -392,6 +403,7 @@ declare_clippy_lint! { /// // Good /// let (c, d) = (a, b); /// ``` + #[clippy::version = "1.43.0"] pub MATCH_SINGLE_BINDING, complexity, "a match with a single binding instead of using `let` statement" @@ -422,6 +434,7 @@ declare_clippy_lint! { /// _ => {}, /// } /// ``` + #[clippy::version = "1.43.0"] pub REST_PAT_IN_FULLY_BOUND_STRUCTS, restriction, "a match on a struct that binds all fields but still uses the wildcard pattern" @@ -477,6 +490,7 @@ declare_clippy_lint! { /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {} /// Ok::(42).is_ok(); /// ``` + #[clippy::version = "1.31.0"] pub REDUNDANT_PATTERN_MATCHING, style, "use the proper utility function avoiding an `if let`" @@ -513,6 +527,7 @@ declare_clippy_lint! { /// // Good /// let a = matches!(x, Some(0)); /// ``` + #[clippy::version = "1.47.0"] pub MATCH_LIKE_MATCHES_MACRO, style, "a match that could be written with the matches! macro" @@ -557,6 +572,7 @@ declare_clippy_lint! { /// Quz => quz(), /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MATCH_SAME_ARMS, pedantic, "`match` with identical arm bodies" diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index eb437dc47af..5ffcfd4d264 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -19,6 +19,7 @@ declare_clippy_lint! { /// # use std::rc::Rc; /// mem::forget(Rc::new(55)) /// ``` + #[clippy::version = "pre 1.29.0"] pub MEM_FORGET, restriction, "`mem::forget` usage on `Drop` types, likely to cause memory leaks" diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index cf721fc65db..7fc39f17232 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// let mut an_option = Some(0); /// let taken = an_option.take(); /// ``` + #[clippy::version = "1.31.0"] pub MEM_REPLACE_OPTION_WITH_NONE, style, "replacing an `Option` with `None` instead of `take()`" @@ -66,6 +67,7 @@ declare_clippy_lint! { /// The [take_mut](https://docs.rs/take_mut) crate offers a sound solution, /// at the cost of either lazily creating a replacement value or aborting /// on panic, to ensure that the uninitialized value cannot be observed. + #[clippy::version = "1.39.0"] pub MEM_REPLACE_WITH_UNINIT, correctness, "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`" @@ -90,6 +92,7 @@ declare_clippy_lint! { /// let mut text = String::from("foo"); /// let taken = std::mem::take(&mut text); /// ``` + #[clippy::version = "1.42.0"] pub MEM_REPLACE_WITH_DEFAULT, style, "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6c4272f9e65..5cb849a56bc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -99,6 +99,7 @@ declare_clippy_lint! { /// ```rust /// [1, 2, 3].iter().copied(); /// ``` + #[clippy::version = "1.53.0"] pub CLONED_INSTEAD_OF_COPIED, pedantic, "used `cloned` where `copied` could be used instead" @@ -121,6 +122,7 @@ declare_clippy_lint! { /// ```rust /// let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); /// ``` + #[clippy::version = "1.53.0"] pub FLAT_MAP_OPTION, pedantic, "used `flat_map` where `filter_map` could be used instead" @@ -166,6 +168,7 @@ declare_clippy_lint! { /// // Good /// res.expect("more helpful message"); /// ``` + #[clippy::version = "1.45.0"] pub UNWRAP_USED, restriction, "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`" @@ -208,6 +211,7 @@ declare_clippy_lint! { /// res?; /// # Ok::<(), ()>(()) /// ``` + #[clippy::version = "1.45.0"] pub EXPECT_USED, restriction, "using `.expect()` on `Result` or `Option`, which might be better handled" @@ -237,6 +241,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub SHOULD_IMPLEMENT_TRAIT, style, "defining a method that should be implementing a std trait" @@ -284,6 +289,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub WRONG_SELF_CONVENTION, style, "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention" @@ -310,6 +316,7 @@ declare_clippy_lint! { /// // Good /// x.expect("why did I do this again?"); /// ``` + #[clippy::version = "pre 1.29.0"] pub OK_EXPECT, style, "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result" @@ -335,6 +342,7 @@ declare_clippy_lint! { /// // Good /// x.unwrap_or_default(); /// ``` + #[clippy::version = "1.56.0"] pub UNWRAP_OR_ELSE_DEFAULT, style, "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`" @@ -375,6 +383,7 @@ declare_clippy_lint! { /// // Good /// x.map_or_else(some_function, |a| a + 1); /// ``` + #[clippy::version = "1.45.0"] pub MAP_UNWRAP_OR, pedantic, "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`" @@ -401,6 +410,7 @@ declare_clippy_lint! { /// // Good /// opt.and_then(|a| Some(a + 1)); /// ``` + #[clippy::version = "pre 1.29.0"] pub OPTION_MAP_OR_NONE, style, "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`" @@ -426,6 +436,7 @@ declare_clippy_lint! { /// # let r: Result = Ok(1); /// assert_eq!(Some(1), r.ok()); /// ``` + #[clippy::version = "1.44.0"] pub RESULT_MAP_OR_INTO_OPTION, style, "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`" @@ -458,6 +469,7 @@ declare_clippy_lint! { /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 }); /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 }); /// ``` + #[clippy::version = "1.45.0"] pub BIND_INSTEAD_OF_MAP, complexity, "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`" @@ -481,6 +493,7 @@ declare_clippy_lint! { /// # let vec = vec![1]; /// vec.iter().find(|x| **x == 0); /// ``` + #[clippy::version = "pre 1.29.0"] pub FILTER_NEXT, complexity, "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`" @@ -504,6 +517,7 @@ declare_clippy_lint! { /// # let vec = vec![1]; /// vec.iter().find(|x| **x != 0); /// ``` + #[clippy::version = "1.42.0"] pub SKIP_WHILE_NEXT, complexity, "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`" @@ -527,6 +541,7 @@ declare_clippy_lint! { /// // Good /// vec.iter().flat_map(|x| x.iter()); /// ``` + #[clippy::version = "1.31.0"] pub MAP_FLATTEN, pedantic, "using combinations of `flatten` and `map` which can usually be written as a single method call" @@ -553,6 +568,7 @@ declare_clippy_lint! { /// ```rust /// (0_i32..10).filter_map(|n| n.checked_add(1)); /// ``` + #[clippy::version = "1.51.0"] pub MANUAL_FILTER_MAP, complexity, "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`" @@ -579,6 +595,7 @@ declare_clippy_lint! { /// ```rust /// (0_i32..10).find_map(|n| n.checked_add(1)); /// ``` + #[clippy::version = "1.51.0"] pub MANUAL_FIND_MAP, complexity, "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`" @@ -601,6 +618,7 @@ declare_clippy_lint! { /// ```rust /// (0..3).find_map(|x| if x == 2 { Some(x) } else { None }); /// ``` + #[clippy::version = "1.36.0"] pub FILTER_MAP_NEXT, pedantic, "using combination of `filter_map` and `next` which can usually be written as a single method call" @@ -623,6 +641,7 @@ declare_clippy_lint! { /// # let iter = vec![vec![0]].into_iter(); /// iter.flatten(); /// ``` + #[clippy::version = "1.39.0"] pub FLAT_MAP_IDENTITY, complexity, "call to `flat_map` where `flatten` is sufficient" @@ -652,6 +671,7 @@ declare_clippy_lint! { /// /// let _ = !"hello world".contains("world"); /// ``` + #[clippy::version = "pre 1.29.0"] pub SEARCH_IS_SOME, complexity, "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)" @@ -676,6 +696,7 @@ declare_clippy_lint! { /// let name = "foo"; /// if name.starts_with('_') {}; /// ``` + #[clippy::version = "pre 1.29.0"] pub CHARS_NEXT_CMP, style, "using `.chars().next()` to check if a string starts with a char" @@ -710,6 +731,7 @@ declare_clippy_lint! { /// # let foo = Some(String::new()); /// foo.unwrap_or_default(); /// ``` + #[clippy::version = "pre 1.29.0"] pub OR_FUN_CALL, perf, "using any `*or` method with a function call, which suggests `*or_else`" @@ -748,6 +770,7 @@ declare_clippy_lint! { /// # let err_msg = "I'm a teapot"; /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg)); /// ``` + #[clippy::version = "pre 1.29.0"] pub EXPECT_FUN_CALL, perf, "using any `expect` method with a function call" @@ -765,6 +788,7 @@ declare_clippy_lint! { /// ```rust /// 42u64.clone(); /// ``` + #[clippy::version = "pre 1.29.0"] pub CLONE_ON_COPY, complexity, "using `clone` on a `Copy` type" @@ -792,6 +816,7 @@ declare_clippy_lint! { /// // Good /// Rc::clone(&x); /// ``` + #[clippy::version = "pre 1.29.0"] pub CLONE_ON_REF_PTR, restriction, "using 'clone' on a ref-counted pointer" @@ -814,6 +839,7 @@ declare_clippy_lint! { /// println!("{:p} {:p}", *y, z); // prints out the same pointer /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub CLONE_DOUBLE_REF, correctness, "using `clone` on `&&T`" @@ -837,6 +863,7 @@ declare_clippy_lint! { /// // OK, the specialized impl is used /// ["foo", "bar"].iter().map(|&s| s.to_string()); /// ``` + #[clippy::version = "1.40.0"] pub INEFFICIENT_TO_STRING, pedantic, "using `to_string` on `&&T` where `T: ToString`" @@ -898,6 +925,7 @@ declare_clippy_lint! { /// fn new() -> Self; /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEW_RET_NO_SELF, style, "not returning type containing `Self` in a `new` method" @@ -922,6 +950,7 @@ declare_clippy_lint! { /// /// // Good /// _.split('x'); + #[clippy::version = "pre 1.29.0"] pub SINGLE_CHAR_PATTERN, perf, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" @@ -941,6 +970,7 @@ declare_clippy_lint! { /// //.. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub ITERATOR_STEP_BY_ZERO, correctness, "using `Iterator::step_by(0)`, which will panic at runtime" @@ -962,6 +992,7 @@ declare_clippy_lint! { /// ```rust /// let _ = std::iter::empty::>().flatten(); /// ``` + #[clippy::version = "1.53.0"] pub OPTION_FILTER_MAP, complexity, "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation" @@ -989,6 +1020,7 @@ declare_clippy_lint! { /// # s.insert(1); /// let x = s.iter().next(); /// ``` + #[clippy::version = "1.42.0"] pub ITER_NTH_ZERO, style, "replace `iter.nth(0)` with `iter.next()`" @@ -1015,6 +1047,7 @@ declare_clippy_lint! { /// let bad_vec = some_vec.get(3); /// let bad_slice = &some_vec[..].get(3); /// ``` + #[clippy::version = "pre 1.29.0"] pub ITER_NTH, perf, "using `.iter().nth()` on a standard library type with O(1) element access" @@ -1039,6 +1072,7 @@ declare_clippy_lint! { /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); /// ``` + #[clippy::version = "pre 1.29.0"] pub ITER_SKIP_NEXT, style, "using `.skip(x).next()` on an iterator" @@ -1075,6 +1109,7 @@ declare_clippy_lint! { /// let last = some_vec[3]; /// some_vec[0] = 1; /// ``` + #[clippy::version = "pre 1.29.0"] pub GET_UNWRAP, restriction, "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead" @@ -1098,6 +1133,7 @@ declare_clippy_lint! { /// // Good /// a.append(&mut b); /// ``` + #[clippy::version = "1.55.0"] pub EXTEND_WITH_DRAIN, perf, "using vec.append(&mut vec) to move the full range of a vecor to another" @@ -1127,6 +1163,7 @@ declare_clippy_lint! { /// s.push_str(abc); /// s.push_str(&def); /// ``` + #[clippy::version = "pre 1.29.0"] pub STRING_EXTEND_CHARS, style, "using `x.extend(s.chars())` where s is a `&str` or `String`" @@ -1150,6 +1187,7 @@ declare_clippy_lint! { /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec = s.to_vec(); /// ``` + #[clippy::version = "pre 1.29.0"] pub ITER_CLONED_COLLECT, style, "using `.cloned().collect()` on slice to create a `Vec`" @@ -1174,6 +1212,7 @@ declare_clippy_lint! { /// // Good /// name.ends_with('_') || name.ends_with('-'); /// ``` + #[clippy::version = "pre 1.29.0"] pub CHARS_LAST_CMP, style, "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char" @@ -1199,6 +1238,7 @@ declare_clippy_lint! { /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x); /// ``` + #[clippy::version = "pre 1.29.0"] pub USELESS_ASREF, complexity, "using `as_ref` where the types before and after the call are the same" @@ -1221,6 +1261,7 @@ declare_clippy_lint! { /// ```rust /// let _ = (0..3).any(|x| x > 2); /// ``` + #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_FOLD, style, "using `fold` when a more succinct alternative exists" @@ -1250,6 +1291,7 @@ declare_clippy_lint! { /// // As there is no conditional check on the argument this could be written as: /// let _ = (0..4).map(|x| x + 1); /// ``` + #[clippy::version = "1.31.0"] pub UNNECESSARY_FILTER_MAP, complexity, "using `filter_map` when a more succinct alternative exists" @@ -1273,6 +1315,7 @@ declare_clippy_lint! { /// // Good /// let _ = (&vec![3, 4, 5]).iter(); /// ``` + #[clippy::version = "1.32.0"] pub INTO_ITER_ON_REF, style, "using `.into_iter()` on a reference" @@ -1292,6 +1335,7 @@ declare_clippy_lint! { /// ```rust /// let _ = (0..3).map(|x| x + 2).count(); /// ``` + #[clippy::version = "1.39.0"] pub SUSPICIOUS_MAP, suspicious, "suspicious usage of map" @@ -1326,6 +1370,7 @@ declare_clippy_lint! { /// MaybeUninit::uninit().assume_init() /// }; /// ``` + #[clippy::version = "1.39.0"] pub UNINIT_ASSUMED_INIT, correctness, "`MaybeUninit::uninit().assume_init()`" @@ -1354,6 +1399,7 @@ declare_clippy_lint! { /// let add = x.saturating_add(y); /// let sub = x.saturating_sub(y); /// ``` + #[clippy::version = "1.39.0"] pub MANUAL_SATURATING_ARITHMETIC, style, "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`" @@ -1371,6 +1417,7 @@ declare_clippy_lint! { /// ```rust /// unsafe { (&() as *const ()).offset(1) }; /// ``` + #[clippy::version = "1.41.0"] pub ZST_OFFSET, correctness, "Check for offset calculations on raw pointers to zero-sized types" @@ -1412,6 +1459,7 @@ declare_clippy_lint! { /// # Ok::<_, std::io::Error>(()) /// # }; /// ``` + #[clippy::version = "1.42.0"] pub FILETYPE_IS_FILE, restriction, "`FileType::is_file` is not recommended to test for readable file type" @@ -1437,6 +1485,7 @@ declare_clippy_lint! { /// opt.as_deref() /// # ; /// ``` + #[clippy::version = "1.42.0"] pub OPTION_AS_REF_DEREF, complexity, "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`" @@ -1463,6 +1512,7 @@ declare_clippy_lint! { /// a.get(2); /// b.get(0); /// ``` + #[clippy::version = "1.46.0"] pub ITER_NEXT_SLICE, style, "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`" @@ -1488,6 +1538,7 @@ declare_clippy_lint! { /// string.insert(0, 'R'); /// string.push('R'); /// ``` + #[clippy::version = "1.49.0"] pub SINGLE_CHAR_ADD_STR, style, "`push_str()` or `insert_str()` used with a single-character string literal as parameter" @@ -1526,6 +1577,7 @@ declare_clippy_lint! { /// /// opt.unwrap_or(42); /// ``` + #[clippy::version = "1.48.0"] pub UNNECESSARY_LAZY_EVALUATIONS, style, "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation" @@ -1546,6 +1598,7 @@ declare_clippy_lint! { /// ```rust /// (0..3).try_for_each(|t| Err(t)); /// ``` + #[clippy::version = "1.49.0"] pub MAP_COLLECT_RESULT_UNIT, style, "using `.map(_).collect::()`, which can be replaced with `try_for_each`" @@ -1578,6 +1631,7 @@ declare_clippy_lint! { /// /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` + #[clippy::version = "1.49.0"] pub FROM_ITER_INSTEAD_OF_COLLECT, pedantic, "use `.collect()` instead of `::from_iter()`" @@ -1607,6 +1661,7 @@ declare_clippy_lint! { /// assert!(x >= 0); /// }); /// ``` + #[clippy::version = "1.51.0"] pub INSPECT_FOR_EACH, complexity, "using `.inspect().for_each()`, which can be replaced with `.for_each()`" @@ -1629,6 +1684,7 @@ declare_clippy_lint! { /// # let iter = vec![Some(1)].into_iter(); /// iter.flatten(); /// ``` + #[clippy::version = "1.52.0"] pub FILTER_MAP_IDENTITY, complexity, "call to `filter_map` where `flatten` is sufficient" @@ -1651,6 +1707,7 @@ declare_clippy_lint! { /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); /// ``` + #[clippy::version = "1.52.0"] pub MAP_IDENTITY, complexity, "using iterator.map(|x| x)" @@ -1672,6 +1729,7 @@ declare_clippy_lint! { /// // Good /// let _ = "Hello".as_bytes().get(3); /// ``` + #[clippy::version = "1.52.0"] pub BYTES_NTH, style, "replace `.bytes().nth()` with `.as_bytes().get()`" @@ -1697,6 +1755,7 @@ declare_clippy_lint! { /// let b = a.clone(); /// let c = a.clone(); /// ``` + #[clippy::version = "1.52.0"] pub IMPLICIT_CLONE, pedantic, "implicitly cloning a value by invoking a function on its dereferenced type" @@ -1722,6 +1781,7 @@ declare_clippy_lint! { /// let _ = some_vec.len(); /// let _ = &some_vec[..].len(); /// ``` + #[clippy::version = "1.52.0"] pub ITER_COUNT, complexity, "replace `.iter().count()` with `.len()`" @@ -1751,6 +1811,7 @@ declare_clippy_lint! { /// // use x /// } /// ``` + #[clippy::version = "1.54.0"] pub SUSPICIOUS_SPLITN, correctness, "checks for `.splitn(0, ..)` and `.splitn(1, ..)`" @@ -1771,6 +1832,7 @@ declare_clippy_lint! { /// // Good /// let x: String = "x".repeat(10); /// ``` + #[clippy::version = "1.54.0"] pub MANUAL_STR_REPEAT, perf, "manual implementation of `str::repeat`" @@ -1793,6 +1855,7 @@ declare_clippy_lint! { /// let (key, value) = _.split_once('=')?; /// let value = _.split_once('=')?.1; /// ``` + #[clippy::version = "1.57.0"] pub MANUAL_SPLIT_ONCE, complexity, "replace `.splitn(2, pat)` with `.split_once(pat)`" diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index dc2dd45e4ed..a6450aec4f7 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// ``` /// It will always be equal to `0`. Probably the author meant to clamp the value /// between 0 and 100, but has erroneously swapped `min` and `max`. + #[clippy::version = "pre 1.29.0"] pub MIN_MAX, correctness, "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant" diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 0f32cd9164e..a93537104bf 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -56,6 +56,7 @@ declare_clippy_lint! { /// true /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub TOPLEVEL_REF_ARG, style, "an entire binding declared as `ref`, in a function argument or a `let` statement" @@ -79,6 +80,7 @@ declare_clippy_lint! { /// // Good /// if x.is_nan() { } /// ``` + #[clippy::version = "pre 1.29.0"] pub CMP_NAN, correctness, "comparisons to `NAN`, which will always return false, probably not intended" @@ -112,6 +114,7 @@ declare_clippy_lint! { /// if (y - 1.23f64).abs() < error_margin { } /// if (y - x).abs() > error_margin { } /// ``` + #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP, pedantic, "using `==` or `!=` on float values instead of comparing difference with an epsilon" @@ -139,6 +142,7 @@ declare_clippy_lint! { /// # let y = String::from("foo"); /// if x == y {} /// ``` + #[clippy::version = "pre 1.29.0"] pub CMP_OWNED, perf, "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`" @@ -162,6 +166,7 @@ declare_clippy_lint! { /// let a = x % 1; /// let a = x % -1; /// ``` + #[clippy::version = "pre 1.29.0"] pub MODULO_ONE, correctness, "taking a number modulo +/-1, which can either panic/overflow or always returns 0" @@ -187,6 +192,7 @@ declare_clippy_lint! { /// let y = _x + 1; // Here we are using `_x`, even though it has a leading /// // underscore. We should rename `_x` to `x` /// ``` + #[clippy::version = "pre 1.29.0"] pub USED_UNDERSCORE_BINDING, pedantic, "using a binding which is prefixed with an underscore" @@ -207,6 +213,7 @@ declare_clippy_lint! { /// ```rust,ignore /// f() && g(); // We should write `if f() { g(); }`. /// ``` + #[clippy::version = "pre 1.29.0"] pub SHORT_CIRCUIT_STATEMENT, complexity, "using a short circuit boolean condition as a statement" @@ -228,6 +235,7 @@ declare_clippy_lint! { /// // Good /// let a = std::ptr::null::(); /// ``` + #[clippy::version = "pre 1.29.0"] pub ZERO_PTR, style, "using `0 as *{const, mut} T`" @@ -259,6 +267,7 @@ declare_clippy_lint! { /// // let error_margin = std::f64::EPSILON; /// if (x - ONE).abs() < error_margin { } /// ``` + #[clippy::version = "pre 1.29.0"] pub FLOAT_CMP_CONST, restriction, "using `==` or `!=` on float constants instead of comparing difference with an epsilon" diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 7c3f5f22ade..4b56eaebaea 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -46,6 +46,7 @@ declare_clippy_lint! { /// Foo { .. } => {}, /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub UNNEEDED_FIELD_PATTERN, restriction, "struct fields bound to a wildcard instead of using `..`" @@ -67,6 +68,7 @@ declare_clippy_lint! { /// // Good /// fn bar(a: i32, _b: i32) {} /// ``` + #[clippy::version = "pre 1.29.0"] pub DUPLICATE_UNDERSCORE_ARGUMENT, style, "function arguments having names which only differ by an underscore" @@ -85,6 +87,7 @@ declare_clippy_lint! { /// let mut x = 3; /// --x; /// ``` + #[clippy::version = "pre 1.29.0"] pub DOUBLE_NEG, style, "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++" @@ -106,6 +109,7 @@ declare_clippy_lint! { /// // Good /// let y = 0x1A9BACD; /// ``` + #[clippy::version = "pre 1.29.0"] pub MIXED_CASE_HEX_LITERALS, style, "hex literals whose letter digits are not consistently upper- or lowercased" @@ -129,6 +133,7 @@ declare_clippy_lint! { /// // Good /// let y = 123832_i32; /// ``` + #[clippy::version = "pre 1.29.0"] pub UNSEPARATED_LITERAL_SUFFIX, restriction, "literals whose suffix is not separated by an underscore" @@ -189,6 +194,7 @@ declare_clippy_lint! { /// ``` /// /// prints `83` (as `83 == 0o123` while `123 == 0o173`). + #[clippy::version = "pre 1.29.0"] pub ZERO_PREFIXED_LITERAL, complexity, "integer literals starting with `0`" @@ -210,6 +216,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub BUILTIN_TYPE_SHADOW, style, "shadowing a builtin type" @@ -239,6 +246,7 @@ declare_clippy_lint! { /// y => (), /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub REDUNDANT_PATTERN, style, "using `name @ _` in a pattern" @@ -273,6 +281,7 @@ declare_clippy_lint! { /// _ => (), /// } /// ``` + #[clippy::version = "1.40.0"] pub UNNEEDED_WILDCARD_PATTERN, complexity, "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)" diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 5b2584d43a1..a8d41050856 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -63,6 +63,7 @@ declare_clippy_lint! { /// } /// # } /// ``` + #[clippy::version = "1.34.0"] pub MISSING_CONST_FOR_FN, nursery, "Lint functions definitions that could be made `const fn`" diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 6920b4f72ea..db6aab0671b 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// allowed-by-default lint for /// public members, but has no way to enforce documentation of private items. /// This lint fixes that. + #[clippy::version = "pre 1.29.0"] pub MISSING_DOCS_IN_PRIVATE_ITEMS, restriction, "detects missing documentation for public and private members" diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 448bfc2fdd6..68d49e0f150 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// ```rust,ignore /// use serde_json::Value as JsonValue; /// ``` + #[clippy::version = "1.55.0"] pub MISSING_ENFORCED_IMPORT_RENAMES, restriction, "enforce import renames" diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index b593c747498..ac2f16b49e3 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -52,6 +52,7 @@ declare_clippy_lint! { /// fn def_bar() {} // missing #[inline] /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub MISSING_INLINE_IN_PUBLIC_ITEMS, restriction, "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)" diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index d41b5474564..3b65f80cba2 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// stuff.rs /// lib.rs /// ``` + #[clippy::version = "1.57.0"] pub MOD_MODULE_FILES, restriction, "checks that module layout is consistent" @@ -61,6 +62,7 @@ declare_clippy_lint! { /// lib.rs /// ``` + #[clippy::version = "1.57.0"] pub SELF_NAMED_MODULE_FILES, restriction, "checks that module layout is consistent" diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index f45e68233a1..d182a7d5249 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -24,6 +24,7 @@ declare_clippy_lint! { /// ```rust /// let x = -17 % 3; /// ``` + #[clippy::version = "1.42.0"] pub MODULO_ARITHMETIC, restriction, "any modulo arithmetic statement" diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index 816b2f275fb..e45cc86d417 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// ctrlc = "=3.1.0" /// ansi_term = "=0.11.0" /// ``` + #[clippy::version = "pre 1.29.0"] pub MULTIPLE_CRATE_VERSIONS, cargo, "multiple versions of the same crate being used" diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 8476257f086..5fe887a4573 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -72,6 +72,7 @@ declare_clippy_lint! { /// let _: HashSet = HashSet::new(); /// } /// ``` + #[clippy::version = "1.42.0"] pub MUTABLE_KEY_TYPE, suspicious, "Check for mutable `Map`/`Set` key type" diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 7c4cac29ba8..bcbea8f1e66 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -22,6 +22,7 @@ declare_clippy_lint! { /// # let mut y = 1; /// let x = &mut &mut y; /// ``` + #[clippy::version = "pre 1.29.0"] pub MUT_MUT, pedantic, "usage of double-mut refs, e.g., `&mut &mut ...`" diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs index b96fa4774cb..b1e6308d2e1 100644 --- a/clippy_lints/src/mut_mutex_lock.rs +++ b/clippy_lints/src/mut_mutex_lock.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// let value = value_mutex.get_mut().unwrap(); /// *value += 1; /// ``` + #[clippy::version = "1.49.0"] pub MUT_MUTEX_LOCK, style, "`&mut Mutex::lock` does unnecessary locking" diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 8d5d7951fc5..63a1cf7b7d5 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// // Good /// my_vec.push(&value) /// ``` + #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_MUT_PASSED, style, "an argument passed as a mutable reference although the callee only demands an immutable reference" diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index ee50891cc31..fa7274990db 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() } /// debug_assert!(take_a_mut_parameter(&mut 5)); /// ``` + #[clippy::version = "1.40.0"] pub DEBUG_ASSERT_WITH_MUT_CALL, nursery, "mutable arguments in `debug_assert{,_ne,_eq}!`" diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 5feddcbfc61..816377fe65e 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// # use std::sync::atomic::AtomicBool; /// let x = AtomicBool::new(y); /// ``` + #[clippy::version = "pre 1.29.0"] pub MUTEX_ATOMIC, perf, "using a mutex where an atomic value could be used instead" @@ -64,6 +65,7 @@ declare_clippy_lint! { /// # use std::sync::atomic::AtomicUsize; /// let x = AtomicUsize::new(0usize); /// ``` + #[clippy::version = "pre 1.29.0"] pub MUTEX_INTEGER, nursery, "using a mutex for an integer type" diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index c8a8750c2ff..9838d3cad9f 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -52,6 +52,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.47.0"] pub NEEDLESS_ARBITRARY_SELF_TYPE, complexity, "type of `self` parameter is already by default `Self`" diff --git a/clippy_lints/src/needless_bitwise_bool.rs b/clippy_lints/src/needless_bitwise_bool.rs index ad981599473..a8a8d174a82 100644 --- a/clippy_lints/src/needless_bitwise_bool.rs +++ b/clippy_lints/src/needless_bitwise_bool.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// let (x,y) = (true, false); /// if x && !y {} /// ``` + #[clippy::version = "1.54.0"] pub NEEDLESS_BITWISE_BOOL, pedantic, "Boolean expressions that use bitwise rather than lazy operators" diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 91944653500..3709f3948c2 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// ```rust,ignore /// !x /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BOOL, complexity, "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`" @@ -65,6 +66,7 @@ declare_clippy_lint! { /// if x {} /// if !y {} /// ``` + #[clippy::version = "pre 1.29.0"] pub BOOL_COMPARISON, complexity, "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`" diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 085be6650cc..6709fed91bd 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -37,6 +37,7 @@ declare_clippy_lint! { /// let x: &i32 = &5; /// fun(x); /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BORROW, style, "taking a reference that is going to be automatically dereferenced" @@ -63,6 +64,7 @@ declare_clippy_lint! { /// // use `&x` here /// } /// ``` + #[clippy::version = "1.54.0"] pub REF_BINDING_TO_REFERENCE, pedantic, "`ref` binding to a reference" diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 36879eda7c0..0fcc419e722 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// let mut v = Vec::::new(); /// let _ = v.iter_mut().filter(|a| a.is_empty()); /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BORROWED_REFERENCE, complexity, "destructuring a reference and borrowing the inner value" diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 7aa93ed7839..98a3bce1ff3 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -110,6 +110,7 @@ declare_clippy_lint! { /// # break; /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_CONTINUE, pedantic, "`continue` statements that can be replaced by a rearrangement of code" diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 9a6ddc72ce5..0c1da035173 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// println!("{}", elem); /// } /// ``` + #[clippy::version = "1.53.0"] pub NEEDLESS_FOR_EACH, pedantic, "using `for_each` where a `for` loop would be simpler" diff --git a/clippy_lints/src/needless_option_as_deref.rs b/clippy_lints/src/needless_option_as_deref.rs index e88e98e6081..a28b08c33ec 100644 --- a/clippy_lints/src/needless_option_as_deref.rs +++ b/clippy_lints/src/needless_option_as_deref.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// let a = Some(&1); /// let b = a; /// ``` + #[clippy::version = "1.57.0"] pub NEEDLESS_OPTION_AS_DEREF, complexity, "no-op use of `deref` or `deref_mut` method to `Option`." diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 352dc6f8bec..35877d51c0c 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -51,6 +51,7 @@ declare_clippy_lint! { /// assert_eq!(v.len(), 42); /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_PASS_BY_VALUE, pedantic, "functions taking arguments by value, but not consuming them in its body" diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 42e48336e15..3ca933ea8fb 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -53,6 +53,7 @@ declare_clippy_lint! { /// tr.and_then(|t| t.magic) /// } /// ``` + #[clippy::version = "1.51.0"] pub NEEDLESS_QUESTION_MARK, complexity, "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result`." diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 2a33b7392ca..ed315efaa2f 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -40,6 +40,7 @@ declare_clippy_lint! { /// ..zero_point /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_UPDATE, complexity, "using `Foo { ..base }` when there are no missing fields" diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 6ad49b70605..efe31a15441 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// _ => false, /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub NEG_CMP_OP_ON_PARTIAL_ORD, complexity, "The use of negated comparison operators on partially ordered types may produce confusing code." diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 1b15d29439f..cb67fab1740 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// ```ignore /// x * -1 /// ``` + #[clippy::version = "pre 1.29.0"] pub NEG_MULTIPLY, style, "multiplying integers with `-1`" diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 0ac27f1cba2..f0c0c89ca8f 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -45,6 +45,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEW_WITHOUT_DEFAULT, style, "`fn new() -> Self` method without `Default` implementation" diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 6dae8f32043..31134743d02 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -22,6 +22,7 @@ declare_clippy_lint! { /// ```rust /// 0; /// ``` + #[clippy::version = "pre 1.29.0"] pub NO_EFFECT, complexity, "statements with no effect" @@ -44,6 +45,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let _i_serve_no_purpose = 1; /// ``` + #[clippy::version = "1.58.0"] pub NO_EFFECT_UNDERSCORE_BINDING, pedantic, "binding to `_` prefixed variable with no side-effect" @@ -62,6 +64,7 @@ declare_clippy_lint! { /// ```rust,ignore /// compute_array()[0]; /// ``` + #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_OPERATION, complexity, "outer expressions with no effect" diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 2a85a67fa09..df82775d507 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -69,6 +69,7 @@ declare_clippy_lint! { /// STATIC_ATOM.store(9, SeqCst); /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance /// ``` + #[clippy::version = "pre 1.29.0"] pub DECLARE_INTERIOR_MUTABLE_CONST, style, "declaring `const` with interior mutability" @@ -113,6 +114,7 @@ declare_clippy_lint! { /// STATIC_ATOM.store(9, SeqCst); /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance /// ``` + #[clippy::version = "pre 1.29.0"] pub BORROW_INTERIOR_MUTABLE_CONST, style, "referencing `const` with interior mutability" diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 5b254bc8133..1a124e2d3cb 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -24,6 +24,7 @@ declare_clippy_lint! { /// let checked_exp = something; /// let checked_expr = something_else; /// ``` + #[clippy::version = "pre 1.29.0"] pub SIMILAR_NAMES, pedantic, "similarly named items and bindings" @@ -42,6 +43,7 @@ declare_clippy_lint! { /// ```ignore /// let (a, b, c, d, e, f, g) = (...); /// ``` + #[clippy::version = "pre 1.29.0"] pub MANY_SINGLE_CHAR_NAMES, pedantic, "too many single character bindings" @@ -62,6 +64,7 @@ declare_clippy_lint! { /// let ___1 = 1; /// let __1___2 = 11; /// ``` + #[clippy::version = "pre 1.29.0"] pub JUST_UNDERSCORES_AND_DIGITS, style, "unclear name" diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 3b74f69d375..4b57dbc4c41 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// let mut options = OpenOptions::new(); /// options.mode(0o644); /// ``` + #[clippy::version = "1.53.0"] pub NON_OCTAL_UNIX_PERMISSIONS, correctness, "use of non-octal value to set unix file permissions, which will be translated into octal" diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 7ebf84d400f..9c07488bfe6 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -43,6 +43,7 @@ declare_clippy_lint! { /// ``` /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) /// or specify correct bounds on generic type parameters (`T: Send`). + #[clippy::version = "1.57.0"] pub NON_SEND_FIELDS_IN_SEND_TY, suspicious, "there is field that does not implement `Send` in a `Send` struct" diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index bab15217d52..3dcc9e26c9e 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// ```rust /// vec![1, 2, 3]; /// ``` + #[clippy::version = "1.55.0"] pub NONSTANDARD_MACRO_BRACES, nursery, "check consistent use of braces in macro" diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 5752342cf62..2c77100bdcf 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -22,6 +22,7 @@ declare_clippy_lint! { /// /// OpenOptions::new().read(true).truncate(true); /// ``` + #[clippy::version = "pre 1.29.0"] pub NONSENSICAL_OPEN_OPTIONS, correctness, "nonsensical combination of options for opening a file" diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index d7306628030..3f5286ba097 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// ```rust,no_run /// let _ = env!("HOME"); /// ``` + #[clippy::version = "1.43.0"] pub OPTION_ENV_UNWRAP, correctness, "using `option_env!(...).unwrap()` to get environment variable" diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index ed5583799fe..df72f4b0eb2 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -59,6 +59,7 @@ declare_clippy_lint! { /// y*y /// }, |foo| foo); /// ``` + #[clippy::version = "1.47.0"] pub OPTION_IF_LET_ELSE, nursery, "reimplementation of Option::map_or" diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 0f9e5ada3a8..6dabbd48031 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -19,6 +19,7 @@ declare_clippy_lint! { /// # let b = 2; /// a + b < a; /// ``` + #[clippy::version = "pre 1.29.0"] pub OVERFLOW_CHECK_CONDITIONAL, complexity, "overflow checks inspired by C which are likely to panic" diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 583c42b6563..8769c045214 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// Err(String::from("error")) /// } /// ``` + #[clippy::version = "1.48.0"] pub PANIC_IN_RESULT_FN, restriction, "functions of type `Result<..>` that contain `panic!()`, `todo!()`, `unreachable()`, `unimplemented()` or assertion" diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index d8d9081d6f1..edfac824ded 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -17,6 +17,7 @@ declare_clippy_lint! { /// ```no_run /// panic!("even with a good reason"); /// ``` + #[clippy::version = "1.40.0"] pub PANIC, restriction, "usage of the `panic!` macro" @@ -33,6 +34,7 @@ declare_clippy_lint! { /// ```no_run /// unimplemented!(); /// ``` + #[clippy::version = "pre 1.29.0"] pub UNIMPLEMENTED, restriction, "`unimplemented!` should not be present in production code" @@ -49,6 +51,7 @@ declare_clippy_lint! { /// ```no_run /// todo!(); /// ``` + #[clippy::version = "1.40.0"] pub TODO, restriction, "`todo!` should not be present in production code" @@ -65,6 +68,7 @@ declare_clippy_lint! { /// ```no_run /// unreachable!(); /// ``` + #[clippy::version = "1.40.0"] pub UNREACHABLE, restriction, "usage of the `unreachable!` macro" diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 4ec493e5f45..e827cdaae87 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -25,6 +25,7 @@ declare_clippy_lint! { /// fn ne(&self, other: &Foo) -> bool { !(self == other) } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub PARTIALEQ_NE_IMPL, complexity, "re-implementing `PartialEq::ne`" diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 6229b9608b3..3092ab8392a 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -65,6 +65,7 @@ declare_clippy_lint! { /// // Better /// fn foo(v: u32) {} /// ``` + #[clippy::version = "pre 1.29.0"] pub TRIVIALLY_COPY_PASS_BY_REF, pedantic, "functions taking small copyable arguments by reference" @@ -98,6 +99,7 @@ declare_clippy_lint! { /// // Good /// fn foo(v: &TooLarge) {} /// ``` + #[clippy::version = "1.49.0"] pub LARGE_TYPES_PASSED_BY_VALUE, pedantic, "functions taking large arguments by value" diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 3df7a72d295..8ebee9bd04d 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// x.push("bar"); /// assert_eq!(x, PathBuf::from("/foo/bar")); /// ``` + #[clippy::version = "1.36.0"] pub PATH_BUF_PUSH_OVERWRITE, nursery, "calling `push` with file system root on `PathBuf` can overwrite it" diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index e7bc2446590..3e7eef4edac 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -77,6 +77,7 @@ declare_clippy_lint! { /// *a += b; /// } /// ``` + #[clippy::version = "1.47.0"] pub PATTERN_TYPE_MISMATCH, restriction, "type of pattern does not match the expression type" diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 1a8da00d9d6..cc0533c9f5d 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -42,6 +42,7 @@ declare_clippy_lint! { /// ### Example /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 + #[clippy::version = "pre 1.29.0"] pub PRECEDENCE, complexity, "operations where precedence may be unclear" diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 8a36e20fc97..c08a19d520b 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -70,6 +70,7 @@ declare_clippy_lint! { /// // Good /// fn foo(&[u32]) { .. } /// ``` + #[clippy::version = "pre 1.29.0"] pub PTR_ARG, style, "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively" @@ -96,6 +97,7 @@ declare_clippy_lint! { /// .. /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub CMP_NULL, style, "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead" @@ -121,6 +123,7 @@ declare_clippy_lint! { /// ```ignore /// fn foo(&Foo) -> &mut Bar { .. } /// ``` + #[clippy::version = "pre 1.29.0"] pub MUT_FROM_REF, correctness, "fns that create mutable refs from immutable ref args" @@ -143,6 +146,7 @@ declare_clippy_lint! { /// // Good /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } /// ``` + #[clippy::version = "1.53.0"] pub INVALID_NULL_PTR_USAGE, correctness, "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead" diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 2df34d6d9b9..3c126fc1ca6 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// /// assert!(std::ptr::eq(a, b)); /// ``` + #[clippy::version = "1.49.0"] pub PTR_EQ, style, "use `std::ptr::eq` when comparing raw pointers" diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index cfb5287c667..964564b5794 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -38,6 +38,7 @@ declare_clippy_lint! { /// ptr.add(offset); /// } /// ``` + #[clippy::version = "1.30.0"] pub PTR_OFFSET_WITH_CAST, complexity, "unneeded pointer offset cast" diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f63ef163bcb..a5531993ee6 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// ```ignore /// option?; /// ``` + #[clippy::version = "pre 1.29.0"] pub QUESTION_MARK, style, "checks for expressions that could be replaced by the question mark operator" diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 87364a88ed0..09c64485bbb 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// # let x = vec![1]; /// x.iter().enumerate(); /// ``` + #[clippy::version = "pre 1.29.0"] pub RANGE_ZIP_WITH_LEN, complexity, "zipping iterator with a range when `enumerate()` would do" @@ -72,6 +73,7 @@ declare_clippy_lint! { /// ```rust,ignore /// for x..=y { .. } /// ``` + #[clippy::version = "pre 1.29.0"] pub RANGE_PLUS_ONE, pedantic, "`x..(y+1)` reads better as `x..=y`" @@ -100,6 +102,7 @@ declare_clippy_lint! { /// ```rust,ignore /// for x..y { .. } /// ``` + #[clippy::version = "pre 1.29.0"] pub RANGE_MINUS_ONE, pedantic, "`x..=(y-1)` reads better as `x..y`" @@ -132,6 +135,7 @@ declare_clippy_lint! { /// let sub = &arr[1..3]; /// } /// ``` + #[clippy::version = "1.45.0"] pub REVERSED_EMPTY_RANGES, correctness, "reversing the limits of range expressions, resulting in empty ranges" @@ -158,6 +162,7 @@ declare_clippy_lint! { ///# let x = 6; /// assert!((3..8).contains(&x)); /// ``` + #[clippy::version = "1.49.0"] pub MANUAL_RANGE_CONTAINS, style, "manually reimplementing {`Range`, `RangeInclusive`}`::contains`" diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index f7711b6fe94..1a2c86a7686 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -62,6 +62,7 @@ declare_clippy_lint! { /// /// Path::new("/a/b").join("c").to_path_buf(); /// ``` + #[clippy::version = "1.32.0"] pub REDUNDANT_CLONE, perf, "`clone()` of an owned value that is going to be dropped immediately" diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 90e3c3f4b3e..0de282542fc 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// // Good /// let a = 42 /// ``` + #[clippy::version = "pre 1.29.0"] pub REDUNDANT_CLOSURE_CALL, complexity, "throwaway closures called in the expression they are defined" diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 68b256d2944..93dbe936d58 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// print!("Moving on..."); /// } /// ``` + #[clippy::version = "1.50.0"] pub REDUNDANT_ELSE, pedantic, "`else` branch that can be removed without changing semantics" diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 47df4917510..0dea4a784b2 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// ```ignore /// let foo = Foo { bar }; /// ``` + #[clippy::version = "pre 1.29.0"] pub REDUNDANT_FIELD_NAMES, style, "checks for fields in struct literals where shorthands could be used" diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 919d4e11e5a..2cee3c14d7f 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// pub fn internal_fn() { } /// } /// ``` + #[clippy::version = "1.44.0"] pub REDUNDANT_PUB_CRATE, nursery, "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them." diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 0c460150087..b2bd0103d11 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// x /// } /// ``` + #[clippy::version = "1.51.0"] pub REDUNDANT_SLICING, complexity, "redundant slicing of the whole range of a type" diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index d5a1a61da6b..ea5064217ab 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] /// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] /// ``` + #[clippy::version = "1.37.0"] pub REDUNDANT_STATIC_LIFETIMES, style, "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them." diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index d543832e314..909d6971a54 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let x: Option<&u32> = Some(&0u32); /// ``` + #[clippy::version = "1.49.0"] pub REF_OPTION_REF, pedantic, "use `Option<&T>` instead of `&Option<&T>`" diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 70dff5ad313..22ae7a291d0 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// let a = f(b); /// let c = d; /// ``` + #[clippy::version = "pre 1.29.0"] pub DEREF_ADDROF, complexity, "use of `*&` or `*&mut` in an expression" @@ -124,6 +125,7 @@ declare_clippy_lint! { /// # let point = Point(30, 20); /// let x = point.0; /// ``` + #[clippy::version = "pre 1.29.0"] pub REF_IN_DEREF, complexity, "Use of reference in auto dereference expression." diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 5d08aee1e5f..8e5983b4773 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -22,6 +22,7 @@ declare_clippy_lint! { /// ```ignore /// Regex::new("|") /// ``` + #[clippy::version = "pre 1.29.0"] pub INVALID_REGEX, correctness, "invalid regular expressions" @@ -46,6 +47,7 @@ declare_clippy_lint! { /// ```ignore /// Regex::new("^foobar") /// ``` + #[clippy::version = "pre 1.29.0"] pub TRIVIAL_REGEX, nursery, "trivial regular expressions" diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index e5e55ee7505..b5dd2de6337 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// let x = String::from("hello world").clone(); /// } /// ``` + #[clippy::version = "1.47.0"] pub REPEAT_ONCE, complexity, "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e2b1a33746e..494bc7dda18 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -37,6 +37,7 @@ declare_clippy_lint! { /// String::new() /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub LET_AND_RETURN, style, "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block" @@ -62,6 +63,7 @@ declare_clippy_lint! { /// x /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_RETURN, style, "using a return statement like `return expr;` where an expression would suffice" diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 737ff634e44..3f38d12fb55 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// fn foo(&self) {} /// } /// ``` + #[clippy::version = "1.57.0"] pub SAME_NAME_METHOD, restriction, "two method with same name" diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs index fbd65fef7d1..b14f0518bdb 100644 --- a/clippy_lints/src/self_assignment.rs +++ b/clippy_lints/src/self_assignment.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// a.y = a.y; /// } /// ``` + #[clippy::version = "1.48.0"] pub SELF_ASSIGNMENT, correctness, "explicit self-assignment" diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 4ba5e1a0f53..dd73dbfe09e 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -32,6 +32,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.55.0"] pub SELF_NAMED_CONSTRUCTORS, style, "method should not have the same name as the type it is implemented for" diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index d3b4929a189..0b3bbbc8155 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// println!("Hello world"); /// } /// ``` + #[clippy::version = "1.52.0"] pub SEMICOLON_IF_NOTHING_RETURNED, pedantic, "add a semicolon if nothing is returned" diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 2cd0f85999c..a38b3c4ab69 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -15,6 +15,7 @@ declare_clippy_lint! { /// ### Example /// Implementing `Visitor::visit_string` but not /// `Visitor::visit_str`. + #[clippy::version = "pre 1.29.0"] pub SERDE_API_MISUSE, correctness, "various things that will negatively affect your serde experience" diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 64841f33cc3..5f82aed872c 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// // Good /// let y = &x; // use different variable name /// ``` + #[clippy::version = "pre 1.29.0"] pub SHADOW_SAME, restriction, "rebinding a name to itself, e.g., `let mut x = &mut x`" @@ -55,6 +56,7 @@ declare_clippy_lint! { /// let x = 2; /// let y = x + 1; /// ``` + #[clippy::version = "pre 1.29.0"] pub SHADOW_REUSE, restriction, "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`" @@ -84,6 +86,7 @@ declare_clippy_lint! { /// // Good /// let w = z; // use different variable name /// ``` + #[clippy::version = "pre 1.29.0"] pub SHADOW_UNRELATED, restriction, "rebinding a name without even using the original value" diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 87aa02b6585..28d32203da9 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); /// } /// ``` + #[clippy::version = "1.43.0"] pub SINGLE_COMPONENT_PATH_IMPORTS, style, "imports with single component path are redundant" diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 3e4e4a8d0c0..df1e85afdd7 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// let mut y = [2u8; SIZE]; /// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; /// ``` + #[clippy::version = "1.50.0"] pub SIZE_OF_IN_ELEMENT_COUNT, correctness, "using `size_of::` or `size_of_val::` where a count of elements of `T` is expected" diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 3608fe1472d..1ae772ef70b 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// let mut vec1 = vec![0; len]; /// let mut vec2 = vec![0; len]; /// ``` + #[clippy::version = "1.32.0"] pub SLOW_VECTOR_INITIALIZATION, perf, "slow vector initialization" diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index 4ea1293d504..953d21e07a3 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// let mut vec = vec![2, 1, 3]; /// vec.sort_unstable(); /// ``` + #[clippy::version = "1.47.0"] pub STABLE_SORT_PRIMITIVE, perf, "use of sort() when sort_unstable() is equivalent" diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 6435107b8b4..368274440d5 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// x += ", World"; /// x.push_str(", World"); /// ``` + #[clippy::version = "pre 1.29.0"] pub STRING_ADD_ASSIGN, pedantic, "using `x = x + ..` where x is a `String` instead of `push_str()`" @@ -58,6 +59,7 @@ declare_clippy_lint! { /// let x = "Hello".to_owned(); /// x + ", World"; /// ``` + #[clippy::version = "pre 1.29.0"] pub STRING_ADD, restriction, "using `x + ..` where x is a `String` instead of `push_str()`" @@ -102,6 +104,7 @@ declare_clippy_lint! { /// // Good /// let bs = b"a byte string"; /// ``` + #[clippy::version = "pre 1.29.0"] pub STRING_LIT_AS_BYTES, nursery, "calling `as_bytes` on a string literal instead of using a byte string literal" @@ -125,6 +128,7 @@ declare_clippy_lint! { /// ```rust,should_panic /// &"Ölkanne"[1..]; /// ``` + #[clippy::version = "1.58.0"] pub STRING_SLICE, restriction, "slicing a string" @@ -227,6 +231,7 @@ declare_clippy_lint! { /// ```rust /// let _ = &"Hello World!"[6..11]; /// ``` + #[clippy::version = "1.50.0"] pub STRING_FROM_UTF8_AS_BYTES, complexity, "casting string slices to byte slices and back" @@ -371,6 +376,7 @@ declare_clippy_lint! { /// // example code which does not raise clippy warning /// let _ = "str".to_owned(); /// ``` + #[clippy::version = "pre 1.29.0"] pub STR_TO_STRING, restriction, "using `to_string()` on a `&str`, which should be `to_owned()`" @@ -420,6 +426,7 @@ declare_clippy_lint! { /// let msg = String::from("Hello World"); /// let _ = msg.clone(); /// ``` + #[clippy::version = "pre 1.29.0"] pub STRING_TO_STRING, restriction, "using `to_string()` on a `String`, which should be `clone()`" diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 8bf40ec5312..be7431f11aa 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// let cstring = CString::new("foo").expect("CString::new failed"); /// let len = cstring.as_bytes().len(); /// ``` + #[clippy::version = "1.55.0"] pub STRLEN_ON_C_STRINGS, complexity, "using `libc::strlen` on a `CString` or `CStr` value, while `as_bytes().len()` or `to_bytes().len()` respectively can be used instead" diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 201aa067824..faf43fd9fc1 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -59,6 +59,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.50.0"] pub SUSPICIOUS_OPERATION_GROUPINGS, nursery, "groupings of binary operations that look suspiciously like typos" diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 682fad00a13..a3195de81d1 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -25,6 +25,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub SUSPICIOUS_ARITHMETIC_IMPL, suspicious, "suspicious use of operators in impl of arithmetic trait" @@ -46,6 +47,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub SUSPICIOUS_OP_ASSIGN_IMPL, suspicious, "suspicious use of operators in impl of OpAssign trait" diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index ef26de5b6b9..a8c7ca4c916 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -35,6 +35,7 @@ declare_clippy_lint! { /// let mut b = 2; /// std::mem::swap(&mut a, &mut b); /// ``` + #[clippy::version = "pre 1.29.0"] pub MANUAL_SWAP, complexity, "manual swap of two variables" @@ -60,6 +61,7 @@ declare_clippy_lint! { /// # let mut b = 2; /// std::mem::swap(&mut a, &mut b); /// ``` + #[clippy::version = "pre 1.29.0"] pub ALMOST_SWAPPED, correctness, "`foo = bar; bar = foo` sequence" diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index 4a67cabf323..c9b4b245f4c 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -51,6 +51,7 @@ declare_clippy_lint! { /// second_string: String, ///} /// ``` + #[clippy::version = "1.41.0"] pub TABS_IN_DOC_COMMENTS, style, "using tabs in doc comments is not recommended" diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index a9da690339c..3766b8f8ed1 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -17,6 +17,7 @@ declare_clippy_lint! { /// ```rust /// (0, 0).0 = 1 /// ``` + #[clippy::version = "pre 1.29.0"] pub TEMPORARY_ASSIGNMENT, complexity, "assignments to temporaries" diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 1c14a919995..5eb58b47838 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// # let radix = 10; /// let is_digit = c.is_digit(radix); /// ``` + #[clippy::version = "1.41.0"] pub TO_DIGIT_IS_SOME, style, "`char.is_digit()` is clearer" diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index b7414cec87c..f8b6bdcd3e1 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.48.0"] pub TO_STRING_IN_DISPLAY, correctness, "`to_string` method used while implementing `Display` trait" diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index c216a1f81ea..47c0a84cd46 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// last: [u32; 0], /// } /// ``` + #[clippy::version = "1.58.0"] pub TRAILING_EMPTY_ARRAY, nursery, "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute" diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 73bdcae9e39..fb4abceac25 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// ```rust /// pub fn foo(t: T) where T: Copy + Clone {} /// ``` + #[clippy::version = "1.38.0"] pub TYPE_REPETITION_IN_BOUNDS, pedantic, "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" @@ -57,6 +58,7 @@ declare_clippy_lint! { /// ```rust /// fn func(arg: T) where T: Clone + Default {} /// ``` + #[clippy::version = "1.47.0"] pub TRAIT_DUPLICATION_IN_BOUNDS, pedantic, "Check if the same trait bounds are specified twice during a function declaration" diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index e6acf1a94c9..3ad4ec74bf5 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// ```ignore /// let ptr: *const T = core::intrinsics::transmute('x') /// ``` + #[clippy::version = "pre 1.29.0"] pub WRONG_TRANSMUTE, correctness, "transmutes that are confusing at best, undefined behaviour at worst and always useless" @@ -55,6 +56,7 @@ declare_clippy_lint! { /// ```rust,ignore /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s /// ``` + #[clippy::version = "pre 1.29.0"] pub USELESS_TRANSMUTE, nursery, "transmutes that have the same to and from types or could be a cast/coercion" @@ -80,6 +82,7 @@ declare_clippy_lint! { /// # let p: *const [i32] = &[]; /// p as *const [u16]; /// ``` + #[clippy::version = "1.47.0"] pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, complexity, "transmutes that could be a pointer cast" @@ -98,6 +101,7 @@ declare_clippy_lint! { /// core::intrinsics::transmute(t) // where the result type is the same as /// // `*t` or `&t`'s /// ``` + #[clippy::version = "pre 1.29.0"] pub CROSSPOINTER_TRANSMUTE, complexity, "transmutes that have to or from types that are a pointer to the other" @@ -125,6 +129,7 @@ declare_clippy_lint! { /// // can be written: /// let _: &T = &*p; /// ``` + #[clippy::version = "pre 1.29.0"] pub TRANSMUTE_PTR_TO_REF, complexity, "transmutes from a pointer to a reference type" @@ -158,6 +163,7 @@ declare_clippy_lint! { /// // should be: /// let _ = std::char::from_u32(x).unwrap(); /// ``` + #[clippy::version = "pre 1.29.0"] pub TRANSMUTE_INT_TO_CHAR, complexity, "transmutes from an integer to a `char`" @@ -191,6 +197,7 @@ declare_clippy_lint! { /// // should be: /// let _ = std::str::from_utf8(b).unwrap(); /// ``` + #[clippy::version = "pre 1.29.0"] pub TRANSMUTE_BYTES_TO_STR, complexity, "transmutes from a `&[u8]` to a `&str`" @@ -213,6 +220,7 @@ declare_clippy_lint! { /// // should be: /// let _: bool = x != 0; /// ``` + #[clippy::version = "pre 1.29.0"] pub TRANSMUTE_INT_TO_BOOL, complexity, "transmutes from an integer to a `bool`" @@ -235,6 +243,7 @@ declare_clippy_lint! { /// // should be: /// let _: f32 = f32::from_bits(1_u32); /// ``` + #[clippy::version = "pre 1.29.0"] pub TRANSMUTE_INT_TO_FLOAT, complexity, "transmutes from an integer to a float" @@ -257,6 +266,7 @@ declare_clippy_lint! { /// // should be: /// let _: u32 = 1f32.to_bits(); /// ``` + #[clippy::version = "1.41.0"] pub TRANSMUTE_FLOAT_TO_INT, complexity, "transmutes from a float to an integer" @@ -279,6 +289,7 @@ declare_clippy_lint! { /// // should be /// let x: [u8; 8] = 0i64.to_ne_bytes(); /// ``` + #[clippy::version = "1.58.0"] pub TRANSMUTE_NUM_TO_BYTES, complexity, "transmutes from a number to an array of `u8`" @@ -306,6 +317,7 @@ declare_clippy_lint! { /// let _ = ptr as *const f32; /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) }; /// ``` + #[clippy::version = "pre 1.29.0"] pub TRANSMUTE_PTR_TO_PTR, pedantic, "transmutes from a pointer to a pointer / a reference to a reference" @@ -337,6 +349,7 @@ declare_clippy_lint! { /// ```rust /// vec![2_u16].into_iter().map(u32::from).collect::>(); /// ``` + #[clippy::version = "1.40.0"] pub UNSOUND_COLLECTION_TRANSMUTE, correctness, "transmute between collections of layout-incompatible types" diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index ef80663d1da..7939dfedc3a 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -25,6 +25,7 @@ declare_clippy_lint! { /// ```rust /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; /// ``` + #[clippy::version = "1.35.0"] pub TRANSMUTING_NULL, correctness, "transmutes from a null pointer to a reference, which is undefined behavior" diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index cc450b1e599..e0e7ec9a452 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// Ok(0) /// } /// ``` + #[clippy::version = "1.38.0"] pub TRY_ERR, style, "return errors explicitly rather than hiding them behind a `?`" diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index bbe07db5358..5a7ef760a30 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -43,6 +43,7 @@ declare_clippy_lint! { /// values: Vec, /// } /// ``` + #[clippy::version = "1.57.0"] pub BOX_COLLECTION, perf, "usage of `Box>`, vector elements are already on the heap" @@ -75,6 +76,7 @@ declare_clippy_lint! { /// values: Vec, /// } /// ``` + #[clippy::version = "1.33.0"] pub VEC_BOX, complexity, "usage of `Vec>` where T: Sized, vector elements are already on the heap" @@ -113,6 +115,7 @@ declare_clippy_lint! { /// Contents::None /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub OPTION_OPTION, pedantic, "usage of `Option>`" @@ -152,6 +155,7 @@ declare_clippy_lint! { /// # use std::collections::LinkedList; /// let x: LinkedList = LinkedList::new(); /// ``` + #[clippy::version = "pre 1.29.0"] pub LINKEDLIST, pedantic, "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`" @@ -176,6 +180,7 @@ declare_clippy_lint! { /// ```rust,ignore /// fn foo(bar: &T) { ... } /// ``` + #[clippy::version = "pre 1.29.0"] pub BORROWED_BOX, complexity, "a borrow of a boxed type" @@ -200,6 +205,7 @@ declare_clippy_lint! { /// ```rust /// fn foo(bar: &usize) {} /// ``` + #[clippy::version = "1.44.0"] pub REDUNDANT_ALLOCATION, perf, "redundant allocation" @@ -234,6 +240,7 @@ declare_clippy_lint! { /// ```rust,ignore /// fn foo(interned: Rc) { ... } /// ``` + #[clippy::version = "1.48.0"] pub RC_BUFFER, restriction, "shared ownership of a buffer type" @@ -255,6 +262,7 @@ declare_clippy_lint! { /// inner: Rc>>>, /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub TYPE_COMPLEXITY, complexity, "usage of very complex types that might be better factored into `type` definitions" @@ -287,6 +295,7 @@ declare_clippy_lint! { /// use std::cell::RefCell /// fn foo(interned: Rc>) { ... } /// ``` + #[clippy::version = "1.55.0"] pub RC_MUTEX, restriction, "usage of `Rc>`" diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index fbf66712261..c886faf5d28 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// // Safety: references are guaranteed to be non-null. /// let ptr = unsafe { NonNull::new_unchecked(a) }; /// ``` + #[clippy::version = "1.58.0"] pub UNDOCUMENTED_UNSAFE_BLOCKS, restriction, "creating an unsafe block without explaining why it is safe" diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index 09570616593..c58fa67a023 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S)); /// } /// ``` + #[clippy::version = "1.49.0"] pub UNDROPPED_MANUALLY_DROPS, correctness, "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value" diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index f49ce696a04..a514e8c44e2 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// ### Example /// You don't see it, but there may be a zero-width space or soft hyphen /// some­where in this text. + #[clippy::version = "1.49.0"] pub INVISIBLE_CHARACTERS, correctness, "using an invisible character in a string literal, which is confusing" @@ -44,6 +45,7 @@ declare_clippy_lint! { /// ```rust /// let x = String::from("\u{20ac}"); /// ``` + #[clippy::version = "pre 1.29.0"] pub NON_ASCII_LITERAL, restriction, "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape" @@ -62,6 +64,7 @@ declare_clippy_lint! { /// ### Example /// You may not see it, but "à"" and "à"" aren't the same string. The /// former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`. + #[clippy::version = "pre 1.29.0"] pub UNICODE_NOT_NFC, pedantic, "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)" diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index f3e8b688105..46cc76b150e 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -52,6 +52,7 @@ declare_clippy_lint! { /// // perform initialization with `remaining` /// vec.set_len(...); // Safe to call `set_len()` on initialized part /// ``` + #[clippy::version = "1.58.0"] pub UNINIT_VEC, correctness, "Vec with uninitialized data" diff --git a/clippy_lints/src/unit_hash.rs b/clippy_lints/src/unit_hash.rs index a3a3f2d41c7..26b4e0f58a8 100644 --- a/clippy_lints/src/unit_hash.rs +++ b/clippy_lints/src/unit_hash.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// WithValue(x) => x.hash(&mut state), /// } /// ``` + #[clippy::version = "1.58.0"] pub UNIT_HASH, correctness, "hashing a unit value, which does nothing" diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index db0f412f2a1..9fb8f236899 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -30,6 +30,7 @@ declare_clippy_lint! { /// let mut twins = vec!((1, 1), (2, 2)); /// twins.sort_by_key(|x| { x.1; }); /// ``` + #[clippy::version = "1.47.0"] pub UNIT_RETURN_EXPECTING_ORD, correctness, "fn arguments of type Fn(...) -> Ord returning the unit type ()." diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 66b1abbe50b..d9f5b53b413 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -21,6 +21,7 @@ declare_clippy_lint! { /// 1; /// }; /// ``` + #[clippy::version = "pre 1.29.0"] pub LET_UNIT_VALUE, pedantic, "creating a `let` binding to a value of unit type, which usually can't be used afterwards" @@ -68,6 +69,7 @@ declare_clippy_lint! { /// assert_eq!({ foo(); }, { bar(); }); /// ``` /// will always succeed + #[clippy::version = "pre 1.29.0"] pub UNIT_CMP, correctness, "comparing unit values" @@ -88,6 +90,7 @@ declare_clippy_lint! { /// baz(a); /// }) /// ``` + #[clippy::version = "pre 1.29.0"] pub UNIT_ARG, complexity, "passing unit to a function" diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 1eafdee0352..0bcafde658a 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -24,6 +24,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` + #[clippy::version = "1.44.0"] pub FN_ADDRESS_COMPARISONS, correctness, "comparison with an address of a function item" @@ -47,6 +48,7 @@ declare_clippy_lint! { /// ... /// } /// ``` + #[clippy::version = "1.44.0"] pub VTABLE_ADDRESS_COMPARISONS, correctness, "comparison with an address of a trait vtable" diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 4cfd2df551f..839a4bdab09 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -26,6 +26,7 @@ declare_clippy_lint! { /// ```rust /// use std::io; /// ``` + #[clippy::version = "1.53.0"] pub UNNECESSARY_SELF_IMPORTS, restriction, "imports ending in `::{self}`, which can be omitted" diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 26b56e0f2f3..d024577f485 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// # let mut vec: Vec = Vec::new(); /// vec.sort_by_key(|a| a.foo()); /// ``` + #[clippy::version = "1.46.0"] pub UNNECESSARY_SORT_BY, complexity, "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index fcfa8403177..1728533f18b 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -49,6 +49,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "1.50.0"] pub UNNECESSARY_WRAPS, pedantic, "functions that only return `Ok` or `Some`" diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index d6cf7190abb..0bd151fed91 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// if let Some(0 | 2) = Some(0) {} /// } /// ``` + #[clippy::version = "1.46.0"] pub UNNESTED_OR_PATTERNS, pedantic, "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`" diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 3c694af2b9d..44b1989dbc6 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -21,6 +21,7 @@ declare_clippy_lint! { /// extern crate crossbeam; /// use crossbeam::{spawn_unsafe as spawn}; /// ``` + #[clippy::version = "pre 1.29.0"] pub UNSAFE_REMOVED_FROM_NAME, style, "`unsafe` removed from API names on import" diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index f4808682b69..1ccb78425c2 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// } /// let number_future = async { get_random_number_improved() }; /// ``` + #[clippy::version = "1.54.0"] pub UNUSED_ASYNC, pedantic, "finds async functions with no await statements" diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 031b182bd2f..d4b5c9770a2 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// Ok(()) /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub UNUSED_IO_AMOUNT, correctness, "unused written/read amount" diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index e7e249c79a2..fd9d5b52e50 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -29,6 +29,7 @@ declare_clippy_lint! { /// fn method() {} /// } /// ``` + #[clippy::version = "1.40.0"] pub UNUSED_SELF, pedantic, "methods that contain a `self` argument but don't use it" diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 1164ac4938f..48c17fa2a40 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// ```rust /// fn return_unit() {} /// ``` + #[clippy::version = "1.31.0"] pub UNUSED_UNIT, style, "needless unit expression" diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index ebaa9dcbbf8..9e83cae79bc 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { /// do_something_with(value) /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_UNWRAP, complexity, "checks for calls of `unwrap[_err]()` that cannot fail" @@ -65,6 +66,7 @@ declare_clippy_lint! { /// ``` /// /// This code will always panic. The if condition should probably be inverted. + #[clippy::version = "pre 1.29.0"] pub PANICKING_UNWRAP, correctness, "checks for calls of `unwrap[_err]()` that will always fail" diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 6447e3fa2ca..994df85cb8a 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -51,6 +51,7 @@ declare_clippy_lint! { /// Ok(()) /// } /// ``` + #[clippy::version = "1.48.0"] pub UNWRAP_IN_RESULT, restriction, "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`" diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index dbf335a70c8..4773e350760 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { /// ```rust /// struct HttpResponse; /// ``` + #[clippy::version = "1.51.0"] pub UPPER_CASE_ACRONYMS, style, "capitalized acronyms are against the naming convention" diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 09aad296f03..059f7f647f8 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -51,6 +51,7 @@ declare_clippy_lint! { /// } /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub USE_SELF, nursery, "unnecessary structure name repetition whereas `Self` is applicable" diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 88f11542072..0e4b32541c9 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { /// // Good /// let s: String = format!("hello"); /// ``` + #[clippy::version = "1.45.0"] pub USELESS_CONVERSION, complexity, "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type" diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index d3234b5758a..79e7410c3a8 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// // Good /// foo(&[1, 2]); /// ``` + #[clippy::version = "pre 1.29.0"] pub USELESS_VEC, perf, "useless `vec!`" diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index b92b6ca4f43..1bc0eb6303c 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// ```rust /// let v = vec![0]; /// ``` + #[clippy::version = "1.51.0"] pub VEC_INIT_THEN_PUSH, perf, "`push` immediately after `Vec` creation" diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index 5c0429db6b8..3441d9ccdfa 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// ```rust /// vec!(1, 2, 3, 4, 5).resize(0, 5) /// ``` + #[clippy::version = "1.46.0"] pub VEC_RESIZE_TO_ZERO, correctness, "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index e07c12f4f16..ebdaff1e676 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { /// # use std::fs; /// let mut bytes = fs::read("foo.txt").unwrap(); /// ``` + #[clippy::version = "1.44.0"] pub VERBOSE_FILE_READS, restriction, "use of `File::read_to_end` or `File::read_to_string`" diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index d0c98b6bd79..80d7b8a1b6d 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// [dependencies] /// regex = "*" /// ``` + #[clippy::version = "1.32.0"] pub WILDCARD_DEPENDENCIES, cargo, "wildcard dependencies being used" diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 2f3e525fdcf..832da66a536 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -34,6 +34,7 @@ declare_clippy_lint! { /// use std::cmp::Ordering; /// foo(Ordering::Less) /// ``` + #[clippy::version = "pre 1.29.0"] pub ENUM_GLOB_USE, pedantic, "use items that import all variants of an enum" @@ -86,6 +87,7 @@ declare_clippy_lint! { /// /// foo(); /// ``` + #[clippy::version = "1.43.0"] pub WILDCARD_IMPORTS, pedantic, "lint `use _::*` statements" diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 85d1f65c51f..1b3c15fdf23 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { /// // Good /// println!(); /// ``` + #[clippy::version = "pre 1.29.0"] pub PRINTLN_EMPTY_STRING, style, "using `println!(\"\")` with an empty string" @@ -55,6 +56,7 @@ declare_clippy_lint! { /// # let name = "World"; /// println!("Hello {}!", name); /// ``` + #[clippy::version = "pre 1.29.0"] pub PRINT_WITH_NEWLINE, style, "using `print!()` with a format string that ends in a single newline" @@ -76,6 +78,7 @@ declare_clippy_lint! { /// ```rust /// println!("Hello world!"); /// ``` + #[clippy::version = "pre 1.29.0"] pub PRINT_STDOUT, restriction, "printing on stdout" @@ -97,6 +100,7 @@ declare_clippy_lint! { /// ```rust /// eprintln!("Hello world!"); /// ``` + #[clippy::version = "1.50.0"] pub PRINT_STDERR, restriction, "printing on stderr" @@ -116,6 +120,7 @@ declare_clippy_lint! { /// # let foo = "bar"; /// println!("{:?}", foo); /// ``` + #[clippy::version = "pre 1.29.0"] pub USE_DEBUG, restriction, "use of `Debug`-based formatting" @@ -142,6 +147,7 @@ declare_clippy_lint! { /// ```rust /// println!("foo"); /// ``` + #[clippy::version = "pre 1.29.0"] pub PRINT_LITERAL, style, "printing a literal with a format string" @@ -165,6 +171,7 @@ declare_clippy_lint! { /// // Good /// writeln!(buf); /// ``` + #[clippy::version = "pre 1.29.0"] pub WRITELN_EMPTY_STRING, style, "using `writeln!(buf, \"\")` with an empty string" @@ -191,6 +198,7 @@ declare_clippy_lint! { /// // Good /// writeln!(buf, "Hello {}!", name); /// ``` + #[clippy::version = "pre 1.29.0"] pub WRITE_WITH_NEWLINE, style, "using `write!()` with a format string that ends in a single newline" @@ -219,6 +227,7 @@ declare_clippy_lint! { /// // Good /// writeln!(buf, "foo"); /// ``` + #[clippy::version = "pre 1.29.0"] pub WRITE_LITERAL, style, "writing a literal with a format string" diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index e0746ce4d81..641681185a2 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -20,6 +20,7 @@ declare_clippy_lint! { /// // Good /// let nan = f32::NAN; /// ``` + #[clippy::version = "pre 1.29.0"] pub ZERO_DIVIDED_BY_ZERO, complexity, "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`" diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index aa6b2614bbc..eb8436a501d 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -36,6 +36,7 @@ declare_clippy_lint! { /// todo!(); /// } /// ``` + #[clippy::version = "1.50.0"] pub ZERO_SIZED_MAP_VALUES, pedantic, "usage of map with zero-sized value type" -- cgit 1.4.1-3-g733a5 From 2ed4a8a3e6fc8d53225ded631e815a767859184e Mon Sep 17 00:00:00 2001 From: togami2864 Date: Sat, 13 Nov 2021 22:38:28 +0900 Subject: fix suggestion in option_map_or_none --- clippy_lints/src/methods/option_map_or_none.rs | 6 +++--- tests/ui/option_map_or_none.fixed | 4 ++-- tests/ui/option_map_or_none.stderr | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index e99b6b07d15..8f61bd97b45 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -53,12 +53,12 @@ pub(super) fn check<'tcx>( let self_snippet = snippet(cx, recv.span, ".."); let func_snippet = snippet(cx, map_arg.span, ".."); let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `and_then(..)` instead"; + `map(..)` instead"; ( OPTION_MAP_OR_NONE, msg, - "try using `and_then` instead", - format!("{0}.and_then({1})", self_snippet, func_snippet), + "try using `map` instead", + format!("{0}.map({1})", self_snippet, func_snippet), ) } else if f_arg_is_some { let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index d80c3c7c1b7..429ef00003f 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -7,10 +7,10 @@ fn main() { // Check `OPTION_MAP_OR_NONE`. // Single line case. - let _ = opt.and_then(|x| Some(x + 1)); + let _ = opt.map(|x| Some(x + 1)); // Multi-line case. #[rustfmt::skip] - let _ = opt.and_then(|x| { + let _ = opt.map(|x| { Some(x + 1) }); } diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 27d68b85e6f..b011515934d 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,12 +1,12 @@ -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead --> $DIR/option_map_or_none.rs:10:13 | LL | let _ = opt.map_or(None, |x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(|x| Some(x + 1))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| Some(x + 1))` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead --> $DIR/option_map_or_none.rs:13:13 | LL | let _ = opt.map_or(None, |x| { @@ -15,9 +15,9 @@ LL | | Some(x + 1) LL | | }); | |_________________________^ | -help: try using `and_then` instead +help: try using `map` instead | -LL ~ let _ = opt.and_then(|x| { +LL ~ let _ = opt.map(|x| { LL + Some(x + 1) LL ~ }); | -- cgit 1.4.1-3-g733a5 From bbffe825ed12231e333bd641eb46aa477cde3b8f Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 16 Nov 2021 02:06:31 +0900 Subject: add reduce_unit_expression --- clippy_lints/src/methods/option_map_or_none.rs | 138 ++++++++++++++++--------- tests/ui/option_map_or_none.fixed | 6 +- tests/ui/option_map_or_none.stderr | 10 +- 3 files changed, 96 insertions(+), 58 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 8f61bd97b45..00a4dda9701 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_lang_ctor, single_segment_path}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -11,6 +11,26 @@ use rustc_span::symbol::sym; use super::OPTION_MAP_OR_NONE; use super::RESULT_MAP_OR_INTO_OPTION; +fn reduce_unit_expression<'a>( + cx: &LateContext<'_>, + expr: &'a hir::Expr<'_>, +) -> Option<(&'a hir::Expr<'a>, &'a [hir::Expr<'a>])> { + match expr.kind { + hir::ExprKind::Call(func, arg_char) => Some((func, arg_char)), + hir::ExprKind::Block(block, _) => { + match block.expr { + Some(inner_expr) => { + // If block only contains an expression, + // reduce `{ X }` to `X` + reduce_unit_expression(cx, inner_expr) + }, + _ => None, + } + }, + _ => None, + } +} + /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -31,58 +51,78 @@ pub(super) fn check<'tcx>( return; } - let (lint_name, msg, instead, hint) = { - let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { - is_lang_ctor(cx, qpath, OptionNone) - } else { - return; - }; + // let (lint_name, msg, instead, hint) = { + let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { + is_lang_ctor(cx, qpath, OptionNone) + } else { + return; + }; - if !default_arg_is_none { - // nothing to lint! - return; - } + if !default_arg_is_none { + // nothing to lint! + return; + } - let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { - is_lang_ctor(cx, qpath, OptionSome) - } else { - false - }; + let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { + is_lang_ctor(cx, qpath, OptionSome) + } else { + false + }; - if is_option { - let self_snippet = snippet(cx, recv.span, ".."); - let func_snippet = snippet(cx, map_arg.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ + if is_option { + let self_snippet = snippet(cx, recv.span, ".."); + if let hir::ExprKind::Closure(_, _, id, _, _) = map_arg.kind { + if_chain! { + let body = cx.tcx.hir().body(id); + if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value); + if arg_char.len() == 1; + if let hir::ExprKind::Path(ref qpath) = func.kind; + if let Some(segment) = single_segment_path(qpath); + if segment.ident.name == sym::Some; + then { + let func_snippet = snippet(cx, arg_char[0].span, ".."); + let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ `map(..)` instead"; - ( - OPTION_MAP_OR_NONE, - msg, - "try using `map` instead", - format!("{0}.map({1})", self_snippet, func_snippet), - ) - } else if f_arg_is_some { - let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ - `ok()` instead"; - let self_snippet = snippet(cx, recv.span, ".."); - ( - RESULT_MAP_OR_INTO_OPTION, - msg, - "try using `ok` instead", - format!("{0}.ok()", self_snippet), - ) - } else { - // nothing to lint! - return; + return span_lint_and_sugg( + cx, + OPTION_MAP_OR_NONE, + expr.span, + msg, + "try using `map` instead", + format!("{0}.map({1})", self_snippet, func_snippet), + Applicability::MachineApplicable, + ); + } + } } - }; - span_lint_and_sugg( - cx, - lint_name, - expr.span, - msg, - instead, - hint, - Applicability::MachineApplicable, - ); + let func_snippet = snippet(cx, map_arg.span, ".."); + let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ + `and_then(..)` instead"; + span_lint_and_sugg( + cx, + OPTION_MAP_OR_NONE, + expr.span, + msg, + "try using `and_then` instead", + format!("{0}.and_then({1})", self_snippet, func_snippet), + Applicability::MachineApplicable, + ) + } else if f_arg_is_some { + let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ + `ok()` instead"; + let self_snippet = snippet(cx, recv.span, ".."); + span_lint_and_sugg( + cx, + RESULT_MAP_OR_INTO_OPTION, + expr.span, + msg, + "try using `ok` instead", + format!("{0}.ok()", self_snippet), + Applicability::MachineApplicable, + ) + } else { + // nothing to lint! + return; + } } diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index 77ad2d5285a..9333cb89c9a 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -5,7 +5,7 @@ fn main() { let opt = Some(1); let bar = |_| { - Some(1) + Some(1) }; // Check `OPTION_MAP_OR_NONE`. @@ -13,9 +13,7 @@ fn main() { let _ :Option = opt.map(|x| x + 1); // Multi-line case. #[rustfmt::skip] - let _ :Option = opt.map(|x| { - x + 1 - }); + let _ :Option = opt.map(|x| x + 1); // function returning `Option` let _ :Option = opt.and_then(bar); } diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 86ac93b9c80..3d75f2776f6 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,16 +1,16 @@ error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead - --> $DIR/option_map_or_none.rs:10:13 + --> $DIR/option_map_or_none.rs:13:26 | LL | let _ :Option = opt.map_or(None, |x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead - --> $DIR/option_map_or_none.rs:13:13 + --> $DIR/option_map_or_none.rs:16:26 | LL | let _ :Option = opt.map_or(None, |x| { - | _____________^ + | __________________________^ LL | | Some(x + 1) LL | | }); | |_________________________^ @@ -22,7 +22,7 @@ LL + x + 1 LL ~ }); | -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead --> $DIR/option_map_or_none.rs:20:26 | LL | let _ :Option = opt.map_or(None, bar); -- cgit 1.4.1-3-g733a5 From 02e0726149a8fd9963b2b81f8c15587520445cc6 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 16 Nov 2021 02:29:02 +0900 Subject: fix a bug that the closure arguments are not displayed --- clippy_lints/src/methods/option_map_or_none.rs | 19 ++++++++----------- tests/ui/option_map_or_none.stderr | 9 +-------- 2 files changed, 9 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 00a4dda9701..a18db4d9371 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -21,7 +21,7 @@ fn reduce_unit_expression<'a>( match block.expr { Some(inner_expr) => { // If block only contains an expression, - // reduce `{ X }` to `X` + // reduce `|x| { x + 1 }` to `|x| x + 1` reduce_unit_expression(cx, inner_expr) }, _ => None, @@ -51,7 +51,6 @@ pub(super) fn check<'tcx>( return; } - // let (lint_name, msg, instead, hint) = { let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { is_lang_ctor(cx, qpath, OptionNone) } else { @@ -71,7 +70,8 @@ pub(super) fn check<'tcx>( if is_option { let self_snippet = snippet(cx, recv.span, ".."); - if let hir::ExprKind::Closure(_, _, id, _, _) = map_arg.kind { + if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind { + let arg_snippet = snippet(cx, span, ".."); if_chain! { let body = cx.tcx.hir().body(id); if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value); @@ -89,7 +89,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `map` instead", - format!("{0}.map({1})", self_snippet, func_snippet), + format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet), Applicability::MachineApplicable, ); } @@ -99,7 +99,7 @@ pub(super) fn check<'tcx>( let func_snippet = snippet(cx, map_arg.span, ".."); let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ `and_then(..)` instead"; - span_lint_and_sugg( + return span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, expr.span, @@ -107,12 +107,12 @@ pub(super) fn check<'tcx>( "try using `and_then` instead", format!("{0}.and_then({1})", self_snippet, func_snippet), Applicability::MachineApplicable, - ) + ); } else if f_arg_is_some { let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ `ok()` instead"; let self_snippet = snippet(cx, recv.span, ".."); - span_lint_and_sugg( + return span_lint_and_sugg( cx, RESULT_MAP_OR_INTO_OPTION, expr.span, @@ -120,9 +120,6 @@ pub(super) fn check<'tcx>( "try using `ok` instead", format!("{0}.ok()", self_snippet), Applicability::MachineApplicable, - ) - } else { - // nothing to lint! - return; + ); } } diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 3d75f2776f6..560b767fba2 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -13,14 +13,7 @@ LL | let _ :Option = opt.map_or(None, |x| { | __________________________^ LL | | Some(x + 1) LL | | }); - | |_________________________^ - | -help: try using `map` instead - | -LL ~ let _ :Option = opt.map(|x| { -LL + x + 1 -LL ~ }); - | + | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead --> $DIR/option_map_or_none.rs:20:26 -- cgit 1.4.1-3-g733a5 From cd5781648a93ca851459c8397c2bb1dfa3dd393b Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 16 Nov 2021 02:30:54 +0900 Subject: add comment --- clippy_lints/src/methods/option_map_or_none.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index a18db4d9371..ac2a5b70004 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -11,6 +11,7 @@ use rustc_span::symbol::sym; use super::OPTION_MAP_OR_NONE; use super::RESULT_MAP_OR_INTO_OPTION; +/// The expression inside a closure may or may not have surrounding braces fn reduce_unit_expression<'a>( cx: &LateContext<'_>, expr: &'a hir::Expr<'_>, -- cgit 1.4.1-3-g733a5 From 300282c09aa8e922699b4fc7e2c608b4f8d81719 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 16 Nov 2021 02:53:35 +0900 Subject: fix fmt --- clippy_lints/src/methods/option_map_or_none.rs | 3 ++- tests/ui/option_map_or_none.fixed | 10 ++++------ tests/ui/option_map_or_none.rs | 10 ++++------ tests/ui/option_map_or_none.stderr | 12 ++++++------ 4 files changed, 16 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index ac2a5b70004..3a93d912e8c 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -11,7 +11,8 @@ use rustc_span::symbol::sym; use super::OPTION_MAP_OR_NONE; use super::RESULT_MAP_OR_INTO_OPTION; -/// The expression inside a closure may or may not have surrounding braces +// The expression inside a closure may or may not have surrounding braces +// which causes problems when generating a suggestion. fn reduce_unit_expression<'a>( cx: &LateContext<'_>, expr: &'a hir::Expr<'_>, diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index 9333cb89c9a..abaf88be8ca 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -4,16 +4,14 @@ fn main() { let opt = Some(1); - let bar = |_| { - Some(1) - }; + let bar = |_| Some(1); // Check `OPTION_MAP_OR_NONE`. // Single line case. - let _ :Option = opt.map(|x| x + 1); + let _: Option = opt.map(|x| x + 1); // Multi-line case. #[rustfmt::skip] - let _ :Option = opt.map(|x| x + 1); + let _: Option = opt.map(|x| x + 1); // function returning `Option` - let _ :Option = opt.and_then(bar); + let _: Option = opt.and_then(bar); } diff --git a/tests/ui/option_map_or_none.rs b/tests/ui/option_map_or_none.rs index 789531b7215..a63b63c4dc0 100644 --- a/tests/ui/option_map_or_none.rs +++ b/tests/ui/option_map_or_none.rs @@ -4,18 +4,16 @@ fn main() { let opt = Some(1); - let bar = |_| { - Some(1) - }; + let bar = |_| Some(1); // Check `OPTION_MAP_OR_NONE`. // Single line case. - let _ :Option = opt.map_or(None, |x| Some(x + 1)); + let _: Option = opt.map_or(None, |x| Some(x + 1)); // Multi-line case. #[rustfmt::skip] - let _ :Option = opt.map_or(None, |x| { + let _: Option = opt.map_or(None, |x| { Some(x + 1) }); // function returning `Option` - let _ :Option = opt.map_or(None, bar); + let _: Option = opt.map_or(None, bar); } diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 560b767fba2..aec46cb005f 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,24 +1,24 @@ error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead - --> $DIR/option_map_or_none.rs:13:26 + --> $DIR/option_map_or_none.rs:11:26 | -LL | let _ :Option = opt.map_or(None, |x| Some(x + 1)); +LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead - --> $DIR/option_map_or_none.rs:16:26 + --> $DIR/option_map_or_none.rs:14:26 | -LL | let _ :Option = opt.map_or(None, |x| { +LL | let _: Option = opt.map_or(None, |x| { | __________________________^ LL | | Some(x + 1) LL | | }); | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead - --> $DIR/option_map_or_none.rs:20:26 + --> $DIR/option_map_or_none.rs:18:26 | -LL | let _ :Option = opt.map_or(None, bar); +LL | let _: Option = opt.map_or(None, bar); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 0a30fdcd3c5ab9803983671a4452dff7e31f9e80 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 16 Nov 2021 03:02:08 +0900 Subject: move the let statement out of the macro --- clippy_lints/src/methods/option_map_or_none.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 3a93d912e8c..12ccaa24c3b 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -74,8 +74,8 @@ pub(super) fn check<'tcx>( let self_snippet = snippet(cx, recv.span, ".."); if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind { let arg_snippet = snippet(cx, span, ".."); + let body = cx.tcx.hir().body(id); if_chain! { - let body = cx.tcx.hir().body(id); if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value); if arg_char.len() == 1; if let hir::ExprKind::Path(ref qpath) = func.kind; -- cgit 1.4.1-3-g733a5 From 2938ffd0d94d93893ca32202cb3b6a6b69559bfb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 17 Aug 2021 16:22:48 -0400 Subject: Improve heuristics for determining whether eager of lazy evaluation is preferred --- clippy_lints/src/functions/too_many_lines.rs | 4 +- .../src/methods/from_iter_instead_of_collect.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 59 ++-- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 6 +- clippy_utils/src/eager_or_lazy.rs | 307 ++++++++++++++------- clippy_utils/src/paths.rs | 1 + clippy_utils/src/ty.rs | 21 +- clippy_utils/src/visitors.rs | 94 ++++++- tests/ui/needless_return.fixed | 1 + tests/ui/needless_return.rs | 1 + tests/ui/needless_return.stderr | 36 +-- tests/ui/option_if_let_else.fixed | 2 +- tests/ui/option_if_let_else.stderr | 4 +- tests/ui/or_fun_call.fixed | 30 +- tests/ui/or_fun_call.rs | 18 +- tests/ui/or_fun_call.stderr | 60 +--- 17 files changed, 408 insertions(+), 240 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 008ef661b55..65efbbab41a 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -56,8 +56,8 @@ pub(super) fn check_fn( continue; } } else { - let multi_idx = line.find("/*").unwrap_or_else(|| line.len()); - let single_idx = line.find("//").unwrap_or_else(|| line.len()); + let multi_idx = line.find("/*").unwrap_or(line.len()); + let single_idx = line.find("//").unwrap_or(line.len()); code_in_line |= multi_idx > 0 && single_idx > 0; // Implies multi_idx is below line.len() if multi_idx < single_idx { diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 99c03844f49..8ea9312c0f7 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -69,7 +69,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) - // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` let ty_str = ty.to_string(); let start = ty_str.find('<').unwrap_or(0); - let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let end = ty_str.find('>').unwrap_or(ty_str.len()); let nb_wildcard = ty_str[start..end].split(',').count(); let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); format!("{}<{}>", elements.join("::"), wildcards) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index fe9ffde0d33..4e4653dadca 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,16 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::eager_or_lazy::is_lazyness_candidate; -use clippy_utils::is_trait_item; +use clippy_utils::eager_or_lazy::switch_to_lazy_eval; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; -use clippy_utils::ty::implements_trait; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; -use clippy_utils::{contains_return, last_path_segment, paths}; +use clippy_utils::ty::{implements_trait, match_type}; +use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{BlockCheckMode, UnsafeSource}; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym}; use std::borrow::Cow; @@ -96,25 +92,10 @@ pub(super) fn check<'tcx>( (&paths::RESULT, true, &["or", "unwrap_or"], "else"), ]; - if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &arg.kind { - if path.ident.name == sym::len { - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - - match ty.kind() { - ty::Slice(_) | ty::Array(_, _) | ty::Str => return, - _ => (), - } - - if is_type_diagnostic_item(cx, ty, sym::Vec) { - return; - } - } - } - if_chain! { if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); - if is_lazyness_candidate(cx, arg); + if switch_to_lazy_eval(cx, arg); if !contains_return(arg); let self_ty = cx.typeck_results().expr_ty(self_expr); @@ -166,26 +147,30 @@ pub(super) fn check<'tcx>( } } - if args.len() == 2 { - match args[1].kind { + if let [self_arg, arg] = args { + let inner_arg = if let hir::ExprKind::Block( + hir::Block { + stmts: [], + expr: Some(expr), + .. + }, + _, + ) = arg.kind + { + expr + } else { + arg + }; + match inner_arg.kind { hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { + if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); + check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span); } }, hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); - }, - hir::ExprKind::Block(block, _) - if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => - { - if let Some(block_expr) = block.expr { - if let hir::ExprKind::MethodCall(..) = block_expr.kind { - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); - } - } + check_general_case(cx, name, method_span, self_arg, arg, expr.span, None); }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 740af750b48..1e2765263c8 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( return; } - if eager_or_lazy::is_eagerness_candidate(cx, body_expr) { + if eager_or_lazy::switch_to_eager_eval(cx, body_expr) { let msg = if is_option { "unnecessary closure used to substitute value for `Option::None`" } else { diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index f7c19baf7f9..262be17f617 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -147,11 +147,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_expr(if_then)?; let none_body = extract_body_from_expr(if_else)?; - let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { - "map_or" - } else { - "map_or_else" - }; + let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; let capture_name = id.name.to_ident_string(); let (as_ref, as_mut) = match &let_expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 1ea7ccfb752..c2645ac730a 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -9,128 +9,227 @@ //! - or-fun-call //! - option-if-let-else -use crate::is_ctor_or_promotable_const_function; -use crate::ty::is_type_diagnostic_item; +use crate::ty::{all_predicates_of, is_copy}; +use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; - -use rustc_hir::intravisit; -use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; - -use rustc_hir::{Block, Expr, ExprKind, Path, QPath}; +use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}; +use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; -use rustc_span::sym; - -/// Is the expr pure (is it free from side-effects)? -/// This function is named so to stress that it isn't exhaustive and returns FNs. -fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Path(..) | ExprKind::Field(..) => true, - ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr), - ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(identify_some_pure_patterns), - ExprKind::Struct(_, fields, expr) => { - fields.iter().all(|f| identify_some_pure_patterns(f.expr)) && expr.map_or(true, identify_some_pure_patterns) - }, - ExprKind::Call( - &Expr { - kind: - ExprKind::Path(QPath::Resolved( - _, - Path { - res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..), - .. - }, - )), - .. - }, - args, - ) => args.iter().all(identify_some_pure_patterns), - ExprKind::Block( - &Block { - stmts, - expr: Some(expr), - .. - }, - _, - ) => stmts.is_empty() && identify_some_pure_patterns(expr), - ExprKind::Box(..) - | ExprKind::Array(..) - | ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Binary(..) - | ExprKind::Unary(..) - | ExprKind::Let(..) - | ExprKind::Cast(..) - | ExprKind::Type(..) - | ExprKind::DropTemps(..) - | ExprKind::Loop(..) - | ExprKind::If(..) - | ExprKind::Match(..) - | ExprKind::Closure(..) - | ExprKind::Block(..) - | ExprKind::Assign(..) - | ExprKind::AssignOp(..) - | ExprKind::Index(..) - | ExprKind::Break(..) - | ExprKind::Continue(..) - | ExprKind::Ret(..) - | ExprKind::InlineAsm(..) - | ExprKind::LlvmInlineAsm(..) - | ExprKind::Repeat(..) - | ExprKind::Yield(..) - | ExprKind::Err => false, +use rustc_middle::ty::{self, PredicateKind}; +use rustc_span::{sym, Symbol}; +use std::cmp; +use std::ops; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum EagernessSuggestion { + // The expression is cheap and should be evaluated eagerly + Eager, + // The expression may be cheap, so don't suggested lazy evaluation; or the expression may not be safe to switch to + // eager evaluation. + NoChange, + // The expression is likely expensive and should be evaluated lazily. + Lazy, + // The expression cannot be placed into a closure. + ForceNoChange, +} +impl ops::BitOr for EagernessSuggestion { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + cmp::max(self, rhs) } } - -/// Identify some potentially computationally expensive patterns. -/// This function is named so to stress that its implementation is non-exhaustive. -/// It returns FNs and FPs. -fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - // Searches an expression for method calls or function calls that aren't ctors - struct FunCallFinder<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - found: bool, +impl ops::BitOrAssign for EagernessSuggestion { + fn bitor_assign(&mut self, rhs: Self) { + *self = *self | rhs; } +} - impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - let call_found = match &expr.kind { - // ignore enum and struct constructors - ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), - ExprKind::Index(obj, _) => { - let ty = self.cx.typeck_results().expr_ty(obj); - is_type_diagnostic_item(self.cx, ty, sym::HashMap) - || is_type_diagnostic_item(self.cx, ty, sym::BTreeMap) - }, - ExprKind::MethodCall(..) => true, - _ => false, - }; +/// Determine the eagerness of the given function call. +fn fn_eagerness(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, args: &'tcx [Expr<'_>]) -> EagernessSuggestion { + use EagernessSuggestion::{Eager, Lazy, NoChange}; + let name = &*name.as_str(); - if call_found { - self.found |= true; - } + let ty = match cx.tcx.impl_of_method(fn_id) { + Some(id) => cx.tcx.type_of(id), + None => return Lazy, + }; - if !self.found { - intravisit::walk_expr(self, expr); + if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 { + if matches!( + cx.tcx.crate_name(fn_id.krate), + sym::std | sym::core | sym::alloc | sym::proc_macro + ) { + Eager + } else { + NoChange + } + } else if let ty::Adt(def, subs) = ty.kind() { + // Types where the only fields are generic types (or references to) with no trait bounds other + // than marker traits. + // Due to the limited operations on these types functions should be fairly cheap. + if def + .variants + .iter() + .flat_map(|v| v.fields.iter()) + .any(|x| matches!(cx.tcx.type_of(x.did).peel_refs().kind(), ty::Param(_))) + && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { + PredicateKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, + _ => true, + }) + && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) + { + // Limit the function to either `(self) -> bool` or `(&self) -> bool` + match &**cx.tcx.fn_sig(fn_id).skip_binder().inputs_and_output { + [arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange, + _ => Lazy, } + } else { + Lazy } + } else { + Lazy + } +} +#[allow(clippy::too_many_lines)] +fn expr_eagerness(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion { + struct V<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + eagerness: EagernessSuggestion, + } + + impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> { + type Map = ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + use EagernessSuggestion::{ForceNoChange, Lazy, NoChange}; + if self.eagerness == ForceNoChange { + return; + } + match e.kind { + ExprKind::Call( + &Expr { + kind: ExprKind::Path(ref path), + hir_id, + .. + }, + args, + ) => match self.cx.qpath_res(path, hir_id) { + Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => (), + Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (), + // No need to walk the arguments here, `is_const_evaluatable` already did + Res::Def(..) if is_const_evaluatable(self.cx, e) => { + self.eagerness |= NoChange; + return; + }, + Res::Def(_, id) => match path { + QPath::Resolved(_, p) => { + self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args); + }, + QPath::TypeRelative(_, name) => { + self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args); + }, + QPath::LangItem(..) => self.eagerness = Lazy, + }, + _ => self.eagerness = Lazy, + }, + // No need to walk the arguments here, `is_const_evaluatable` already did + ExprKind::MethodCall(..) if is_const_evaluatable(self.cx, e) => { + self.eagerness |= NoChange; + return; + }, + ExprKind::MethodCall(name, _, args, _) => { + self.eagerness |= self + .cx + .typeck_results() + .type_dependent_def_id(e.hir_id) + .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args)); + }, + ExprKind::Index(_, e) => { + let ty = self.cx.typeck_results().expr_ty_adjusted(e); + if is_copy(self.cx, ty) && !ty.is_ref() { + self.eagerness |= NoChange; + } else { + self.eagerness = Lazy; + } + }, + + // Dereferences should be cheap, but dereferencing a raw pointer earlier may not be safe. + ExprKind::Unary(UnOp::Deref, e) if !self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => (), + ExprKind::Unary(UnOp::Deref, _) => self.eagerness |= NoChange, + + ExprKind::Unary(_, e) + if matches!( + self.cx.typeck_results().expr_ty(e).kind(), + ty::Bool | ty::Int(_) | ty::Uint(_), + ) => {}, + ExprKind::Binary(_, lhs, rhs) + if self.cx.typeck_results().expr_ty(lhs).is_primitive() + && self.cx.typeck_results().expr_ty(rhs).is_primitive() => {}, + + // Can't be moved into a closure + ExprKind::Break(..) + | ExprKind::Continue(_) + | ExprKind::Ret(_) + | ExprKind::InlineAsm(_) + | ExprKind::LlvmInlineAsm(_) + | ExprKind::Yield(..) + | ExprKind::Err => { + self.eagerness = ForceNoChange; + return; + }, + + // Memory allocation, custom operator, loop, or call to an unknown function + ExprKind::Box(_) + | ExprKind::Unary(..) + | ExprKind::Binary(..) + | ExprKind::Loop(..) + | ExprKind::Call(..) => self.eagerness = Lazy, + + ExprKind::ConstBlock(_) + | ExprKind::Array(_) + | ExprKind::Tup(_) + | ExprKind::Lit(_) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::DropTemps(_) + | ExprKind::Let(..) + | ExprKind::If(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Field(..) + | ExprKind::Path(_) + | ExprKind::AddrOf(..) + | ExprKind::Struct(..) + | ExprKind::Repeat(..) + | ExprKind::Block(Block { stmts: [], .. }, _) => (), + + // Assignment might be to a local defined earlier, so don't eagerly evaluate. + // Blocks with multiple statements might be expensive, so don't eagerly evaluate. + // TODO: Actually check if either of these are true here. + ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Block(..) => self.eagerness |= NoChange, + } + walk_expr(self, e); + } } - let mut finder = FunCallFinder { cx, found: false }; - finder.visit_expr(expr); - finder.found + let mut v = V { + cx, + eagerness: EagernessSuggestion::Eager, + }; + v.visit_expr(e); + v.eagerness } -pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - !identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr) +/// Whether the given expression should be changed to evaluate eagerly +pub fn switch_to_eager_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + expr_eagerness(cx, expr) == EagernessSuggestion::Eager } -pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - identify_some_potentially_expensive_patterns(cx, expr) +/// Whether the given expression should be changed to evaluate lazily +pub fn switch_to_lazy_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + expr_eagerness(cx, expr) == EagernessSuggestion::Lazy } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 480923bbb02..b04d1736426 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -28,6 +28,7 @@ pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; /// Preferably use the diagnostic item `sym::Borrow` where possible pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; +pub const BORROW_MUT_TRAIT: [&str; 3] = ["core", "borrow", "BorrowMut"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index babab07ea9f..438c39bea0a 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -10,12 +10,12 @@ use rustc_hir::{TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, TypeFoldable, UintTy}; -use rustc_span::sym; -use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::{self, AdtDef, IntTy, Predicate, Ty, TyCtxt, TypeFoldable, UintTy}; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; +use std::iter; use crate::{match_def_path, must_use_attr}; @@ -391,3 +391,16 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { _ => false, } } + +/// Gets an iterator over all predicates which apply to the given item. +pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { + let mut next_id = Some(id); + iter::from_fn(move || { + next_id.take().map(|id| { + let preds = tcx.predicates_of(id); + next_id = preds.parent; + preds.predicates.iter() + }) + }) + .flatten() +} diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 988f6cf1d51..823df5cb751 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -1,9 +1,11 @@ use crate::path_to_local_id; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{def::Res, Arm, Block, Body, BodyId, Expr, ExprKind, HirId, Stmt}; +use rustc_hir::{Arm, Block, Body, BodyId, Expr, ExprKind, HirId, Stmt, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; +use rustc_middle::ty; /// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested /// bodies (i.e. closures) are visited. @@ -225,3 +227,93 @@ pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id drop(visitor); is_used } + +/// Checks if the given expression is a constant. +pub fn is_const_evaluatable(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { + struct V<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + is_const: bool, + } + impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { + type Map = Map<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if !self.is_const { + return; + } + match e.kind { + ExprKind::ConstBlock(_) => return, + ExprKind::Call( + &Expr { + kind: ExprKind::Path(ref p), + hir_id, + .. + }, + _, + ) if self + .cx + .qpath_res(p, hir_id) + .opt_def_id() + .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {}, + ExprKind::MethodCall(..) + if self + .cx + .typeck_results() + .type_dependent_def_id(e.hir_id) + .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {}, + ExprKind::Binary(_, lhs, rhs) + if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() + && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, + ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_ref() => (), + ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (), + ExprKind::Index(base, _) + if matches!( + self.cx.typeck_results().expr_ty(base).peel_refs().kind(), + ty::Slice(_) | ty::Array(..) + ) => {}, + ExprKind::Path(ref p) + if matches!( + self.cx.qpath_res(p, e.hir_id), + Res::Def( + DefKind::Const + | DefKind::AssocConst + | DefKind::AnonConst + | DefKind::ConstParam + | DefKind::Ctor(..) + | DefKind::Fn + | DefKind::AssocFn, + _ + ) | Res::SelfCtor(_) + ) => {}, + + ExprKind::AddrOf(..) + | ExprKind::Array(_) + | ExprKind::Block(..) + | ExprKind::Cast(..) + | ExprKind::DropTemps(_) + | ExprKind::Field(..) + | ExprKind::If(..) + | ExprKind::Let(..) + | ExprKind::Lit(_) + | ExprKind::Match(..) + | ExprKind::Repeat(..) + | ExprKind::Struct(..) + | ExprKind::Tup(_) + | ExprKind::Type(..) => (), + + _ => { + self.is_const = false; + return; + }, + } + walk_expr(self, e); + } + } + + let mut v = V { cx, is_const: true }; + v.visit_expr(e); + v.is_const +} diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 812ce7163cd..83f467c8400 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -108,6 +108,7 @@ fn test_return_in_macro() { } mod issue6501 { + #[allow(clippy::unnecessary_lazy_evaluations)] fn foo(bar: Result<(), ()>) { bar.unwrap_or_else(|_| {}) } diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index c42567b517c..341caf18bd6 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -108,6 +108,7 @@ fn test_return_in_macro() { } mod issue6501 { + #[allow(clippy::unnecessary_lazy_evaluations)] fn foo(bar: Result<(), ()>) { bar.unwrap_or_else(|_| return) } diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 74dda971fda..c0abc2c63dd 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -85,109 +85,109 @@ LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:112:32 + --> $DIR/needless_return.rs:113:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:117:13 + --> $DIR/needless_return.rs:118:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:119:20 + --> $DIR/needless_return.rs:120:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:125:32 + --> $DIR/needless_return.rs:126:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:134:5 + --> $DIR/needless_return.rs:135:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:138:5 + --> $DIR/needless_return.rs:139:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:143:9 + --> $DIR/needless_return.rs:144:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:145:9 + --> $DIR/needless_return.rs:146:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:151:17 + --> $DIR/needless_return.rs:152:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:153:13 + --> $DIR/needless_return.rs:154:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:160:9 + --> $DIR/needless_return.rs:161:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:162:16 + --> $DIR/needless_return.rs:163:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:170:5 + --> $DIR/needless_return.rs:171:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:175:9 + --> $DIR/needless_return.rs:176:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:177:9 + --> $DIR/needless_return.rs:178:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:184:14 + --> $DIR/needless_return.rs:185:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:199:9 + --> $DIR/needless_return.rs:200:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:201:9 + --> $DIR/needless_return.rs:202:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 9fdea79fe71..ce3093c542a 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -121,7 +121,7 @@ fn main() { let s = String::new(); // Lint, both branches immutably borrow `s`. - let _ = Some(0).map_or_else(|| s.len(), |x| s.len() + x); + let _ = Some(0).map_or(s.len(), |x| s.len() + x); let s = String::new(); // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`. diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index d7711bc1c47..4e64cd7cdb1 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -180,11 +180,11 @@ LL + } LL ~ }); | -error: use Option::map_or_else instead of an if let/else +error: use Option::map_or instead of an if let/else --> $DIR/option_if_let_else.rs:151:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else --> $DIR/option_if_let_else.rs:155:13 diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index c2f94d0e857..d6d6ab49734 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -43,7 +43,7 @@ fn or_fun_call() { with_enum.unwrap_or(Enum::A(5)); let with_const_fn = Some(Duration::from_secs(1)); - with_const_fn.unwrap_or_else(|| Duration::from_secs(5)); + with_const_fn.unwrap_or(Duration::from_secs(5)); let with_constructor = Some(vec![1]); with_constructor.unwrap_or_else(make); @@ -79,16 +79,16 @@ fn or_fun_call() { without_default.unwrap_or_else(Foo::new); let mut map = HashMap::::new(); - map.entry(42).or_insert_with(String::new); + map.entry(42).or_insert(String::new()); let mut map_vec = HashMap::>::new(); - map_vec.entry(42).or_insert_with(Vec::new); + map_vec.entry(42).or_insert(vec![]); let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert_with(String::new); + btree.entry(42).or_insert(String::new()); let mut btree_vec = BTreeMap::>::new(); - btree_vec.entry(42).or_insert_with(Vec::new); + btree_vec.entry(42).or_insert(vec![]); let stringy = Some(String::from("")); let _ = stringy.unwrap_or_else(|| "".to_owned()); @@ -129,7 +129,7 @@ fn test_or_with_ctors() { let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) - .or_else(|| Some(Bar(b, Duration::from_secs(2)))); + .or(Some(Bar(b, Duration::from_secs(2)))); let vec = vec!["foo"]; let _ = opt.ok_or(vec.len()); @@ -155,16 +155,24 @@ fn f() -> Option<()> { } mod issue6675 { + unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T { + #[allow(unused)] + let x = vec![0; 1000]; // future-proofing, make this function expensive. + &*p + } + unsafe fn foo() { - let mut s = "test".to_owned(); - None.unwrap_or_else(|| s.as_mut_vec()); + let s = "test".to_owned(); + let s = &s as *const _; + None.unwrap_or_else(|| ptr_to_ref(s)); } fn bar() { - let mut s = "test".to_owned(); - None.unwrap_or_else(|| unsafe { s.as_mut_vec() }); + let s = "test".to_owned(); + let s = &s as *const _; + None.unwrap_or_else(|| unsafe { ptr_to_ref(s) }); #[rustfmt::skip] - None.unwrap_or_else(|| unsafe { s.as_mut_vec() }); + None.unwrap_or_else(|| unsafe { ptr_to_ref(s) }); } } diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index afaf92961b0..8eadc6ce3b4 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -155,16 +155,24 @@ fn f() -> Option<()> { } mod issue6675 { + unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T { + #[allow(unused)] + let x = vec![0; 1000]; // future-proofing, make this function expensive. + &*p + } + unsafe fn foo() { - let mut s = "test".to_owned(); - None.unwrap_or(s.as_mut_vec()); + let s = "test".to_owned(); + let s = &s as *const _; + None.unwrap_or(ptr_to_ref(s)); } fn bar() { - let mut s = "test".to_owned(); - None.unwrap_or(unsafe { s.as_mut_vec() }); + let s = "test".to_owned(); + let s = &s as *const _; + None.unwrap_or(unsafe { ptr_to_ref(s) }); #[rustfmt::skip] - None.unwrap_or( unsafe { s.as_mut_vec() } ); + None.unwrap_or( unsafe { ptr_to_ref(s) } ); } } diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index b2bcbd38c2d..9d0c42b10c2 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,16 +1,10 @@ -error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:46:19 - | -LL | with_const_fn.unwrap_or(Duration::from_secs(5)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))` - | - = note: `-D clippy::or-fun-call` implied by `-D warnings` - error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:49:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` + | + = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:52:5 @@ -72,30 +66,6 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` -error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:82:19 - | -LL | map.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` - -error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:85:23 - | -LL | map_vec.entry(42).or_insert(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)` - -error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:88:21 - | -LL | btree.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` - -error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:91:25 - | -LL | btree_vec.entry(42).or_insert(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)` - error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:94:21 | @@ -120,29 +90,23 @@ error: use of `or` followed by a function call LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` -error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:132:10 - | -LL | .or(Some(Bar(b, Duration::from_secs(2)))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` - error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:160:14 + --> $DIR/or_fun_call.rs:167:14 | -LL | None.unwrap_or(s.as_mut_vec()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())` +LL | None.unwrap_or(ptr_to_ref(s)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:165:14 + --> $DIR/or_fun_call.rs:173:14 | -LL | None.unwrap_or(unsafe { s.as_mut_vec() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` +LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:167:14 + --> $DIR/or_fun_call.rs:175:14 | -LL | None.unwrap_or( unsafe { s.as_mut_vec() } ); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })` +LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` -error: aborting due to 24 previous errors +error: aborting due to 18 previous errors -- cgit 1.4.1-3-g733a5 From 7605bac2cb72627e29d0a82a70d5496a5a7a1827 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 16 Nov 2021 23:07:19 +0900 Subject: resolve CI --- clippy_lints/src/methods/option_map_or_none.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 12ccaa24c3b..b5652838892 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -72,10 +72,10 @@ pub(super) fn check<'tcx>( if is_option { let self_snippet = snippet(cx, recv.span, ".."); - if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind { + if_chain! { + if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind; let arg_snippet = snippet(cx, span, ".."); let body = cx.tcx.hir().body(id); - if_chain! { if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value); if arg_char.len() == 1; if let hir::ExprKind::Path(ref qpath) = func.kind; @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>( Applicability::MachineApplicable, ); } - } + } let func_snippet = snippet(cx, map_arg.span, ".."); -- cgit 1.4.1-3-g733a5 From c051656c836bf11335781afbabe1690ea7542f49 Mon Sep 17 00:00:00 2001 From: surechen Date: Fri, 29 Oct 2021 11:32:37 +0800 Subject: fixes: #7889 1. Fix the problem of manual_split_once changing the original behavior. 2. Add a new lint needless_splitn. changelog: Fix the problem of manual_split_once changing the original behavior and add a new lint needless_splitn. --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/methods/manual_split_once.rs | 211 ----------------- clippy_lints/src/methods/mod.rs | 34 ++- clippy_lints/src/methods/str_splitn.rs | 323 ++++++++++++++++++++++++++ tests/ui/manual_split_once.fixed | 6 +- tests/ui/manual_split_once.rs | 2 +- tests/ui/manual_split_once.stderr | 10 +- tests/ui/needless_splitn.fixed | 27 +++ tests/ui/needless_splitn.rs | 27 +++ tests/ui/needless_splitn.stderr | 40 ++++ tests/ui/suspicious_splitn.rs | 1 + tests/ui/suspicious_splitn.stderr | 18 +- 15 files changed, 468 insertions(+), 235 deletions(-) delete mode 100644 clippy_lints/src/methods/manual_split_once.rs create mode 100644 clippy_lints/src/methods/str_splitn.rs create mode 100644 tests/ui/needless_splitn.fixed create mode 100644 tests/ui/needless_splitn.rs create mode 100644 tests/ui/needless_splitn.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 267bc07d8fa..55c4c4c7a27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3038,6 +3038,7 @@ Released 2018-09-13 [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return +[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord [`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 4e123f27ec0..32c24a4aade 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -160,6 +160,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_AS_REF_DEREF), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index c51341bdf0c..dcc95cf6c07 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -42,6 +42,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::SEARCH_IS_SOME), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 249bf77a8f2..872e86ffcfb 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -288,6 +288,7 @@ store.register_lints(&[ methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, methods::OPTION_AS_REF_DEREF, diff --git a/clippy_lints/src/methods/manual_split_once.rs b/clippy_lints/src/methods/manual_split_once.rs deleted file mode 100644 index 13eb72251bb..00000000000 --- a/clippy_lints/src/methods/manual_split_once.rs +++ /dev/null @@ -1,211 +0,0 @@ -use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_context; -use clippy_utils::{is_diag_item_method, match_def_path, paths}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; -use rustc_lint::LateContext; -use rustc_middle::ty::{self, adjustment::Adjust}; -use rustc_span::{symbol::sym, Span, SyntaxContext}; - -use super::MANUAL_SPLIT_ONCE; - -pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { - if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { - return; - } - - let ctxt = expr.span.ctxt(); - let (method_name, msg, reverse) = if method_name == "splitn" { - ("split_once", "manual implementation of `split_once`", false) - } else { - ("rsplit_once", "manual implementation of `rsplit_once`", true) - }; - let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) { - Some(x) => x, - None => return, - }; - - let mut app = Applicability::MachineApplicable; - let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; - let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; - - let sugg = match usage.kind { - IterUsageKind::NextTuple => { - format!("{}.{}({})", self_snip, method_name, pat_snip) - }, - IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip), - IterUsageKind::Next => { - let self_deref = { - let adjust = cx.typeck_results().expr_adjustments(self_arg); - if adjust.is_empty() { - String::new() - } else if cx.typeck_results().expr_ty(self_arg).is_box() - || adjust - .iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box()) - { - format!("&{}", "*".repeat(adjust.len() - 1)) - } else { - "*".repeat(adjust.len() - 2) - } - }; - if usage.unwrap_kind.is_some() { - format!( - "{}.{}({}).map_or({}{}, |x| x.0)", - &self_snip, method_name, pat_snip, self_deref, &self_snip - ) - } else { - format!( - "Some({}.{}({}).map_or({}{}, |x| x.0))", - &self_snip, method_name, pat_snip, self_deref, &self_snip - ) - } - }, - IterUsageKind::Second => { - let access_str = match usage.unwrap_kind { - Some(UnwrapKind::Unwrap) => ".unwrap().1", - Some(UnwrapKind::QuestionMark) => "?.1", - None => ".map(|x| x.1)", - }; - format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str) - }, - }; - - span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); -} - -enum IterUsageKind { - Next, - Second, - NextTuple, - RNextTuple, -} - -enum UnwrapKind { - Unwrap, - QuestionMark, -} - -struct IterUsage { - kind: IterUsageKind, - unwrap_kind: Option, - span: Span, -} - -#[allow(clippy::too_many_lines)] -fn parse_iter_usage( - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - mut iter: impl Iterator)>, - reverse: bool, -) -> Option { - let (kind, span) = match iter.next() { - Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let (name, args) = if let ExprKind::MethodCall(name, _, [_, args @ ..], _) = e.kind { - (name, args) - } else { - return None; - }; - let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; - let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; - - match (&*name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if reverse { - (IterUsageKind::Second, e.span) - } else { - (IterUsageKind::Next, e.span) - } - }, - ("next_tuple", []) => { - return if_chain! { - if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); - if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); - if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did); - if let ty::Tuple(subs) = subs.type_at(0).kind(); - if subs.len() == 2; - then { - Some(IterUsage { - kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple }, - span: e.span, - unwrap_kind: None - }) - } else { - None - } - }; - }, - ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { - let span = if name.ident.as_str() == "nth" { - e.span - } else { - if_chain! { - if let Some((_, Node::Expr(next_expr))) = iter.next(); - if let ExprKind::MethodCall(next_name, _, [_], _) = next_expr.kind; - if next_name.ident.name == sym::next; - if next_expr.span.ctxt() == ctxt; - if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); - if cx.tcx.trait_of_item(next_id) == Some(iter_id); - then { - next_expr.span - } else { - return None; - } - } - }; - match if reverse { idx ^ 1 } else { idx } { - 0 => (IterUsageKind::Next, span), - 1 => (IterUsageKind::Second, span), - _ => return None, - } - } else { - return None; - } - }, - _ => return None, - } - }, - _ => return None, - }; - - let (unwrap_kind, span) = if let Some((_, Node::Expr(e))) = iter.next() { - match e.kind { - ExprKind::Call( - Expr { - kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)), - .. - }, - _, - ) => { - let parent_span = e.span.parent_callsite().unwrap(); - if parent_span.ctxt() == ctxt { - (Some(UnwrapKind::QuestionMark), parent_span) - } else { - (None, span) - } - }, - _ if e.span.ctxt() != ctxt => (None, span), - ExprKind::MethodCall(name, _, [_], _) - if name.ident.name == sym::unwrap - && cx - .typeck_results() - .type_dependent_def_id(e.hir_id) - .map_or(false, |id| is_diag_item_method(cx, id, sym::Option)) => - { - (Some(UnwrapKind::Unwrap), e.span) - }, - _ => (None, span), - } - } else { - (None, span) - }; - - Some(IterUsage { - kind, - unwrap_kind, - span, - }) -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 26c29fbb289..d36d84c9c43 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,7 +33,6 @@ mod iter_nth_zero; mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; -mod manual_split_once; mod manual_str_repeat; mod map_collect_result_unit; mod map_flatten; @@ -50,6 +49,7 @@ mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; mod skip_while_next; +mod str_splitn; mod string_extend_chars; mod suspicious_map; mod suspicious_splitn; @@ -1798,6 +1798,30 @@ declare_clippy_lint! { "replace `.splitn(2, pat)` with `.split_once(pat)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. + /// ### Why is this bad? + /// The function `split` is simpler and there is no performance difference in these cases, considering + /// that both functions return a lazy iterator. + /// ### Example + /// ```rust + /// // Bad + /// let str = "key=value=add"; + /// let _ = str.splitn(3, '=').next().unwrap(); + /// ``` + /// Use instead: + /// ```rust + /// // Good + /// let str = "key=value=add"; + /// let _ = str.split('=').next().unwrap(); + /// ``` + #[clippy::version = "1.58.0"] + pub NEEDLESS_SPLITN, + complexity, + "usages of `str::splitn` that can be replaced with `str::split`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -1876,7 +1900,8 @@ impl_lint_pass!(Methods => [ SUSPICIOUS_SPLITN, MANUAL_STR_REPEAT, EXTEND_WITH_DRAIN, - MANUAL_SPLIT_ONCE + MANUAL_SPLIT_ONCE, + NEEDLESS_SPLITN ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2208,7 +2233,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) { - manual_split_once::check(cx, name, expr, recv, pat_arg); + str_splitn::check_manual_split_once(cx, name, expr, recv, pat_arg); + } + if count >= 2 { + str_splitn::check_needless_splitn(cx, name, expr, recv, pat_arg, count); } } }, diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs new file mode 100644 index 00000000000..2595f734f11 --- /dev/null +++ b/clippy_lints/src/methods/str_splitn.rs @@ -0,0 +1,323 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::{is_diag_item_method, match_def_path, paths}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_span::{symbol::sym, Span, SyntaxContext}; + +use super::MANUAL_SPLIT_ONCE; + +pub(super) fn check_manual_split_once( + cx: &LateContext<'_>, + method_name: &str, + expr: &Expr<'_>, + self_arg: &Expr<'_>, + pat_arg: &Expr<'_>, +) { + if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { + return; + } + + let ctxt = expr.span.ctxt(); + let (method_name, msg, reverse) = if method_name == "splitn" { + ("split_once", "manual implementation of `split_once`", false) + } else { + ("rsplit_once", "manual implementation of `rsplit_once`", true) + }; + let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) { + Some(x) => x, + None => return, + }; + + let mut app = Applicability::MachineApplicable; + let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; + let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; + + let sugg = match usage.kind { + IterUsageKind::NextTuple => { + format!("{}.{}({})", self_snip, method_name, pat_snip) + }, + IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip), + IterUsageKind::Next | IterUsageKind::Second => { + let self_deref = { + let adjust = cx.typeck_results().expr_adjustments(self_arg); + if adjust.is_empty() { + String::new() + } else if cx.typeck_results().expr_ty(self_arg).is_box() + || adjust + .iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box()) + { + format!("&{}", "*".repeat(adjust.len() - 1)) + } else { + "*".repeat(adjust.len() - 2) + } + }; + if matches!(usage.kind, IterUsageKind::Next) { + match usage.unwrap_kind { + Some(UnwrapKind::Unwrap) => { + if reverse { + format!("{}.{}({}).unwrap().0", self_snip, method_name, pat_snip) + } else { + format!( + "{}.{}({}).map_or({}{}, |x| x.0)", + self_snip, method_name, pat_snip, self_deref, &self_snip + ) + } + }, + Some(UnwrapKind::QuestionMark) => { + format!( + "{}.{}({}).map_or({}{}, |x| x.0)", + self_snip, method_name, pat_snip, self_deref, &self_snip + ) + }, + None => { + format!( + "Some({}.{}({}).map_or({}{}, |x| x.0))", + &self_snip, method_name, pat_snip, self_deref, &self_snip + ) + }, + } + } else { + match usage.unwrap_kind { + Some(UnwrapKind::Unwrap) => { + if reverse { + // In this case, no better suggestion is offered. + return; + } + format!("{}.{}({}).unwrap().1", self_snip, method_name, pat_snip) + }, + Some(UnwrapKind::QuestionMark) => { + format!("{}.{}({})?.1", self_snip, method_name, pat_snip) + }, + None => { + format!("{}.{}({}).map(|x| x.1)", self_snip, method_name, pat_snip) + }, + } + } + }, + }; + + span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); +} + +enum IterUsageKind { + Next, + Second, + NextTuple, + RNextTuple, +} + +enum UnwrapKind { + Unwrap, + QuestionMark, +} + +struct IterUsage { + kind: IterUsageKind, + unwrap_kind: Option, + span: Span, +} + +#[allow(clippy::too_many_lines)] +fn parse_iter_usage( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + mut iter: impl Iterator)>, + reverse: bool, +) -> Option { + let (kind, span) = match iter.next() { + Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { + let (name, args) = if let ExprKind::MethodCall(name, _, [_, args @ ..], _) = e.kind { + (name, args) + } else { + return None; + }; + let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; + let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; + + match (&*name.ident.as_str(), args) { + ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if reverse { + (IterUsageKind::Second, e.span) + } else { + (IterUsageKind::Next, e.span) + } + }, + ("next_tuple", []) => { + return if_chain! { + if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); + if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); + if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did); + if let ty::Tuple(subs) = subs.type_at(0).kind(); + if subs.len() == 2; + then { + Some(IterUsage { + kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple }, + span: e.span, + unwrap_kind: None + }) + } else { + None + } + }; + }, + ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + let span = if name.ident.as_str() == "nth" { + e.span + } else { + if_chain! { + if let Some((_, Node::Expr(next_expr))) = iter.next(); + if let ExprKind::MethodCall(next_name, _, [_], _) = next_expr.kind; + if next_name.ident.name == sym::next; + if next_expr.span.ctxt() == ctxt; + if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); + if cx.tcx.trait_of_item(next_id) == Some(iter_id); + then { + next_expr.span + } else { + return None; + } + } + }; + match if reverse { idx ^ 1 } else { idx } { + 0 => (IterUsageKind::Next, span), + 1 => (IterUsageKind::Second, span), + _ => return None, + } + } else { + return None; + } + }, + _ => return None, + } + }, + _ => return None, + }; + + let (unwrap_kind, span) = if let Some((_, Node::Expr(e))) = iter.next() { + match e.kind { + ExprKind::Call( + Expr { + kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)), + .. + }, + _, + ) => { + let parent_span = e.span.parent_callsite().unwrap(); + if parent_span.ctxt() == ctxt { + (Some(UnwrapKind::QuestionMark), parent_span) + } else { + (None, span) + } + }, + _ if e.span.ctxt() != ctxt => (None, span), + ExprKind::MethodCall(name, _, [_], _) + if name.ident.name == sym::unwrap + && cx + .typeck_results() + .type_dependent_def_id(e.hir_id) + .map_or(false, |id| is_diag_item_method(cx, id, sym::Option)) => + { + (Some(UnwrapKind::Unwrap), e.span) + }, + _ => (None, span), + } + } else { + (None, span) + }; + + Some(IterUsage { + kind, + unwrap_kind, + span, + }) +} + +use super::NEEDLESS_SPLITN; + +pub(super) fn check_needless_splitn( + cx: &LateContext<'_>, + method_name: &str, + expr: &Expr<'_>, + self_arg: &Expr<'_>, + pat_arg: &Expr<'_>, + count: u128, +) { + if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { + return; + } + let ctxt = expr.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let (reverse, message) = if method_name == "splitn" { + (false, "unnecessary use of `splitn`") + } else { + (true, "unnecessary use of `rsplitn`") + }; + if_chain! { + if count >= 2; + if check_iter(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), count); + then { + span_lint_and_sugg( + cx, + NEEDLESS_SPLITN, + expr.span, + message, + "try this", + format!( + "{}.{}({})", + snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0, + if reverse {"rsplit"} else {"split"}, + snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0 + ), + app, + ); + } + } +} + +fn check_iter( + cx: &LateContext<'tcx>, + ctxt: SyntaxContext, + mut iter: impl Iterator)>, + count: u128, +) -> bool { + match iter.next() { + Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { + let (name, args) = if let ExprKind::MethodCall(name, _, [_, args @ ..], _) = e.kind { + (name, args) + } else { + return false; + }; + if_chain! { + if let Some(did) = cx.typeck_results().type_dependent_def_id(e.hir_id); + if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + then { + match (&*name.ident.as_str(), args) { + ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + return true; + }, + ("next_tuple", []) if count > 2 => { + return true; + }, + ("nth", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + if count > idx + 1 { + return true; + } + } + }, + _ => return false, + } + } + } + }, + _ => return false, + }; + false +} diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed index 992baf1f185..d5113df569a 100644 --- a/tests/ui/manual_split_once.fixed +++ b/tests/ui/manual_split_once.fixed @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![warn(clippy::manual_split_once)] -#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::needless_splitn)] extern crate itertools; @@ -38,8 +38,8 @@ fn main() { let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); // `rsplitn` gives the results in the reverse order of `rsplit_once` - let _ = "key=value".rsplit_once('=').unwrap().1; - let _ = "key=value".rsplit_once('=').map_or("key=value", |x| x.0); + let _ = "key=value".rsplitn(2, '=').next().unwrap(); + let _ = "key=value".rsplit_once('=').unwrap().0; let _ = "key=value".rsplit_once('=').map(|x| x.1); let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); } diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index 4f92ab6b812..80e02952dbd 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![warn(clippy::manual_split_once)] -#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::needless_splitn)] extern crate itertools; diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index 7bea2303d92..af9c7a2d41b 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -72,17 +72,11 @@ error: manual implementation of `split_once` LL | let _ = s.splitn(2, "key=value").skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` -error: manual implementation of `rsplit_once` - --> $DIR/manual_split_once.rs:41:13 - | -LL | let _ = "key=value".rsplitn(2, '=').next().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().1` - error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:42:13 | LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map_or("key=value", |x| x.0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().0` error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:43:13 @@ -102,5 +96,5 @@ error: manual implementation of `split_once` LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/needless_splitn.fixed b/tests/ui/needless_splitn.fixed new file mode 100644 index 00000000000..f6a4b2f17d3 --- /dev/null +++ b/tests/ui/needless_splitn.fixed @@ -0,0 +1,27 @@ +// run-rustfix +// edition:2018 + +#![feature(custom_inner_attributes)] +#![warn(clippy::needless_splitn)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let str = "key=value=end"; + let _ = str.split('=').next(); + let _ = str.split('=').nth(0); + let _ = str.splitn(2, '=').nth(1); + let (_, _) = str.splitn(2, '=').next_tuple().unwrap(); + let (_, _) = str.split('=').next_tuple().unwrap(); + let _: Vec<&str> = str.splitn(3, '=').collect(); + + let _ = str.rsplit('=').next(); + let _ = str.rsplit('=').nth(0); + let _ = str.rsplitn(2, '=').nth(1); + let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap(); + let (_, _) = str.rsplit('=').next_tuple().unwrap(); +} diff --git a/tests/ui/needless_splitn.rs b/tests/ui/needless_splitn.rs new file mode 100644 index 00000000000..6ba32255bb2 --- /dev/null +++ b/tests/ui/needless_splitn.rs @@ -0,0 +1,27 @@ +// run-rustfix +// edition:2018 + +#![feature(custom_inner_attributes)] +#![warn(clippy::needless_splitn)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] + +extern crate itertools; + +#[allow(unused_imports)] +use itertools::Itertools; + +fn main() { + let str = "key=value=end"; + let _ = str.splitn(2, '=').next(); + let _ = str.splitn(2, '=').nth(0); + let _ = str.splitn(2, '=').nth(1); + let (_, _) = str.splitn(2, '=').next_tuple().unwrap(); + let (_, _) = str.splitn(3, '=').next_tuple().unwrap(); + let _: Vec<&str> = str.splitn(3, '=').collect(); + + let _ = str.rsplitn(2, '=').next(); + let _ = str.rsplitn(2, '=').nth(0); + let _ = str.rsplitn(2, '=').nth(1); + let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap(); + let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); +} diff --git a/tests/ui/needless_splitn.stderr b/tests/ui/needless_splitn.stderr new file mode 100644 index 00000000000..66de2256554 --- /dev/null +++ b/tests/ui/needless_splitn.stderr @@ -0,0 +1,40 @@ +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:15:13 + | +LL | let _ = str.splitn(2, '=').next(); + | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | + = note: `-D clippy::needless-splitn` implied by `-D warnings` + +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:16:13 + | +LL | let _ = str.splitn(2, '=').nth(0); + | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:19:18 + | +LL | let (_, _) = str.splitn(3, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + +error: unnecessary use of `rsplitn` + --> $DIR/needless_splitn.rs:22:13 + | +LL | let _ = str.rsplitn(2, '=').next(); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + +error: unnecessary use of `rsplitn` + --> $DIR/needless_splitn.rs:23:13 + | +LL | let _ = str.rsplitn(2, '=').nth(0); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + +error: unnecessary use of `rsplitn` + --> $DIR/needless_splitn.rs:26:18 + | +LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/suspicious_splitn.rs b/tests/ui/suspicious_splitn.rs index a21d94cf20b..528f2ddcc86 100644 --- a/tests/ui/suspicious_splitn.rs +++ b/tests/ui/suspicious_splitn.rs @@ -1,4 +1,5 @@ #![warn(clippy::suspicious_splitn)] +#![allow(clippy::needless_splitn)] fn main() { let _ = "a,b,c".splitn(3, ','); diff --git a/tests/ui/suspicious_splitn.stderr b/tests/ui/suspicious_splitn.stderr index b6220ae2393..3bcd681fa49 100644 --- a/tests/ui/suspicious_splitn.stderr +++ b/tests/ui/suspicious_splitn.stderr @@ -1,5 +1,5 @@ error: `splitn` called with `0` splits - --> $DIR/suspicious_splitn.rs:9:13 + --> $DIR/suspicious_splitn.rs:10:13 | LL | let _ = "a,b".splitn(0, ','); | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = "a,b".splitn(0, ','); = note: the resulting iterator will always return `None` error: `rsplitn` called with `0` splits - --> $DIR/suspicious_splitn.rs:10:13 + --> $DIR/suspicious_splitn.rs:11:13 | LL | let _ = "a,b".rsplitn(0, ','); | ^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = "a,b".rsplitn(0, ','); = note: the resulting iterator will always return `None` error: `splitn` called with `1` split - --> $DIR/suspicious_splitn.rs:11:13 + --> $DIR/suspicious_splitn.rs:12:13 | LL | let _ = "a,b".splitn(1, ','); | ^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = "a,b".splitn(1, ','); = note: the resulting iterator will always return the entire string followed by `None` error: `splitn` called with `0` splits - --> $DIR/suspicious_splitn.rs:12:13 + --> $DIR/suspicious_splitn.rs:13:13 | LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1); = note: the resulting iterator will always return `None` error: `splitn_mut` called with `0` splits - --> $DIR/suspicious_splitn.rs:13:13 + --> $DIR/suspicious_splitn.rs:14:13 | LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); = note: the resulting iterator will always return `None` error: `splitn` called with `1` split - --> $DIR/suspicious_splitn.rs:14:13 + --> $DIR/suspicious_splitn.rs:15:13 | LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1); = note: the resulting iterator will always return the entire slice followed by `None` error: `rsplitn_mut` called with `1` split - --> $DIR/suspicious_splitn.rs:15:13 + --> $DIR/suspicious_splitn.rs:16:13 | LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); = note: the resulting iterator will always return the entire slice followed by `None` error: `splitn` called with `1` split - --> $DIR/suspicious_splitn.rs:18:13 + --> $DIR/suspicious_splitn.rs:19:13 | LL | let _ = "a,b".splitn(X + 1, ','); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = "a,b".splitn(X + 1, ','); = note: the resulting iterator will always return the entire string followed by `None` error: `splitn` called with `0` splits - --> $DIR/suspicious_splitn.rs:19:13 + --> $DIR/suspicious_splitn.rs:20:13 | LL | let _ = "a,b".splitn(X, ','); | ^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 006c4426577bf243f7218f951d0c9ada6b4fe737 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Thu, 18 Nov 2021 00:36:11 +0900 Subject: check whether stmts is empty or not in block --- clippy_lints/src/methods/option_map_or_none.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index b5652838892..5e5c1038e82 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -20,8 +20,8 @@ fn reduce_unit_expression<'a>( match expr.kind { hir::ExprKind::Call(func, arg_char) => Some((func, arg_char)), hir::ExprKind::Block(block, _) => { - match block.expr { - Some(inner_expr) => { + match (block.stmts, block.expr) { + (&[], Some(inner_expr)) => { // If block only contains an expression, // reduce `|x| { x + 1 }` to `|x| x + 1` reduce_unit_expression(cx, inner_expr) -- cgit 1.4.1-3-g733a5 From f4c75cde5e5226912995f6809e96efd2ac2c2348 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 13 Jul 2021 11:26:24 +0200 Subject: Fix `any()` not taking reference in `search_is_some` lint --- clippy_lints/src/methods/search_is_some.rs | 22 +++++++++++++++++-- tests/ui/search_is_some_fixable.fixed | 35 ++++++++++++++++++++++++++++++ tests/ui/search_is_some_fixable.rs | 35 ++++++++++++++++++++++++++++++ tests/ui/search_is_some_fixable.stderr | 14 +++++++++++- 4 files changed, 103 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 0f2e58d8983..42a0a09f385 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -45,9 +45,27 @@ pub(super) fn check<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(closure_arg.pat).kind { + } else if let PatKind::Binding(annotation, _, ident, _) = strip_pat_refs(closure_arg.pat).kind { let name = &*ident.name.as_str(); - Some(search_snippet.replace(&format!("*{}", name), name)) + let old_search_snippet = search_snippet.clone(); + let search_snippet = search_snippet.replace(&format!("*{}", name), name); + + if_chain! { + // if there is no dereferencing used in closure body + if old_search_snippet == search_snippet; + if annotation == hir::BindingAnnotation::Unannotated; + if let ty::Ref(_, inner_ty, _) = cx.typeck_results().node_type(closure_arg.hir_id).kind(); + if let ty::Ref(..) = inner_ty.kind(); + // put an `&` in the closure body, but skip closure params + if let Some((start, end)) = old_search_snippet.split_once(&name); + + then { + let end = end.replace(name, &format!("&{}", name)); + Some(format!("{}{}{}", start, name, end)) + } else { + Some(search_snippet) + } + } } else { None } diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed index 62ff16f67f4..029f557ffa6 100644 --- a/tests/ui/search_is_some_fixable.fixed +++ b/tests/ui/search_is_some_fixable.fixed @@ -66,3 +66,38 @@ fn is_none() { let _ = !s1[2..].contains(&s2); let _ = !s1[2..].contains(&s2[2..]); } + +#[allow(clippy::clone_on_copy, clippy::map_clone)] +mod issue7392 { + struct Player { + hand: Vec, + } + fn filter() { + let p = Player { + hand: vec![1, 2, 3, 4, 5], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|c| !filter_hand.iter().any(|cc| c == &cc)) + .map(|c| c.clone()) + .collect::>(); + } + + struct PlayerTuple { + hand: Vec<(usize, char)>, + } + fn filter_tuple() { + let p = PlayerTuple { + hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc)) + .map(|c| c.clone()) + .collect::>(); + } +} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs index 8407f716647..b8f8fe3d3c1 100644 --- a/tests/ui/search_is_some_fixable.rs +++ b/tests/ui/search_is_some_fixable.rs @@ -66,3 +66,38 @@ fn is_none() { let _ = s1[2..].find(&s2).is_none(); let _ = s1[2..].find(&s2[2..]).is_none(); } + +#[allow(clippy::clone_on_copy, clippy::map_clone)] +mod issue7392 { + struct Player { + hand: Vec, + } + fn filter() { + let p = Player { + hand: vec![1, 2, 3, 4, 5], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + .map(|c| c.clone()) + .collect::>(); + } + + struct PlayerTuple { + hand: Vec<(usize, char)>, + } + fn filter_tuple() { + let p = PlayerTuple { + hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + .map(|c| c.clone()) + .collect::>(); + } +} diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index bd1b6955a97..0d92722229c 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -180,5 +180,17 @@ error: called `is_none()` after calling `find()` on a string LL | let _ = s1[2..].find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` -error: aborting due to 30 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:83:25 + | +LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:99:30 + | +LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)` + +error: aborting due to 32 previous errors -- cgit 1.4.1-3-g733a5 From 5ed93af9c41e552c8d85390e2387d01eb9429174 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 9 Aug 2021 12:00:35 +0200 Subject: Use `ExprUseVisitor` and multipart suggestion to avoid iffy `String` replacement --- clippy_lints/src/methods/search_is_some.rs | 186 ++++++++++++++++++++++------- tests/ui/search_is_some.rs | 45 +++++++ tests/ui/search_is_some.stderr | 128 +++++++++++++++++++- tests/ui/search_is_some_fixable.fixed | 43 ------- tests/ui/search_is_some_fixable.rs | 43 ------- tests/ui/search_is_some_fixable.stderr | 98 ++++----------- 6 files changed, 334 insertions(+), 209 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 42a0a09f385..71fca601747 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,15 +1,19 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::PatKind; +use rustc_hir::{self, HirId, HirIdMap, HirIdSet, PatKind}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; +use rustc_middle::hir::place::ProjectionKind; +use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; use rustc_span::source_map::Span; use rustc_span::symbol::sym; +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use super::SEARCH_IS_SOME; @@ -42,30 +46,42 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind; let closure_body = cx.tcx.hir().body(body_id); if let Some(closure_arg) = closure_body.params.get(0); + then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { - Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(annotation, _, ident, _) = strip_pat_refs(closure_arg.pat).kind { - let name = &*ident.name.as_str(); - let old_search_snippet = search_snippet.clone(); - let search_snippet = search_snippet.replace(&format!("*{}", name), name); - - if_chain! { - // if there is no dereferencing used in closure body - if old_search_snippet == search_snippet; - if annotation == hir::BindingAnnotation::Unannotated; - if let ty::Ref(_, inner_ty, _) = cx.typeck_results().node_type(closure_arg.hir_id).kind(); - if let ty::Ref(..) = inner_ty.kind(); - // put an `&` in the closure body, but skip closure params - if let Some((start, end)) = old_search_snippet.split_once(&name); - - then { - let end = end.replace(name, &format!("&{}", name)); - Some(format!("{}{}{}", start, name, end)) - } else { - Some(search_snippet) + Some((search_snippet.replacen('&', "", 1), None)) + } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { + let mut visitor = DerefDelegate { + cx, + set: HirIdSet::default(), + deref_suggs: HirIdMap::default(), + borrow_suggs: HirIdMap::default() + }; + + let fn_def_id = cx.tcx.hir().local_def_id(search_arg.hir_id); + cx.tcx.infer_ctxt().enter(|infcx| { + ExprUseVisitor::new( + &mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results() + ).consume_body(closure_body); + }); + + let replacements = if visitor.set.is_empty() { + None + } else { + let mut deref_suggs = Vec::new(); + let mut borrow_suggs = Vec::new(); + for node in visitor.set { + let span = cx.tcx.hir().span(node); + if let Some(sugg) = visitor.deref_suggs.get(&node) { + deref_suggs.push((span, sugg.clone())); + } + if let Some(sugg) = visitor.borrow_suggs.get(&node) { + borrow_suggs.push((span, sugg.clone())); + } } - } + Some((deref_suggs, borrow_suggs)) + }; + Some((search_snippet.to_string(), replacements)) } else { None } @@ -74,35 +90,38 @@ pub(super) fn check<'tcx>( } }; // add note if not multi-line - if is_some { - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, + let (closure_snippet, replacements) = any_search_snippet + .as_ref() + .map_or((&*search_snippet, None), |s| (&s.0, s.1.clone())); + let (span, help, sugg) = if is_some { + ( method_span.with_hi(expr.span.hi()), - &msg, "use `any()` instead", - format!( - "any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); + format!("any({})", closure_snippet), + ) } else { let iter = snippet(cx, search_recv.span, ".."); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, + ( expr.span, - &msg, "use `!_.any()` instead", - format!( - "!{}.any({})", - iter, - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), - Applicability::MachineApplicable, - ); - } + format!("!{}.any({})", iter, closure_snippet), + ) + }; + + span_lint_and_then(cx, SEARCH_IS_SOME, span, &msg, |db| { + if let Some((deref_suggs, borrow_suggs)) = replacements { + db.span_suggestion(span, help, sugg, Applicability::MaybeIncorrect); + + if !deref_suggs.is_empty() { + db.multipart_suggestion("...and remove deref", deref_suggs, Applicability::MaybeIncorrect); + } + if !borrow_suggs.is_empty() { + db.multipart_suggestion("...and borrow variable", borrow_suggs, Applicability::MaybeIncorrect); + } + } else { + db.span_suggestion(span, help, sugg, Applicability::MachineApplicable); + } + }); } else { let hint = format!( "this is more succinctly expressed by calling `any()`{}", @@ -164,3 +183,78 @@ pub(super) fn check<'tcx>( } } } + +struct DerefDelegate<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + set: HirIdSet, + deref_suggs: HirIdMap, + borrow_suggs: HirIdMap, +} + +impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { + fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { + if let PlaceBase::Local(id) = cmt.place.base { + let map = self.cx.tcx.hir(); + if cmt.place.projections.is_empty() { + self.set.insert(cmt.hir_id); + } else { + let mut replacement_str = map.name(id).to_string(); + let last_deref = cmt + .place + .projections + .iter() + .rposition(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(pos) = last_deref { + let mut projections = cmt.place.projections.clone(); + projections.truncate(pos); + + for item in projections { + if item.kind == ProjectionKind::Deref { + replacement_str = format!("*{}", replacement_str); + } + } + + self.set.insert(cmt.hir_id); + self.deref_suggs.insert(cmt.hir_id, replacement_str); + } + } + } + } + + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { + if let PlaceBase::Local(id) = cmt.place.base { + let map = self.cx.tcx.hir(); + if cmt.place.projections.is_empty() { + let replacement_str = format!("&{}", map.name(id).to_string()); + self.set.insert(cmt.hir_id); + self.borrow_suggs.insert(cmt.hir_id, replacement_str); + } else { + let mut replacement_str = map.name(id).to_string(); + let last_deref = cmt + .place + .projections + .iter() + .rposition(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(pos) = last_deref { + let mut projections = cmt.place.projections.clone(); + projections.truncate(pos); + + for item in projections { + if item.kind == ProjectionKind::Deref { + replacement_str = format!("*{}", replacement_str); + } + } + + self.set.insert(cmt.hir_id); + self.deref_suggs.insert(cmt.hir_id, replacement_str); + } + } + } + } + + fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} +} diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index 72bc6ef35d3..dfc79207ca7 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -36,6 +36,11 @@ fn main() { // check that we don't lint if `find()` is called with // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); + + // Check `find().is_some()`, single-line case. + let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_some(); + let _ = v.iter().find(|x| **x == 0).is_some(); } #[rustfmt::skip] @@ -70,4 +75,44 @@ fn is_none() { // check that we don't lint if `find()` is called with // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none(); + + // Check `find().is_none()`, single-line case. + let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_none(); + let _ = v.iter().find(|x| **x == 0).is_none(); +} + +#[allow(clippy::clone_on_copy, clippy::map_clone)] +mod issue7392 { + struct Player { + hand: Vec, + } + fn filter() { + let p = Player { + hand: vec![1, 2, 3, 4, 5], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + .map(|c| c.clone()) + .collect::>(); + } + + struct PlayerTuple { + hand: Vec<(usize, char)>, + } + fn filter_tuple() { + let p = PlayerTuple { + hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + .map(|c| c.clone()) + .collect::>(); + } } diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index f3c758e451e..8db936fd948 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -35,8 +35,53 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:41:20 + | +LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `any()` instead + | +LL | let _ = (0..1).any(|x| **y == *x); // one dereference less + | ^^^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | let _ = (0..1).find(|x| **y == x).is_some(); // one dereference less + | ^ + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:42:20 + | +LL | let _ = (0..1).find(|x| *x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `any()` instead + | +LL | let _ = (0..1).any(|x| *x == 0); + | ^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | let _ = (0..1).find(|x| x == 0).is_some(); + | ^ + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:43:22 + | +LL | let _ = v.iter().find(|x| **x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `any()` instead + | +LL | let _ = v.iter().any(|x| **x == 0); + | ^^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | let _ = v.iter().find(|x| *x == 0).is_some(); + | ^^ + error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:48:13 + --> $DIR/search_is_some.rs:53:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -48,7 +93,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> $DIR/search_is_some.rs:54:13 + --> $DIR/search_is_some.rs:59:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -60,7 +105,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some.rs:60:13 + --> $DIR/search_is_some.rs:65:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -71,5 +116,80 @@ LL | | ).is_none(); | = help: this is more succinctly expressed by calling `any()` with negation -error: aborting due to 6 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:80:13 + | +LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!_.any()` instead + | +LL | let _ = !(0..1).any(|x| **y == *x); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | let _ = (0..1).find(|x| **y == x).is_none(); // one dereference less + | ^ + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:81:13 + | +LL | let _ = (0..1).find(|x| *x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!_.any()` instead + | +LL | let _ = !(0..1).any(|x| *x == 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | let _ = (0..1).find(|x| x == 0).is_none(); + | ^ + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:82:13 + | +LL | let _ = v.iter().find(|x| **x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!_.any()` instead + | +LL | let _ = !v.iter().any(|x| **x == 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | let _ = v.iter().find(|x| *x == 0).is_none(); + | ^^ + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:98:25 + | +LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!_.any()` instead + | +LL | .filter(|c| !filter_hand.iter().any(|cc| c == cc)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: ...and borrow variable + | +LL | .filter(|c| filter_hand.iter().find(|cc| c == &cc).is_none()) + | ^^^ + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:114:30 + | +LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `!_.any()` instead + | +LL | .filter(|(c, _)| !filter_hand.iter().any(|cc| c == *cc)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: ...and remove deref + | +LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == cc).is_none()) + | ^^ + +error: aborting due to 14 previous errors diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed index 029f557ffa6..6994df427ba 100644 --- a/tests/ui/search_is_some_fixable.fixed +++ b/tests/ui/search_is_some_fixable.fixed @@ -4,13 +4,9 @@ fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; // Check `find().is_some()`, single-line case. let _ = v.iter().any(|x| *x < 0); - let _ = (0..1).any(|x| **y == x); // one dereference less - let _ = (0..1).any(|x| x == 0); - let _ = v.iter().any(|x| *x == 0); // Check `position().is_some()`, single-line case. let _ = v.iter().any(|&x| x < 0); @@ -36,13 +32,9 @@ fn main() { fn is_none() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; // Check `find().is_none()`, single-line case. let _ = !v.iter().any(|x| *x < 0); - let _ = !(0..1).any(|x| **y == x); // one dereference less - let _ = !(0..1).any(|x| x == 0); - let _ = !v.iter().any(|x| *x == 0); // Check `position().is_none()`, single-line case. let _ = !v.iter().any(|&x| x < 0); @@ -66,38 +58,3 @@ fn is_none() { let _ = !s1[2..].contains(&s2); let _ = !s1[2..].contains(&s2[2..]); } - -#[allow(clippy::clone_on_copy, clippy::map_clone)] -mod issue7392 { - struct Player { - hand: Vec, - } - fn filter() { - let p = Player { - hand: vec![1, 2, 3, 4, 5], - }; - let filter_hand = vec![5]; - let _ = p - .hand - .iter() - .filter(|c| !filter_hand.iter().any(|cc| c == &cc)) - .map(|c| c.clone()) - .collect::>(); - } - - struct PlayerTuple { - hand: Vec<(usize, char)>, - } - fn filter_tuple() { - let p = PlayerTuple { - hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], - }; - let filter_hand = vec![5]; - let _ = p - .hand - .iter() - .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc)) - .map(|c| c.clone()) - .collect::>(); - } -} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs index b8f8fe3d3c1..d4c9d89e7b8 100644 --- a/tests/ui/search_is_some_fixable.rs +++ b/tests/ui/search_is_some_fixable.rs @@ -4,13 +4,9 @@ fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; // Check `find().is_some()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_some(); - let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_some(); - let _ = v.iter().find(|x| **x == 0).is_some(); // Check `position().is_some()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_some(); @@ -36,13 +32,9 @@ fn main() { fn is_none() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; // Check `find().is_none()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_none(); - let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_none(); - let _ = v.iter().find(|x| **x == 0).is_none(); // Check `position().is_none()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_none(); @@ -66,38 +58,3 @@ fn is_none() { let _ = s1[2..].find(&s2).is_none(); let _ = s1[2..].find(&s2[2..]).is_none(); } - -#[allow(clippy::clone_on_copy, clippy::map_clone)] -mod issue7392 { - struct Player { - hand: Vec, - } - fn filter() { - let p = Player { - hand: vec![1, 2, 3, 4, 5], - }; - let filter_hand = vec![5]; - let _ = p - .hand - .iter() - .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) - .map(|c| c.clone()) - .collect::>(); - } - - struct PlayerTuple { - hand: Vec<(usize, char)>, - } - fn filter_tuple() { - let p = PlayerTuple { - hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], - }; - let filter_hand = vec![5]; - let _ = p - .hand - .iter() - .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) - .map(|c| c.clone()) - .collect::>(); - } -} diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index 0d92722229c..5e77c9a5bac 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -1,196 +1,148 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:10:22 + --> $DIR/search_is_some_fixable.rs:9:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:11:20 - | -LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` - -error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:12:20 - | -LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` - -error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:13:22 - | -LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` - error: called `is_some()` after searching an `Iterator` with `position` - --> $DIR/search_is_some_fixable.rs:16:22 + --> $DIR/search_is_some_fixable.rs:12:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some_fixable.rs:19:22 + --> $DIR/search_is_some_fixable.rs:15:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:24:27 + --> $DIR/search_is_some_fixable.rs:20:27 | LL | let _ = "hello world".find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:25:27 + --> $DIR/search_is_some_fixable.rs:21:27 | LL | let _ = "hello world".find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:26:27 + --> $DIR/search_is_some_fixable.rs:22:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:28:16 + --> $DIR/search_is_some_fixable.rs:24:16 | LL | let _ = s1.find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:29:16 + --> $DIR/search_is_some_fixable.rs:25:16 | LL | let _ = s1.find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:30:16 + --> $DIR/search_is_some_fixable.rs:26:16 | LL | let _ = s1.find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:32:21 + --> $DIR/search_is_some_fixable.rs:28:21 | LL | let _ = s1[2..].find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:33:21 + --> $DIR/search_is_some_fixable.rs:29:21 | LL | let _ = s1[2..].find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:34:21 + --> $DIR/search_is_some_fixable.rs:30:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:42:13 + --> $DIR/search_is_some_fixable.rs:37:13 | LL | let _ = v.iter().find(|&x| *x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:43:13 - | -LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)` - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:44:13 - | -LL | let _ = (0..1).find(|x| *x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)` - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:45:13 - | -LL | let _ = v.iter().find(|x| **x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)` - error: called `is_none()` after searching an `Iterator` with `position` - --> $DIR/search_is_some_fixable.rs:48:13 + --> $DIR/search_is_some_fixable.rs:40:13 | LL | let _ = v.iter().position(|&x| x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some_fixable.rs:51:13 + --> $DIR/search_is_some_fixable.rs:43:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:57:13 + --> $DIR/search_is_some_fixable.rs:49:13 | LL | let _ = "hello world".find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:58:13 + --> $DIR/search_is_some_fixable.rs:50:13 | LL | let _ = "hello world".find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:59:13 + --> $DIR/search_is_some_fixable.rs:51:13 | LL | let _ = "hello world".find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:61:13 + --> $DIR/search_is_some_fixable.rs:53:13 | LL | let _ = s1.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:62:13 + --> $DIR/search_is_some_fixable.rs:54:13 | LL | let _ = s1.find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:63:13 + --> $DIR/search_is_some_fixable.rs:55:13 | LL | let _ = s1.find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:65:13 + --> $DIR/search_is_some_fixable.rs:57:13 | LL | let _ = s1[2..].find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:66:13 + --> $DIR/search_is_some_fixable.rs:58:13 | LL | let _ = s1[2..].find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:67:13 + --> $DIR/search_is_some_fixable.rs:59:13 | LL | let _ = s1[2..].find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:83:25 - | -LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)` - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:99:30 - | -LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)` - -error: aborting due to 32 previous errors +error: aborting due to 24 previous errors -- cgit 1.4.1-3-g733a5 From b38f173aa329d6a5932414b9c76227d790faee76 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Wed, 18 Aug 2021 16:51:34 +0200 Subject: Build suggestion within visitor + add more tests --- clippy_lints/src/methods/search_is_some.rs | 202 +++++++++++++++-------------- tests/ui/search_is_some.rs | 45 ------- tests/ui/search_is_some.stderr | 128 +----------------- tests/ui/search_is_some_fixable.fixed | 54 ++++++++ tests/ui/search_is_some_fixable.rs | 57 ++++++++ tests/ui/search_is_some_fixable.stderr | 163 +++++++++++++++++++---- 6 files changed, 355 insertions(+), 294 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 71fca601747..ee0e6d3a33f 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,17 +1,17 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_trait_method, strip_pat_refs}; +use clippy_utils::{get_parent_expr_for_hir, is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{self, HirId, HirIdMap, HirIdSet, PatKind}; +use rustc_hir::{self, Expr, ExprKind, HirId, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::place::ProjectionKind; -use rustc_middle::mir::FakeReadCause; +use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty; -use rustc_span::source_map::Span; +use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::sym; use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -46,42 +46,12 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind; let closure_body = cx.tcx.hir().body(body_id); if let Some(closure_arg) = closure_body.params.get(0); - then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { - Some((search_snippet.replacen('&', "", 1), None)) + Some(search_snippet.replacen('&', "", 1)) } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { - let mut visitor = DerefDelegate { - cx, - set: HirIdSet::default(), - deref_suggs: HirIdMap::default(), - borrow_suggs: HirIdMap::default() - }; - - let fn_def_id = cx.tcx.hir().local_def_id(search_arg.hir_id); - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new( - &mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results() - ).consume_body(closure_body); - }); - - let replacements = if visitor.set.is_empty() { - None - } else { - let mut deref_suggs = Vec::new(); - let mut borrow_suggs = Vec::new(); - for node in visitor.set { - let span = cx.tcx.hir().span(node); - if let Some(sugg) = visitor.deref_suggs.get(&node) { - deref_suggs.push((span, sugg.clone())); - } - if let Some(sugg) = visitor.borrow_suggs.get(&node) { - borrow_suggs.push((span, sugg.clone())); - } - } - Some((deref_suggs, borrow_suggs)) - }; - Some((search_snippet.to_string(), replacements)) + get_closure_suggestion(cx, search_arg, closure_body) + .or_else(|| Some(search_snippet.to_string())) } else { None } @@ -90,38 +60,35 @@ pub(super) fn check<'tcx>( } }; // add note if not multi-line - let (closure_snippet, replacements) = any_search_snippet - .as_ref() - .map_or((&*search_snippet, None), |s| (&s.0, s.1.clone())); - let (span, help, sugg) = if is_some { - ( + if is_some { + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), + &msg, "use `any()` instead", - format!("any({})", closure_snippet), - ) + format!( + "any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); } else { let iter = snippet(cx, search_recv.span, ".."); - ( + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, expr.span, + &msg, "use `!_.any()` instead", - format!("!{}.any({})", iter, closure_snippet), - ) - }; - - span_lint_and_then(cx, SEARCH_IS_SOME, span, &msg, |db| { - if let Some((deref_suggs, borrow_suggs)) = replacements { - db.span_suggestion(span, help, sugg, Applicability::MaybeIncorrect); - - if !deref_suggs.is_empty() { - db.multipart_suggestion("...and remove deref", deref_suggs, Applicability::MaybeIncorrect); - } - if !borrow_suggs.is_empty() { - db.multipart_suggestion("...and borrow variable", borrow_suggs, Applicability::MaybeIncorrect); - } - } else { - db.span_suggestion(span, help, sugg, Applicability::MachineApplicable); - } - }); + format!( + "!{}.any({})", + iter, + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ), + Applicability::MachineApplicable, + ); + } } else { let hint = format!( "this is more succinctly expressed by calling `any()`{}", @@ -184,53 +151,86 @@ pub(super) fn check<'tcx>( } } +fn get_closure_suggestion<'tcx>( + cx: &LateContext<'_>, + search_arg: &'tcx hir::Expr<'_>, + closure_body: &hir::Body<'_>, +) -> Option { + let mut visitor = DerefDelegate { + cx, + closure_span: search_arg.span, + next_pos: None, + suggestion_start: String::new(), + suggestion_end: String::new(), + }; + + let fn_def_id = cx.tcx.hir().local_def_id(search_arg.hir_id); + cx.tcx.infer_ctxt().enter(|infcx| { + ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) + .consume_body(closure_body); + }); + + if visitor.suggestion_start.is_empty() { + None + } else { + Some(format!("{}{}", visitor.suggestion_start, visitor.suggestion_end)) + } +} + struct DerefDelegate<'a, 'tcx> { cx: &'a LateContext<'tcx>, - set: HirIdSet, - deref_suggs: HirIdMap, - borrow_suggs: HirIdMap, + closure_span: Span, + next_pos: Option, + suggestion_start: String, + suggestion_end: String, } impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { - fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if let PlaceBase::Local(id) = cmt.place.base { let map = self.cx.tcx.hir(); - if cmt.place.projections.is_empty() { - self.set.insert(cmt.hir_id); + let ident_str = map.name(id).to_string(); + let span = map.span(cmt.hir_id); + let start_span = if let Some(next_pos) = self.next_pos { + Span::new(next_pos, span.lo(), span.ctxt()) } else { - let mut replacement_str = map.name(id).to_string(); - let last_deref = cmt - .place - .projections - .iter() - .rposition(|proj| proj.kind == ProjectionKind::Deref); + self.closure_span.until(span) + }; + let start_snip = snippet(self.cx, start_span, ".."); + let end_span = Span::new(span.hi(), self.closure_span.hi(), span.ctxt()); + let end_snip = snippet(self.cx, end_span, ".."); - if let Some(pos) = last_deref { - let mut projections = cmt.place.projections.clone(); - projections.truncate(pos); + if cmt.place.projections.is_empty() { + self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); + } else { + let parent_expr = get_parent_expr_for_hir(self.cx, cmt.hir_id); + if let Some(Expr { hir_id: _, kind, .. }) = parent_expr { + if let ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) = kind { + let args_to_handle = args.iter().filter(|arg| arg.hir_id == cmt.hir_id).collect::>(); + if !args_to_handle.is_empty() { + for arg in &args_to_handle { + let arg_ty_kind = self.cx.typeck_results().expr_ty(arg).kind(); + if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { + let start_span = if let Some(next_pos) = self.next_pos { + Span::new(next_pos, span.lo(), span.ctxt()) + } else { + self.closure_span.until(span) + }; + let start_snip = snippet(self.cx, start_span, ".."); - for item in projections { - if item.kind == ProjectionKind::Deref { - replacement_str = format!("*{}", replacement_str); + self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); + self.suggestion_end = end_snip.to_string(); + self.next_pos = Some(span.hi()); + } + } + return; } } - - self.set.insert(cmt.hir_id); - self.deref_suggs.insert(cmt.hir_id, replacement_str); } - } - } - } - fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { - if let PlaceBase::Local(id) = cmt.place.base { - let map = self.cx.tcx.hir(); - if cmt.place.projections.is_empty() { - let replacement_str = format!("&{}", map.name(id).to_string()); - self.set.insert(cmt.hir_id); - self.borrow_suggs.insert(cmt.hir_id, replacement_str); - } else { - let mut replacement_str = map.name(id).to_string(); + let mut replacement_str = ident_str; let last_deref = cmt .place .projections @@ -246,11 +246,13 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { replacement_str = format!("*{}", replacement_str); } } - - self.set.insert(cmt.hir_id); - self.deref_suggs.insert(cmt.hir_id, replacement_str); } + + self.suggestion_start + .push_str(&format!("{}{}", start_snip, replacement_str)); + self.suggestion_end = end_snip.to_string(); } + self.next_pos = Some(span.hi()); } } diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index dfc79207ca7..72bc6ef35d3 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -36,11 +36,6 @@ fn main() { // check that we don't lint if `find()` is called with // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); - - // Check `find().is_some()`, single-line case. - let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_some(); - let _ = v.iter().find(|x| **x == 0).is_some(); } #[rustfmt::skip] @@ -75,44 +70,4 @@ fn is_none() { // check that we don't lint if `find()` is called with // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none(); - - // Check `find().is_none()`, single-line case. - let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_none(); - let _ = v.iter().find(|x| **x == 0).is_none(); -} - -#[allow(clippy::clone_on_copy, clippy::map_clone)] -mod issue7392 { - struct Player { - hand: Vec, - } - fn filter() { - let p = Player { - hand: vec![1, 2, 3, 4, 5], - }; - let filter_hand = vec![5]; - let _ = p - .hand - .iter() - .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) - .map(|c| c.clone()) - .collect::>(); - } - - struct PlayerTuple { - hand: Vec<(usize, char)>, - } - fn filter_tuple() { - let p = PlayerTuple { - hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], - }; - let filter_hand = vec![5]; - let _ = p - .hand - .iter() - .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) - .map(|c| c.clone()) - .collect::>(); - } } diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index 8db936fd948..f3c758e451e 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -35,53 +35,8 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:41:20 - | -LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `any()` instead - | -LL | let _ = (0..1).any(|x| **y == *x); // one dereference less - | ^^^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | let _ = (0..1).find(|x| **y == x).is_some(); // one dereference less - | ^ - -error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:42:20 - | -LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `any()` instead - | -LL | let _ = (0..1).any(|x| *x == 0); - | ^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | let _ = (0..1).find(|x| x == 0).is_some(); - | ^ - -error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:43:22 - | -LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `any()` instead - | -LL | let _ = v.iter().any(|x| **x == 0); - | ^^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | let _ = v.iter().find(|x| *x == 0).is_some(); - | ^^ - error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:53:13 + --> $DIR/search_is_some.rs:48:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -93,7 +48,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> $DIR/search_is_some.rs:59:13 + --> $DIR/search_is_some.rs:54:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -105,7 +60,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some.rs:65:13 + --> $DIR/search_is_some.rs:60:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -116,80 +71,5 @@ LL | | ).is_none(); | = help: this is more succinctly expressed by calling `any()` with negation -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:80:13 - | -LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `!_.any()` instead - | -LL | let _ = !(0..1).any(|x| **y == *x); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | let _ = (0..1).find(|x| **y == x).is_none(); // one dereference less - | ^ - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:81:13 - | -LL | let _ = (0..1).find(|x| *x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `!_.any()` instead - | -LL | let _ = !(0..1).any(|x| *x == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | let _ = (0..1).find(|x| x == 0).is_none(); - | ^ - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:82:13 - | -LL | let _ = v.iter().find(|x| **x == 0).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `!_.any()` instead - | -LL | let _ = !v.iter().any(|x| **x == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | let _ = v.iter().find(|x| *x == 0).is_none(); - | ^^ - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:98:25 - | -LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `!_.any()` instead - | -LL | .filter(|c| !filter_hand.iter().any(|cc| c == cc)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: ...and borrow variable - | -LL | .filter(|c| filter_hand.iter().find(|cc| c == &cc).is_none()) - | ^^^ - -error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:114:30 - | -LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `!_.any()` instead - | -LL | .filter(|(c, _)| !filter_hand.iter().any(|cc| c == *cc)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: ...and remove deref - | -LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == cc).is_none()) - | ^^ - -error: aborting due to 14 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed index 6994df427ba..967b3d1be43 100644 --- a/tests/ui/search_is_some_fixable.fixed +++ b/tests/ui/search_is_some_fixable.fixed @@ -4,9 +4,19 @@ fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; // Check `find().is_some()`, single-line case. let _ = v.iter().any(|x| *x < 0); + let _ = (0..1).any(|x| **y == x); // one dereference less + let _ = (0..1).any(|x| x == 0); + let _ = v.iter().any(|x| *x == 0); + let _ = (4..5).any(|x| x == 1 || x == 3 || x == 5); + let _ = (1..3).any(|x| [1, 2, 3].contains(&x)); + let _ = (1..3).any(|x| x == 0 || [1, 2, 3].contains(&x)); + let _ = (1..3).any(|x| [1, 2, 3].contains(&x) || x == 0); + let _ = (1..3) + .any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1); // Check `position().is_some()`, single-line case. let _ = v.iter().any(|&x| x < 0); @@ -32,9 +42,18 @@ fn main() { fn is_none() { let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; // Check `find().is_none()`, single-line case. let _ = !v.iter().any(|x| *x < 0); + let _ = !(0..1).any(|x| **y == x); // one dereference less + let _ = !(0..1).any(|x| x == 0); + let _ = !v.iter().any(|x| *x == 0); + let _ = !(4..5).any(|x| x == 1 || x == 3 || x == 5); + let _ = !(1..3).any(|x| [1, 2, 3].contains(&x)); + let _ = !(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x)); + let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0); + let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1); // Check `position().is_none()`, single-line case. let _ = !v.iter().any(|&x| x < 0); @@ -58,3 +77,38 @@ fn is_none() { let _ = !s1[2..].contains(&s2); let _ = !s1[2..].contains(&s2[2..]); } + +#[allow(clippy::clone_on_copy, clippy::map_clone)] +mod issue7392 { + struct Player { + hand: Vec, + } + fn filter() { + let p = Player { + hand: vec![1, 2, 3, 4, 5], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|c| !filter_hand.iter().any(|cc| c == &cc)) + .map(|c| c.clone()) + .collect::>(); + } + + struct PlayerTuple { + hand: Vec<(usize, char)>, + } + fn filter_tuple() { + let p = PlayerTuple { + hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc)) + .map(|c| c.clone()) + .collect::>(); + } +} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs index d4c9d89e7b8..e642523a532 100644 --- a/tests/ui/search_is_some_fixable.rs +++ b/tests/ui/search_is_some_fixable.rs @@ -4,9 +4,20 @@ fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; // Check `find().is_some()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_some(); + let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_some(); + let _ = v.iter().find(|x| **x == 0).is_some(); + let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some(); + let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some(); + let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some(); + let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some(); + let _ = (1..3) + .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) + .is_some(); // Check `position().is_some()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_some(); @@ -32,9 +43,20 @@ fn main() { fn is_none() { let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; // Check `find().is_none()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_none(); + let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_none(); + let _ = v.iter().find(|x| **x == 0).is_none(); + let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none(); + let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none(); + let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none(); + let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none(); + let _ = (1..3) + .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) + .is_none(); // Check `position().is_none()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_none(); @@ -58,3 +80,38 @@ fn is_none() { let _ = s1[2..].find(&s2).is_none(); let _ = s1[2..].find(&s2[2..]).is_none(); } + +#[allow(clippy::clone_on_copy, clippy::map_clone)] +mod issue7392 { + struct Player { + hand: Vec, + } + fn filter() { + let p = Player { + hand: vec![1, 2, 3, 4, 5], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + .map(|c| c.clone()) + .collect::>(); + } + + struct PlayerTuple { + hand: Vec<(usize, char)>, + } + fn filter_tuple() { + let p = PlayerTuple { + hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')], + }; + let filter_hand = vec![5]; + let _ = p + .hand + .iter() + .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + .map(|c| c.clone()) + .collect::>(); + } +} diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index 5e77c9a5bac..3bb8cc573ec 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -1,148 +1,261 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:9:22 + --> $DIR/search_is_some_fixable.rs:10:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:11:20 + | +LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:12:20 + | +LL | let _ = (0..1).find(|x| *x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:13:22 + | +LL | let _ = v.iter().find(|x| **x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:14:20 + | +LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 1 || x == 3 || x == 5)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:15:20 + | +LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:16:20 + | +LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0 || [1, 2, 3].contains(&x))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:17:20 + | +LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:19:10 + | +LL | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) + | __________^ +LL | | .is_some(); + | |__________________^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` + error: called `is_some()` after searching an `Iterator` with `position` - --> $DIR/search_is_some_fixable.rs:12:22 + --> $DIR/search_is_some_fixable.rs:23:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some_fixable.rs:15:22 + --> $DIR/search_is_some_fixable.rs:26:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:20:27 + --> $DIR/search_is_some_fixable.rs:31:27 | LL | let _ = "hello world".find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:21:27 + --> $DIR/search_is_some_fixable.rs:32:27 | LL | let _ = "hello world".find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:22:27 + --> $DIR/search_is_some_fixable.rs:33:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:24:16 + --> $DIR/search_is_some_fixable.rs:35:16 | LL | let _ = s1.find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:25:16 + --> $DIR/search_is_some_fixable.rs:36:16 | LL | let _ = s1.find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:26:16 + --> $DIR/search_is_some_fixable.rs:37:16 | LL | let _ = s1.find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:28:21 + --> $DIR/search_is_some_fixable.rs:39:21 | LL | let _ = s1[2..].find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:29:21 + --> $DIR/search_is_some_fixable.rs:40:21 | LL | let _ = s1[2..].find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:30:21 + --> $DIR/search_is_some_fixable.rs:41:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable.rs:37:13 + --> $DIR/search_is_some_fixable.rs:49:13 | LL | let _ = v.iter().find(|&x| *x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:50:13 + | +LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:51:13 + | +LL | let _ = (0..1).find(|x| *x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:52:13 + | +LL | let _ = v.iter().find(|x| **x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:53:13 + | +LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:54:13 + | +LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:55:13 + | +LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:56:13 + | +LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:57:13 + | +LL | let _ = (1..3) + | _____________^ +LL | | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) +LL | | .is_none(); + | |__________________^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` + error: called `is_none()` after searching an `Iterator` with `position` - --> $DIR/search_is_some_fixable.rs:40:13 + --> $DIR/search_is_some_fixable.rs:62:13 | LL | let _ = v.iter().position(|&x| x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some_fixable.rs:43:13 + --> $DIR/search_is_some_fixable.rs:65:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:49:13 + --> $DIR/search_is_some_fixable.rs:71:13 | LL | let _ = "hello world".find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:50:13 + --> $DIR/search_is_some_fixable.rs:72:13 | LL | let _ = "hello world".find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:51:13 + --> $DIR/search_is_some_fixable.rs:73:13 | LL | let _ = "hello world".find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:53:13 + --> $DIR/search_is_some_fixable.rs:75:13 | LL | let _ = s1.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:54:13 + --> $DIR/search_is_some_fixable.rs:76:13 | LL | let _ = s1.find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:55:13 + --> $DIR/search_is_some_fixable.rs:77:13 | LL | let _ = s1.find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:57:13 + --> $DIR/search_is_some_fixable.rs:79:13 | LL | let _ = s1[2..].find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:58:13 + --> $DIR/search_is_some_fixable.rs:80:13 | LL | let _ = s1[2..].find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable.rs:59:13 + --> $DIR/search_is_some_fixable.rs:81:13 | LL | let _ = s1[2..].find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])` -error: aborting due to 24 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:97:25 + | +LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:113:30 + | +LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)` + +error: aborting due to 42 previous errors -- cgit 1.4.1-3-g733a5 From 6dca4f261d01584aac507379649458fbaf04d4c8 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 19 Aug 2021 11:50:05 +0200 Subject: Add some doc for `search_is_some` lint --- clippy_lints/src/methods/search_is_some.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ee0e6d3a33f..b0bfe8d80e0 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -50,6 +50,8 @@ pub(super) fn check<'tcx>( if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { + // `find()` provides a reference to the item, but `any` does not, + // so we should fix item usages for suggestion get_closure_suggestion(cx, search_arg, closure_body) .or_else(|| Some(search_snippet.to_string())) } else { @@ -151,6 +153,9 @@ pub(super) fn check<'tcx>( } } +// Build suggestion gradually by handling closure arg specific usages, +// such as explicit deref and borrowing cases. +// Returns `None` if no such use cases have been triggered in closure body fn get_closure_suggestion<'tcx>( cx: &LateContext<'_>, search_arg: &'tcx hir::Expr<'_>, @@ -203,8 +208,12 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let end_snip = snippet(self.cx, end_span, ".."); if cmt.place.projections.is_empty() { + // handle item without any projection, that needs an explicit borrowing + // i.e.: suggest `&x` instead of `x` self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); } else { + // cases where a parent call is using the item + // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` let parent_expr = get_parent_expr_for_hir(self.cx, cmt.hir_id); if let Some(Expr { hir_id: _, kind, .. }) = parent_expr { if let ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) = kind { @@ -230,6 +239,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } } + // handle item projections by removing one explicit deref + // i.e.: suggest `*x` instead of `**x` let mut replacement_str = ident_str; let last_deref = cmt .place -- cgit 1.4.1-3-g733a5 From e24aba2c1a8663c2ddebdae740689f8a7bdcadb7 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 7 Sep 2021 11:06:50 +0200 Subject: Use applicability for snippets --- clippy_lints/src/methods/search_is_some.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index b0bfe8d80e0..ec09bfd743d 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -167,6 +167,7 @@ fn get_closure_suggestion<'tcx>( next_pos: None, suggestion_start: String::new(), suggestion_end: String::new(), + applicability: Applicability::MachineApplicable, }; let fn_def_id = cx.tcx.hir().local_def_id(search_arg.hir_id); @@ -188,6 +189,7 @@ struct DerefDelegate<'a, 'tcx> { next_pos: Option, suggestion_start: String, suggestion_end: String, + applicability: Applicability, } impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { @@ -203,9 +205,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } else { self.closure_span.until(span) }; - let start_snip = snippet(self.cx, start_span, ".."); + let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); let end_span = Span::new(span.hi(), self.closure_span.hi(), span.ctxt()); - let end_snip = snippet(self.cx, end_span, ".."); + let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing @@ -227,11 +229,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } else { self.closure_span.until(span) }; - let start_snip = snippet(self.cx, start_span, ".."); + let start_snip = + snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); self.suggestion_end = end_snip.to_string(); self.next_pos = Some(span.hi()); + } else { + self.applicability = Applicability::Unspecified; } } return; -- cgit 1.4.1-3-g733a5 From 9ab4b673eb41cca04a626797bb130bda4a14bd1b Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 7 Sep 2021 11:18:27 +0200 Subject: Simplifying `next_pos` init --- clippy_lints/src/methods/search_is_some.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ec09bfd743d..b38b8e44f1c 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -164,7 +164,7 @@ fn get_closure_suggestion<'tcx>( let mut visitor = DerefDelegate { cx, closure_span: search_arg.span, - next_pos: None, + next_pos: search_arg.span.lo(), suggestion_start: String::new(), suggestion_end: String::new(), applicability: Applicability::MachineApplicable, @@ -186,7 +186,7 @@ fn get_closure_suggestion<'tcx>( struct DerefDelegate<'a, 'tcx> { cx: &'a LateContext<'tcx>, closure_span: Span, - next_pos: Option, + next_pos: BytePos, suggestion_start: String, suggestion_end: String, applicability: Applicability, @@ -200,11 +200,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let map = self.cx.tcx.hir(); let ident_str = map.name(id).to_string(); let span = map.span(cmt.hir_id); - let start_span = if let Some(next_pos) = self.next_pos { - Span::new(next_pos, span.lo(), span.ctxt()) - } else { - self.closure_span.until(span) - }; + let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); let end_span = Span::new(span.hi(), self.closure_span.hi(), span.ctxt()); let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); @@ -224,17 +220,13 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { for arg in &args_to_handle { let arg_ty_kind = self.cx.typeck_results().expr_ty(arg).kind(); if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { - let start_span = if let Some(next_pos) = self.next_pos { - Span::new(next_pos, span.lo(), span.ctxt()) - } else { - self.closure_span.until(span) - }; + let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); self.suggestion_end = end_snip.to_string(); - self.next_pos = Some(span.hi()); + self.next_pos = span.hi(); } else { self.applicability = Applicability::Unspecified; } @@ -268,7 +260,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { .push_str(&format!("{}{}", start_snip, replacement_str)); self.suggestion_end = end_snip.to_string(); } - self.next_pos = Some(span.hi()); + self.next_pos = span.hi(); } } -- cgit 1.4.1-3-g733a5 From d0dd797709540f460ee6c9ac26f1231335781b40 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 7 Sep 2021 11:59:53 +0200 Subject: Build end of suggestion only once at the end of the process --- clippy_lints/src/methods/search_is_some.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index b38b8e44f1c..e793c50ac9d 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -166,7 +166,6 @@ fn get_closure_suggestion<'tcx>( closure_span: search_arg.span, next_pos: search_arg.span.lo(), suggestion_start: String::new(), - suggestion_end: String::new(), applicability: Applicability::MachineApplicable, }; @@ -179,7 +178,7 @@ fn get_closure_suggestion<'tcx>( if visitor.suggestion_start.is_empty() { None } else { - Some(format!("{}{}", visitor.suggestion_start, visitor.suggestion_end)) + Some(visitor.finish()) } } @@ -188,10 +187,17 @@ struct DerefDelegate<'a, 'tcx> { closure_span: Span, next_pos: BytePos, suggestion_start: String, - suggestion_end: String, applicability: Applicability, } +impl DerefDelegate<'_, 'tcx> { + pub fn finish(&mut self) -> String { + let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt()); + let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); + format!("{}{}", self.suggestion_start, end_snip) + } +} + impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} @@ -202,8 +208,6 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let span = map.span(cmt.hir_id); let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); - let end_span = Span::new(span.hi(), self.closure_span.hi(), span.ctxt()); - let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing @@ -225,7 +229,6 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); - self.suggestion_end = end_snip.to_string(); self.next_pos = span.hi(); } else { self.applicability = Applicability::Unspecified; @@ -258,7 +261,6 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { self.suggestion_start .push_str(&format!("{}{}", start_snip, replacement_str)); - self.suggestion_end = end_snip.to_string(); } self.next_pos = span.hi(); } -- cgit 1.4.1-3-g733a5 From 97783a8cb9b154b17abbf0084fe8a16d490cf801 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 7 Sep 2021 12:31:14 +0200 Subject: Return a struct and add applicability --- clippy_lints/src/methods/search_is_some.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index e793c50ac9d..a1206199460 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -41,6 +41,7 @@ pub(super) fn check<'tcx>( if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` + let mut applicability = Applicability::MachineApplicable; let any_search_snippet = if_chain! { if search_method == "find"; if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind; @@ -52,8 +53,12 @@ pub(super) fn check<'tcx>( } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { // `find()` provides a reference to the item, but `any` does not, // so we should fix item usages for suggestion - get_closure_suggestion(cx, search_arg, closure_body) - .or_else(|| Some(search_snippet.to_string())) + if let Some(closure_sugg) = get_closure_suggestion(cx, search_arg, closure_body) { + applicability = closure_sugg.applicability; + Some(closure_sugg.suggestion) + } else { + Some(search_snippet.to_string()) + } } else { None } @@ -73,7 +78,7 @@ pub(super) fn check<'tcx>( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) ), - Applicability::MachineApplicable, + applicability, ); } else { let iter = snippet(cx, search_recv.span, ".."); @@ -88,7 +93,7 @@ pub(super) fn check<'tcx>( iter, any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) ), - Applicability::MachineApplicable, + applicability, ); } } else { @@ -153,6 +158,11 @@ pub(super) fn check<'tcx>( } } +struct ClosureSugg { + applicability: Applicability, + suggestion: String, +} + // Build suggestion gradually by handling closure arg specific usages, // such as explicit deref and borrowing cases. // Returns `None` if no such use cases have been triggered in closure body @@ -160,7 +170,7 @@ fn get_closure_suggestion<'tcx>( cx: &LateContext<'_>, search_arg: &'tcx hir::Expr<'_>, closure_body: &hir::Body<'_>, -) -> Option { +) -> Option { let mut visitor = DerefDelegate { cx, closure_span: search_arg.span, @@ -178,7 +188,10 @@ fn get_closure_suggestion<'tcx>( if visitor.suggestion_start.is_empty() { None } else { - Some(visitor.finish()) + Some(ClosureSugg { + applicability: visitor.applicability, + suggestion: visitor.finish(), + }) } } -- cgit 1.4.1-3-g733a5 From 91dd9c46de11b9abeb391d5b19707c5e7ddfef98 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 12 Sep 2021 11:31:11 +0200 Subject: Handle other projection kinds --- clippy_lints/src/methods/search_is_some.rs | 80 ++++++++++++++++++++++++----- tests/ui/search_is_some_fixable_none.fixed | 24 +++++++++ tests/ui/search_is_some_fixable_none.rs | 26 ++++++++++ tests/ui/search_is_some_fixable_none.stderr | 36 ++++++++++++- tests/ui/search_is_some_fixable_some.fixed | 25 +++++++++ tests/ui/search_is_some_fixable_some.rs | 26 ++++++++++ tests/ui/search_is_some_fixable_some.stderr | 28 +++++++++- 7 files changed, 231 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index a1206199460..d09baf50e49 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -220,7 +220,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let ident_str = map.name(id).to_string(); let span = map.span(cmt.hir_id); let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); - let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing @@ -255,19 +255,75 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // handle item projections by removing one explicit deref // i.e.: suggest `*x` instead of `**x` let mut replacement_str = ident_str; - let last_deref = cmt - .place - .projections - .iter() - .rposition(|proj| proj.kind == ProjectionKind::Deref); - if let Some(pos) = last_deref { - let mut projections = cmt.place.projections.clone(); - projections.truncate(pos); + // handle index projection first + let index_handled = cmt.place.projections.iter().any(|proj| match proj.kind { + // Index projection like `|x| foo[x]` + // the index is dropped so we can't get it to build the suggestion, + // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`) + // instead of `span.lo()` (i.e.: `foo`) + ProjectionKind::Index => { + let start_span = Span::new(self.next_pos, span.hi(), span.ctxt()); + start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + replacement_str.clear(); + true + }, + _ => false, + }); + + // looking for projections other that need to be handled differently + let other_projections_handled = cmt.place.projections.iter().enumerate().any(|(i, proj)| { + match proj.kind { + // Field projection like `|v| v.foo` + ProjectionKind::Field(idx, variant) => match cmt.place.ty_before_projection(i).kind() { + ty::Adt(def, ..) => { + replacement_str = format!( + "{}.{}", + replacement_str, + def.variants[variant].fields[idx as usize].ident.name.as_str() + ); + true + }, + ty::Tuple(_) => { + replacement_str = format!("{}.{}", replacement_str, idx); + true + }, + _ => false, + }, + ProjectionKind::Index => false, /* handled previously */ + // note: unable to capture `Subslice` kind in tests + ProjectionKind::Subslice => false, + ProjectionKind::Deref => { + // explicit deref for arrays should be avoided in the suggestion + // i.e.: `|sub| *sub[1..4].len() == 3` is not expected + match cmt.place.ty_before_projection(i).kind() { + // dereferencing an array (i.e.: `|sub| sub[1..4].len() == 3`) + ty::Ref(_, inner, _) => match inner.kind() { + ty::Ref(_, innermost, _) if innermost.is_array() => true, + _ => false, + }, + _ => false, + } + }, + } + }); - for item in projections { - if item.kind == ProjectionKind::Deref { - replacement_str = format!("*{}", replacement_str); + // handle `ProjectionKind::Deref` if no special case detected + if !index_handled && !other_projections_handled { + let last_deref = cmt + .place + .projections + .iter() + .rposition(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(pos) = last_deref { + let mut projections = cmt.place.projections.clone(); + projections.truncate(pos); + + for item in projections { + if item.kind == ProjectionKind::Deref { + replacement_str = format!("*{}", replacement_str); + } } } } diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 5d9953f9b3c..222731fd212 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -73,4 +73,28 @@ mod issue7392 { .map(|c| c.clone()) .collect::>(); } + + fn field_projection() { + struct Foo { + foo: i32, + bar: u32, + } + let vfoo = vec![Foo { foo: 1, bar: 2 }]; + let _ = !vfoo.iter().any(|v| v.foo == 1 && v.bar == 2); + + let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; + let _ = !vfoo + .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); + } + + fn index_projection() { + let vfoo = vec![[0, 1, 2, 3]]; + let _ = !vfoo.iter().any(|a| a[0] == 42); + } + + #[allow(clippy::match_like_matches_macro)] + fn slice_projection() { + let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; + let _ = !vfoo.iter().any(|sub| sub[1..4].len() == 3); + } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 2a8aadfd0e0..43ac1a07667 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -75,4 +75,30 @@ mod issue7392 { .map(|c| c.clone()) .collect::>(); } + + fn field_projection() { + struct Foo { + foo: i32, + bar: u32, + } + let vfoo = vec![Foo { foo: 1, bar: 2 }]; + let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none(); + + let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; + let _ = vfoo + .iter() + .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) + .is_none(); + } + + fn index_projection() { + let vfoo = vec![[0, 1, 2, 3]]; + let _ = vfoo.iter().find(|a| a[0] == 42).is_none(); + } + + #[allow(clippy::match_like_matches_macro)] + fn slice_projection() { + let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; + let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); + } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 34768feb6dd..fa344046aeb 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -135,5 +135,39 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)` -error: aborting due to 22 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:85:17 + | +LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:88:17 + | +LL | let _ = vfoo + | _________________^ +LL | | .iter() +LL | | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) +LL | | .is_none(); + | |______________________^ + | +help: use `!_.any()` instead + | +LL ~ let _ = !vfoo +LL ~ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); + | + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:96:17 + | +LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|a| a[0] == 42)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:102:17 + | +LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` + +error: aborting due to 26 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 94a4c7b3639..ae9478a42e9 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -73,4 +73,29 @@ mod issue7392 { .map(|c| c.clone()) .collect::>(); } + + fn field_projection() { + struct Foo { + foo: i32, + bar: u32, + } + let vfoo = vec![Foo { foo: 1, bar: 2 }]; + let _ = vfoo.iter().any(|v| v.foo == 1 && v.bar == 2); + + let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; + let _ = vfoo + .iter() + .any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); + } + + fn index_projection() { + let vfoo = vec![[0, 1, 2, 3]]; + let _ = vfoo.iter().any(|a| a[0] == 42); + } + + #[allow(clippy::match_like_matches_macro)] + fn slice_projection() { + let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; + let _ = vfoo.iter().any(|sub| sub[1..4].len() == 3); + } } diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index 8887b0327e2..98c3e7c1a68 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -74,4 +74,30 @@ mod issue7392 { .map(|c| c.clone()) .collect::>(); } + + fn field_projection() { + struct Foo { + foo: i32, + bar: u32, + } + let vfoo = vec![Foo { foo: 1, bar: 2 }]; + let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some(); + + let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; + let _ = vfoo + .iter() + .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) + .is_some(); + } + + fn index_projection() { + let vfoo = vec![[0, 1, 2, 3]]; + let _ = vfoo.iter().find(|a| a[0] == 42).is_some(); + } + + #[allow(clippy::match_like_matches_macro)] + fn slice_projection() { + let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; + let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); + } } diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index 90615a85ca3..4161b5eec0a 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -134,5 +134,31 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == cc)` -error: aborting due to 22 previous errors +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:84:29 + | +LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.foo == 1 && v.bar == 2)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:89:14 + | +LL | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) + | ______________^ +LL | | .is_some(); + | |______________________^ help: use `any()` instead: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:95:29 + | +LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|a| a[0] == 42)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:101:29 + | +LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)` + +error: aborting due to 26 previous errors -- cgit 1.4.1-3-g733a5 From 788c9ccc938ac0384fd06a071806502121af1a5a Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 12 Sep 2021 11:40:14 +0200 Subject: Applying refactoring for simplified code --- clippy_lints/src/methods/search_is_some.rs | 47 ++++++++++++++---------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index d09baf50e49..a5e6a8df03f 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -5,7 +5,7 @@ use clippy_utils::{get_parent_expr_for_hir, is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{self, Expr, ExprKind, HirId, PatKind}; +use rustc_hir::{self, ExprKind, HirId, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::place::ProjectionKind; @@ -229,26 +229,23 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } else { // cases where a parent call is using the item // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` - let parent_expr = get_parent_expr_for_hir(self.cx, cmt.hir_id); - if let Some(Expr { hir_id: _, kind, .. }) = parent_expr { - if let ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) = kind { - let args_to_handle = args.iter().filter(|arg| arg.hir_id == cmt.hir_id).collect::>(); - if !args_to_handle.is_empty() { - for arg in &args_to_handle { - let arg_ty_kind = self.cx.typeck_results().expr_ty(arg).kind(); - if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { - let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); - let start_snip = - snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) { + if let ExprKind::Call(..) | ExprKind::MethodCall(..) = parent_expr.kind { + let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); + let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); - self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); - self.next_pos = span.hi(); - } else { - self.applicability = Applicability::Unspecified; - } - } - return; + // Note: this should always be true, as `find` only gives us a reference which are not mutable + if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { + let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); + let start_snip = + snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + + self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); + self.next_pos = span.hi(); + } else { + self.applicability = Applicability::Unspecified; } + return; } } @@ -290,17 +287,17 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { }, _ => false, }, - ProjectionKind::Index => false, /* handled previously */ - // note: unable to capture `Subslice` kind in tests - ProjectionKind::Subslice => false, + // handled previously + ProjectionKind::Index | + // note: unable to trigger `Subslice` kind in tests + ProjectionKind::Subslice => false, ProjectionKind::Deref => { // explicit deref for arrays should be avoided in the suggestion // i.e.: `|sub| *sub[1..4].len() == 3` is not expected match cmt.place.ty_before_projection(i).kind() { // dereferencing an array (i.e.: `|sub| sub[1..4].len() == 3`) - ty::Ref(_, inner, _) => match inner.kind() { - ty::Ref(_, innermost, _) if innermost.is_array() => true, - _ => false, + ty::Ref(_, inner, _) => { + matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) }, _ => false, } -- cgit 1.4.1-3-g733a5 From ac45a83ad5df284a4680f0c3c90d86f7a177e41f Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 14 Sep 2021 14:53:28 +0200 Subject: Handle multiple reference levels into binding type and add more tests --- clippy_lints/src/methods/search_is_some.rs | 29 ++++++++++++++++++++++++----- tests/ui/search_is_some_fixable_none.fixed | 11 +++++++++++ tests/ui/search_is_some_fixable_none.rs | 11 +++++++++++ tests/ui/search_is_some_fixable_none.stderr | 14 +++++++++++++- tests/ui/search_is_some_fixable_some.fixed | 11 +++++++++++ tests/ui/search_is_some_fixable_some.rs | 11 +++++++++++ tests/ui/search_is_some_fixable_some.stderr | 14 +++++++++++++- 7 files changed, 94 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index a5e6a8df03f..dca4d84f6b1 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -50,12 +50,26 @@ pub(super) fn check<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { + } else if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(closure_arg.pat).kind { + // this binding is composed of at least two levels of references, so we need to remove one + let binding_type = cx.typeck_results().node_type(binding_id); + let innermost_is_ref = if let ty::Ref(_, inner,_) = binding_type.kind() { + matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_ref()) + } else { + false + }; + // `find()` provides a reference to the item, but `any` does not, // so we should fix item usages for suggestion if let Some(closure_sugg) = get_closure_suggestion(cx, search_arg, closure_body) { applicability = closure_sugg.applicability; - Some(closure_sugg.suggestion) + if innermost_is_ref { + Some(closure_sugg.suggestion.replacen('&', "", 1)) + } else { + Some(closure_sugg.suggestion) + } + } else if innermost_is_ref { + Some(search_snippet.replacen('&', "", 1)) } else { Some(search_snippet.to_string()) } @@ -230,7 +244,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // cases where a parent call is using the item // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) { - if let ExprKind::Call(..) | ExprKind::MethodCall(..) = parent_expr.kind { + if let ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) = parent_expr.kind { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); @@ -239,8 +253,13 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); - - self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); + // do not suggest ampersand if the ident is the method caller + let ident_sugg = if !call_args.is_empty() && call_args[0].hir_id == cmt.hir_id { + format!("{}{}", start_snip, ident_str) + } else { + format!("{}&{}", start_snip, ident_str) + }; + self.suggestion_start.push_str(&ident_sugg); self.next_pos = span.hi(); } else { self.applicability = Applicability::Unspecified; diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 222731fd212..811bb1e3176 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -97,4 +97,15 @@ mod issue7392 { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = !vfoo.iter().any(|sub| sub[1..4].len() == 3); } + + fn please(x: &u32) -> bool { + *x == 9 + } + + fn more_projections() { + let x = 19; + let ppx: &u32 = &x; + let _ = ![ppx].iter().any(|ppp_x: &&u32| please(ppp_x)); + let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2); + } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 43ac1a07667..c6fbb5e2d26 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -101,4 +101,15 @@ mod issue7392 { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); } + + fn please(x: &u32) -> bool { + *x == 9 + } + + fn more_projections() { + let x = 19; + let ppx: &u32 = &x; + let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); + let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); + } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index fa344046aeb..b89ddabee55 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -169,5 +169,17 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` -error: aborting due to 26 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:112:17 + | +LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:113:17 + | +LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` + +error: aborting due to 28 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index ae9478a42e9..76b7f3d05d5 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -98,4 +98,15 @@ mod issue7392 { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = vfoo.iter().any(|sub| sub[1..4].len() == 3); } + + fn please(x: &u32) -> bool { + *x == 9 + } + + fn more_projections() { + let x = 19; + let ppx: &u32 = &x; + let _ = [ppx].iter().any(|ppp_x: &&u32| please(ppp_x)); + let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2); + } } diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index 98c3e7c1a68..364250e6ed8 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -100,4 +100,15 @@ mod issue7392 { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); } + + fn please(x: &u32) -> bool { + *x == 9 + } + + fn more_projections() { + let x = 19; + let ppx: &u32 = &x; + let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); + let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); + } } diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index 4161b5eec0a..183d99497ac 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -160,5 +160,17 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)` -error: aborting due to 26 previous errors +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:111:30 + | +LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:112:50 + | +LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)` + +error: aborting due to 28 previous errors -- cgit 1.4.1-3-g733a5 From 6d1ccbf46682b99f0301488bfffff403e824b4d7 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 19 Sep 2021 08:08:54 +0200 Subject: Correct suggestion when dereferencing enough, calling a function --- clippy_lints/src/methods/search_is_some.rs | 3 +-- tests/ui/search_is_some_fixable_none.fixed | 7 +++++++ tests/ui/search_is_some_fixable_none.rs | 7 +++++++ tests/ui/search_is_some_fixable_none.stderr | 12 +++++++++--- tests/ui/search_is_some_fixable_some.fixed | 7 +++++++ tests/ui/search_is_some_fixable_some.rs | 7 +++++++ tests/ui/search_is_some_fixable_some.stderr | 12 +++++++++--- 7 files changed, 47 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index dca4d84f6b1..98ad7f3866f 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -248,7 +248,6 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); - // Note: this should always be true, as `find` only gives us a reference which are not mutable if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); let start_snip = @@ -261,10 +260,10 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { }; self.suggestion_start.push_str(&ident_sugg); self.next_pos = span.hi(); + return; } else { self.applicability = Applicability::Unspecified; } - return; } } diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 811bb1e3176..c7c0b766015 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -102,10 +102,17 @@ mod issue7392 { *x == 9 } + fn simple_fn(x: u32) -> bool { + x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; let _ = ![ppx].iter().any(|ppp_x: &&u32| please(ppp_x)); let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2); + + let v = vec![3, 2, 1, 0]; + let _ = !v.iter().any(|x| simple_fn(*x)); } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index c6fbb5e2d26..6b41da4f2f8 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -106,10 +106,17 @@ mod issue7392 { *x == 9 } + fn simple_fn(x: u32) -> bool { + x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); + + let v = vec![3, 2, 1, 0]; + let _ = v.iter().find(|x| simple_fn(**x)).is_none(); } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index b89ddabee55..4313a2d526c 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -170,16 +170,22 @@ LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:112:17 + --> $DIR/search_is_some_fixable_none.rs:116:17 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:113:17 + --> $DIR/search_is_some_fixable_none.rs:117:17 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` -error: aborting due to 28 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:120:17 + | +LL | let _ = v.iter().find(|x| simple_fn(**x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| simple_fn(*x))` + +error: aborting due to 29 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 76b7f3d05d5..833168cf242 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -103,10 +103,17 @@ mod issue7392 { *x == 9 } + fn simple_fn(x: u32) -> bool { + x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; let _ = [ppx].iter().any(|ppp_x: &&u32| please(ppp_x)); let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2); + + let v = vec![3, 2, 1, 0]; + let _ = v.iter().any(|x| simple_fn(*x)); } } diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index 364250e6ed8..f9fb241de3f 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -105,10 +105,17 @@ mod issue7392 { *x == 9 } + fn simple_fn(x: u32) -> bool { + x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); + + let v = vec![3, 2, 1, 0]; + let _ = v.iter().find(|x| simple_fn(**x)).is_some(); } } diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index 183d99497ac..01b13cea2cd 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -161,16 +161,22 @@ LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:111:30 + --> $DIR/search_is_some_fixable_some.rs:115:30 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:112:50 + --> $DIR/search_is_some_fixable_some.rs:116:50 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)` -error: aborting due to 28 previous errors +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:119:26 + | +LL | let _ = v.iter().find(|x| simple_fn(**x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| simple_fn(*x))` + +error: aborting due to 29 previous errors -- cgit 1.4.1-3-g733a5 From 7a55407cc37ddb1bf1d3d95e52db7b6402259966 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 21 Sep 2021 14:54:19 +0200 Subject: Fix suggestions when call functions involved taking by ref --- clippy_lints/src/methods/search_is_some.rs | 93 +++++++++++++++++------------ tests/ui/search_is_some_fixable_none.fixed | 50 +++++++++++++++- tests/ui/search_is_some_fixable_none.rs | 52 +++++++++++++++- tests/ui/search_is_some_fixable_none.stderr | 46 ++++++++++++-- tests/ui/search_is_some_fixable_some.fixed | 51 +++++++++++++++- tests/ui/search_is_some_fixable_some.rs | 52 +++++++++++++++- tests/ui/search_is_some_fixable_some.stderr | 38 ++++++++++-- 7 files changed, 325 insertions(+), 57 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 98ad7f3866f..25a2c48e269 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,3 +1,5 @@ +use std::iter; + use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; @@ -223,6 +225,26 @@ impl DerefDelegate<'_, 'tcx> { let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); format!("{}{}", self.suggestion_start, end_snip) } + + fn func_takes_arg_by_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { + if_chain! { + if let ExprKind::Call(func, call_args) = parent_expr.kind; + let typ = self.cx.typeck_results().expr_ty(func); + if let ty::FnDef(..) = typ.kind(); + + then { + let mut takes_by_ref = false; + for (arg, ty) in iter::zip(call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs()) { + if arg.hir_id == cmt_hir_id { + takes_by_ref = matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()); + } + } + takes_by_ref + } else { + false + } + } + } } impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { @@ -252,18 +274,23 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); let start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + + // suggest ampersand if call function is taking args by ref + let takes_arg_by_ref = self.func_takes_arg_by_ref(parent_expr, cmt.hir_id); + // do not suggest ampersand if the ident is the method caller - let ident_sugg = if !call_args.is_empty() && call_args[0].hir_id == cmt.hir_id { - format!("{}{}", start_snip, ident_str) - } else { - format!("{}&{}", start_snip, ident_str) - }; + let ident_sugg = + if !call_args.is_empty() && call_args[0].hir_id == cmt.hir_id && !takes_arg_by_ref { + format!("{}{}", start_snip, ident_str) + } else { + format!("{}&{}", start_snip, ident_str) + }; self.suggestion_start.push_str(&ident_sugg); self.next_pos = span.hi(); return; - } else { - self.applicability = Applicability::Unspecified; } + + self.applicability = Applicability::Unspecified; } } @@ -271,23 +298,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // i.e.: suggest `*x` instead of `**x` let mut replacement_str = ident_str; - // handle index projection first - let index_handled = cmt.place.projections.iter().any(|proj| match proj.kind { - // Index projection like `|x| foo[x]` - // the index is dropped so we can't get it to build the suggestion, - // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`) - // instead of `span.lo()` (i.e.: `foo`) - ProjectionKind::Index => { - let start_span = Span::new(self.next_pos, span.hi(), span.ctxt()); - start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); - replacement_str.clear(); - true - }, - _ => false, - }); - - // looking for projections other that need to be handled differently - let other_projections_handled = cmt.place.projections.iter().enumerate().any(|(i, proj)| { + let mut projections_handled = false; + cmt.place.projections.iter().enumerate().for_each(|(i, proj)| { match proj.kind { // Field projection like `|v| v.foo` ProjectionKind::Field(idx, variant) => match cmt.place.ty_before_projection(i).kind() { @@ -297,34 +309,41 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { replacement_str, def.variants[variant].fields[idx as usize].ident.name.as_str() ); - true + projections_handled = true; }, ty::Tuple(_) => { replacement_str = format!("{}.{}", replacement_str, idx); - true + projections_handled = true; }, - _ => false, + _ => (), + }, + // Index projection like `|x| foo[x]` + // the index is dropped so we can't get it to build the suggestion, + // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`) + // instead of `span.lo()` (i.e.: `foo`) + ProjectionKind::Index => { + let start_span = Span::new(self.next_pos, span.hi(), span.ctxt()); + start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + replacement_str.clear(); + projections_handled = true; }, - // handled previously - ProjectionKind::Index | - // note: unable to trigger `Subslice` kind in tests - ProjectionKind::Subslice => false, + // note: unable to trigger `Subslice` kind in tests + ProjectionKind::Subslice => (), ProjectionKind::Deref => { // explicit deref for arrays should be avoided in the suggestion // i.e.: `|sub| *sub[1..4].len() == 3` is not expected - match cmt.place.ty_before_projection(i).kind() { + if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() { // dereferencing an array (i.e.: `|sub| sub[1..4].len() == 3`) - ty::Ref(_, inner, _) => { - matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) - }, - _ => false, + if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) { + projections_handled = true; + } } }, } }); // handle `ProjectionKind::Deref` if no special case detected - if !index_handled && !other_projections_handled { + if !projections_handled { let last_deref = cmt .place .projections diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index c7c0b766015..6b8a614bbda 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -102,10 +102,14 @@ mod issue7392 { *x == 9 } - fn simple_fn(x: u32) -> bool { + fn deref_enough(x: u32) -> bool { x == 78 } + fn arg_no_deref(x: &&u32) -> bool { + **x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; @@ -113,6 +117,48 @@ mod issue7392 { let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2); let v = vec![3, 2, 1, 0]; - let _ = !v.iter().any(|x| simple_fn(*x)); + let _ = !v.iter().any(|x| deref_enough(*x)); + + #[allow(clippy::redundant_closure)] + let _ = !v.iter().any(|x| arg_no_deref(&x)); + } + + fn field_index_projection() { + struct FooDouble { + bar: Vec>, + } + struct Foo { + bar: Vec, + } + struct FooOuter { + inner: Foo, + inner_double: FooDouble, + } + let vfoo = vec![FooOuter { + inner: Foo { bar: vec![0, 1, 2, 3] }, + inner_double: FooDouble { + bar: vec![vec![0, 1, 2, 3]], + }, + }]; + let _ = !vfoo + .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); + } + + fn index_field_projection() { + struct Foo { + bar: i32, + } + struct FooOuter { + inner: Vec, + } + let vfoo = vec![FooOuter { + inner: vec![Foo { bar: 0 }], + }]; + let _ = !vfoo.iter().any(|v| v.inner[0].bar == 2); + } + + fn double_deref_index_projection() { + let vfoo = vec![&&[0, 1, 2, 3]]; + let _ = !vfoo.iter().any(|x| (**x)[0] == 9); } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 6b41da4f2f8..acaae650921 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -106,10 +106,14 @@ mod issue7392 { *x == 9 } - fn simple_fn(x: u32) -> bool { + fn deref_enough(x: u32) -> bool { x == 78 } + fn arg_no_deref(x: &&u32) -> bool { + **x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; @@ -117,6 +121,50 @@ mod issue7392 { let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); let v = vec![3, 2, 1, 0]; - let _ = v.iter().find(|x| simple_fn(**x)).is_none(); + let _ = v.iter().find(|x| deref_enough(**x)).is_none(); + + #[allow(clippy::redundant_closure)] + let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); + } + + fn field_index_projection() { + struct FooDouble { + bar: Vec>, + } + struct Foo { + bar: Vec, + } + struct FooOuter { + inner: Foo, + inner_double: FooDouble, + } + let vfoo = vec![FooOuter { + inner: Foo { bar: vec![0, 1, 2, 3] }, + inner_double: FooDouble { + bar: vec![vec![0, 1, 2, 3]], + }, + }]; + let _ = vfoo + .iter() + .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) + .is_none(); + } + + fn index_field_projection() { + struct Foo { + bar: i32, + } + struct FooOuter { + inner: Vec, + } + let vfoo = vec![FooOuter { + inner: vec![Foo { bar: 0 }], + }]; + let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); + } + + fn double_deref_index_projection() { + let vfoo = vec![&&[0, 1, 2, 3]]; + let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 4313a2d526c..64e81c6b94a 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -170,22 +170,56 @@ LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:116:17 + --> $DIR/search_is_some_fixable_none.rs:120:17 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:117:17 + --> $DIR/search_is_some_fixable_none.rs:121:17 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:120:17 + --> $DIR/search_is_some_fixable_none.rs:124:17 + | +LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| deref_enough(*x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:127:17 + | +LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| arg_no_deref(&x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:147:17 + | +LL | let _ = vfoo + | _________________^ +LL | | .iter() +LL | | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) +LL | | .is_none(); + | |______________________^ + | +help: use `!_.any()` instead + | +LL ~ let _ = !vfoo +LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); + | + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:163:17 + | +LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:168:17 | -LL | let _ = v.iter().find(|x| simple_fn(**x)).is_none(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| simple_fn(*x))` +LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)` -error: aborting due to 29 previous errors +error: aborting due to 33 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 833168cf242..7eb07d639a5 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -103,10 +103,14 @@ mod issue7392 { *x == 9 } - fn simple_fn(x: u32) -> bool { + fn deref_enough(x: u32) -> bool { x == 78 } + fn arg_no_deref(x: &&u32) -> bool { + **x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; @@ -114,6 +118,49 @@ mod issue7392 { let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2); let v = vec![3, 2, 1, 0]; - let _ = v.iter().any(|x| simple_fn(*x)); + let _ = v.iter().any(|x| deref_enough(*x)); + + #[allow(clippy::redundant_closure)] + let _ = v.iter().any(|x| arg_no_deref(&x)); + } + + fn field_index_projection() { + struct FooDouble { + bar: Vec>, + } + struct Foo { + bar: Vec, + } + struct FooOuter { + inner: Foo, + inner_double: FooDouble, + } + let vfoo = vec![FooOuter { + inner: Foo { bar: vec![0, 1, 2, 3] }, + inner_double: FooDouble { + bar: vec![vec![0, 1, 2, 3]], + }, + }]; + let _ = vfoo + .iter() + .any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); + } + + fn index_field_projection() { + struct Foo { + bar: i32, + } + struct FooOuter { + inner: Vec, + } + let vfoo = vec![FooOuter { + inner: vec![Foo { bar: 0 }], + }]; + let _ = vfoo.iter().any(|v| v.inner[0].bar == 2); + } + + fn double_deref_index_projection() { + let vfoo = vec![&&[0, 1, 2, 3]]; + let _ = vfoo.iter().any(|x| (**x)[0] == 9); } } diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index f9fb241de3f..b9ebd399a35 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -105,10 +105,14 @@ mod issue7392 { *x == 9 } - fn simple_fn(x: u32) -> bool { + fn deref_enough(x: u32) -> bool { x == 78 } + fn arg_no_deref(x: &&u32) -> bool { + **x == 78 + } + fn more_projections() { let x = 19; let ppx: &u32 = &x; @@ -116,6 +120,50 @@ mod issue7392 { let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); let v = vec![3, 2, 1, 0]; - let _ = v.iter().find(|x| simple_fn(**x)).is_some(); + let _ = v.iter().find(|x| deref_enough(**x)).is_some(); + + #[allow(clippy::redundant_closure)] + let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); + } + + fn field_index_projection() { + struct FooDouble { + bar: Vec>, + } + struct Foo { + bar: Vec, + } + struct FooOuter { + inner: Foo, + inner_double: FooDouble, + } + let vfoo = vec![FooOuter { + inner: Foo { bar: vec![0, 1, 2, 3] }, + inner_double: FooDouble { + bar: vec![vec![0, 1, 2, 3]], + }, + }]; + let _ = vfoo + .iter() + .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) + .is_some(); + } + + fn index_field_projection() { + struct Foo { + bar: i32, + } + struct FooOuter { + inner: Vec, + } + let vfoo = vec![FooOuter { + inner: vec![Foo { bar: 0 }], + }]; + let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); + } + + fn double_deref_index_projection() { + let vfoo = vec![&&[0, 1, 2, 3]]; + let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); } } diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index 01b13cea2cd..b62cf9c4702 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -161,22 +161,48 @@ LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:115:30 + --> $DIR/search_is_some_fixable_some.rs:119:30 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:116:50 + --> $DIR/search_is_some_fixable_some.rs:120:50 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:119:26 + --> $DIR/search_is_some_fixable_some.rs:123:26 | -LL | let _ = v.iter().find(|x| simple_fn(**x)).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| simple_fn(*x))` +LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| deref_enough(*x))` -error: aborting due to 29 previous errors +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:126:26 + | +LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| arg_no_deref(&x))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:148:14 + | +LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) + | ______________^ +LL | | .is_some(); + | |______________________^ help: use `any()` instead: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:162:29 + | +LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.inner[0].bar == 2)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:167:29 + | +LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)` + +error: aborting due to 33 previous errors -- cgit 1.4.1-3-g733a5 From 90a72f506c55b2c2fc1f64b13c9c048a65846bba Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 1 Oct 2021 16:57:57 +0200 Subject: Handle args taken by ref also for `MethodCall` --- clippy_lints/src/methods/search_is_some.rs | 43 +++++++++++++---------------- tests/ui/search_is_some_fixable_none.fixed | 13 +++++++++ tests/ui/search_is_some_fixable_none.rs | 13 +++++++++ tests/ui/search_is_some_fixable_none.stderr | 8 +++++- tests/ui/search_is_some_fixable_some.fixed | 13 +++++++++ tests/ui/search_is_some_fixable_some.rs | 13 +++++++++ tests/ui/search_is_some_fixable_some.stderr | 8 +++++- 7 files changed, 85 insertions(+), 26 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 25a2c48e269..4f8517b946a 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -227,23 +227,23 @@ impl DerefDelegate<'_, 'tcx> { } fn func_takes_arg_by_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { - if_chain! { - if let ExprKind::Call(func, call_args) = parent_expr.kind; - let typ = self.cx.typeck_results().expr_ty(func); - if let ty::FnDef(..) = typ.kind(); - - then { - let mut takes_by_ref = false; - for (arg, ty) in iter::zip(call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs()) { - if arg.hir_id == cmt_hir_id { - takes_by_ref = matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()); - } + let (call_args, inputs) = match parent_expr.kind { + ExprKind::MethodCall(_, _, call_args, _) => { + if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) { + (call_args, self.cx.tcx.fn_sig(method_did).skip_binder().inputs()) + } else { + return false; } - takes_by_ref - } else { - false - } - } + }, + ExprKind::Call(func, call_args) => { + let typ = self.cx.typeck_results().expr_ty(func); + (call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs()) + }, + _ => return false, + }; + + iter::zip(call_args, inputs) + .any(|(arg, ty)| arg.hir_id == cmt_hir_id && matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) } } @@ -271,10 +271,6 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { - let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); - let start_snip = - snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); - // suggest ampersand if call function is taking args by ref let takes_arg_by_ref = self.func_takes_arg_by_ref(parent_expr, cmt.hir_id); @@ -294,14 +290,12 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } } - // handle item projections by removing one explicit deref - // i.e.: suggest `*x` instead of `**x` let mut replacement_str = ident_str; - let mut projections_handled = false; cmt.place.projections.iter().enumerate().for_each(|(i, proj)| { match proj.kind { // Field projection like `|v| v.foo` + // no adjustment needed here, as field projections are handled by the compiler ProjectionKind::Field(idx, variant) => match cmt.place.ty_before_projection(i).kind() { ty::Adt(def, ..) => { replacement_str = format!( @@ -342,7 +336,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } }); - // handle `ProjectionKind::Deref` if no special case detected + // handle `ProjectionKind::Deref` by removing one explicit deref + // if no special case was detected (i.e.: suggest `*x` instead of `**x`) if !projections_handled { let last_deref = cmt .place diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 6b8a614bbda..0d1ed343c0c 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -161,4 +161,17 @@ mod issue7392 { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = !vfoo.iter().any(|x| (**x)[0] == 9); } + + fn method_call_by_ref() { + struct Foo { + bar: u32, + } + impl Foo { + pub fn by_ref(&self, x: &u32) -> bool { + *x == self.bar + } + } + let vfoo = vec![Foo { bar: 1 }]; + let _ = !vfoo.iter().any(|v| v.by_ref(&v.bar)); + } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index acaae650921..2c638d929cb 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -167,4 +167,17 @@ mod issue7392 { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); } + + fn method_call_by_ref() { + struct Foo { + bar: u32, + } + impl Foo { + pub fn by_ref(&self, x: &u32) -> bool { + *x == self.bar + } + } + let vfoo = vec![Foo { bar: 1 }]; + let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); + } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 64e81c6b94a..0c34067c139 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -221,5 +221,11 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)` -error: aborting due to 33 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:181:17 + | +LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` + +error: aborting due to 34 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 7eb07d639a5..43471e35493 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -163,4 +163,17 @@ mod issue7392 { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = vfoo.iter().any(|x| (**x)[0] == 9); } + + fn method_call_by_ref() { + struct Foo { + bar: u32, + } + impl Foo { + pub fn by_ref(&self, x: &u32) -> bool { + *x == self.bar + } + } + let vfoo = vec![Foo { bar: 1 }]; + let _ = vfoo.iter().any(|v| v.by_ref(&v.bar)); + } } diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index b9ebd399a35..82d3072d2f3 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -166,4 +166,17 @@ mod issue7392 { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); } + + fn method_call_by_ref() { + struct Foo { + bar: u32, + } + impl Foo { + pub fn by_ref(&self, x: &u32) -> bool { + *x == self.bar + } + } + let vfoo = vec![Foo { bar: 1 }]; + let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); + } } diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index b62cf9c4702..5e8885991ac 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -204,5 +204,11 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)` -error: aborting due to 33 previous errors +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:180:29 + | +LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.by_ref(&v.bar))` + +error: aborting due to 34 previous errors -- cgit 1.4.1-3-g733a5 From abaaf744fdbe8106bc82ceaa34e8499d5436fc3c Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 1 Oct 2021 17:29:37 +0200 Subject: Add some notes about `MethodCall` cases --- clippy_lints/src/methods/search_is_some.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 4f8517b946a..d08abc5b3de 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -221,7 +221,7 @@ struct DerefDelegate<'a, 'tcx> { impl DerefDelegate<'_, 'tcx> { pub fn finish(&mut self) -> String { - let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt()); + let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None); let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); format!("{}{}", self.suggestion_start, end_snip) } @@ -255,7 +255,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let map = self.cx.tcx.hir(); let ident_str = map.name(id).to_string(); let span = map.span(cmt.hir_id); - let start_span = Span::new(self.next_pos, span.lo(), span.ctxt()); + let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None); let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); if cmt.place.projections.is_empty() { @@ -263,8 +263,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // i.e.: suggest `&x` instead of `x` self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); } else { - // cases where a parent call is using the item + // cases where a parent `Call` or `MethodCall` is using the item // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` + // + // Note about method calls: + // - compiler automatically dereference references if the target type is a reference (works also for + // function call) + // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and + // no projection should be suggested if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) { if let ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) = parent_expr.kind { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); @@ -316,7 +322,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`) // instead of `span.lo()` (i.e.: `foo`) ProjectionKind::Index => { - let start_span = Span::new(self.next_pos, span.hi(), span.ctxt()); + let start_span = Span::new(self.next_pos, span.hi(), span.ctxt(), None); start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); replacement_str.clear(); projections_handled = true; -- cgit 1.4.1-3-g733a5 From 2ff702cbb547ea02381820536b27a575f14ba59e Mon Sep 17 00:00:00 2001 From: ThibsG Date: Wed, 20 Oct 2021 22:18:12 +0200 Subject: Rephrase the fn checking for a double ref, not only one --- clippy_lints/src/methods/search_is_some.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index d08abc5b3de..96e040d9261 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -226,7 +226,7 @@ impl DerefDelegate<'_, 'tcx> { format!("{}{}", self.suggestion_start, end_snip) } - fn func_takes_arg_by_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { + fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { let (call_args, inputs) = match parent_expr.kind { ExprKind::MethodCall(_, _, call_args, _) => { if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) { @@ -277,16 +277,18 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { - // suggest ampersand if call function is taking args by ref - let takes_arg_by_ref = self.func_takes_arg_by_ref(parent_expr, cmt.hir_id); + // suggest ampersand if call function is taking args by double reference + let takes_arg_by_double_ref = self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id); // do not suggest ampersand if the ident is the method caller - let ident_sugg = - if !call_args.is_empty() && call_args[0].hir_id == cmt.hir_id && !takes_arg_by_ref { - format!("{}{}", start_snip, ident_str) - } else { - format!("{}&{}", start_snip, ident_str) - }; + let ident_sugg = if !call_args.is_empty() + && call_args[0].hir_id == cmt.hir_id + && !takes_arg_by_double_ref + { + format!("{}{}", start_snip, ident_str) + } else { + format!("{}&{}", start_snip, ident_str) + }; self.suggestion_start.push_str(&ident_sugg); self.next_pos = span.hi(); return; -- cgit 1.4.1-3-g733a5 From 1176b8e5e9e697978ad563924f1561b52b330c07 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 1 Nov 2021 09:11:43 +0100 Subject: Handle closures with type annotations on args --- clippy_lints/src/methods/search_is_some.rs | 144 +++++++++++++++------------- tests/ui/search_is_some_fixable_none.fixed | 3 + tests/ui/search_is_some_fixable_none.rs | 3 + tests/ui/search_is_some_fixable_none.stderr | 28 ++++-- tests/ui/search_is_some_fixable_some.fixed | 3 + tests/ui/search_is_some_fixable_some.rs | 3 + tests/ui/search_is_some_fixable_some.stderr | 28 ++++-- 7 files changed, 132 insertions(+), 80 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 96e040d9261..7baae4faa23 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -7,7 +7,7 @@ use clippy_utils::{get_parent_expr_for_hir, is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{self, ExprKind, HirId, PatKind}; +use rustc_hir::{self, ExprKind, HirId, MutTy, PatKind, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::place::ProjectionKind; @@ -52,26 +52,12 @@ pub(super) fn check<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(closure_arg.pat).kind { - // this binding is composed of at least two levels of references, so we need to remove one - let binding_type = cx.typeck_results().node_type(binding_id); - let innermost_is_ref = if let ty::Ref(_, inner,_) = binding_type.kind() { - matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_ref()) - } else { - false - }; - + } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { // `find()` provides a reference to the item, but `any` does not, // so we should fix item usages for suggestion - if let Some(closure_sugg) = get_closure_suggestion(cx, search_arg, closure_body) { + if let Some(closure_sugg) = get_closure_suggestion(cx, search_arg) { applicability = closure_sugg.applicability; - if innermost_is_ref { - Some(closure_sugg.suggestion.replacen('&', "", 1)) - } else { - Some(closure_sugg.suggestion) - } - } else if innermost_is_ref { - Some(search_snippet.replacen('&', "", 1)) + Some(closure_sugg.suggestion) } else { Some(search_snippet.to_string()) } @@ -174,6 +160,7 @@ pub(super) fn check<'tcx>( } } +#[derive(Debug)] struct ClosureSugg { applicability: Applicability, suggestion: String, @@ -182,38 +169,45 @@ struct ClosureSugg { // Build suggestion gradually by handling closure arg specific usages, // such as explicit deref and borrowing cases. // Returns `None` if no such use cases have been triggered in closure body -fn get_closure_suggestion<'tcx>( - cx: &LateContext<'_>, - search_arg: &'tcx hir::Expr<'_>, - closure_body: &hir::Body<'_>, -) -> Option { - let mut visitor = DerefDelegate { - cx, - closure_span: search_arg.span, - next_pos: search_arg.span.lo(), - suggestion_start: String::new(), - applicability: Applicability::MachineApplicable, - }; +fn get_closure_suggestion<'tcx>(cx: &LateContext<'_>, search_expr: &'tcx hir::Expr<'_>) -> Option { + if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = search_expr.kind { + let closure_body = cx.tcx.hir().body(body_id); + // is closure arg a double reference (i.e.: `|x: &&i32| ...`) + let closure_arg_is_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind { + matches!(ty.kind, TyKind::Rptr(_, MutTy { .. })) + } else { + false + }; + + let mut visitor = DerefDelegate { + cx, + closure_span: search_expr.span, + closure_arg_is_double_ref, + next_pos: search_expr.span.lo(), + suggestion_start: String::new(), + applicability: Applicability::MachineApplicable, + }; - let fn_def_id = cx.tcx.hir().local_def_id(search_arg.hir_id); - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) - .consume_body(closure_body); - }); + let fn_def_id = cx.tcx.hir().local_def_id(search_expr.hir_id); + cx.tcx.infer_ctxt().enter(|infcx| { + ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) + .consume_body(closure_body); + }); - if visitor.suggestion_start.is_empty() { - None - } else { - Some(ClosureSugg { - applicability: visitor.applicability, - suggestion: visitor.finish(), - }) + if !visitor.suggestion_start.is_empty() { + return Some(ClosureSugg { + applicability: visitor.applicability, + suggestion: visitor.finish(), + }); + } } + None } struct DerefDelegate<'a, 'tcx> { cx: &'a LateContext<'tcx>, closure_span: Span, + closure_arg_is_double_ref: bool, next_pos: BytePos, suggestion_start: String, applicability: Applicability, @@ -223,7 +217,12 @@ impl DerefDelegate<'_, 'tcx> { pub fn finish(&mut self) -> String { let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None); let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); - format!("{}{}", self.suggestion_start, end_snip) + let sugg = format!("{}{}", self.suggestion_start, end_snip); + if self.closure_arg_is_double_ref { + sugg.replacen('&', "", 1) + } else { + sugg + } } fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { @@ -261,6 +260,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing // i.e.: suggest `&x` instead of `x` + self.closure_arg_is_double_ref = false; self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); } else { // cases where a parent `Call` or `MethodCall` is using the item @@ -272,29 +272,43 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and // no projection should be suggested if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) { - if let ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) = parent_expr.kind { - let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); - let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); - - if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { - // suggest ampersand if call function is taking args by double reference - let takes_arg_by_double_ref = self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id); - - // do not suggest ampersand if the ident is the method caller - let ident_sugg = if !call_args.is_empty() - && call_args[0].hir_id == cmt.hir_id - && !takes_arg_by_double_ref - { - format!("{}{}", start_snip, ident_str) - } else { - format!("{}&{}", start_snip, ident_str) - }; - self.suggestion_start.push_str(&ident_sugg); + match &parent_expr.kind { + // given expression is the self argument and will be handled completely by the compiler + // i.e.: `|x| x.is_something()` + ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => { + self.suggestion_start.push_str(&format!("{}{}", start_snip, ident_str)); self.next_pos = span.hi(); return; - } + }, + // item is used in a call + // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` + ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [_, call_args @ ..], _) => { + let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); + let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); - self.applicability = Applicability::Unspecified; + if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { + // suggest ampersand if call function is taking args by double reference + let takes_arg_by_double_ref = + self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id); + + // no need to bind again if the function doesn't take arg by double ref + // and if the item is already a double ref + let ident_sugg = if !call_args.is_empty() + && !takes_arg_by_double_ref + && self.closure_arg_is_double_ref + { + format!("{}{}", start_snip, ident_str) + } else { + format!("{}&{}", start_snip, ident_str) + }; + self.suggestion_start.push_str(&ident_sugg); + self.next_pos = span.hi(); + return; + } + + self.applicability = Applicability::Unspecified; + }, + _ => (), } } @@ -346,7 +360,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // handle `ProjectionKind::Deref` by removing one explicit deref // if no special case was detected (i.e.: suggest `*x` instead of `**x`) - if !projections_handled { + if projections_handled { + self.closure_arg_is_double_ref = false; + } else { let last_deref = cmt .place .projections diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 240a6957893..adc6b2739c4 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -118,9 +118,12 @@ mod issue7392 { let v = vec![3, 2, 1, 0]; let _ = !v.iter().any(|x| deref_enough(*x)); + let _ = !v.iter().any(|x: &u32| deref_enough(*x)); #[allow(clippy::redundant_closure)] let _ = !v.iter().any(|x| arg_no_deref(&x)); + #[allow(clippy::redundant_closure)] + let _ = !v.iter().any(|x: &u32| arg_no_deref(&x)); } fn field_index_projection() { diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 7e8fc14a7bd..f0be2be4788 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -122,9 +122,12 @@ mod issue7392 { let v = vec![3, 2, 1, 0]; let _ = v.iter().find(|x| deref_enough(**x)).is_none(); + let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none(); #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); + #[allow(clippy::redundant_closure)] + let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none(); } fn field_index_projection() { diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index c78830a3b5d..910d5ad37b8 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -188,13 +188,25 @@ LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:127:17 + --> $DIR/search_is_some_fixable_none.rs:125:17 + | +LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| deref_enough(*x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:128:17 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:147:17 + --> $DIR/search_is_some_fixable_none.rs:130:17 + | +LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| arg_no_deref(&x))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:150:17 | LL | let _ = vfoo | _________________^ @@ -210,34 +222,34 @@ LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] | error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:163:17 + --> $DIR/search_is_some_fixable_none.rs:166:17 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:168:17 + --> $DIR/search_is_some_fixable_none.rs:171:17 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:181:17 + --> $DIR/search_is_some_fixable_none.rs:184:17 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:185:17 + --> $DIR/search_is_some_fixable_none.rs:188:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:186:17 + --> $DIR/search_is_some_fixable_none.rs:189:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` -error: aborting due to 36 previous errors +error: aborting due to 38 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 267324cbe6a..2799ae0a98b 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -119,9 +119,12 @@ mod issue7392 { let v = vec![3, 2, 1, 0]; let _ = v.iter().any(|x| deref_enough(*x)); + let _ = v.iter().any(|x: &u32| deref_enough(*x)); #[allow(clippy::redundant_closure)] let _ = v.iter().any(|x| arg_no_deref(&x)); + #[allow(clippy::redundant_closure)] + let _ = v.iter().any(|x: &u32| arg_no_deref(&x)); } fn field_index_projection() { diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index 53f80e2c87e..bf9d50d9057 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -121,9 +121,12 @@ mod issue7392 { let v = vec![3, 2, 1, 0]; let _ = v.iter().find(|x| deref_enough(**x)).is_some(); + let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some(); #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); + #[allow(clippy::redundant_closure)] + let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some(); } fn field_index_projection() { diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index e8784bba6eb..71680bc8d2a 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -179,13 +179,25 @@ LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:126:26 + --> $DIR/search_is_some_fixable_some.rs:124:26 + | +LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| deref_enough(*x))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:127:26 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:148:14 + --> $DIR/search_is_some_fixable_some.rs:129:26 + | +LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref(&x))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:151:14 | LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) | ______________^ @@ -193,34 +205,34 @@ LL | | .is_some(); | |______________________^ help: use `any()` instead: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:162:29 + --> $DIR/search_is_some_fixable_some.rs:165:29 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.inner[0].bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:167:29 + --> $DIR/search_is_some_fixable_some.rs:170:29 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:180:29 + --> $DIR/search_is_some_fixable_some.rs:183:29 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.by_ref(&v.bar))` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:184:55 + --> $DIR/search_is_some_fixable_some.rs:187:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_some.rs:185:55 + --> $DIR/search_is_some_fixable_some.rs:188:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` -error: aborting due to 36 previous errors +error: aborting due to 38 previous errors -- cgit 1.4.1-3-g733a5 From 5ebede0c14d00f50a2db3d5a8e944563e40244c7 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 20 Nov 2021 09:37:37 +0100 Subject: Fix full projection identifier + move applicability to `MaybeIncorrect` --- clippy_lints/src/methods/search_is_some.rs | 42 ++++++++++++++++++----------- tests/ui/search_is_some_fixable_none.fixed | 31 +++++++++++++++++++++ tests/ui/search_is_some_fixable_none.rs | 31 +++++++++++++++++++++ tests/ui/search_is_some_fixable_none.stderr | 40 ++++++++++++++++++++++++++- tests/ui/search_is_some_fixable_some.fixed | 31 +++++++++++++++++++++ tests/ui/search_is_some_fixable_some.rs | 31 +++++++++++++++++++++ tests/ui/search_is_some_fixable_some.stderr | 40 ++++++++++++++++++++++++++- 7 files changed, 228 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 7baae4faa23..a3449c1fe12 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -185,7 +185,7 @@ fn get_closure_suggestion<'tcx>(cx: &LateContext<'_>, search_expr: &'tcx hir::Ex closure_arg_is_double_ref, next_pos: search_expr.span.lo(), suggestion_start: String::new(), - applicability: Applicability::MachineApplicable, + applicability: Applicability::MaybeIncorrect, }; let fn_def_id = cx.tcx.hir().local_def_id(search_expr.hir_id); @@ -252,11 +252,15 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if let PlaceBase::Local(id) = cmt.place.base { let map = self.cx.tcx.hir(); - let ident_str = map.name(id).to_string(); let span = map.span(cmt.hir_id); let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None); let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + // identifier referring to the variable currently triggered (i.e.: `fp`) + let ident_str = map.name(id).to_string(); + // full identifier that includes projection (i.e.: `fp.field`) + let ident_str_with_proj = snippet(self.cx, span, "..").to_string(); + if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing // i.e.: suggest `&x` instead of `x` @@ -276,7 +280,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // given expression is the self argument and will be handled completely by the compiler // i.e.: `|x| x.is_something()` ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => { - self.suggestion_start.push_str(&format!("{}{}", start_snip, ident_str)); + self.suggestion_start + .push_str(&format!("{}{}", start_snip, ident_str_with_proj)); self.next_pos = span.hi(); return; }, @@ -291,13 +296,26 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let takes_arg_by_double_ref = self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id); + // compiler will automatically dereference field projection, so no need + // to suggest ampersand, but full identifier that includes projection is required + let has_field_projection = cmt + .place + .projections + .iter() + .any(|proj| matches!(proj.kind, ProjectionKind::Field(..))); + // no need to bind again if the function doesn't take arg by double ref // and if the item is already a double ref let ident_sugg = if !call_args.is_empty() && !takes_arg_by_double_ref - && self.closure_arg_is_double_ref + && (self.closure_arg_is_double_ref || has_field_projection) { - format!("{}{}", start_snip, ident_str) + let ident = if has_field_projection { + ident_str_with_proj + } else { + ident_str + }; + format!("{}{}", start_snip, ident) } else { format!("{}&{}", start_snip, ident_str) }; @@ -318,17 +336,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { match proj.kind { // Field projection like `|v| v.foo` // no adjustment needed here, as field projections are handled by the compiler - ProjectionKind::Field(idx, variant) => match cmt.place.ty_before_projection(i).kind() { - ty::Adt(def, ..) => { - replacement_str = format!( - "{}.{}", - replacement_str, - def.variants[variant].fields[idx as usize].ident.name.as_str() - ); - projections_handled = true; - }, - ty::Tuple(_) => { - replacement_str = format!("{}.{}", replacement_str, idx); + ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() { + ty::Adt(..) | ty::Tuple(_) => { + replacement_str = ident_str_with_proj.clone(); projections_handled = true; }, _ => (), diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index adc6b2739c4..6831fb2cf59 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -182,4 +182,35 @@ mod issue7392 { let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); } + + fn test_string_1(s: &str) -> bool { + s.is_empty() + } + + fn test_u32_1(s: &u32) -> bool { + s.is_power_of_two() + } + + fn test_u32_2(s: u32) -> bool { + s.is_power_of_two() + } + + fn projection_in_args_test() { + // Index projections + let lst = &[String::from("Hello"), String::from("world")]; + let v: Vec<&[String]> = vec![lst]; + let _ = !v.iter().any(|s| s[0].is_empty()); + let _ = !v.iter().any(|s| test_string_1(&s[0])); + + // Field projections + struct FieldProjection<'a> { + field: &'a u32, + } + let field = 123456789; + let instance = FieldProjection { field: &field }; + let v = vec![instance]; + let _ = !v.iter().any(|fp| fp.field.is_power_of_two()); + let _ = !v.iter().any(|fp| test_u32_1(fp.field)); + let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); + } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index f0be2be4788..778f4f6fa25 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -188,4 +188,35 @@ mod issue7392 { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); } + + fn test_string_1(s: &String) -> bool { + s.is_empty() + } + + fn test_u32_1(s: &u32) -> bool { + s.is_power_of_two() + } + + fn test_u32_2(s: u32) -> bool { + s.is_power_of_two() + } + + fn projection_in_args_test() { + // Index projections + let lst = &[String::from("Hello"), String::from("world")]; + let v: Vec<&[String]> = vec![lst]; + let _ = v.iter().find(|s| s[0].is_empty()).is_none(); + let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); + + // Field projections + struct FieldProjection<'a> { + field: &'a u32, + } + let field = 123456789; + let instance = FieldProjection { field: &field }; + let v = vec![instance]; + let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); + let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); + let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); + } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 910d5ad37b8..7c5e5eb589c 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -251,5 +251,43 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` -error: aborting due to 38 previous errors +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> $DIR/search_is_some_fixable_none.rs:192:25 + | +LL | fn test_string_1(s: &String) -> bool { + | ^^^^^^^ help: change this to: `&str` + | + = note: `-D clippy::ptr-arg` implied by `-D warnings` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:208:17 + | +LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| s[0].is_empty())` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:209:17 + | +LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| test_string_1(&s[0]))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:218:17 + | +LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| fp.field.is_power_of_two())` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:219:17 + | +LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_1(fp.field))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:220:17 + | +LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))` + +error: aborting due to 44 previous errors diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 2799ae0a98b..7c940a2b069 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -184,4 +184,35 @@ mod issue7392 { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); } + + fn test_string_1(s: &str) -> bool { + s.is_empty() + } + + fn test_u32_1(s: &u32) -> bool { + s.is_power_of_two() + } + + fn test_u32_2(s: u32) -> bool { + s.is_power_of_two() + } + + fn projection_in_args_test() { + // Index projections + let lst = &[String::from("Hello"), String::from("world")]; + let v: Vec<&[String]> = vec![lst]; + let _ = v.iter().any(|s| s[0].is_empty()); + let _ = v.iter().any(|s| test_string_1(&s[0])); + + // Field projections + struct FieldProjection<'a> { + field: &'a u32, + } + let field = 123456789; + let instance = FieldProjection { field: &field }; + let v = vec![instance]; + let _ = v.iter().any(|fp| fp.field.is_power_of_two()); + let _ = v.iter().any(|fp| test_u32_1(fp.field)); + let _ = v.iter().any(|fp| test_u32_2(*fp.field)); + } } diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index bf9d50d9057..241641fceae 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -187,4 +187,35 @@ mod issue7392 { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); } + + fn test_string_1(s: &String) -> bool { + s.is_empty() + } + + fn test_u32_1(s: &u32) -> bool { + s.is_power_of_two() + } + + fn test_u32_2(s: u32) -> bool { + s.is_power_of_two() + } + + fn projection_in_args_test() { + // Index projections + let lst = &[String::from("Hello"), String::from("world")]; + let v: Vec<&[String]> = vec![lst]; + let _ = v.iter().find(|s| s[0].is_empty()).is_some(); + let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); + + // Field projections + struct FieldProjection<'a> { + field: &'a u32, + } + let field = 123456789; + let instance = FieldProjection { field: &field }; + let v = vec![instance]; + let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); + let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); + let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); + } } diff --git a/tests/ui/search_is_some_fixable_some.stderr b/tests/ui/search_is_some_fixable_some.stderr index 71680bc8d2a..9212c6e71ff 100644 --- a/tests/ui/search_is_some_fixable_some.stderr +++ b/tests/ui/search_is_some_fixable_some.stderr @@ -234,5 +234,43 @@ error: called `is_some()` after searching an `Iterator` with `find` LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)` -error: aborting due to 38 previous errors +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> $DIR/search_is_some_fixable_some.rs:191:25 + | +LL | fn test_string_1(s: &String) -> bool { + | ^^^^^^^ help: change this to: `&str` + | + = note: `-D clippy::ptr-arg` implied by `-D warnings` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:207:26 + | +LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s[0].is_empty())` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:208:26 + | +LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| test_string_1(&s[0]))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:217:26 + | +LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| fp.field.is_power_of_two())` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:218:26 + | +LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_1(fp.field))` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_some.rs:219:26 + | +LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))` + +error: aborting due to 44 previous errors -- cgit 1.4.1-3-g733a5 From 092fe209a6568ade22046dbf4e78455d5aeeb5fa Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 20 Nov 2021 10:00:50 +0100 Subject: Move deref closure builder to `clippy_utils::sugg` module --- clippy_lints/src/methods/search_is_some.rs | 258 +------------------------- clippy_utils/src/sugg.rs | 278 ++++++++++++++++++++++++++++- 2 files changed, 279 insertions(+), 257 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index a3449c1fe12..5ed4ba94884 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -1,21 +1,16 @@ -use std::iter; - use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{get_parent_expr_for_hir, is_trait_method, strip_pat_refs}; +use clippy_utils::{is_trait_method, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{self, ExprKind, HirId, MutTy, PatKind, TyKind}; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_middle::hir::place::ProjectionKind; -use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty; -use rustc_span::source_map::{BytePos, Span}; +use rustc_span::source_map::Span; use rustc_span::symbol::sym; -use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use super::SEARCH_IS_SOME; @@ -55,7 +50,7 @@ pub(super) fn check<'tcx>( } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { // `find()` provides a reference to the item, but `any` does not, // so we should fix item usages for suggestion - if let Some(closure_sugg) = get_closure_suggestion(cx, search_arg) { + if let Some(closure_sugg) = deref_closure_args(cx, search_arg) { applicability = closure_sugg.applicability; Some(closure_sugg.suggestion) } else { @@ -159,246 +154,3 @@ pub(super) fn check<'tcx>( } } } - -#[derive(Debug)] -struct ClosureSugg { - applicability: Applicability, - suggestion: String, -} - -// Build suggestion gradually by handling closure arg specific usages, -// such as explicit deref and borrowing cases. -// Returns `None` if no such use cases have been triggered in closure body -fn get_closure_suggestion<'tcx>(cx: &LateContext<'_>, search_expr: &'tcx hir::Expr<'_>) -> Option { - if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = search_expr.kind { - let closure_body = cx.tcx.hir().body(body_id); - // is closure arg a double reference (i.e.: `|x: &&i32| ...`) - let closure_arg_is_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind { - matches!(ty.kind, TyKind::Rptr(_, MutTy { .. })) - } else { - false - }; - - let mut visitor = DerefDelegate { - cx, - closure_span: search_expr.span, - closure_arg_is_double_ref, - next_pos: search_expr.span.lo(), - suggestion_start: String::new(), - applicability: Applicability::MaybeIncorrect, - }; - - let fn_def_id = cx.tcx.hir().local_def_id(search_expr.hir_id); - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) - .consume_body(closure_body); - }); - - if !visitor.suggestion_start.is_empty() { - return Some(ClosureSugg { - applicability: visitor.applicability, - suggestion: visitor.finish(), - }); - } - } - None -} - -struct DerefDelegate<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - closure_span: Span, - closure_arg_is_double_ref: bool, - next_pos: BytePos, - suggestion_start: String, - applicability: Applicability, -} - -impl DerefDelegate<'_, 'tcx> { - pub fn finish(&mut self) -> String { - let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None); - let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); - let sugg = format!("{}{}", self.suggestion_start, end_snip); - if self.closure_arg_is_double_ref { - sugg.replacen('&', "", 1) - } else { - sugg - } - } - - fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { - let (call_args, inputs) = match parent_expr.kind { - ExprKind::MethodCall(_, _, call_args, _) => { - if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) { - (call_args, self.cx.tcx.fn_sig(method_did).skip_binder().inputs()) - } else { - return false; - } - }, - ExprKind::Call(func, call_args) => { - let typ = self.cx.typeck_results().expr_ty(func); - (call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs()) - }, - _ => return false, - }; - - iter::zip(call_args, inputs) - .any(|(arg, ty)| arg.hir_id == cmt_hir_id && matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) - } -} - -impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { - fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} - - fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { - if let PlaceBase::Local(id) = cmt.place.base { - let map = self.cx.tcx.hir(); - let span = map.span(cmt.hir_id); - let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None); - let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); - - // identifier referring to the variable currently triggered (i.e.: `fp`) - let ident_str = map.name(id).to_string(); - // full identifier that includes projection (i.e.: `fp.field`) - let ident_str_with_proj = snippet(self.cx, span, "..").to_string(); - - if cmt.place.projections.is_empty() { - // handle item without any projection, that needs an explicit borrowing - // i.e.: suggest `&x` instead of `x` - self.closure_arg_is_double_ref = false; - self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); - } else { - // cases where a parent `Call` or `MethodCall` is using the item - // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` - // - // Note about method calls: - // - compiler automatically dereference references if the target type is a reference (works also for - // function call) - // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and - // no projection should be suggested - if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) { - match &parent_expr.kind { - // given expression is the self argument and will be handled completely by the compiler - // i.e.: `|x| x.is_something()` - ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => { - self.suggestion_start - .push_str(&format!("{}{}", start_snip, ident_str_with_proj)); - self.next_pos = span.hi(); - return; - }, - // item is used in a call - // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` - ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [_, call_args @ ..], _) => { - let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); - let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); - - if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { - // suggest ampersand if call function is taking args by double reference - let takes_arg_by_double_ref = - self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id); - - // compiler will automatically dereference field projection, so no need - // to suggest ampersand, but full identifier that includes projection is required - let has_field_projection = cmt - .place - .projections - .iter() - .any(|proj| matches!(proj.kind, ProjectionKind::Field(..))); - - // no need to bind again if the function doesn't take arg by double ref - // and if the item is already a double ref - let ident_sugg = if !call_args.is_empty() - && !takes_arg_by_double_ref - && (self.closure_arg_is_double_ref || has_field_projection) - { - let ident = if has_field_projection { - ident_str_with_proj - } else { - ident_str - }; - format!("{}{}", start_snip, ident) - } else { - format!("{}&{}", start_snip, ident_str) - }; - self.suggestion_start.push_str(&ident_sugg); - self.next_pos = span.hi(); - return; - } - - self.applicability = Applicability::Unspecified; - }, - _ => (), - } - } - - let mut replacement_str = ident_str; - let mut projections_handled = false; - cmt.place.projections.iter().enumerate().for_each(|(i, proj)| { - match proj.kind { - // Field projection like `|v| v.foo` - // no adjustment needed here, as field projections are handled by the compiler - ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() { - ty::Adt(..) | ty::Tuple(_) => { - replacement_str = ident_str_with_proj.clone(); - projections_handled = true; - }, - _ => (), - }, - // Index projection like `|x| foo[x]` - // the index is dropped so we can't get it to build the suggestion, - // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`) - // instead of `span.lo()` (i.e.: `foo`) - ProjectionKind::Index => { - let start_span = Span::new(self.next_pos, span.hi(), span.ctxt(), None); - start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); - replacement_str.clear(); - projections_handled = true; - }, - // note: unable to trigger `Subslice` kind in tests - ProjectionKind::Subslice => (), - ProjectionKind::Deref => { - // explicit deref for arrays should be avoided in the suggestion - // i.e.: `|sub| *sub[1..4].len() == 3` is not expected - if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() { - // dereferencing an array (i.e.: `|sub| sub[1..4].len() == 3`) - if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) { - projections_handled = true; - } - } - }, - } - }); - - // handle `ProjectionKind::Deref` by removing one explicit deref - // if no special case was detected (i.e.: suggest `*x` instead of `**x`) - if projections_handled { - self.closure_arg_is_double_ref = false; - } else { - let last_deref = cmt - .place - .projections - .iter() - .rposition(|proj| proj.kind == ProjectionKind::Deref); - - if let Some(pos) = last_deref { - let mut projections = cmt.place.projections.clone(); - projections.truncate(pos); - - for item in projections { - if item.kind == ProjectionKind::Deref { - replacement_str = format!("*{}", replacement_str); - } - } - } - } - - self.suggestion_start - .push_str(&format!("{}{}", start_snip, replacement_str)); - } - self.next_pos = span.hi(); - } - } - - fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} - - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} -} diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 01fb944cc36..e8a35f8c8dc 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -1,19 +1,27 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::higher; -use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite}; +use crate::source::{ + snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite, +}; +use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ast, token}; use rustc_ast_pretty::pprust::token_kind_to_string; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::{ExprKind, HirId, MutTy, TyKind}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{EarlyContext, LateContext, LintContext}; -use rustc_span::source_map::{CharPos, Span}; -use rustc_span::{BytePos, Pos, SyntaxContext}; +use rustc_middle::hir::place::ProjectionKind; +use rustc_middle::mir::{FakeReadCause, Mutability}; +use rustc_middle::ty; +use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext}; +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; +use std::iter; use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parentheses. @@ -716,6 +724,268 @@ impl DiagnosticBuilderExt for rustc_errors::DiagnosticBuilder } } +/// Suggestion results for handling closure +/// args dereferencing and borrowing +pub struct DerefClosure { + /// confidence on the built suggestion + pub applicability: Applicability, + /// gradually built suggestion + pub suggestion: String, +} + +/// Build suggestion gradually by handling closure arg specific usages, +/// such as explicit deref and borrowing cases. +/// Returns `None` if no such use cases have been triggered in closure body +/// +/// note: this only works on single line immutable closures +pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, search_expr: &'tcx hir::Expr<'_>) -> Option { + if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = search_expr.kind { + let closure_body = cx.tcx.hir().body(body_id); + // is closure arg a double reference (i.e.: `|x: &&i32| ...`) + let closure_arg_is_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind { + matches!(ty.kind, TyKind::Rptr(_, MutTy { .. })) + } else { + false + }; + + let mut visitor = DerefDelegate { + cx, + closure_span: search_expr.span, + closure_arg_is_double_ref, + next_pos: search_expr.span.lo(), + suggestion_start: String::new(), + applicability: Applicability::MaybeIncorrect, + }; + + let fn_def_id = cx.tcx.hir().local_def_id(search_expr.hir_id); + cx.tcx.infer_ctxt().enter(|infcx| { + ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) + .consume_body(closure_body); + }); + + if !visitor.suggestion_start.is_empty() { + return Some(DerefClosure { + applicability: visitor.applicability, + suggestion: visitor.finish(), + }); + } + } + None +} + +/// Visitor struct used for tracking down +/// dereferencing and borrowing of closure's args +struct DerefDelegate<'a, 'tcx> { + /// The late context of the lint + cx: &'a LateContext<'tcx>, + /// The span of the input closure to adapt + closure_span: Span, + /// Indicates if the arg of the closure is a double reference + closure_arg_is_double_ref: bool, + /// last position of the span to gradually build the suggestion + next_pos: BytePos, + /// starting part of the gradually built suggestion + suggestion_start: String, + /// confidence on the built suggestion + applicability: Applicability, +} + +impl DerefDelegate<'_, 'tcx> { + /// build final suggestion: + /// - create the ending part of suggestion + /// - concatenate starting and ending parts + /// - potentially remove needless borrowing + pub fn finish(&mut self) -> String { + let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None); + let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability); + let sugg = format!("{}{}", self.suggestion_start, end_snip); + if self.closure_arg_is_double_ref { + sugg.replacen('&', "", 1) + } else { + sugg + } + } + + /// indicates whether the function from `parent_expr` takes its args by double reference + fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { + let (call_args, inputs) = match parent_expr.kind { + ExprKind::MethodCall(_, _, call_args, _) => { + if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) { + (call_args, self.cx.tcx.fn_sig(method_did).skip_binder().inputs()) + } else { + return false; + } + }, + ExprKind::Call(func, call_args) => { + let typ = self.cx.typeck_results().expr_ty(func); + (call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs()) + }, + _ => return false, + }; + + iter::zip(call_args, inputs) + .any(|(arg, ty)| arg.hir_id == cmt_hir_id && matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) + } +} + +impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + + #[allow(clippy::too_many_lines)] + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { + if let PlaceBase::Local(id) = cmt.place.base { + let map = self.cx.tcx.hir(); + let span = map.span(cmt.hir_id); + let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None); + let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + + // identifier referring to the variable currently triggered (i.e.: `fp`) + let ident_str = map.name(id).to_string(); + // full identifier that includes projection (i.e.: `fp.field`) + let ident_str_with_proj = snippet(self.cx, span, "..").to_string(); + + if cmt.place.projections.is_empty() { + // handle item without any projection, that needs an explicit borrowing + // i.e.: suggest `&x` instead of `x` + self.closure_arg_is_double_ref = false; + self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str)); + } else { + // cases where a parent `Call` or `MethodCall` is using the item + // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` + // + // Note about method calls: + // - compiler automatically dereference references if the target type is a reference (works also for + // function call) + // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and + // no projection should be suggested + if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) { + match &parent_expr.kind { + // given expression is the self argument and will be handled completely by the compiler + // i.e.: `|x| x.is_something()` + ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => { + self.suggestion_start + .push_str(&format!("{}{}", start_snip, ident_str_with_proj)); + self.next_pos = span.hi(); + return; + }, + // item is used in a call + // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` + ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [_, call_args @ ..], _) => { + let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); + let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); + + if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { + // suggest ampersand if call function is taking args by double reference + let takes_arg_by_double_ref = + self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id); + + // compiler will automatically dereference field projection, so no need + // to suggest ampersand, but full identifier that includes projection is required + let has_field_projection = cmt + .place + .projections + .iter() + .any(|proj| matches!(proj.kind, ProjectionKind::Field(..))); + + // no need to bind again if the function doesn't take arg by double ref + // and if the item is already a double ref + let ident_sugg = if !call_args.is_empty() + && !takes_arg_by_double_ref + && (self.closure_arg_is_double_ref || has_field_projection) + { + let ident = if has_field_projection { + ident_str_with_proj + } else { + ident_str + }; + format!("{}{}", start_snip, ident) + } else { + format!("{}&{}", start_snip, ident_str) + }; + self.suggestion_start.push_str(&ident_sugg); + self.next_pos = span.hi(); + return; + } + + self.applicability = Applicability::Unspecified; + }, + _ => (), + } + } + + let mut replacement_str = ident_str; + let mut projections_handled = false; + cmt.place.projections.iter().enumerate().for_each(|(i, proj)| { + match proj.kind { + // Field projection like `|v| v.foo` + // no adjustment needed here, as field projections are handled by the compiler + ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() { + ty::Adt(..) | ty::Tuple(_) => { + replacement_str = ident_str_with_proj.clone(); + projections_handled = true; + }, + _ => (), + }, + // Index projection like `|x| foo[x]` + // the index is dropped so we can't get it to build the suggestion, + // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`) + // instead of `span.lo()` (i.e.: `foo`) + ProjectionKind::Index => { + let start_span = Span::new(self.next_pos, span.hi(), span.ctxt(), None); + start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); + replacement_str.clear(); + projections_handled = true; + }, + // note: unable to trigger `Subslice` kind in tests + ProjectionKind::Subslice => (), + ProjectionKind::Deref => { + // explicit deref for arrays should be avoided in the suggestion + // i.e.: `|sub| *sub[1..4].len() == 3` is not expected + if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() { + // dereferencing an array (i.e.: `|sub| sub[1..4].len() == 3`) + if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) { + projections_handled = true; + } + } + }, + } + }); + + // handle `ProjectionKind::Deref` by removing one explicit deref + // if no special case was detected (i.e.: suggest `*x` instead of `**x`) + if projections_handled { + self.closure_arg_is_double_ref = false; + } else { + let last_deref = cmt + .place + .projections + .iter() + .rposition(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(pos) = last_deref { + let mut projections = cmt.place.projections.clone(); + projections.truncate(pos); + + for item in projections { + if item.kind == ProjectionKind::Deref { + replacement_str = format!("*{}", replacement_str); + } + } + } + } + + self.suggestion_start + .push_str(&format!("{}{}", start_snip, replacement_str)); + } + self.next_pos = span.hi(); + } + } + + fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} +} + #[cfg(test)] mod test { use super::Sugg; -- cgit 1.4.1-3-g733a5 From f51bbc7db93e1e15489d0b43abc110410e44576b Mon Sep 17 00:00:00 2001 From: togami2864 Date: Sat, 20 Nov 2021 18:53:15 +0900 Subject: apply iter_cloned_collect to copied() --- clippy_lints/src/methods/iter_cloned_collect.rs | 6 +++--- clippy_lints/src/methods/mod.rs | 4 +++- tests/ui/iter_cloned_collect.fixed | 3 +++ tests/ui/iter_cloned_collect.stderr | 8 +++++++- 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index dd4ef6e4b58..30d56113c6c 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -9,7 +9,7 @@ use rustc_span::sym; use super::ITER_CLONED_COLLECT; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { if_chain! { if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec); if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)); @@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &' cx, ITER_CLONED_COLLECT, to_replace, - "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable", + &format!("called `iter().{}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable", method_name), "try", ".to_vec()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6ab5015ca78..a325da75ba6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2204,7 +2204,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv), ("collect", []) => match method_call!(recv) { - Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2), + 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); }, diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 39cc58cd298..9b862133580 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -23,4 +23,7 @@ fn main() { // Issue #6808 let arr: [u8; 64] = [0; 64]; let _: Vec<_> = arr.to_vec(); + + // Issue #6703 + let _: Vec = v.to_vec(); } diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index e1df61794ce..b2cc497bf43 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -28,5 +28,11 @@ error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling LL | let _: Vec<_> = arr.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` -error: aborting due to 4 previous errors +error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable + --> $DIR/iter_cloned_collect.rs:31:26 + | +LL | let _: Vec = v.iter().copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` + +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From 5cc451bc6cb9fc74c85e44be4a510e9c14f03914 Mon Sep 17 00:00:00 2001 From: frobiac Date: Thu, 2 Dec 2021 23:47:23 +0100 Subject: Escape backslash for singe_char_pattern.rs --- clippy_lints/src/methods/utils.rs | 8 +++++++- tests/ui/single_char_pattern.fixed | 3 +++ tests/ui/single_char_pattern.rs | 3 +++ tests/ui/single_char_pattern.stderr | 14 +++++++++++++- 4 files changed, 26 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index ba2ce73a116..11ad881ee7b 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -66,7 +66,13 @@ pub(super) fn get_hint_if_single_char_arg( // for regular string: "a" &snip[1..(snip.len() - 1)] }; - let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch }); + + let hint = format!("'{}'", match ch { + "'" => "\\'" , + r"\" => "\\\\", + _ => ch, + }); + Some(hint) } else { None diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 1abd2b7883d..ea26defd3d5 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -56,4 +56,7 @@ fn main() { x.split('a'); x.split('\''); x.split('#'); + // Must escape backslash in raw strings when converting to char #8060 + x.split('\\'); + x.split('\\'); } diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index e662bf34be2..eb2d0274fa2 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -56,4 +56,7 @@ fn main() { x.split(r###"a"###); x.split(r###"'"###); x.split(r###"#"###); + // Must escape backslash in raw strings when converting to char #8060 + x.split(r#"\"#); + x.split(r"\"); } diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 22d4b2d460f..f438d3da8ee 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -192,5 +192,17 @@ error: single-character string constant used as pattern LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` -error: aborting due to 32 previous errors +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:60:13 + | +LL | x.split(r#"/"#); + | ^^^^^^ help: try using a `char` instead: `'/'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:61:13 + | +LL | x.split(r"/"); + | ^^^^ help: try using a `char` instead: `'/'` + +error: aborting due to 34 previous errors -- cgit 1.4.1-3-g733a5 From de9de4fef1219a98b0203ef67f348e6548dc80fe Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 1 Dec 2021 08:38:54 -0600 Subject: Upgrade map_flatten to complexity --- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 - clippy_lints/src/methods/mod.rs | 2 +- tests/ui/option_env_unwrap.rs | 1 + tests/ui/option_env_unwrap.stderr | 12 ++++++------ tests/ui/option_filter_map.fixed | 10 ++++++---- tests/ui/option_filter_map.rs | 10 ++++++---- tests/ui/option_filter_map.stderr | 16 ++++++++-------- 9 files changed, 30 insertions(+), 24 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 04912120e27..b7b5f059de6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -159,6 +159,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index dcc95cf6c07..a21ddf73a11 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -41,6 +41,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SPLIT_ONCE), + LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::OPTION_AS_REF_DEREF), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 5ee7799f9c5..70a4a624378 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -63,7 +63,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), - LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_UNWRAP_OR), LintId::of(misc::FLOAT_CMP), LintId::of(misc::USED_UNDERSCORE_BINDING), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a325da75ba6..ad6fb0c613b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -543,7 +543,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.31.0"] pub MAP_FLATTEN, - pedantic, + complexity, "using combinations of `flatten` and `map` which can usually be written as a single method call" } diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs index 642c77460a3..0141fb7856d 100644 --- a/tests/ui/option_env_unwrap.rs +++ b/tests/ui/option_env_unwrap.rs @@ -1,5 +1,6 @@ // aux-build:macro_rules.rs #![warn(clippy::option_env_unwrap)] +#![allow(clippy::map_flatten)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr index e6a58b0b2b7..885ac096cc8 100644 --- a/tests/ui/option_env_unwrap.stderr +++ b/tests/ui/option_env_unwrap.stderr @@ -1,5 +1,5 @@ error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:17:13 + --> $DIR/option_env_unwrap.rs:18:13 | LL | let _ = option_env!("PATH").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = option_env!("PATH").unwrap(); = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:18:13 + --> $DIR/option_env_unwrap.rs:19:13 | LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:9:9 + --> $DIR/option_env_unwrap.rs:10:9 | LL | option_env!($env).unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _ = option_env_unwrap!("PATH"); = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:12:9 + --> $DIR/option_env_unwrap.rs:13:9 | LL | option_env!($env).expect($message) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:21:13 + --> $DIR/option_env_unwrap.rs:22:13 | LL | let _ = option_env_unwrap_external!("PATH"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = option_env_unwrap_external!("PATH"); = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:22:13 + --> $DIR/option_env_unwrap.rs:23:13 | LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_filter_map.fixed b/tests/ui/option_filter_map.fixed index f9d1825ade0..b20f73f3110 100644 --- a/tests/ui/option_filter_map.fixed +++ b/tests/ui/option_filter_map.fixed @@ -1,8 +1,6 @@ -#![warn(clippy::option_filter_map)] // run-rustfix -fn odds_out(x: i32) -> Option { - if x % 2 == 0 { Some(x) } else { None } -} +#![warn(clippy::option_filter_map)] +#![allow(clippy::map_flatten)] fn main() { let _ = Some(Some(1)).flatten(); @@ -21,3 +19,7 @@ fn main() { .map(odds_out) .flatten(); } + +fn odds_out(x: i32) -> Option { + if x % 2 == 0 { Some(x) } else { None } +} diff --git a/tests/ui/option_filter_map.rs b/tests/ui/option_filter_map.rs index 588e1ccccce..7abaaa0fb83 100644 --- a/tests/ui/option_filter_map.rs +++ b/tests/ui/option_filter_map.rs @@ -1,8 +1,6 @@ -#![warn(clippy::option_filter_map)] // run-rustfix -fn odds_out(x: i32) -> Option { - if x % 2 == 0 { Some(x) } else { None } -} +#![warn(clippy::option_filter_map)] +#![allow(clippy::map_flatten)] fn main() { let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); @@ -23,3 +21,7 @@ fn main() { .filter(|o| o.is_some()) .map(|o| o.unwrap()); } + +fn odds_out(x: i32) -> Option { + if x % 2 == 0 { Some(x) } else { None } +} diff --git a/tests/ui/option_filter_map.stderr b/tests/ui/option_filter_map.stderr index 31a82969d5a..4a030ac9ab0 100644 --- a/tests/ui/option_filter_map.stderr +++ b/tests/ui/option_filter_map.stderr @@ -1,5 +1,5 @@ error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:8:27 + --> $DIR/option_filter_map.rs:6:27 | LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` @@ -7,37 +7,37 @@ LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); = note: `-D clippy::option-filter-map` implied by `-D warnings` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:9:27 + --> $DIR/option_filter_map.rs:7:27 | LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:10:35 + --> $DIR/option_filter_map.rs:8:35 | LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:11:35 + --> $DIR/option_filter_map.rs:9:35 | LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:13:39 + --> $DIR/option_filter_map.rs:11:39 | LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:14:39 + --> $DIR/option_filter_map.rs:12:39 | LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:18:10 + --> $DIR/option_filter_map.rs:16:10 | LL | .filter(Option::is_some) | __________^ @@ -45,7 +45,7 @@ LL | | .map(Option::unwrap); | |____________________________^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:23:10 + --> $DIR/option_filter_map.rs:21:10 | LL | .filter(|o| o.is_some()) | __________^ -- cgit 1.4.1-3-g733a5 From e3c60444ce6652198c0986c98fe7bd0f8de5f987 Mon Sep 17 00:00:00 2001 From: nixx quality Date: Sun, 5 Dec 2021 17:33:52 +0100 Subject: fix some false negatives for single_char_pattern --- clippy_lints/src/methods/single_char_pattern.rs | 7 +- tests/ui/single_char_pattern.fixed | 7 +- tests/ui/single_char_pattern.rs | 7 +- tests/ui/single_char_pattern.stderr | 94 ++++++++++++++++--------- 4 files changed, 80 insertions(+), 35 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index d313a3db479..bf9006c6906 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -9,18 +9,21 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; -const PATTERN_METHODS: [(&str, usize); 19] = [ +const PATTERN_METHODS: [(&str, usize); 24] = [ ("contains", 1), ("starts_with", 1), ("ends_with", 1), ("find", 1), ("rfind", 1), ("split", 1), + ("split_inclusive", 1), ("rsplit", 1), ("split_terminator", 1), ("rsplit_terminator", 1), ("splitn", 2), ("rsplitn", 2), + ("split_once", 1), + ("rsplit_once", 1), ("matches", 1), ("rmatches", 1), ("match_indices", 1), @@ -29,6 +32,8 @@ const PATTERN_METHODS: [(&str, usize); 19] = [ ("strip_suffix", 1), ("trim_start_matches", 1), ("trim_end_matches", 1), + ("replace", 1), + ("replacen", 1), ]; /// lint for length-1 `str`s for methods in `PATTERN_METHODS` diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index ea26defd3d5..68e26726724 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -17,6 +17,7 @@ fn main() { x.split('💣'); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); + x.split_inclusive('x'); x.contains('x'); x.starts_with('x'); x.ends_with('x'); @@ -27,6 +28,8 @@ fn main() { x.rsplit_terminator('x'); x.splitn(2, 'x'); x.rsplitn(2, 'x'); + x.split_once('x'); + x.rsplit_once('x'); x.matches('x'); x.rmatches('x'); x.match_indices('x'); @@ -35,6 +38,8 @@ fn main() { x.trim_end_matches('x'); x.strip_prefix('x'); x.strip_suffix('x'); + x.replace('x', "y"); + x.replacen('x', "y", 3); // Make sure we escape characters correctly. x.split('\n'); x.split('\''); @@ -43,7 +48,7 @@ fn main() { let h = HashSet::::new(); h.contains("X"); // should not warn - x.replace(";", ",").split(','); // issue #2978 + x.replace(';', ",").split(','); // issue #2978 x.starts_with('\x03'); // issue #2996 // Issue #3204 diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index eb2d0274fa2..186202d78ec 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -17,6 +17,7 @@ fn main() { x.split("💣"); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); + x.split_inclusive("x"); x.contains("x"); x.starts_with("x"); x.ends_with("x"); @@ -27,6 +28,8 @@ fn main() { x.rsplit_terminator("x"); x.splitn(2, "x"); x.rsplitn(2, "x"); + x.split_once("x"); + x.rsplit_once("x"); x.matches("x"); x.rmatches("x"); x.match_indices("x"); @@ -35,6 +38,8 @@ fn main() { x.trim_end_matches("x"); x.strip_prefix("x"); x.strip_suffix("x"); + x.replace("x", "y"); + x.replacen("x", "y", 3); // Make sure we escape characters correctly. x.split("\n"); x.split("'"); @@ -43,7 +48,7 @@ fn main() { let h = HashSet::::new(); h.contains("X"); // should not warn - x.replace(";", ",").split(","); // issue #2978 + x.replace(';', ",").split(","); // issue #2978 x.starts_with("\x03"); // issue #2996 // Issue #3204 diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index f438d3da8ee..5564aac674d 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -25,184 +25,214 @@ LL | x.split("💣"); | ^^^^ help: try using a `char` instead: `'💣'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:20:16 + --> $DIR/single_char_pattern.rs:20:23 + | +LL | x.split_inclusive("x"); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:21:16 | LL | x.contains("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:21:19 + --> $DIR/single_char_pattern.rs:22:19 | LL | x.starts_with("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:22:17 + --> $DIR/single_char_pattern.rs:23:17 | LL | x.ends_with("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:23:12 + --> $DIR/single_char_pattern.rs:24:12 | LL | x.find("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:24:13 + --> $DIR/single_char_pattern.rs:25:13 | LL | x.rfind("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:25:14 + --> $DIR/single_char_pattern.rs:26:14 | LL | x.rsplit("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:26:24 + --> $DIR/single_char_pattern.rs:27:24 | LL | x.split_terminator("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:27:25 + --> $DIR/single_char_pattern.rs:28:25 | LL | x.rsplit_terminator("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:28:17 + --> $DIR/single_char_pattern.rs:29:17 | LL | x.splitn(2, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:29:18 + --> $DIR/single_char_pattern.rs:30:18 | LL | x.rsplitn(2, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:30:15 + --> $DIR/single_char_pattern.rs:31:18 + | +LL | x.split_once("x"); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:32:19 + | +LL | x.rsplit_once("x"); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:33:15 | LL | x.matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:31:16 + --> $DIR/single_char_pattern.rs:34:16 | LL | x.rmatches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:32:21 + --> $DIR/single_char_pattern.rs:35:21 | LL | x.match_indices("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:33:22 + --> $DIR/single_char_pattern.rs:36:22 | LL | x.rmatch_indices("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:34:26 + --> $DIR/single_char_pattern.rs:37:26 | LL | x.trim_start_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:35:24 + --> $DIR/single_char_pattern.rs:38:24 | LL | x.trim_end_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:36:20 + --> $DIR/single_char_pattern.rs:39:20 | LL | x.strip_prefix("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:37:20 + --> $DIR/single_char_pattern.rs:40:20 | LL | x.strip_suffix("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:39:13 + --> $DIR/single_char_pattern.rs:41:15 + | +LL | x.replace("x", "y"); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:42:16 + | +LL | x.replacen("x", "y", 3); + | ^^^ help: try using a `char` instead: `'x'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:44:13 | LL | x.split("/n"); | ^^^^ help: try using a `char` instead: `'/n'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:40:13 + --> $DIR/single_char_pattern.rs:45:13 | LL | x.split("'"); | ^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:41:13 + --> $DIR/single_char_pattern.rs:46:13 | LL | x.split("/'"); | ^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:46:31 + --> $DIR/single_char_pattern.rs:51:31 | -LL | x.replace(";", ",").split(","); // issue #2978 +LL | x.replace(';', ",").split(","); // issue #2978 | ^^^ help: try using a `char` instead: `','` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:47:19 + --> $DIR/single_char_pattern.rs:52:19 | LL | x.starts_with("/x03"); // issue #2996 | ^^^^^^ help: try using a `char` instead: `'/x03'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:54:13 + --> $DIR/single_char_pattern.rs:59:13 | LL | x.split(r"a"); | ^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:55:13 + --> $DIR/single_char_pattern.rs:60:13 | LL | x.split(r#"a"#); | ^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:56:13 + --> $DIR/single_char_pattern.rs:61:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:57:13 + --> $DIR/single_char_pattern.rs:62:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:58:13 + --> $DIR/single_char_pattern.rs:63:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:60:13 + --> $DIR/single_char_pattern.rs:65:13 | LL | x.split(r#"/"#); | ^^^^^^ help: try using a `char` instead: `'/'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:61:13 + --> $DIR/single_char_pattern.rs:66:13 | LL | x.split(r"/"); | ^^^^ help: try using a `char` instead: `'/'` -error: aborting due to 34 previous errors +error: aborting due to 39 previous errors -- cgit 1.4.1-3-g733a5 From 284b63a687cf9aef61ae4a1ef178ba2c4df60735 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 1 Apr 2021 10:31:11 -0500 Subject: Rename remove_blocks to peel_blocks --- clippy_lints/src/bytecount.rs | 4 +-- clippy_lints/src/derivable_impls.rs | 4 +-- clippy_lints/src/map_clone.rs | 5 ++-- clippy_lints/src/matches.rs | 10 ++++---- clippy_lints/src/methods/bind_instead_of_map.rs | 4 +-- clippy_lints/src/methods/filter_map.rs | 4 +-- clippy_lints/src/methods/option_as_ref_deref.rs | 4 +-- clippy_lints/src/methods/unnecessary_fold.rs | 4 +-- clippy_utils/src/lib.rs | 33 ++++++++++++++----------- 9 files changed, 38 insertions(+), 34 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index afb317421d0..657c1f88c7d 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::match_type; use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_ref_operators, remove_blocks, strip_pat_refs}; +use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { cx.typeck_results().expr_ty(filter_recv).peel_refs(), &paths::SLICE_ITER); let operand_is_arg = |expr| { - let expr = peel_ref_operators(cx, remove_blocks(expr)); + let expr = peel_ref_operators(cx, peel_blocks(expr)); path_to_local_id(expr, arg_id) }; let needle = if operand_is_arg(l) { diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index d0fab2b48fb..eccb18982f3 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_automatically_derived, is_default_equivalent, remove_blocks}; +use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks}; use rustc_hir::{ def::{DefKind, Res}, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { } } } - let should_emit = match remove_blocks(func_expr).kind { + let should_emit = match peel_blocks(func_expr).kind { ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index c2b78e21861..174c7da28d3 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; -use clippy_utils::remove_blocks; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::{is_trait_method, peel_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -60,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; then { let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); + let closure_expr = peel_blocks(&closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( hir::BindingAnnotation::Unannotated, .., name, None diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 08c23ca6d32..385232f4d71 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -9,7 +9,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, pe use clippy_utils::visitors::is_local_used; use clippy_utils::{ get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs, - path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, + path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, strip_pat_refs, }; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; @@ -659,7 +659,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind; if args.len() == 1; if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind; - let body = remove_blocks(arms[0].body); + let body = peel_blocks(arms[0].body); if path_to_local_id(body, arg); then { @@ -724,7 +724,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp return; } let els = arms[1].body; - let els = if is_unit_expr(remove_blocks(els)) { + let els = if is_unit_expr(peel_blocks(els)) { None } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind { if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() { @@ -1482,7 +1482,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A let matched_vars = ex.span; let bind_names = arms[0].pat.span; - let match_body = remove_blocks(arms[0].body); + let match_body = peel_blocks(arms[0].body); let mut snippet_body = if match_body.span.from_expansion() { Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string() } else { @@ -1679,7 +1679,7 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); + let closure_expr = peel_blocks(&closure_body.value); if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) { true diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index c96c817bb8b..6d8733c08b4 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq}; +use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -25,7 +25,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy }, hir::ExprKind::Closure(_, _, c, _, _) => { let body = cx.tcx.hir().body(*c); - let closure_expr = remove_blocks(&body.value); + let closure_expr = peel_blocks(&body.value); let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, args, _) => { diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index d3f40d26208..fa74a8f3dc3 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks}; +use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -53,7 +53,7 @@ pub(super) fn check<'tcx>( }), hir::ExprKind::Closure(_, _, body_id, _, _) => { let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); + let closure_expr = peel_blocks(&closure_body.value); match &closure_expr.kind { hir::ExprKind::MethodCall(_, _, args, _) => { diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 4c4034437da..47a81199608 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs}; +use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -31,7 +31,7 @@ pub(super) fn check( // Extract the body of the closure passed to fold if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind; let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); + let closure_expr = peel_blocks(&closure_body.value); // Check if the closure body is of the form `acc some_expr(x)` if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f011380c127..2991c5880d5 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1224,6 +1224,25 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { } } +/// Removes blocks around an expression, only if the block contains just one expression +/// and no statements. +/// +/// Examples: +/// * `{}` -> `{}` +/// * `{ x }` -> `x` +/// * `{{ x }}` -> `x` +/// * `{ x; }` -> `{ x; }` +/// * `{ x; y }` -> `{ x; y }` +pub fn peel_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { + while let ExprKind::Block(block, ..) = expr.kind { + match (block.stmts.is_empty(), block.expr.as_ref()) { + (true, Some(e)) => expr = e, + _ => break, + } + } + expr +} + /// Checks if the given expression is the else clause of either an `if` or `if let` expression. pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { let mut iter = tcx.hir().parent_iter(expr.hir_id); @@ -1405,20 +1424,6 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { has_attr(attrs, sym::automatically_derived) } -/// Remove blocks around an expression. -/// -/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return -/// themselves. -pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { - while let ExprKind::Block(block, ..) = expr.kind { - match (block.stmts.is_empty(), block.expr.as_ref()) { - (true, Some(e)) => expr = e, - _ => break, - } - } - expr -} - pub fn is_self(slf: &Param<'_>) -> bool { if let PatKind::Binding(.., name, _) = slf.pat.kind { name.name == kw::SelfLower -- cgit 1.4.1-3-g733a5 From 468c86e4a3fa31b8c670422ea63875428e899b7f Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Mon, 15 Nov 2021 19:25:08 -0500 Subject: Add `unnecessary_to_owned` lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_perf.rs | 1 + clippy_lints/src/methods/mod.rs | 31 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 328 +++++++++++++++++++ clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_utils/src/paths.rs | 2 + tests/ui/unnecessary_to_owned.fixed | 170 ++++++++++ tests/ui/unnecessary_to_owned.rs | 170 ++++++++++ tests/ui/unnecessary_to_owned.stderr | 382 +++++++++++++++++++++++ 11 files changed, 1087 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_to_owned.rs create mode 100644 tests/ui/unnecessary_to_owned.fixed create mode 100644 tests/ui/unnecessary_to_owned.rs create mode 100644 tests/ui/unnecessary_to_owned.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f64cd0e914..7b5279cda6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3210,6 +3210,7 @@ Released 2018-09-13 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by +[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 9ac77d63879..3d3999d4cc0 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -181,6 +181,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FOLD), LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), LintId::of(methods::WRONG_SELF_CONVENTION), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 68889f4f50a..766c5ba1bcb 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -315,6 +315,7 @@ store.register_lints(&[ methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FOLD, methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNNECESSARY_TO_OWNED, methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, methods::USELESS_ASREF, diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index a0d5cf9418e..2ea0b696f1f 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -17,6 +17,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(misc::CMP_OWNED), LintId::of(mutex_atomic::MUTEX_ATOMIC), LintId::of(redundant_clone::REDUNDANT_CLONE), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 58ec2213535..a0de296fd07 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -57,6 +57,7 @@ mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_lazy_eval; +mod unnecessary_to_owned; mod unwrap_or_else_default; mod unwrap_used; mod useless_asref; @@ -1885,6 +1886,32 @@ declare_clippy_lint! { "usages of `str::splitn` that can be replaced with `str::split`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned) + /// and other `to_owned`-like functions. + /// + /// ### Why is this bad? + /// The unnecessary calls result in unnecessary allocations. + /// + /// ### Example + /// ```rust + /// let path = std::path::Path::new("x"); + /// foo(&path.to_string_lossy().to_string()); + /// fn foo(s: &str) {} + /// ``` + /// Use instead: + /// ```rust + /// let path = std::path::Path::new("x"); + /// foo(&path.to_string_lossy()); + /// fn foo(s: &str) {} + /// ``` + #[clippy::version = "1.58.0"] + pub UNNECESSARY_TO_OWNED, + perf, + "unnecessary calls to `to_owned`-like functions" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -1964,7 +1991,8 @@ impl_lint_pass!(Methods => [ MANUAL_STR_REPEAT, EXTEND_WITH_DRAIN, MANUAL_SPLIT_ONCE, - NEEDLESS_SPLITN + NEEDLESS_SPLITN, + UNNECESSARY_TO_OWNED ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2007,6 +2035,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { single_char_add_str::check(cx, expr, args); into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args); single_char_pattern::check(cx, expr, method_call.ident.name, args); + unnecessary_to_owned::check(cx, expr, method_call.ident.name, args); }, hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs new file mode 100644 index 00000000000..307de7bb65a --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -0,0 +1,328 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::{get_parent_expr, match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::mir::Mutability; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; +use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_span::{sym, Symbol}; +use std::cmp::max; + +use super::UNNECESSARY_TO_OWNED; + +const TO_OWNED_LIKE_PATHS: &[&[&str]] = &[ + &paths::COW_INTO_OWNED, + &paths::OS_STR_TO_OS_STRING, + &paths::PATH_TO_PATH_BUF, + &paths::SLICE_TO_VEC, + &paths::TO_OWNED_METHOD, + &paths::TO_STRING_METHOD, +]; + +pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) { + if_chain! { + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if TO_OWNED_LIKE_PATHS + .iter() + .any(|path| match_def_path(cx, method_def_id, path)); + if let [receiver] = args; + then { + // At this point, we know the call is of a `to_owned`-like function. The functions + // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary + // based on its context, that is, whether it is a referent in an `AddrOf` expression or + // an argument in a function call. + if check_addr_of_expr(cx, expr, method_name, receiver) { + return; + } + check_call_arg(cx, expr, method_name, receiver); + } + } +} + +/// Checks whether `expr` is a referent in an `AddrOf` expression and, if so, determines whether its +/// call of a `to_owned`-like function is unnecessary. +fn check_addr_of_expr( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + method_name: Symbol, + receiver: &'tcx Expr<'tcx>, +) -> bool { + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind; + let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::>(); + if let Some(target_ty) = match adjustments[..] + { + // For matching uses of `Cow::from` + [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Borrow(_), + target: target_ty, + }, + ] + // For matching uses of arrays + | [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Borrow(_), + .. + }, + Adjustment { + kind: Adjust::Pointer(_), + target: target_ty, + }, + ] + // For matching everything else + | [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Deref(Some(OverloadedDeref { .. })), + .. + }, + Adjustment { + kind: Adjust::Borrow(_), + target: target_ty, + }, + ] => Some(target_ty), + _ => None, + }; + then { + let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); + if_chain! { + if receiver_ty == target_ty; + if n_target_refs >= n_receiver_refs; + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); + then { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{}`", method_name), + "use", + format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs), + Applicability::MachineApplicable, + ); + return true; + } + } + if implements_deref_trait(cx, receiver_ty, target_ty) { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + expr.span.with_lo(receiver.span.hi()), + &format!("unnecessary use of `{}`", method_name), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + return true; + } + if_chain! { + if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); + if implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]); + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); + then { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{}`", method_name), + "use", + format!("{}.as_ref()", receiver_snippet), + Applicability::MachineApplicable, + ); + return true; + } + } + } + } + false +} + +/// Checks whether `expr` is an argument in a function call and, if so, determines whether its call +/// of a `to_owned`-like function is unnecessary. +fn check_call_arg(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) { + if_chain! { + if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); + if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call); + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id); + if let Some(input) = fn_sig.inputs().get(i); + let (input, n_refs) = peel_mid_ty_refs(input); + if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); + if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait(); + if let [trait_predicate] = trait_predicates + .iter() + .filter(|trait_predicate| trait_predicate.def_id() != sized_def_id) + .collect::>()[..]; + if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); + if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + // If the callee has type parameters, they could appear in `projection_predicate.ty` or the + // types of `trait_predicate.trait_ref.substs`. + if if trait_predicate.def_id() == deref_trait_id { + if let [projection_predicate] = projection_predicates[..] { + let normalized_ty = + cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty); + implements_deref_trait(cx, receiver_ty, normalized_ty) + } else { + false + } + } else if trait_predicate.def_id() == as_ref_trait_id { + let composed_substs = compose_substs( + cx, + &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], + call_substs + ); + implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + } else { + false + }; + // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match + // `Target = T`. + if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; + let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); + then { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + maybe_arg.span, + &format!("unnecessary use of `{}`", method_name), + "use", + format!("{:&>width$}{}", "", receiver_snippet, width = n_refs), + Applicability::MachineApplicable, + ); + } + } +} + +/// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such +/// expression found (if any) along with the immediately prior expression. +fn skip_addr_of_ancestors( + cx: &LateContext<'tcx>, + mut expr: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + while let Some(parent) = get_parent_expr(cx, expr) { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind { + expr = parent; + } else { + return Some((parent, expr)); + } + } + None +} + +/// Checks whether an expression is a function or method call and, if so, returns its `DefId`, +/// `Substs`, and arguments. +fn get_callee_substs_and_args( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> { + if_chain! { + if let ExprKind::Call(callee, args) = expr.kind; + let callee_ty = cx.typeck_results().expr_ty(callee); + if let ty::FnDef(callee_def_id, _) = callee_ty.kind(); + then { + let substs = cx.typeck_results().node_substs(callee.hir_id); + return Some((*callee_def_id, substs, args)); + } + } + if_chain! { + if let ExprKind::MethodCall(_, _, args, _) = expr.kind; + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + then { + let substs = cx.typeck_results().node_substs(expr.hir_id); + return Some((method_def_id, substs, args)); + } + } + None +} + +/// Returns the `TraitPredicate`s and `ProjectionPredicate`s for a function's input type. +fn get_input_traits_and_projections( + cx: &LateContext<'tcx>, + callee_def_id: DefId, + input: Ty<'tcx>, +) -> (Vec>, Vec>) { + let mut trait_predicates = Vec::new(); + let mut projection_predicates = Vec::new(); + for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() { + // `substs` should have 1 + n elements. The first is the type on the left hand side of an + // `as`. The remaining n are trait parameters. + let is_input_substs = |substs: SubstsRef<'tcx>| { + if_chain! { + if let Some(arg) = substs.iter().next(); + if let GenericArgKind::Type(arg_ty) = arg.unpack(); + if arg_ty == input; + then { + true + } else { + false + } + } + }; + match predicate.kind().skip_binder() { + PredicateKind::Trait(trait_predicate) => { + if is_input_substs(trait_predicate.trait_ref.substs) { + trait_predicates.push(trait_predicate); + } + }, + PredicateKind::Projection(projection_predicate) => { + if is_input_substs(projection_predicate.projection_ty.substs) { + projection_predicates.push(projection_predicate); + } + }, + _ => {}, + } + } + (trait_predicates, projection_predicates) +} + +/// Composes two substitutions by applying the latter to the types of the former. +fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: SubstsRef<'tcx>) -> Vec> { + left.iter() + .map(|arg| { + if let GenericArgKind::Type(arg_ty) = arg.unpack() { + let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty); + GenericArg::from(normalized_ty) + } else { + *arg + } + }) + .collect() +} + +/// Helper function to check whether a type implements the `Deref` trait. +fn implements_deref_trait(cx: &LateContext<'tcx>, ty: Ty<'tcx>, deref_target_ty: Ty<'tcx>) -> bool { + if_chain! { + if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); + if implements_trait(cx, ty, deref_trait_id, &[]); + if let Some(deref_target_id) = cx.tcx.lang_items().deref_target(); + let substs = cx.tcx.mk_substs_trait(ty, &[]); + let projection_ty = cx.tcx.mk_projection(deref_target_id, substs); + let normalized_ty = cx.tcx.normalize_erasing_regions(cx.param_env, projection_ty); + if normalized_ty == deref_target_ty; + then { + true + } else { + false + } + } +} diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 9fb8f236899..fe35ff33d35 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -169,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { trait_name ), Some(last_semi), - &"probably caused by this trailing semicolon".to_string(), + "probably caused by this trailing semicolon", ); }, None => {}, diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 6171823abbb..634a452d6f1 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -36,6 +36,7 @@ pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; +pub const COW_INTO_OWNED: [&str; 4] = ["alloc", "borrow", "Cow", "into_owned"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; @@ -170,6 +171,7 @@ pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_p pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; +pub const SLICE_TO_VEC: [&str; 4] = ["alloc", "slice", "", "to_vec"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed new file mode 100644 index 00000000000..f1a5dc91a7e --- /dev/null +++ b/tests/ui/unnecessary_to_owned.fixed @@ -0,0 +1,170 @@ +// run-rustfix + +#![allow(clippy::ptr_arg)] +// Some of the expressions that `redundant_clone` flags overlap with ours. Enabling it interferes +// with `rustfix`. +#![allow(clippy::redundant_clone)] +// `needless_borrow` is for checking the fixed code. +#![warn(clippy::needless_borrow)] +#![warn(clippy::unnecessary_to_owned)] + +use std::borrow::Cow; +use std::ffi::{CStr, OsStr}; +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 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) -> Self { + let mut s = self.0.clone(); + s.push_str(other.as_ref()); + Self(s) + } +} + +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")); + + require_c_str(&Cow::from(c_str)); + require_c_str(c_str); + + require_os_str(os_str); + require_os_str(&Cow::from(os_str)); + require_os_str(os_str); + + require_path(path); + require_path(&Cow::from(path)); + require_path(path); + + require_str(s); + require_str(&Cow::from(s)); + require_str(s); + require_str(x.as_ref()); + + require_slice(slice); + require_slice(&Cow::from(slice)); + require_slice(array.as_ref()); + require_slice(array_ref.as_ref()); + require_slice(slice); + require_slice(&x); + + require_x(&Cow::::Owned(x.clone())); + require_x(&x); + + require_deref_c_str(c_str); + require_deref_os_str(os_str); + require_deref_path(path); + require_deref_str(s); + require_deref_slice(slice); + + require_impl_deref_c_str(c_str); + require_impl_deref_os_str(os_str); + require_impl_deref_path(path); + require_impl_deref_str(s); + require_impl_deref_slice(slice); + + require_deref_str_slice(s, slice); + require_deref_slice_str(slice, s); + + require_as_ref_c_str(c_str); + require_as_ref_os_str(os_str); + require_as_ref_path(path); + require_as_ref_str(s); + require_as_ref_str(&x); + require_as_ref_slice(array); + require_as_ref_slice(array_ref); + require_as_ref_slice(slice); + + require_impl_as_ref_c_str(c_str); + require_impl_as_ref_os_str(os_str); + require_impl_as_ref_path(path); + require_impl_as_ref_str(s); + require_impl_as_ref_str(&x); + require_impl_as_ref_slice(array); + require_impl_as_ref_slice(array_ref); + require_impl_as_ref_slice(slice); + + require_as_ref_str_slice(s, array); + require_as_ref_str_slice(s, array_ref); + require_as_ref_str_slice(s, slice); + require_as_ref_slice_str(array, s); + require_as_ref_slice_str(array_ref, s); + require_as_ref_slice_str(slice, s); + + let _ = x.join(&x); + + // negative tests + require_string(&s.to_string()); + require_string(&Cow::from(s).into_owned()); + require_string(&s.to_owned()); + require_string(&x.to_string()); + + // `X` isn't copy. + require_deref_slice(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]) {} +fn require_x(_: &X) {} + +fn require_deref_c_str>(_: T) {} +fn require_deref_os_str>(_: T) {} +fn require_deref_path>(_: T) {} +fn require_deref_str>(_: T) {} +fn require_deref_slice>(_: U) {} + +fn require_impl_deref_c_str(_: impl Deref) {} +fn require_impl_deref_os_str(_: impl Deref) {} +fn require_impl_deref_path(_: impl Deref) {} +fn require_impl_deref_str(_: impl Deref) {} +fn require_impl_deref_slice(_: impl Deref) {} + +fn require_deref_str_slice, U, V: Deref>(_: T, _: V) {} +fn require_deref_slice_str, V: Deref>(_: U, _: V) {} + +fn require_as_ref_c_str>(_: T) {} +fn require_as_ref_os_str>(_: T) {} +fn require_as_ref_path>(_: T) {} +fn require_as_ref_str>(_: T) {} +fn require_as_ref_slice>(_: U) {} + +fn require_impl_as_ref_c_str(_: impl AsRef) {} +fn require_impl_as_ref_os_str(_: impl AsRef) {} +fn require_impl_as_ref_path(_: impl AsRef) {} +fn require_impl_as_ref_str(_: impl AsRef) {} +fn require_impl_as_ref_slice(_: impl AsRef<[T]>) {} + +fn require_as_ref_str_slice, U, V: AsRef<[U]>>(_: T, _: V) {} +fn require_as_ref_slice_str, V: AsRef>(_: U, _: V) {} + +fn require_string(_: &String) {} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs new file mode 100644 index 00000000000..081ff635bbd --- /dev/null +++ b/tests/ui/unnecessary_to_owned.rs @@ -0,0 +1,170 @@ +// run-rustfix + +#![allow(clippy::ptr_arg)] +// Some of the expressions that `redundant_clone` flags overlap with ours. Enabling it interferes +// with `rustfix`. +#![allow(clippy::redundant_clone)] +// `needless_borrow` is for checking the fixed code. +#![warn(clippy::needless_borrow)] +#![warn(clippy::unnecessary_to_owned)] + +use std::borrow::Cow; +use std::ffi::{CStr, OsStr}; +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 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) -> Self { + let mut s = self.0.clone(); + s.push_str(other.as_ref()); + Self(s) + } +} + +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")); + + 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.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.to_owned()); + + require_x(&Cow::::Owned(x.clone()).into_owned()); + require_x(&x.to_owned()); + + 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.to_string()); + + // negative tests + require_string(&s.to_string()); + require_string(&Cow::from(s).into_owned()); + require_string(&s.to_owned()); + require_string(&x.to_string()); + + // `X` isn't copy. + require_deref_slice(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]) {} +fn require_x(_: &X) {} + +fn require_deref_c_str>(_: T) {} +fn require_deref_os_str>(_: T) {} +fn require_deref_path>(_: T) {} +fn require_deref_str>(_: T) {} +fn require_deref_slice>(_: U) {} + +fn require_impl_deref_c_str(_: impl Deref) {} +fn require_impl_deref_os_str(_: impl Deref) {} +fn require_impl_deref_path(_: impl Deref) {} +fn require_impl_deref_str(_: impl Deref) {} +fn require_impl_deref_slice(_: impl Deref) {} + +fn require_deref_str_slice, U, V: Deref>(_: T, _: V) {} +fn require_deref_slice_str, V: Deref>(_: U, _: V) {} + +fn require_as_ref_c_str>(_: T) {} +fn require_as_ref_os_str>(_: T) {} +fn require_as_ref_path>(_: T) {} +fn require_as_ref_str>(_: T) {} +fn require_as_ref_slice>(_: U) {} + +fn require_impl_as_ref_c_str(_: impl AsRef) {} +fn require_impl_as_ref_os_str(_: impl AsRef) {} +fn require_impl_as_ref_path(_: impl AsRef) {} +fn require_impl_as_ref_str(_: impl AsRef) {} +fn require_impl_as_ref_slice(_: impl AsRef<[T]>) {} + +fn require_as_ref_str_slice, U, V: AsRef<[U]>>(_: T, _: V) {} +fn require_as_ref_slice_str, V: AsRef>(_: U, _: V) {} + +fn require_string(_: &String) {} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr new file mode 100644 index 00000000000..b15dd4c7ee7 --- /dev/null +++ b/tests/ui/unnecessary_to_owned.stderr @@ -0,0 +1,382 @@ +error: unnecessary use of `into_owned` + --> $DIR/unnecessary_to_owned.rs:55:36 + | +LL | require_c_str(&Cow::from(c_str).into_owned()); + | ^^^^^^^^^^^^^ help: remove this + | + = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:56:19 + | +LL | require_c_str(&c_str.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `c_str` + +error: unnecessary use of `to_os_string` + --> $DIR/unnecessary_to_owned.rs:58:20 + | +LL | require_os_str(&os_str.to_os_string()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` + +error: unnecessary use of `into_owned` + --> $DIR/unnecessary_to_owned.rs:59:38 + | +LL | require_os_str(&Cow::from(os_str).into_owned()); + | ^^^^^^^^^^^^^ help: remove this + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:60:20 + | +LL | require_os_str(&os_str.to_owned()); + | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` + +error: unnecessary use of `to_path_buf` + --> $DIR/unnecessary_to_owned.rs:62:18 + | +LL | require_path(&path.to_path_buf()); + | ^^^^^^^^^^^^^^^^^^^ help: use: `path` + +error: unnecessary use of `into_owned` + --> $DIR/unnecessary_to_owned.rs:63:34 + | +LL | require_path(&Cow::from(path).into_owned()); + | ^^^^^^^^^^^^^ help: remove this + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:64:18 + | +LL | require_path(&path.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `path` + +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:66:17 + | +LL | require_str(&s.to_string()); + | ^^^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `into_owned` + --> $DIR/unnecessary_to_owned.rs:67:30 + | +LL | require_str(&Cow::from(s).into_owned()); + | ^^^^^^^^^^^^^ help: remove this + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:68:17 + | +LL | require_str(&s.to_owned()); + | ^^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:69:17 + | +LL | require_str(&x.to_string()); + | ^^^^^^^^^^^^^^ help: use: `x.as_ref()` + +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:71:19 + | +LL | require_slice(&slice.to_vec()); + | ^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `into_owned` + --> $DIR/unnecessary_to_owned.rs:72:36 + | +LL | require_slice(&Cow::from(slice).into_owned()); + | ^^^^^^^^^^^^^ help: remove this + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:73:19 + | +LL | require_slice(&array.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:74:19 + | +LL | require_slice(&array_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:75:19 + | +LL | require_slice(&slice.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:76:21 + | +LL | require_slice(&x.to_owned()); + | ^^^^^^^^^^^ help: remove this + +error: unnecessary use of `into_owned` + --> $DIR/unnecessary_to_owned.rs:78:42 + | +LL | require_x(&Cow::::Owned(x.clone()).into_owned()); + | ^^^^^^^^^^^^^ help: remove this + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:79:15 + | +LL | require_x(&x.to_owned()); + | ^^^^^^^^^^^^^ help: use: `&x` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:81:25 + | +LL | require_deref_c_str(c_str.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `c_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:82:26 + | +LL | require_deref_os_str(os_str.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `os_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:83:24 + | +LL | require_deref_path(path.to_owned()); + | ^^^^^^^^^^^^^^^ help: use: `path` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:84:23 + | +LL | require_deref_str(s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:85:25 + | +LL | require_deref_slice(slice.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:87:30 + | +LL | require_impl_deref_c_str(c_str.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `c_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:88:31 + | +LL | require_impl_deref_os_str(os_str.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `os_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:89:29 + | +LL | require_impl_deref_path(path.to_owned()); + | ^^^^^^^^^^^^^^^ help: use: `path` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:90:28 + | +LL | require_impl_deref_str(s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:91:30 + | +LL | require_impl_deref_slice(slice.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:93:29 + | +LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:93:43 + | +LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:94:29 + | +LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:94:47 + | +LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:96:26 + | +LL | require_as_ref_c_str(c_str.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `c_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:97:27 + | +LL | require_as_ref_os_str(os_str.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `os_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:98:25 + | +LL | require_as_ref_path(path.to_owned()); + | ^^^^^^^^^^^^^^^ help: use: `path` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:99:24 + | +LL | require_as_ref_str(s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:100:24 + | +LL | require_as_ref_str(x.to_owned()); + | ^^^^^^^^^^^^ help: use: `&x` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:101:26 + | +LL | require_as_ref_slice(array.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `array` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:102:26 + | +LL | require_as_ref_slice(array_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:103:26 + | +LL | require_as_ref_slice(slice.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:105:31 + | +LL | require_impl_as_ref_c_str(c_str.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `c_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:106:32 + | +LL | require_impl_as_ref_os_str(os_str.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `os_str` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:107:30 + | +LL | require_impl_as_ref_path(path.to_owned()); + | ^^^^^^^^^^^^^^^ help: use: `path` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:108:29 + | +LL | require_impl_as_ref_str(s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:109:29 + | +LL | require_impl_as_ref_str(x.to_owned()); + | ^^^^^^^^^^^^ help: use: `&x` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:110:31 + | +LL | require_impl_as_ref_slice(array.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `array` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:111:31 + | +LL | require_impl_as_ref_slice(array_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:112:31 + | +LL | require_impl_as_ref_slice(slice.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:114:30 + | +LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:114:44 + | +LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `array` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:115:30 + | +LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:115:44 + | +LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:116:30 + | +LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:116:44 + | +LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:117:30 + | +LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `array` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:117:48 + | +LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:118:30 + | +LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:118:52 + | +LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:119:30 + | +LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^^^^^ help: use: `slice` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:119:48 + | +LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); + | ^^^^^^^^^^^^ help: use: `s` + +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:121:20 + | +LL | let _ = x.join(&x.to_string()); + | ^^^^^^^^^^^^^^ help: use: `&x` + +error: aborting due to 63 previous errors + -- cgit 1.4.1-3-g733a5 From 290f74be4e83fc610ad99d9c1cc1d7d5d96f2697 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Tue, 30 Nov 2021 05:52:01 -0500 Subject: Address review comments * Share a list of methods with `implicit_clone` * Ensure no overlap with `redundant_clone` --- clippy_lints/src/methods/implicit_clone.rs | 26 +++++--- clippy_lints/src/methods/unnecessary_to_owned.rs | 76 ++++++++++++++++-------- clippy_utils/src/paths.rs | 2 - tests/ui/unnecessary_to_owned.fixed | 27 +++++---- tests/ui/unnecessary_to_owned.rs | 27 +++++---- tests/ui/unnecessary_to_owned.stderr | 69 +++++++++++++++++---- 6 files changed, 160 insertions(+), 67 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 81c42de145f..ff7904ce582 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -12,15 +12,7 @@ use super::IMPLICIT_CLONE; pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match method_name { - "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), - "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), - "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), - "to_vec" => cx.tcx.impl_of_method(method_def_id) - .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl()) - == Some(true), - _ => false, - }; + if is_clone_like(cx, method_name, method_def_id); let return_type = cx.typeck_results().expr_ty(expr); let input_type = cx.typeck_results().expr_ty(recv).peel_refs(); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); @@ -38,3 +30,19 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv } } } + +/// Returns true if the named method can be used to clone the receiver. +pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool { + match method_name { + "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), + "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), + "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), + "to_vec" => { + cx.tcx + .impl_of_method(method_def_id) + .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl()) + == Some(true) + }, + _ => false, + } +} diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 307de7bb65a..b380f734bff 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,7 +1,8 @@ +use super::implicit_clone::is_clone_like; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_copy, peel_mid_ty_refs}; -use clippy_utils::{get_parent_expr, match_def_path, paths}; +use clippy_utils::{get_parent_expr, is_diag_item_method, is_diag_trait_item}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -14,28 +15,17 @@ use std::cmp::max; use super::UNNECESSARY_TO_OWNED; -const TO_OWNED_LIKE_PATHS: &[&[&str]] = &[ - &paths::COW_INTO_OWNED, - &paths::OS_STR_TO_OS_STRING, - &paths::PATH_TO_PATH_BUF, - &paths::SLICE_TO_VEC, - &paths::TO_OWNED_METHOD, - &paths::TO_STRING_METHOD, -]; - pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if TO_OWNED_LIKE_PATHS - .iter() - .any(|path| match_def_path(cx, method_def_id, path)); + if is_to_owned_like(cx, method_name, method_def_id); if let [receiver] = args; then { // At this point, we know the call is of a `to_owned`-like function. The functions // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary // based on its context, that is, whether it is a referent in an `AddrOf` expression or // an argument in a function call. - if check_addr_of_expr(cx, expr, method_name, receiver) { + if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) { return; } check_call_arg(cx, expr, method_name, receiver); @@ -45,10 +35,12 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol /// Checks whether `expr` is a referent in an `AddrOf` expression and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. +#[allow(clippy::too_many_lines)] fn check_addr_of_expr( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, + method_def_id: DefId, receiver: &'tcx Expr<'tcx>, ) -> bool { if_chain! { @@ -100,14 +92,17 @@ fn check_addr_of_expr( ] => Some(target_ty), _ => None, }; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + // Only flag cases where the receiver is copyable or the method is `Cow::into_owned`. This + // restriction is to ensure there is not overlap between `redundant_clone` and this lint. + if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id); + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty); - let receiver_ty = cx.typeck_results().expr_ty(receiver); let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); if_chain! { if receiver_ty == target_ty; if n_target_refs >= n_receiver_refs; - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( cx, @@ -122,21 +117,32 @@ fn check_addr_of_expr( } } if implements_deref_trait(cx, receiver_ty, target_ty) { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{}`", method_name), - "remove this", - String::new(), - Applicability::MachineApplicable, - ); + if n_receiver_refs > 0 { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{}`", method_name), + "use", + receiver_snippet, + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + expr.span.with_lo(receiver.span.hi()), + &format!("unnecessary use of `{}`", method_name), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + } return true; } if_chain! { if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); if implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]); - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( cx, @@ -326,3 +332,21 @@ fn implements_deref_trait(cx: &LateContext<'tcx>, ty: Ty<'tcx>, deref_target_ty: } } } + +/// Returns true if the named method can be used to convert the receiver to its "owned" +/// representation. +fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { + is_clone_like(cx, &*method_name.as_str(), method_def_id) + || is_cow_into_owned(cx, method_name, method_def_id) + || is_to_string(cx, method_name, method_def_id) +} + +/// Returns true if the named method is `Cow::into_owned`. +fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { + method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) +} + +/// Returns true if the named method is `ToString::to_string`. +fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { + method_name.as_str() == "to_string" && is_diag_trait_item(cx, method_def_id, sym::ToString) +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 634a452d6f1..6171823abbb 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -36,7 +36,6 @@ pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; -pub const COW_INTO_OWNED: [&str; 4] = ["alloc", "borrow", "Cow", "into_owned"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; @@ -171,7 +170,6 @@ pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_p pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; -pub const SLICE_TO_VEC: [&str; 4] = ["alloc", "slice", "", "to_vec"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index f1a5dc91a7e..bd9ef1fff42 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,15 +1,14 @@ // run-rustfix #![allow(clippy::ptr_arg)] -// Some of the expressions that `redundant_clone` flags overlap with ours. Enabling it interferes -// with `rustfix`. -#![allow(clippy::redundant_clone)] -// `needless_borrow` is for checking the fixed code. +// `needless_borrow` is to ensure there are no needles borrows in the fixed code. #![warn(clippy::needless_borrow)] +// `redundant_clone` is to ensure there is no overlap between that lint and this one. +#![warn(clippy::redundant_clone)] #![warn(clippy::unnecessary_to_owned)] use std::borrow::Cow; -use std::ffi::{CStr, OsStr}; +use std::ffi::{CStr, CString, OsStr, OsString}; use std::ops::Deref; #[derive(Clone)] @@ -51,6 +50,7 @@ fn main() { let array_ref = &["x"]; let slice = &["x"][..]; let x = X(String::from("x")); + let x_ref = &x; require_c_str(&Cow::from(c_str)); require_c_str(c_str); @@ -66,17 +66,17 @@ fn main() { require_str(s); require_str(&Cow::from(s)); require_str(s); - require_str(x.as_ref()); + require_str(x_ref.as_ref()); require_slice(slice); require_slice(&Cow::from(slice)); require_slice(array.as_ref()); require_slice(array_ref.as_ref()); require_slice(slice); - require_slice(&x); + require_slice(x_ref); require_x(&Cow::::Owned(x.clone())); - require_x(&x); + require_x(x_ref); require_deref_c_str(c_str); require_deref_os_str(os_str); @@ -118,16 +118,23 @@ fn main() { require_as_ref_slice_str(array_ref, s); require_as_ref_slice_str(slice, s); - let _ = x.join(&x); + let _ = x.join(x_ref); // negative tests require_string(&s.to_string()); require_string(&Cow::from(s).into_owned()); require_string(&s.to_owned()); - require_string(&x.to_string()); + 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()); + require_os_str(&OsString::from("x")); + require_path(&std::path::PathBuf::from("x")); + require_str(&String::from("x")); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 081ff635bbd..1bf30e22893 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,15 +1,14 @@ // run-rustfix #![allow(clippy::ptr_arg)] -// Some of the expressions that `redundant_clone` flags overlap with ours. Enabling it interferes -// with `rustfix`. -#![allow(clippy::redundant_clone)] -// `needless_borrow` is for checking the fixed code. +// `needless_borrow` is to ensure there are no needles borrows in the fixed code. #![warn(clippy::needless_borrow)] +// `redundant_clone` is to ensure there is no overlap between that lint and this one. +#![warn(clippy::redundant_clone)] #![warn(clippy::unnecessary_to_owned)] use std::borrow::Cow; -use std::ffi::{CStr, OsStr}; +use std::ffi::{CStr, CString, OsStr, OsString}; use std::ops::Deref; #[derive(Clone)] @@ -51,6 +50,7 @@ fn main() { 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()); @@ -66,17 +66,17 @@ fn main() { require_str(&s.to_string()); require_str(&Cow::from(s).into_owned()); require_str(&s.to_owned()); - require_str(&x.to_string()); + 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.to_owned()); + require_slice(&x_ref.to_owned()); require_x(&Cow::::Owned(x.clone()).into_owned()); - require_x(&x.to_owned()); + require_x(&x_ref.to_owned()); require_deref_c_str(c_str.to_owned()); require_deref_os_str(os_str.to_owned()); @@ -118,16 +118,23 @@ fn main() { 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.to_string()); + let _ = x.join(&x_ref.to_string()); // negative tests require_string(&s.to_string()); require_string(&Cow::from(s).into_owned()); require_string(&s.to_owned()); - require_string(&x.to_string()); + 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()); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index b15dd4c7ee7..83cc53ef3a2 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -1,3 +1,52 @@ +error: redundant clone + --> $DIR/unnecessary_to_owned.rs:134:64 + | +LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); + | ^^^^^^^^^^^ help: remove this + | + = note: `-D clippy::redundant-clone` implied by `-D warnings` +note: this value is dropped without further use + --> $DIR/unnecessary_to_owned.rs:134:20 + | +LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant clone + --> $DIR/unnecessary_to_owned.rs:135:40 + | +LL | require_os_str(&OsString::from("x").to_os_string()); + | ^^^^^^^^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/unnecessary_to_owned.rs:135:21 + | +LL | require_os_str(&OsString::from("x").to_os_string()); + | ^^^^^^^^^^^^^^^^^^^ + +error: redundant clone + --> $DIR/unnecessary_to_owned.rs:136:48 + | +LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); + | ^^^^^^^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/unnecessary_to_owned.rs:136:19 + | +LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant clone + --> $DIR/unnecessary_to_owned.rs:137:35 + | +LL | require_str(&String::from("x").to_string()); + | ^^^^^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/unnecessary_to_owned.rs:137:18 + | +LL | require_str(&String::from("x").to_string()); + | ^^^^^^^^^^^^^^^^^ + error: unnecessary use of `into_owned` --> $DIR/unnecessary_to_owned.rs:55:36 | @@ -69,8 +118,8 @@ LL | require_str(&s.to_owned()); error: unnecessary use of `to_string` --> $DIR/unnecessary_to_owned.rs:69:17 | -LL | require_str(&x.to_string()); - | ^^^^^^^^^^^^^^ help: use: `x.as_ref()` +LL | require_str(&x_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` --> $DIR/unnecessary_to_owned.rs:71:19 @@ -103,10 +152,10 @@ LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:76:21 + --> $DIR/unnecessary_to_owned.rs:76:19 | -LL | require_slice(&x.to_owned()); - | ^^^^^^^^^^^ help: remove this +LL | require_slice(&x_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `into_owned` --> $DIR/unnecessary_to_owned.rs:78:42 @@ -117,8 +166,8 @@ LL | require_x(&Cow::::Owned(x.clone()).into_owned()); error: unnecessary use of `to_owned` --> $DIR/unnecessary_to_owned.rs:79:15 | -LL | require_x(&x.to_owned()); - | ^^^^^^^^^^^^^ help: use: `&x` +LL | require_x(&x_ref.to_owned()); + | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_owned` --> $DIR/unnecessary_to_owned.rs:81:25 @@ -375,8 +424,8 @@ LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); error: unnecessary use of `to_string` --> $DIR/unnecessary_to_owned.rs:121:20 | -LL | let _ = x.join(&x.to_string()); - | ^^^^^^^^^^^^^^ help: use: `&x` +LL | let _ = x.join(&x_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` -error: aborting due to 63 previous errors +error: aborting due to 67 previous errors -- cgit 1.4.1-3-g733a5 From 3807905e08a8b5bee2160766d12b12ea4e71392f Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Mon, 13 Dec 2021 05:49:43 -0500 Subject: Handle `to_vec` on for loop expression #8069 --- clippy_lints/src/methods/mod.rs | 1 + .../src/methods/unnecessary_iter_cloned.rs | 177 ++++++++++++++++++ clippy_lints/src/methods/unnecessary_to_owned.rs | 149 ++++++++++----- clippy_utils/src/ty.rs | 22 ++- clippy_utils/src/usage.rs | 2 +- tests/ui/unnecessary_iter_cloned.fixed | 142 ++++++++++++++ tests/ui/unnecessary_iter_cloned.rs | 142 ++++++++++++++ tests/ui/unnecessary_iter_cloned.stderr | 35 ++++ tests/ui/unnecessary_to_owned.fixed | 45 ++++- tests/ui/unnecessary_to_owned.rs | 45 ++++- tests/ui/unnecessary_to_owned.stderr | 208 ++++++++++++++------- 11 files changed, 829 insertions(+), 139 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_iter_cloned.rs create mode 100644 tests/ui/unnecessary_iter_cloned.fixed create mode 100644 tests/ui/unnecessary_iter_cloned.rs create mode 100644 tests/ui/unnecessary_iter_cloned.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a0de296fd07..6a61e662698 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -56,6 +56,7 @@ mod suspicious_splitn; mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_fold; +mod unnecessary_iter_cloned; mod unnecessary_lazy_eval; mod unnecessary_to_owned; mod unwrap_or_else_default; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs new file mode 100644 index 00000000000..8300df03e99 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -0,0 +1,177 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher::ForLoop; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait}; +use clippy_utils::{fn_def_id, get_parent_expr, path_to_local_id, usage}; +use rustc_errors::Applicability; +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, HirId, LangItem, Mutability, Pat}; +use rustc_lint::LateContext; +use rustc_middle::{hir::map::Map, ty}; +use rustc_span::{sym, Symbol}; + +use super::UNNECESSARY_TO_OWNED; + +pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) -> bool { + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let Some(callee_def_id) = fn_def_id(cx, parent); + if is_into_iter(cx, callee_def_id); + then { + check_for_loop_iter(cx, parent, method_name, receiver) + } else { + false + } + } +} + +/// Checks whether `expr` is an iterator in a `for` loop and, if so, determines whether the +/// iterated-over items could be iterated over by reference. The reason why `check` above does not +/// include this code directly is so that it can be called from +/// `unnecessary_into_owned::check_into_iter_call_arg`. +pub fn check_for_loop_iter( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + method_name: Symbol, + receiver: &'tcx Expr<'tcx>, +) -> bool { + if_chain! { + if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent)); + if let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent); + let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body); + if !clone_or_copy_needed; + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); + then { + let snippet = if_chain! { + if let ExprKind::MethodCall(maybe_iter_method_name, _, [collection], _) = receiver.kind; + if maybe_iter_method_name.ident.name == sym::iter; + + if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + if implements_trait(cx, receiver_ty, iterator_trait_id, &[]); + if let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty); + + if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator); + let collection_ty = cx.typeck_results().expr_ty(collection); + if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]); + if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item"); + + if iter_item_ty == into_iter_item_ty; + if let Some(collection_snippet) = snippet_opt(cx, collection.span); + then { + collection_snippet + } else { + receiver_snippet + } + }; + span_lint_and_then( + cx, + UNNECESSARY_TO_OWNED, + expr.span, + &format!("unnecessary use of `{}`", method_name), + |diag| { + diag.span_suggestion(expr.span, "use", snippet, Applicability::MachineApplicable); + for addr_of_expr in addr_of_exprs { + match addr_of_expr.kind { + ExprKind::AddrOf(_, _, referent) => { + let span = addr_of_expr.span.with_hi(referent.span.lo()); + diag.span_suggestion(span, "remove this `&`", String::new(), Applicability::MachineApplicable); + } + _ => unreachable!(), + } + } + } + ); + return true; + } + } + false +} + +/// The core logic of `check_for_loop_iter` above, this function wraps a use of +/// `CloneOrCopyVisitor`. +fn clone_or_copy_needed( + cx: &LateContext<'tcx>, + pat: &Pat<'tcx>, + body: &'tcx Expr<'tcx>, +) -> (bool, Vec<&'tcx Expr<'tcx>>) { + let mut visitor = CloneOrCopyVisitor { + cx, + binding_hir_ids: pat_bindings(pat), + clone_or_copy_needed: false, + addr_of_exprs: Vec::new(), + }; + visitor.visit_expr(body); + (visitor.clone_or_copy_needed, visitor.addr_of_exprs) +} + +/// Returns a vector of all `HirId`s bound by the pattern. +fn pat_bindings(pat: &Pat<'_>) -> Vec { + let mut collector = usage::ParamBindingIdCollector { + binding_hir_ids: Vec::new(), + }; + collector.visit_pat(pat); + collector.binding_hir_ids +} + +/// `clone_or_copy_needed` will be false when `CloneOrCopyVisitor` is done visiting if the only +/// operations performed on `binding_hir_ids` are: +/// * to take non-mutable references to them +/// * to use them as non-mutable `&self` in method calls +/// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true +/// when `CloneOrCopyVisitor` is done visiting. +struct CloneOrCopyVisitor<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + binding_hir_ids: Vec, + clone_or_copy_needed: bool, + addr_of_exprs: Vec<&'tcx Expr<'tcx>>, +} + +impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + walk_expr(self, expr); + if self.is_binding(expr) { + if let Some(parent) = get_parent_expr(self.cx, expr) { + match parent.kind { + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => { + self.addr_of_exprs.push(parent); + return; + }, + ExprKind::MethodCall(_, _, args, _) => { + if_chain! { + if args.iter().skip(1).all(|arg| !self.is_binding(arg)); + if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); + let method_ty = self.cx.tcx.type_of(method_def_id); + let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); + if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)); + then { + return; + } + } + }, + _ => {}, + } + } + self.clone_or_copy_needed = true; + } + } +} + +impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { + fn is_binding(&self, expr: &Expr<'tcx>) -> bool { + self.binding_hir_ids + .iter() + .any(|hir_id| path_to_local_id(expr, *hir_id)) + } +} + +/// Returns true if the named method is `IntoIterator::into_iter`. +pub fn is_into_iter(cx: &LateContext<'_>, callee_def_id: DefId) -> bool { + cx.tcx.lang_items().require(LangItem::IntoIterIntoIter) == Ok(callee_def_id) +} diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index b380f734bff..c5af7483ae6 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,8 +1,9 @@ use super::implicit_clone::is_clone_like; +use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{implements_trait, is_copy, peel_mid_ty_refs}; -use clippy_utils::{get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -18,17 +19,23 @@ use super::UNNECESSARY_TO_OWNED; pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_to_owned_like(cx, method_name, method_def_id); if let [receiver] = args; then { - // At this point, we know the call is of a `to_owned`-like function. The functions - // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary - // based on its context, that is, whether it is a referent in an `AddrOf` expression or - // an argument in a function call. - if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) { - return; + if is_cloned_or_copied(cx, method_name, method_def_id) { + unnecessary_iter_cloned::check(cx, expr, method_name, receiver); + } else if is_to_owned_like(cx, method_name, method_def_id) { + // At this point, we know the call is of a `to_owned`-like function. The functions + // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary + // based on its context, that is, whether it is a referent in an `AddrOf` expression, an + // argument in a `into_iter` call, or an argument in the call of some other function. + if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) { + return; + } + if check_into_iter_call_arg(cx, expr, method_name, receiver) { + return; + } + check_other_call_arg(cx, expr, method_name, receiver); } - check_call_arg(cx, expr, method_name, receiver); } } } @@ -116,29 +123,34 @@ fn check_addr_of_expr( return true; } } - if implements_deref_trait(cx, receiver_ty, target_ty) { - if n_receiver_refs > 0 { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - parent.span, - &format!("unnecessary use of `{}`", method_name), - "use", - receiver_snippet, - Applicability::MachineApplicable, - ); - } else { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{}`", method_name), - "remove this", - String::new(), - Applicability::MachineApplicable, - ); + if_chain! { + if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); + if implements_trait(cx, receiver_ty, deref_trait_id, &[]); + if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty); + then { + if n_receiver_refs > 0 { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{}`", method_name), + "use", + receiver_snippet, + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + expr.span.with_lo(receiver.span.hi()), + &format!("unnecessary use of `{}`", method_name), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + } + return true; } - return true; } if_chain! { if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); @@ -161,9 +173,55 @@ fn check_addr_of_expr( false } +/// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its +/// call of a `to_owned`-like function is unnecessary. +fn check_into_iter_call_arg( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + method_name: Symbol, + receiver: &'tcx Expr<'tcx>, +) -> bool { + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let Some(callee_def_id) = fn_def_id(cx, parent); + if is_into_iter(cx, callee_def_id); + if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + let parent_ty = cx.typeck_results().expr_ty(parent); + if implements_trait(cx, parent_ty, iterator_trait_id, &[]); + if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty); + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); + then { + if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver) { + return true; + } + let cloned_or_copied = if is_copy(cx, item_ty) { + "copied" + } else { + "cloned" + }; + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{}`", method_name), + "use", + format!("{}.iter().{}()", receiver_snippet, cloned_or_copied), + Applicability::MachineApplicable, + ); + return true; + } + } + false +} + /// Checks whether `expr` is an argument in a function call and, if so, determines whether its call /// of a `to_owned`-like function is unnecessary. -fn check_call_arg(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) { +fn check_other_call_arg( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + method_name: Symbol, + receiver: &'tcx Expr<'tcx>, +) -> bool { if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call); @@ -186,7 +244,8 @@ fn check_call_arg(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: S if let [projection_predicate] = projection_predicates[..] { let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty); - implements_deref_trait(cx, receiver_ty, normalized_ty) + implements_trait(cx, receiver_ty, deref_trait_id, &[]) + && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty) } else { false } @@ -215,8 +274,10 @@ fn check_call_arg(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: S format!("{:&>width$}{}", "", receiver_snippet, width = n_refs), Applicability::MachineApplicable, ); + return true; } } + false } /// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such @@ -315,22 +376,10 @@ fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: Subs .collect() } -/// Helper function to check whether a type implements the `Deref` trait. -fn implements_deref_trait(cx: &LateContext<'tcx>, ty: Ty<'tcx>, deref_target_ty: Ty<'tcx>) -> bool { - if_chain! { - if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); - if implements_trait(cx, ty, deref_trait_id, &[]); - if let Some(deref_target_id) = cx.tcx.lang_items().deref_target(); - let substs = cx.tcx.mk_substs_trait(ty, &[]); - let projection_ty = cx.tcx.mk_projection(deref_target_id, substs); - let normalized_ty = cx.tcx.normalize_erasing_regions(cx.param_env, projection_ty); - if normalized_ty == deref_target_ty; - then { - true - } else { - false - } - } +/// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. +fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { + (method_name.as_str() == "cloned" || method_name.as_str() == "copied") + && is_diag_trait_item(cx, method_def_id, sym::Iterator) } /// Returns true if the named method can be used to convert the receiver to its "owned" diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 438c39bea0a..6d191d4a59b 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -58,14 +58,20 @@ pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tc pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { cx.tcx .get_diagnostic_item(sym::Iterator) - .and_then(|iter_did| { - cx.tcx.associated_items(iter_did).find_by_name_and_kind( - cx.tcx, - Ident::from_str("Item"), - ty::AssocKind::Type, - iter_did, - ) - }) + .and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item")) +} + +/// Returns the associated type `name` for `ty` as an implementation of `trait_id`. +/// Do not invoke without first verifying that the type implements the trait. +pub fn get_associated_type<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + trait_id: DefId, + name: &str, +) -> Option> { + cx.tcx + .associated_items(trait_id) + .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) .map(|assoc| { let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[])); cx.tcx.normalize_erasing_regions(cx.param_env, proj) diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index dfe8a66c2a1..2066915e1d1 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -78,7 +78,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { } pub struct ParamBindingIdCollector { - binding_hir_ids: Vec, + pub binding_hir_ids: Vec, } impl<'tcx> ParamBindingIdCollector { fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed new file mode 100644 index 00000000000..e01e9f07baf --- /dev/null +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -0,0 +1,142 @@ +// run-rustfix + +#![allow(unused_assignments)] +#![warn(clippy::unnecessary_to_owned)] + +#[allow(dead_code)] +#[derive(Clone, Copy)] +enum FileType { + Account, + PrivateKey, + Certificate, +} + +fn main() { + let path = std::path::Path::new("x"); + + let _ = check_files(&[(FileType::Account, path)]); + let _ = check_files_vec(vec![(FileType::Account, path)]); + + // negative tests + let _ = check_files_ref(&[(FileType::Account, path)]); + let _ = check_files_mut(&[(FileType::Account, path)]); + let _ = check_files_ref_mut(&[(FileType::Account, path)]); + let _ = check_files_self_and_arg(&[(FileType::Account, path)]); + let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); +} + +// `check_files` and its variants are based on: +// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 +fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { + for (t, path) in files { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool { + for (t, path) in files.iter() { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool { + for (ref t, path) in files.iter().copied() { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +#[allow(unused_assignments)] +fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool { + for (mut t, path) in files.iter().copied() { + t = FileType::PrivateKey; + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool { + for (ref mut t, path) in files.iter().copied() { + *t = FileType::PrivateKey; + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool { + for (t, path) in files.iter().copied() { + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.join(path).is_file() || !other.is_file() { + return false; + } + } + true +} + +#[allow(unused_assignments)] +fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { + for (mut t, path) in files.iter().cloned() { + t = FileType::PrivateKey; + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn get_file_path(_file_type: &FileType) -> Result { + Ok(std::path::PathBuf::new()) +} diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs new file mode 100644 index 00000000000..6ef2966c8b7 --- /dev/null +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -0,0 +1,142 @@ +// run-rustfix + +#![allow(unused_assignments)] +#![warn(clippy::unnecessary_to_owned)] + +#[allow(dead_code)] +#[derive(Clone, Copy)] +enum FileType { + Account, + PrivateKey, + Certificate, +} + +fn main() { + let path = std::path::Path::new("x"); + + let _ = check_files(&[(FileType::Account, path)]); + let _ = check_files_vec(vec![(FileType::Account, path)]); + + // negative tests + let _ = check_files_ref(&[(FileType::Account, path)]); + let _ = check_files_mut(&[(FileType::Account, path)]); + let _ = check_files_ref_mut(&[(FileType::Account, path)]); + let _ = check_files_self_and_arg(&[(FileType::Account, path)]); + let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); +} + +// `check_files` and its variants are based on: +// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 +fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { + for (t, path) in files.iter().copied() { + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool { + for (t, path) in files.iter().copied() { + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool { + for (ref t, path) in files.iter().copied() { + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +#[allow(unused_assignments)] +fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool { + for (mut t, path) in files.iter().copied() { + t = FileType::PrivateKey; + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool { + for (ref mut t, path) in files.iter().copied() { + *t = FileType::PrivateKey; + let other = match get_file_path(t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool { + for (t, path) in files.iter().copied() { + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.join(path).is_file() || !other.is_file() { + return false; + } + } + true +} + +#[allow(unused_assignments)] +fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { + for (mut t, path) in files.iter().cloned() { + t = FileType::PrivateKey; + let other = match get_file_path(&t) { + Ok(p) => p, + Err(_) => { + return false; + }, + }; + if !path.is_file() || !other.is_file() { + return false; + } + } + true +} + +fn get_file_path(_file_type: &FileType) -> Result { + Ok(std::path::PathBuf::new()) +} diff --git a/tests/ui/unnecessary_iter_cloned.stderr b/tests/ui/unnecessary_iter_cloned.stderr new file mode 100644 index 00000000000..e44379f8aa0 --- /dev/null +++ b/tests/ui/unnecessary_iter_cloned.stderr @@ -0,0 +1,35 @@ +error: unnecessary use of `copied` + --> $DIR/unnecessary_iter_cloned.rs:31:22 + | +LL | for (t, path) in files.iter().copied() { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` +help: use + | +LL | for (t, path) in files { + | ~~~~~ +help: remove this `&` + | +LL - let other = match get_file_path(&t) { +LL + let other = match get_file_path(t) { + | + +error: unnecessary use of `copied` + --> $DIR/unnecessary_iter_cloned.rs:46:22 + | +LL | for (t, path) in files.iter().copied() { + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL | for (t, path) in files.iter() { + | ~~~~~~~~~~~~ +help: remove this `&` + | +LL - let other = match get_file_path(&t) { +LL + let other = match get_file_path(t) { + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index bd9ef1fff42..720138db137 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,10 +1,6 @@ // run-rustfix #![allow(clippy::ptr_arg)] -// `needless_borrow` is to ensure there are no needles borrows in the fixed code. -#![warn(clippy::needless_borrow)] -// `redundant_clone` is to ensure there is no overlap between that lint and this one. -#![warn(clippy::redundant_clone)] #![warn(clippy::unnecessary_to_owned)] use std::borrow::Cow; @@ -41,6 +37,14 @@ impl X { } } +#[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"); @@ -120,6 +124,18 @@ fn main() { let _ = x.join(x_ref); + let _ = slice.iter().copied(); + let _ = slice.iter().copied(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + + let _ = slice.iter().copied(); + let _ = slice.iter().copied(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + let _ = [std::path::PathBuf::new()][..].iter().cloned(); + + let _ = check_files(&[FileType::Account]); + // negative tests require_string(&s.to_string()); require_string(&Cow::from(s).into_owned()); @@ -174,4 +190,25 @@ fn require_impl_as_ref_slice(_: impl AsRef<[T]>) {} fn require_as_ref_str_slice, U, V: AsRef<[U]>>(_: T, _: V) {} fn require_as_ref_slice_str, V: AsRef>(_: 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 { + 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 { + Ok(std::path::PathBuf::new()) +} + fn require_string(_: &String) {} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 1bf30e22893..60b2e718f5d 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,10 +1,6 @@ // run-rustfix #![allow(clippy::ptr_arg)] -// `needless_borrow` is to ensure there are no needles borrows in the fixed code. -#![warn(clippy::needless_borrow)] -// `redundant_clone` is to ensure there is no overlap between that lint and this one. -#![warn(clippy::redundant_clone)] #![warn(clippy::unnecessary_to_owned)] use std::borrow::Cow; @@ -41,6 +37,14 @@ impl X { } } +#[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"); @@ -120,6 +124,18 @@ fn main() { 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()); @@ -174,4 +190,25 @@ fn require_impl_as_ref_slice(_: impl AsRef<[T]>) {} fn require_as_ref_str_slice, U, V: AsRef<[U]>>(_: T, _: V) {} fn require_as_ref_slice_str, V: AsRef>(_: 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 { + Ok(std::path::PathBuf::new()) +} + fn require_string(_: &String) {} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 83cc53ef3a2..1dfc65e22e2 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -1,54 +1,54 @@ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:134:64 + --> $DIR/unnecessary_to_owned.rs:150:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:134:20 + --> $DIR/unnecessary_to_owned.rs:150:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:135:40 + --> $DIR/unnecessary_to_owned.rs:151:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:135:21 + --> $DIR/unnecessary_to_owned.rs:151:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:136:48 + --> $DIR/unnecessary_to_owned.rs:152:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:136:19 + --> $DIR/unnecessary_to_owned.rs:152:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:137:35 + --> $DIR/unnecessary_to_owned.rs:153:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:137:18 + --> $DIR/unnecessary_to_owned.rs:153:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:55:36 + --> $DIR/unnecessary_to_owned.rs:59:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -56,376 +56,440 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:56:19 + --> $DIR/unnecessary_to_owned.rs:60:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> $DIR/unnecessary_to_owned.rs:58:20 + --> $DIR/unnecessary_to_owned.rs:62:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:59:38 + --> $DIR/unnecessary_to_owned.rs:63:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:60:20 + --> $DIR/unnecessary_to_owned.rs:64:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> $DIR/unnecessary_to_owned.rs:62:18 + --> $DIR/unnecessary_to_owned.rs:66:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:63:34 + --> $DIR/unnecessary_to_owned.rs:67:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:64:18 + --> $DIR/unnecessary_to_owned.rs:68:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:66:17 + --> $DIR/unnecessary_to_owned.rs:70:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:67:30 + --> $DIR/unnecessary_to_owned.rs:71:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:68:17 + --> $DIR/unnecessary_to_owned.rs:72:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:69:17 + --> $DIR/unnecessary_to_owned.rs:73:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:71:19 + --> $DIR/unnecessary_to_owned.rs:75:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:72:36 + --> $DIR/unnecessary_to_owned.rs:76:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:73:19 + --> $DIR/unnecessary_to_owned.rs:77:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:74:19 + --> $DIR/unnecessary_to_owned.rs:78:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:75:19 + --> $DIR/unnecessary_to_owned.rs:79:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:76:19 + --> $DIR/unnecessary_to_owned.rs:80:19 | LL | require_slice(&x_ref.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:78:42 + --> $DIR/unnecessary_to_owned.rs:82:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:79:15 + --> $DIR/unnecessary_to_owned.rs:83:15 | LL | require_x(&x_ref.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:81:25 + --> $DIR/unnecessary_to_owned.rs:85:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:82:26 + --> $DIR/unnecessary_to_owned.rs:86:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:83:24 + --> $DIR/unnecessary_to_owned.rs:87:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:84:23 + --> $DIR/unnecessary_to_owned.rs:88:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:85:25 + --> $DIR/unnecessary_to_owned.rs:89:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:87:30 + --> $DIR/unnecessary_to_owned.rs:91:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:88:31 + --> $DIR/unnecessary_to_owned.rs:92:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:89:29 + --> $DIR/unnecessary_to_owned.rs:93:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:90:28 + --> $DIR/unnecessary_to_owned.rs:94:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:91:30 + --> $DIR/unnecessary_to_owned.rs:95:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:93:29 + --> $DIR/unnecessary_to_owned.rs:97:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:93:43 + --> $DIR/unnecessary_to_owned.rs:97:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:94:29 + --> $DIR/unnecessary_to_owned.rs:98:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:94:47 + --> $DIR/unnecessary_to_owned.rs:98:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:96:26 + --> $DIR/unnecessary_to_owned.rs:100:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:97:27 + --> $DIR/unnecessary_to_owned.rs:101:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:98:25 + --> $DIR/unnecessary_to_owned.rs:102:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:99:24 + --> $DIR/unnecessary_to_owned.rs:103:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:100:24 + --> $DIR/unnecessary_to_owned.rs:104:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:101:26 + --> $DIR/unnecessary_to_owned.rs:105:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:102:26 + --> $DIR/unnecessary_to_owned.rs:106:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:103:26 + --> $DIR/unnecessary_to_owned.rs:107:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:105:31 + --> $DIR/unnecessary_to_owned.rs:109:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:106:32 + --> $DIR/unnecessary_to_owned.rs:110:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:107:30 + --> $DIR/unnecessary_to_owned.rs:111:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:108:29 + --> $DIR/unnecessary_to_owned.rs:112:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:109:29 + --> $DIR/unnecessary_to_owned.rs:113:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:110:31 + --> $DIR/unnecessary_to_owned.rs:114:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:111:31 + --> $DIR/unnecessary_to_owned.rs:115:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:112:31 + --> $DIR/unnecessary_to_owned.rs:116:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:114:30 + --> $DIR/unnecessary_to_owned.rs:118:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:114:44 + --> $DIR/unnecessary_to_owned.rs:118:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:115:30 + --> $DIR/unnecessary_to_owned.rs:119:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:115:44 + --> $DIR/unnecessary_to_owned.rs:119:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:30 + --> $DIR/unnecessary_to_owned.rs:120:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:44 + --> $DIR/unnecessary_to_owned.rs:120:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:117:30 + --> $DIR/unnecessary_to_owned.rs:121:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:117:48 + --> $DIR/unnecessary_to_owned.rs:121:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:30 + --> $DIR/unnecessary_to_owned.rs:122:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:52 + --> $DIR/unnecessary_to_owned.rs:122:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:30 + --> $DIR/unnecessary_to_owned.rs:123:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:48 + --> $DIR/unnecessary_to_owned.rs:123:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:121:20 + --> $DIR/unnecessary_to_owned.rs:125:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` -error: aborting due to 67 previous errors +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:127:13 + | +LL | let _ = slice.to_vec().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:128:13 + | +LL | let _ = slice.to_owned().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` + +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:129:13 + | +LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:130:13 + | +LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` + +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:132:13 + | +LL | let _ = IntoIterator::into_iter(slice.to_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:133:13 + | +LL | let _ = IntoIterator::into_iter(slice.to_owned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` + +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:134:13 + | +LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` + +error: unnecessary use of `to_owned` + --> $DIR/unnecessary_to_owned.rs:135:13 + | +LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` + +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:196:14 + | +LL | for t in file_types.to_vec() { + | ^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL | for t in file_types { + | ~~~~~~~~~~ +help: remove this `&` + | +LL - let path = match get_file_path(&t) { +LL + let path = match get_file_path(t) { + | + +error: aborting due to 76 previous errors -- cgit 1.4.1-3-g733a5 From cb609a99044adc07ea4cdb0b4927f4ad461bb4b5 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Mon, 13 Dec 2021 12:27:47 -0500 Subject: Add comma --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6a61e662698..27189180248 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1993,7 +1993,7 @@ impl_lint_pass!(Methods => [ EXTEND_WITH_DRAIN, MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN, - UNNECESSARY_TO_OWNED + UNNECESSARY_TO_OWNED, ]); /// Extracts a method call name, args, and `Span` of the method name. -- cgit 1.4.1-3-g733a5 From 3beb6b1908e03bbf645ecdac7d56a772b5d8a8ef Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Tue, 14 Dec 2021 18:36:19 -0500 Subject: Address review comments --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 26 ++++++++++-------------- 2 files changed, 12 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 27189180248..3c43671dd34 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1893,7 +1893,7 @@ declare_clippy_lint! { /// and other `to_owned`-like functions. /// /// ### Why is this bad? - /// The unnecessary calls result in unnecessary allocations. + /// The unnecessary calls result in useless allocations. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index c5af7483ae6..c48bacfce0d 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -107,21 +107,17 @@ fn check_addr_of_expr( then { let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty); let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); - if_chain! { - if receiver_ty == target_ty; - if n_target_refs >= n_receiver_refs; - then { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - parent.span, - &format!("unnecessary use of `{}`", method_name), - "use", - format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs), - Applicability::MachineApplicable, - ); - return true; - } + if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{}`", method_name), + "use", + format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs), + Applicability::MachineApplicable, + ); + return true; } if_chain! { if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); -- cgit 1.4.1-3-g733a5 From b8913894a13431bea99400dc9f53a1fd9f41a6c6 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Wed, 15 Dec 2021 05:25:47 -0500 Subject: Expand `is_clone_like` comment --- clippy_lints/src/methods/implicit_clone.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index ff7904ce582..90492ffda3c 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -32,6 +32,9 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv } /// Returns true if the named method can be used to clone the receiver. +/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call +/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g., +/// `is_to_owned_like` in `unnecessary_to_owned.rs`. pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool { match method_name { "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), -- cgit 1.4.1-3-g733a5 From 79cf41297af69b2e46be6ad77986ebe2a41a4667 Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 19:13:57 -0800 Subject: Imrpove `unwrap_or_else_default` --- clippy_lints/src/methods/unwrap_or_else_default.rs | 5 +++-- tests/ui/unwrap_or_else_default.fixed | 3 +++ tests/ui/unwrap_or_else_default.rs | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index 276467b1dfd..4811048439c 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -2,7 +2,8 @@ use super::UNWRAP_OR_ELSE_DEFAULT; use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item, + diagnostics::span_lint_and_sugg, is_default_equivalent, is_trait_item, source::snippet_with_applicability, + ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; use rustc_hir as hir; @@ -24,7 +25,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if is_trait_item(cx, u_arg, sym::Default); + if is_trait_item(cx, u_arg, sym::Default) || is_default_equivalent(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 7ac3f426c97..5849dc4cebb 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -66,6 +66,9 @@ fn unwrap_or_else_default() { let with_default_type = Some(1); with_default_type.unwrap_or_default(); + + let with_default_type: Option> = None; + with_default_type.unwrap_or_default(); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index 82b727a039e..d55664990ae 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -66,6 +66,9 @@ fn unwrap_or_else_default() { let with_default_type = Some(1); with_default_type.unwrap_or_else(u64::default); + + let with_default_type: Option> = None; + with_default_type.unwrap_or_else(Vec::new); } fn main() {} -- cgit 1.4.1-3-g733a5 From 26cc55133ea52a7909b37183d3dea724bdf1c87b Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 21:41:00 -0800 Subject: rewrite the PR --- clippy_lints/src/methods/unwrap_or_else_default.rs | 25 ++++++++++++++++++---- clippy_utils/src/lib.rs | 2 +- tests/ui/unwrap_or_else_default.fixed | 2 +- tests/ui/unwrap_or_else_default.stderr | 10 +++++++-- 4 files changed, 31 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index 4811048439c..5f04d8e1828 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -1,10 +1,11 @@ //! Lint for `some_result_or_option.unwrap_or_else(Default::default)` use super::UNWRAP_OR_ELSE_DEFAULT; -use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_default_equivalent, is_trait_item, source::snippet_with_applicability, - ty::is_type_diagnostic_item, +use clippy_utils::{diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item, + is_default_equivalent_ctor, is_diag_trait_item }; +use rustc_hir::ExprKind; + use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -23,9 +24,25 @@ pub(super) fn check<'tcx>( let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option); let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result); + let is_default_eq = match &u_arg.kind { + ExprKind::Path(qpath) => { + if let Some(repl_def_id) = cx.qpath_res(qpath, u_arg.hir_id).opt_def_id() { + if is_diag_trait_item(cx, repl_def_id, sym::Default) + || is_default_equivalent_ctor(cx, repl_def_id, qpath) { + true + } else { + false + } + } else { + false + } + }, + _ => {false} + }; + if_chain! { if is_option || is_result; - if is_trait_item(cx, u_arg, sym::Default) || is_default_equivalent(cx, u_arg); + if is_trait_item(cx, u_arg, sym::Default) || is_default_eq; then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 76f4408573b..1b56bfbe1d6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -637,7 +637,7 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) - /// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent" /// constructor from the std library -fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { +pub fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { let std_types_symbols = &[ sym::String, sym::Vec, diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 5849dc4cebb..c2b9bd2c881 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -45,7 +45,7 @@ fn unwrap_or_else_default() { with_enum.unwrap_or_else(Enum::A); let with_new = Some(vec![1]); - with_new.unwrap_or_else(Vec::new); + with_new.unwrap_or_default(); let with_err: Result<_, ()> = Ok(vec![1]); with_err.unwrap_or_else(make); diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index feb215b09f6..b49b7fb77c2 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -1,10 +1,16 @@ +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:48:5 + | +LL | with_new.unwrap_or_else(Vec::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()` + | + = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` + error: use of `.unwrap_or_else(..)` to construct default value --> $DIR/unwrap_or_else_default.rs:62:5 | LL | with_real_default.unwrap_or_else(::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()` - | - = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` error: use of `.unwrap_or_else(..)` to construct default value --> $DIR/unwrap_or_else_default.rs:65:5 -- cgit 1.4.1-3-g733a5 From ab77c924e9e26dcaa28c0eb861d08eb3ee998b6c Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 21:44:13 -0800 Subject: cargo dev fmt --- clippy_lints/src/methods/unwrap_or_else_default.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index 5f04d8e1828..e8827b1e5af 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -1,8 +1,9 @@ //! Lint for `some_result_or_option.unwrap_or_else(Default::default)` use super::UNWRAP_OR_ELSE_DEFAULT; -use clippy_utils::{diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item, - is_default_equivalent_ctor, is_diag_trait_item +use clippy_utils::{ + diagnostics::span_lint_and_sugg, is_default_equivalent_ctor, is_diag_trait_item, is_trait_item, + source::snippet_with_applicability, ty::is_type_diagnostic_item, }; use rustc_hir::ExprKind; @@ -28,7 +29,8 @@ pub(super) fn check<'tcx>( ExprKind::Path(qpath) => { if let Some(repl_def_id) = cx.qpath_res(qpath, u_arg.hir_id).opt_def_id() { if is_diag_trait_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, qpath) { + || is_default_equivalent_ctor(cx, repl_def_id, qpath) + { true } else { false @@ -37,7 +39,7 @@ pub(super) fn check<'tcx>( false } }, - _ => {false} + _ => false, }; if_chain! { -- cgit 1.4.1-3-g733a5 From 8b19845ffb7b9b6fd760f0bf8066731028377237 Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 21:46:21 -0800 Subject: refactor --- clippy_lints/src/methods/unwrap_or_else_default.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index e8827b1e5af..cde707790ef 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -5,8 +5,6 @@ use clippy_utils::{ diagnostics::span_lint_and_sugg, is_default_equivalent_ctor, is_diag_trait_item, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item, }; -use rustc_hir::ExprKind; - use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -26,7 +24,7 @@ pub(super) fn check<'tcx>( let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result); let is_default_eq = match &u_arg.kind { - ExprKind::Path(qpath) => { + hir::ExprKind::Path(qpath) => { if let Some(repl_def_id) = cx.qpath_res(qpath, u_arg.hir_id).opt_def_id() { if is_diag_trait_item(cx, repl_def_id, sym::Default) || is_default_equivalent_ctor(cx, repl_def_id, qpath) -- cgit 1.4.1-3-g733a5 From 4b3a87f8866bf0a76a7fd63d35331be5566db791 Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 21:47:31 -0800 Subject: clippy --- clippy_lints/src/methods/unwrap_or_else_default.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index cde707790ef..14185503092 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -26,13 +26,8 @@ pub(super) fn check<'tcx>( let is_default_eq = match &u_arg.kind { hir::ExprKind::Path(qpath) => { if let Some(repl_def_id) = cx.qpath_res(qpath, u_arg.hir_id).opt_def_id() { - if is_diag_trait_item(cx, repl_def_id, sym::Default) + is_diag_trait_item(cx, repl_def_id, sym::Default) || is_default_equivalent_ctor(cx, repl_def_id, qpath) - { - true - } else { - false - } } else { false } -- cgit 1.4.1-3-g733a5 From 01b74114824b4e0f6b94986dd93a6f481e29936c Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 22:00:14 -0800 Subject: Refactor --- clippy_lints/src/methods/unwrap_or_else_default.rs | 18 +++---------- clippy_utils/src/lib.rs | 31 +++++++++++++--------- 2 files changed, 21 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index 14185503092..e641b5c4599 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -2,8 +2,8 @@ use super::UNWRAP_OR_ELSE_DEFAULT; use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_default_equivalent_ctor, is_diag_trait_item, is_trait_item, - source::snippet_with_applicability, ty::is_type_diagnostic_item, + diagnostics::span_lint_and_sugg, is_default_equivalent_call, is_trait_item, source::snippet_with_applicability, + ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; use rustc_hir as hir; @@ -23,21 +23,9 @@ pub(super) fn check<'tcx>( let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option); let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result); - let is_default_eq = match &u_arg.kind { - hir::ExprKind::Path(qpath) => { - if let Some(repl_def_id) = cx.qpath_res(qpath, u_arg.hir_id).opt_def_id() { - is_diag_trait_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, qpath) - } else { - false - } - }, - _ => false, - }; - if_chain! { if is_option || is_result; - if is_trait_item(cx, u_arg, sym::Default) || is_default_eq; + if is_trait_item(cx, u_arg, sym::Default) || is_default_equivalent_call(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 1b56bfbe1d6..4af870d3155 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -637,7 +637,7 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) - /// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent" /// constructor from the std library -pub fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { +fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool { let std_types_symbols = &[ sym::String, sym::Vec, @@ -664,6 +664,22 @@ pub fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QP false } +/// Return true if the expr is equal to `Default::default` when evaluated. +pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool { + if_chain! { + if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind; + if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); + if is_diag_trait_item(cx, repl_def_id, sym::Default) + || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); + then { + true + } + else { + false + } + } +} + /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. /// It doesn't cover all cases, for example indirect function calls (some of std /// functions are supported) but it is the best we have. @@ -686,18 +702,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { false } }, - ExprKind::Call(repl_func, _) => if_chain! { - if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diag_trait_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); - then { - true - } - else { - false - } - }, + ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func), ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone), ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])), _ => false, -- cgit 1.4.1-3-g733a5 From 2a47dbc7a67ff691ccfddc7b01d07639215c900b Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 23 Dec 2021 22:12:08 -0800 Subject: Simplify code --- clippy_lints/src/methods/unwrap_or_else_default.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index e641b5c4599..f3af281d6ca 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -2,7 +2,7 @@ use super::UNWRAP_OR_ELSE_DEFAULT; use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_default_equivalent_call, is_trait_item, source::snippet_with_applicability, + diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability, ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if is_trait_item(cx, u_arg, sym::Default) || is_default_equivalent_call(cx, u_arg); + if is_default_equivalent_call(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; -- cgit 1.4.1-3-g733a5 From 4ffd66074a462b30d15da8d40cc0f356dd43bb1c Mon Sep 17 00:00:00 2001 From: surechen Date: Fri, 17 Dec 2021 10:03:59 +0800 Subject: Fixes #8128 changelog: Fix error suggestion of skip(..).next() for immutable variable. --- clippy_lints/src/methods/iter_skip_next.rs | 32 ++++++++++++++++++++---- tests/ui/iter_skip_next.fixed | 15 ++++++++++++ tests/ui/iter_skip_next.rs | 15 ++++++++++++ tests/ui/iter_skip_next.stderr | 28 +++++++++++++++++---- tests/ui/iter_skip_next_unfixable.rs | 19 +++++++++++++++ tests/ui/iter_skip_next_unfixable.stderr | 39 ++++++++++++++++++++++++++++++ 6 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 tests/ui/iter_skip_next_unfixable.rs create mode 100644 tests/ui/iter_skip_next_unfixable.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index e32594757d0..f5410c7fd7f 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -1,8 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; +use clippy_utils::path_to_local; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::{BindingAnnotation, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::sym; @@ -11,14 +13,34 @@ use super::ITER_SKIP_NEXT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { // lint if caller of skip is an Iterator if is_trait_method(cx, expr, sym::Iterator) { - span_lint_and_sugg( + let mut application = Applicability::MachineApplicable; + span_lint_and_then( cx, ITER_SKIP_NEXT, expr.span.trim_start(recv.span).unwrap(), "called `skip(..).next()` on an iterator", - "use `nth` instead", - format!(".nth({})", snippet(cx, arg.span, "..")), - Applicability::MachineApplicable, + |diag| { + if_chain! { + if let Some(id) = path_to_local(recv); + if let Node::Binding(pat) = cx.tcx.hir().get(id); + if let PatKind::Binding(ann, _, _, _) = pat.kind; + if ann != BindingAnnotation::Mutable; + then { + application = Applicability::Unspecified; + diag.span_help( + pat.span, + &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), + ); + } + } + + diag.span_suggestion( + expr.span.trim_start(recv.span).unwrap(), + "use `nth` instead", + format!(".nth({})", snippet(cx, arg.span, "..")), + application, + ); + }, ); } } diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index 928b6acb951..2db4c2bee7f 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -4,6 +4,7 @@ #![warn(clippy::iter_skip_next)] #![allow(clippy::blacklisted_name)] #![allow(clippy::iter_nth)] +#![allow(unused_mut, dead_code)] extern crate option_helpers; @@ -19,4 +20,18 @@ fn main() { let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); + + // fix #8128 + let test_string = "1|1 2"; + let mut sp = test_string.split('|').map(|s| s.trim()); + let _: Vec<&str> = sp.nth(1).unwrap().split(' ').collect(); + if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) { + let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect(); + }; + fn check(mut s: T) + where + T: Iterator, + { + let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect(); + } } diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 7075e2598eb..692edb9aed9 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -4,6 +4,7 @@ #![warn(clippy::iter_skip_next)] #![allow(clippy::blacklisted_name)] #![allow(clippy::iter_nth)] +#![allow(unused_mut, dead_code)] extern crate option_helpers; @@ -19,4 +20,18 @@ fn main() { let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); + + // fix #8128 + let test_string = "1|1 2"; + let mut sp = test_string.split('|').map(|s| s.trim()); + let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + }; + fn check(mut s: T) + where + T: Iterator, + { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + } } diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index 486de718bb5..ca6970b27f1 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,5 +1,5 @@ error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:15:28 + --> $DIR/iter_skip_next.rs:16:28 | LL | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` @@ -7,22 +7,40 @@ LL | let _ = some_vec.iter().skip(42).next(); = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:16:36 + --> $DIR/iter_skip_next.rs:17:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:17:20 + --> $DIR/iter_skip_next.rs:18:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:18:33 + --> $DIR/iter_skip_next.rs:19:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)` -error: aborting due to 4 previous errors +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next.rs:27:26 + | +LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next.rs:29:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next.rs:35:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + +error: aborting due to 7 previous errors diff --git a/tests/ui/iter_skip_next_unfixable.rs b/tests/ui/iter_skip_next_unfixable.rs new file mode 100644 index 00000000000..3607330cfa0 --- /dev/null +++ b/tests/ui/iter_skip_next_unfixable.rs @@ -0,0 +1,19 @@ +#![warn(clippy::iter_skip_next)] +#![allow(dead_code)] + +/// Checks implementation of `ITER_SKIP_NEXT` lint +fn main() { + // fix #8128 + let test_string = "1|1 2"; + let sp = test_string.split('|').map(|s| s.trim()); + let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + }; + fn check(s: T) + where + T: Iterator, + { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + } +} diff --git a/tests/ui/iter_skip_next_unfixable.stderr b/tests/ui/iter_skip_next_unfixable.stderr new file mode 100644 index 00000000000..74c327c7483 --- /dev/null +++ b/tests/ui/iter_skip_next_unfixable.stderr @@ -0,0 +1,39 @@ +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next_unfixable.rs:9:26 + | +LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + | + = note: `-D clippy::iter-skip-next` implied by `-D warnings` +help: for this change `sp` has to be mutable + --> $DIR/iter_skip_next_unfixable.rs:8:9 + | +LL | let sp = test_string.split('|').map(|s| s.trim()); + | ^^ + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next_unfixable.rs:11:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + | +help: for this change `s` has to be mutable + --> $DIR/iter_skip_next_unfixable.rs:10:17 + | +LL | if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) { + | ^ + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next_unfixable.rs:17:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + | +help: for this change `s` has to be mutable + --> $DIR/iter_skip_next_unfixable.rs:13:17 + | +LL | fn check(s: T) + | ^ + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 2b5257e4c770c6a4964a7897fa1348be5050797f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 30 Dec 2021 13:37:14 -0600 Subject: Remove method_call! macro --- clippy_lints/src/methods/mod.rs | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4e33b2ff14c..ad07370f26d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -80,7 +80,6 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; use rustc_typeck::hir_ty_to_ty; @@ -1997,24 +1996,16 @@ impl_lint_pass!(Methods => [ ]); /// Extracts a method call name, args, and `Span` of the method name. -fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(Symbol, &'tcx [hir::Expr<'tcx>], Span)> { +fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> { if let ExprKind::MethodCall(path, span, args, _) = recv.kind { if !args.iter().any(|e| e.span.from_expansion()) { - return Some((path.ident.name, args, span)); + let name = path.ident.name.as_str(); + return Some((name, args, span)); } } None } -/// Same as `method_call` but the `Symbol` is dereferenced into a temporary `&str` -macro_rules! method_call { - ($expr:expr) => { - method_call($expr) - .as_ref() - .map(|&(ref name, args, span)| (name.as_str(), args, span)) - }; -} - impl<'tcx> LateLintPass<'tcx> for Methods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if expr.span.from_expansion() { @@ -2217,7 +2208,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) { - if let Some((name, [recv, args @ ..], span)) = method_call!(expr) { + if let Some((name, [recv, args @ ..], span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); @@ -2233,7 +2224,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("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, msrv), - ("collect", []) => match method_call!(recv) { + ("collect", []) => match method_call(recv) { Some((name @ ("cloned" | "copied"), [recv2], _)) => { iter_cloned_collect::check(cx, name, expr, recv2); }, @@ -2247,14 +2238,14 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, _ => {}, }, - ("count", []) => match method_call!(recv) { + ("count", []) => match method_call(recv) { Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { iter_count::check(cx, expr, recv2, name); }, Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), _ => {}, }, - ("expect", [_]) => match method_call!(recv) { + ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), _ => expect_used::check(cx, expr, recv), }, @@ -2271,13 +2262,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio flat_map_option::check(cx, expr, arg, span); }, ("flatten", []) => { - if let Some(("map", [recv, map_arg], _)) = method_call!(recv) { + if let Some(("map", [recv, map_arg], _)) = method_call(recv) { map_flatten::check(cx, expr, recv, map_arg); } }, ("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); } }, @@ -2286,7 +2277,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), ("map", [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, msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv), @@ -2301,7 +2292,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), ("next", []) => { - if let Some((name, [recv, args @ ..], _)) = method_call!(recv) { + if let Some((name, [recv, args @ ..], _)) = method_call(recv) { match (name, args) { ("filter", [arg]) => filter_next::check(cx, expr, recv, arg), ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv), @@ -2312,7 +2303,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio } } }, - ("nth", [n_arg]) => match method_call!(recv) { + ("nth", [n_arg]) => match method_call(recv) { Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg), 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), @@ -2344,12 +2335,12 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv, span); }, - ("unwrap", []) => match method_call!(recv) { + ("unwrap", []) => match method_call(recv) { Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), _ => unwrap_used::check(cx, expr, recv), }, - ("unwrap_or", [u_arg]) => match method_call!(recv) { + ("unwrap_or", [u_arg]) => match method_call(recv) { Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, @@ -2358,7 +2349,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, _ => {}, }, - ("unwrap_or_else", [u_arg]) => match method_call!(recv) { + ("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, msrv) => {}, _ => { unwrap_or_else_default::check(cx, expr, recv, u_arg); @@ -2371,7 +2362,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio } 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); } } -- cgit 1.4.1-3-g733a5 From 3d41358a554cb70e23e001f6ac92cf79d805b671 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 31 Dec 2021 23:39:40 -0500 Subject: wrong_self_convention: Match `SelfKind::No` more restrictively The `wrong_self_convention` lint uses a `SelfKind` type to decide whether a method has the right kind of "self" for its name, or whether the kind of "self" it has makes its name confusable for a method in a common trait. One possibility is `SelfKind::No`, which is supposed to mean "No `self`". Previously, SelfKind::No matched everything _except_ Self, including references to Self. This patch changes it to match Self, &Self, &mut Self, Box, and so on. For example, this kind of method was allowed before: ``` impl S { // Should trigger the lint, because // "methods called `is_*` usually take `self` by reference or no `self`" fn is_foo(&mut self) -> bool { todo!() } } ``` But since SelfKind::No matched "&mut self", no lint was triggered (see #8142). With this patch, the code above now gives a lint as expected. Fixes #8142 changelog: [`wrong_self_convention`] rejects `self` references in more cases --- clippy_lints/src/methods/mod.rs | 8 +++++++- clippy_lints/src/redundant_clone.rs | 4 ++-- tests/ui/issue_4266.stderr | 11 ++++++++++- tests/ui/wrong_self_convention.rs | 21 +++++++++++++++++++++ tests/ui/wrong_self_convention.stderr | 10 +++++++++- 5 files changed, 49 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4e33b2ff14c..8a2a468c852 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2535,11 +2535,17 @@ impl SelfKind { implements_trait(cx, ty, trait_def_id, &[parent_ty.into()]) } + fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { + !matches_value(cx, parent_ty, ty) + && !matches_ref(cx, hir::Mutability::Not, parent_ty, ty) + && !matches_ref(cx, hir::Mutability::Mut, parent_ty, ty) + } + match self { Self::Value => matches_value(cx, parent_ty, ty), Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty), Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty), - Self::No => ty != parent_ty, + Self::No => matches_none(cx, parent_ty, ty), } } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 1cf349f8aa7..1991a01fb60 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -220,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { continue; } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc { // cloned value is mutated, and the clone is alive. - if possible_borrower.is_alive_at(ret_local, loc) { + if possible_borrower.local_is_alive_at(ret_local, loc) { continue; } } @@ -767,7 +767,7 @@ impl PossibleBorrowerMap<'_, '_> { self.bitset.0 == self.bitset.1 } - fn is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool { + fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool { self.maybe_live.seek_after_primary_effect(at); self.maybe_live.contains(local) } diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index 20419457b47..e5042aaa776 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.stderr @@ -12,5 +12,14 @@ error: explicit lifetimes given in parameter types where they could be elided (o LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: methods called `new` usually take no `self` + --> $DIR/issue_4266.rs:27:22 + | +LL | pub async fn new(&mut self) -> Self { + | ^^^^^^^^^ + | + = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: consider choosing a less ambiguous name + +error: aborting due to 3 previous errors diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 1b9da8a55e5..f8fee4b3ab2 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -188,3 +188,24 @@ mod issue6727 { } } } + +pub mod issue8142 { + struct S; + + impl S { + // Should lint: is_ methods should only take &self, or no self at all. + fn is_still_buggy(&mut self) -> bool { + false + } + + // Should not lint: "no self at all" is allowed. + fn is_forty_two(x: u32) -> bool { + x == 42 + } + + // Should not lint: &self is allowed. + fn is_test_code(&self) -> bool { + true + } + } +} diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 590ee6d9c52..5493a99572e 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -191,5 +191,13 @@ LL | fn to_u64(self) -> u64 { | = help: consider choosing a less ambiguous name -error: aborting due to 24 previous errors +error: methods called `is_*` usually take `self` by reference or no `self` + --> $DIR/wrong_self_convention.rs:197:27 + | +LL | fn is_still_buggy(&mut self) -> bool { + | ^^^^^^^^^ + | + = help: consider choosing a less ambiguous name + +error: aborting due to 25 previous errors -- cgit 1.4.1-3-g733a5 From 786f874c349b995ebed5e3d8f20db1cf65f20782 Mon Sep 17 00:00:00 2001 From: bors Date: Tue, 4 Jan 2022 22:32:02 +0000 Subject: New macro utils changelog: none Sorry, this is a big one. A lot of interrelated changes and I wanted to put the new utils to use to make sure they are somewhat battle-tested. We may want to divide some of the lint-specific refactoring commits into batches for smaller reviewing tasks. I could also split into more PRs. Introduces a bunch of new utils at `clippy_utils::macros::...`. Please read through the docs and give any feedback! I'm happy to introduce `MacroCall` and various functions to retrieve an instance. It feels like the missing puzzle piece. I'm also introducing `ExpnId` from rustc as "useful for Clippy too". `@rust-lang/clippy` Fixes #7843 by not parsing every node of macro implementations, at least the major offenders. I probably want to get rid of `is_expn_of` at some point. --- clippy_lints/src/assertions_on_constants.rs | 120 ++---- clippy_lints/src/attrs.rs | 18 +- clippy_lints/src/bool_assert_comparison.rs | 73 ++-- clippy_lints/src/doc.rs | 33 +- clippy_lints/src/eq_op.rs | 45 +-- clippy_lints/src/explicit_write.rs | 6 +- clippy_lints/src/fallible_impl_from.rs | 15 +- clippy_lints/src/format.rs | 33 +- clippy_lints/src/format_args.rs | 53 +-- clippy_lints/src/manual_assert.rs | 68 +--- clippy_lints/src/matches.rs | 24 +- clippy_lints/src/methods/expect_fun_call.rs | 21 +- clippy_lints/src/mutable_debug_assertion.rs | 42 +- clippy_lints/src/panic_in_result_fn.rs | 32 +- clippy_lints/src/panic_unimplemented.rs | 56 ++- clippy_lints/src/unit_types/unit_cmp.rs | 40 +- clippy_lints/src/utils/internal_lints.rs | 11 +- clippy_utils/Cargo.toml | 1 + clippy_utils/src/ast_utils.rs | 32 -- clippy_utils/src/higher.rs | 295 +------------- clippy_utils/src/lib.rs | 40 +- clippy_utils/src/macros.rs | 539 ++++++++++++++++++++++++++ clippy_utils/src/paths.rs | 5 - tests/ui/assertions_on_constants.rs | 1 - tests/ui/assertions_on_constants.stderr | 42 +- tests/ui/eq_op_macros.stderr | 44 +-- tests/ui/missing_panics_doc.stderr | 6 - tests/ui/panic_in_result_fn.stderr | 6 - tests/ui/panic_in_result_fn_assertions.stderr | 3 - tests/ui/panicking_macros.stderr | 21 - tests/ui/unit_cmp.stderr | 8 - 31 files changed, 868 insertions(+), 865 deletions(-) create mode 100644 clippy_utils/src/macros.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index b7f414742f1..c82837746bd 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,12 +1,10 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::higher; -use clippy_utils::source::snippet_opt; -use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks}; -use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind, UnOp}; +use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -36,107 +34,39 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]); impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - let lint_true = |is_debug: bool| { - span_lint_and_help( - cx, - ASSERTIONS_ON_CONSTANTS, - e.span, - if is_debug { - "`debug_assert!(true)` will be optimized out by the compiler" - } else { - "`assert!(true)` will be optimized out by the compiler" - }, - None, - "remove it", - ); + let Some(macro_call) = root_macro_call_first_node(cx, e) else { return }; + let is_debug = match cx.tcx.get_diagnostic_name(macro_call.def_id) { + Some(sym::debug_assert_macro) => true, + Some(sym::assert_macro) => false, + _ => return, }; - let lint_false_without_message = || { + let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return }; + let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return }; + if val { span_lint_and_help( cx, ASSERTIONS_ON_CONSTANTS, - e.span, - "`assert!(false)` should probably be replaced", + macro_call.span, + &format!( + "`{}!(true)` will be optimized out by the compiler", + cx.tcx.item_name(macro_call.def_id) + ), None, - "use `panic!()` or `unreachable!()`", + "remove it", ); - }; - let lint_false_with_message = |panic_message: String| { + } else if !is_debug { + let (assert_arg, panic_arg) = match panic_expn { + PanicExpn::Empty => ("", ""), + _ => (", ..", ".."), + }; span_lint_and_help( cx, ASSERTIONS_ON_CONSTANTS, - e.span, - &format!("`assert!(false, {})` should probably be replaced", panic_message), + macro_call.span, + &format!("`assert!(false{})` should probably be replaced", assert_arg), None, - &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message), + &format!("use `panic!({})` or `unreachable!({0})`", panic_arg), ); - }; - - if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") { - if debug_assert_span.from_expansion() { - return; - } - if_chain! { - if let ExprKind::Unary(_, lit) = e.kind; - if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit); - if is_true; - then { - lint_true(true); - } - }; - } else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") { - if assert_span.from_expansion() { - return; - } - if let Some(assert_match) = match_assert_with_message(cx, e) { - match assert_match { - // matched assert but not message - AssertKind::WithoutMessage(false) => lint_false_without_message(), - AssertKind::WithoutMessage(true) | AssertKind::WithMessage(_, true) => lint_true(false), - AssertKind::WithMessage(panic_message, false) => lint_false_with_message(panic_message), - }; - } - } - } -} - -/// Result of calling `match_assert_with_message`. -enum AssertKind { - WithMessage(String, bool), - WithoutMessage(bool), -} - -/// Check if the expression matches -/// -/// ```rust,ignore -/// if !c { -/// { -/// ::std::rt::begin_panic(message, _) -/// } -/// } -/// ``` -/// -/// where `message` is any expression and `c` is a constant bool. -fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - if_chain! { - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr); - if let ExprKind::Unary(UnOp::Not, expr) = cond.kind; - // bind the first argument of the `assert!` macro - if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr); - let begin_panic_call = peel_blocks(then); - // function call - if let Some(arg) = match_panic_call(cx, begin_panic_call); - // bind the second argument of the `assert!` macro if it exists - if let panic_message = snippet_opt(cx, arg.span); - // second argument of begin_panic is irrelevant - // as is the second match arm - then { - // an empty message occurs when it was generated by the macro - // (and not passed by the user) - return panic_message - .filter(|msg| !msg.is_empty()) - .map(|msg| AssertKind::WithMessage(msg, is_true)) - .or(Some(AssertKind::WithoutMessage(is_true))); } } - None } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 0629674307b..a58d12ddd6b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,9 +1,10 @@ //! checks for attributes use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::macros::{is_panic, macro_backtrace}; use clippy_utils::msrvs; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; -use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv}; +use clippy_utils::{extract_msrv_attr, meets_msrv}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; @@ -443,20 +444,15 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ } fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { + if macro_backtrace(expr.span).last().map_or(false, |macro_call| { + is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable + }) { + return false; + } match &expr.kind { ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block), ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e), ExprKind::Ret(None) | ExprKind::Break(_, None) => false, - ExprKind::Call(path_expr, _) => { - if let ExprKind::Path(qpath) = &path_expr.kind { - typeck_results - .qpath_res(qpath, path_expr.hir_id) - .opt_def_id() - .map_or(true, |fun_id| !match_panic_def_id(cx, fun_id)) - } else { - true - } - }, _ => true, } } diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index d0b8c52a36a..ea2cfb0bc08 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, higher, is_direct_expn_of, ty::implements_trait}; +use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit}; @@ -66,44 +67,40 @@ fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let macros = ["assert_eq", "debug_assert_eq"]; - let inverted_macros = ["assert_ne", "debug_assert_ne"]; - - for mac in macros.iter().chain(inverted_macros.iter()) { - if let Some(span) = is_direct_expn_of(expr.span, mac) { - if let Some(args) = higher::extract_assert_macro_args(expr) { - if let [a, b, ..] = args[..] { - let nb_bool_args = usize::from(is_bool_lit(a)) + usize::from(is_bool_lit(b)); - - if nb_bool_args != 1 { - // If there are two boolean arguments, we definitely don't understand - // what's going on, so better leave things as is... - // - // Or there is simply no boolean and then we can leave things as is! - return; - } - - if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) { - // At this point the expression which is not a boolean - // literal does not implement Not trait with a bool output, - // so we cannot suggest to rewrite our code - return; - } + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + let macro_name = cx.tcx.item_name(macro_call.def_id); + if !matches!( + macro_name.as_str(), + "assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne" + ) { + return; + } + let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return }; + if !(is_bool_lit(a) ^ is_bool_lit(b)) { + // If there are two boolean arguments, we definitely don't understand + // what's going on, so better leave things as is... + // + // Or there is simply no boolean and then we can leave things as is! + return; + } - let non_eq_mac = &mac[..mac.len() - 3]; - span_lint_and_sugg( - cx, - BOOL_ASSERT_COMPARISON, - span, - &format!("used `{}!` with a literal bool", mac), - "replace it with", - format!("{}!(..)", non_eq_mac), - Applicability::MaybeIncorrect, - ); - return; - } - } - } + if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) { + // At this point the expression which is not a boolean + // literal does not implement Not trait with a bool output, + // so we cannot suggest to rewrite our code + return; } + + let macro_name = macro_name.as_str(); + let non_eq_mac = ¯o_name[..macro_name.len() - 3]; + span_lint_and_sugg( + cx, + BOOL_ASSERT_COMPARISON, + macro_call.span, + &format!("used `{}!` with a literal bool", macro_name), + "replace it with", + format!("{}!(..)", non_eq_mac), + Applicability::MaybeIncorrect, + ); } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 3650e4f91a0..9d4195e400d 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,8 +1,9 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then}; +use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::source::{first_line_of_span, snippet_with_applicability}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; +use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind}; @@ -13,7 +14,7 @@ use rustc_errors::emitter::EmitterWriter; use rustc_errors::{Applicability, Handler, SuggestionStyle}; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{AnonConst, Expr, ExprKind, QPath}; +use rustc_hir::{AnonConst, Expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; @@ -805,24 +806,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { return; } - // check for `begin_panic` - if_chain! { - if let ExprKind::Call(func_expr, _) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind; - if let Some(path_def_id) = path.res.opt_def_id(); - if match_panic_def_id(self.cx, path_def_id); - if is_expn_of(expr.span, "unreachable").is_none(); - if !is_expn_of_debug_assertions(expr.span); - then { - self.panic_span = Some(expr.span); + if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) { + if is_panic(self.cx, macro_call.def_id) + || matches!( + self.cx.tcx.item_name(macro_call.def_id).as_str(), + "assert" | "assert_eq" | "assert_ne" | "todo" + ) + { + self.panic_span = Some(macro_call.span); } } - // check for `assert_eq` or `assert_ne` - if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() { - self.panic_span = Some(expr.span); - } - // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); @@ -844,8 +838,3 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) } } - -fn is_expn_of_debug_assertions(span: Span) -> bool { - const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"]; - MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some()) -} diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 10123460527..df75b815436 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; +use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function}; +use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -68,32 +69,26 @@ declare_clippy_lint! { declare_lint_pass!(EqOp => [EQ_OP, OP_REF]); -const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_eq", "debug_assert_ne"]; - impl<'tcx> LateLintPass<'tcx> for EqOp { #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Block(block, _) = e.kind { - for stmt in block.stmts { - for amn in &ASSERT_MACRO_NAMES { - if_chain! { - if is_expn_of(stmt.span, amn).is_some(); - if let StmtKind::Semi(matchexpr) = stmt.kind; - if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr); - if macro_args.len() == 2; - let (lhs, rhs) = (macro_args[0], macro_args[1]); - if eq_expr_value(cx, lhs, rhs); - if !is_in_test_function(cx.tcx, e.hir_id); - then { - span_lint( - cx, - EQ_OP, - lhs.span.to(rhs.span), - &format!("identical args used in this `{}!` macro call", amn), - ); - } - } - } + if_chain! { + if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { + let name = cx.tcx.item_name(macro_call.def_id); + matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne") + .then(|| (macro_call, name)) + }); + if let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn); + if eq_expr_value(cx, lhs, rhs); + if macro_call.is_local(); + if !is_in_test_function(cx.tcx, e.hir_id); + then { + span_lint( + cx, + EQ_OP, + lhs.span.to(rhs.span), + &format!("identical args used in this `{}!` macro call", macro_name), + ); } } if let ExprKind::Binary(op, left, right) = e.kind { diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 6b327b9ce17..98e5234e0aa 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::higher::FormatArgsExpn; +use clippy_utils::macros::FormatArgsExpn; use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { } else { None }; - if let Some(format_args) = FormatArgsExpn::parse(write_arg); + if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg); then { let calling_macro = // ordering is important here, since `writeln!` uses `write!` internally @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { ) }; let msg = format!("use of `{}.unwrap()`", used); - if let [write_output] = *format_args.format_string_symbols { + if let [write_output] = *format_args.format_string_parts { let mut write_output = write_output.to_string(); if write_output.ends_with('\n') { write_output.pop(); diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 05d300058cf..02f1baf27fa 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::{is_panic, root_macro_call_first_node}; +use clippy_utils::method_chain_args; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) { use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; - use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath}; + use rustc_hir::{Expr, ImplItemKind}; struct FindPanicUnwrap<'a, 'tcx> { lcx: &'a LateContext<'tcx>, @@ -80,14 +81,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - // check for `begin_panic` - if_chain! { - if let ExprKind::Call(func_expr, _) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind; - if let Some(path_def_id) = path.res.opt_def_id(); - if match_panic_def_id(self.lcx, path_def_id); - if is_expn_of(expr.span, "unreachable").is_none(); - then { + if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) { + if is_panic(self.lcx, macro_call.def_id) { self.result.push(expr.span); } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 3f043e5f2f1..688d8f8630f 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::FormatExpn; +use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; @@ -43,38 +43,41 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) { - Some(e) if !e.call_site.from_expansion() => e, - _ => return, + let (format_args, call_site) = if_chain! { + if let Some(macro_call) = root_macro_call_first_node(cx, expr); + if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id); + if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn); + then { + (format_args, macro_call.span) + } else { + return + } }; let mut applicability = Applicability::MachineApplicable; if format_args.value_args.is_empty() { - if format_args.format_string_parts.is_empty() { - span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability); - } else { - if_chain! { - if let [e] = &*format_args.format_string_parts; - if let ExprKind::Lit(lit) = &e.kind; - if let Some(s_src) = snippet_opt(cx, lit.span); - then { + match *format_args.format_string_parts { + [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), + [_] => { + if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) { // Simulate macro expansion, converting {{ and }} to { and }. let s_expand = s_src.replace("{{", "{").replace("}}", "}"); let sugg = format!("{}.to_string()", s_expand); span_useless_format(cx, call_site, sugg, applicability); } - } + }, + [..] => {}, } } else if let [value] = *format_args.value_args { if_chain! { - if format_args.format_string_symbols == [kw::Empty]; + if format_args.format_string_parts == [kw::Empty]; if match cx.typeck_results().expr_ty(value).peel_refs().kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did), ty::Str => true, _ => false, }; if let Some(args) = format_args.args(); - if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting()); + if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting()); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index f0e1a67dcdd..ae423d799d7 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn}; +use clippy_utils::macros::{FormatArgsArg, FormatArgsExpn}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_diag_trait_item, match_def_path, paths}; @@ -83,7 +83,7 @@ const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_m impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { - if let Some(format_args) = FormatArgsExpn::parse(expr); + if let Some(format_args) = FormatArgsExpn::parse(cx, expr); let expr_expn_data = expr.span.ctxt().outer_expn_data(); let outermost_expn_data = outermost_expn_data(expr_expn_data); if let Some(macro_def_id) = outermost_expn_data.macro_def_id; @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if let Some(args) = format_args.args(); then { for (i, arg) in args.iter().enumerate() { - if !arg.is_display() { + if arg.format_trait != sym::Display { continue; } if arg.has_string_formatting() { @@ -106,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if is_aliased(&args, i) { continue; } - check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg); - check_to_string_in_format_args(cx, name, arg); + check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value); + check_to_string_in_format_args(cx, name, arg.value); } } } @@ -122,30 +122,31 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { } } -fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) { - if_chain! { - if FormatExpn::parse(arg.value).is_some(); - if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion(); - then { - span_lint_and_then( - cx, - FORMAT_IN_FORMAT_ARGS, - call_site, - &format!("`format!` in `{}!` args", name), - |diag| { - diag.help(&format!( - "combine the `format!(..)` arguments with the outer `{}!(..)` call", - name - )); - diag.help("or consider changing `format!` to `format_args!`"); - }, - ); - } +fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) { + let expn_data = arg.span.ctxt().outer_expn_data(); + if expn_data.call_site.from_expansion() { + return; + } + let Some(mac_id) = expn_data.macro_def_id else { return }; + if !cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) { + return; } + span_lint_and_then( + cx, + FORMAT_IN_FORMAT_ARGS, + call_site, + &format!("`format!` in `{}!` args", name), + |diag| { + diag.help(&format!( + "combine the `format!(..)` arguments with the outer `{}!(..)` call", + name + )); + diag.help("or consider changing `format!` to `format_args!`"); + }, + ); } -fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) { - let value = arg.value; +fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) { if_chain! { if !value.span.from_expansion(); if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind; diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 5a2a965716c..e3a34b22e32 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::PanicExpn; +use clippy_utils::macros::{root_macro_call, FormatArgsExpn}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_expn_of, sugg}; +use clippy_utils::{peel_blocks_with_stmt, sugg}; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp}; +use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -35,64 +36,33 @@ declare_clippy_lint! { declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]); impl LateLintPass<'_> for ManualAssert { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if_chain! { - if let Expr { - kind: ExprKind:: If(cond, Expr { - kind: ExprKind::Block( - Block { - stmts: [stmt], - .. - }, - _), - .. - }, None), - .. - } = &expr; - if is_expn_of(stmt.span, "panic").is_some(); + if let ExprKind::If(cond, then, None) = expr.kind; if !matches!(cond.kind, ExprKind::Let(_)); - if let StmtKind::Semi(semi) = stmt.kind; + if !expr.span.from_expansion(); + let then = peel_blocks_with_stmt(then); + if let Some(macro_call) = root_macro_call(then.span); + if cx.tcx.item_name(macro_call.def_id) == sym::panic; if !cx.tcx.sess.source_map().is_multiline(cond.span); - + if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn); then { - let call = if_chain! { - if let ExprKind::Block(block, _) = semi.kind; - if let Some(init) = block.expr; - then { - init - } else { - semi - } - }; - let span = if let Some(panic_expn) = PanicExpn::parse(call) { - match *panic_expn.format_args.value_args { - [] => panic_expn.format_args.format_string_span, - [.., last] => panic_expn.format_args.format_string_span.to(last.span), - } - } else if let ExprKind::Call(_, [format_args]) = call.kind { - format_args.span - } else { - return - }; let mut applicability = Applicability::MachineApplicable; - let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); - let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind { - if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e { - sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string() - } else { - format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par()) - } - } else { - format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par()) + let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability); + let cond = cond.peel_drop_temps(); + let (cond, not) = match cond.kind { + ExprKind::Unary(UnOp::Not, e) => (e, ""), + _ => (cond, "!"), }; - + let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); + let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); span_lint_and_sugg( cx, MANUAL_ASSERT, expr.span, "only a `panic!` in `if`-then statement", "try", - format!("assert!({}, {});", cond_sugg, sugg), + sugg, Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 22970507f96..0d693499bc6 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,16 +2,17 @@ use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; use clippy_utils::diagnostics::{ multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; -use clippy_utils::higher; +use clippy_utils::macros::{is_panic, root_macro_call}; use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use clippy_utils::visitors::is_local_used; use clippy_utils::{ - get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs, + get_parent_expr, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs, path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, strip_pat_refs, }; +use clippy_utils::{higher, peel_blocks_with_stmt}; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use core::iter::{once, ExactSizeIterator}; use if_chain::if_chain; @@ -974,7 +975,8 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm } if_chain! { if matching_wild; - if is_panic_call(arm.body); + if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span); + if is_panic(cx, macro_call.def_id); then { // `Err(_)` or `Err(_e)` arm with `panic!` found span_lint_and_note(cx, @@ -1179,22 +1181,6 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) }; } -// If the block contains only a `panic!` macro (as expression or statement) -fn is_panic_call(expr: &Expr<'_>) -> bool { - // Unwrap any wrapping blocks - let span = if let ExprKind::Block(block, _) = expr.kind { - match (&block.expr, block.stmts.len(), block.stmts.first()) { - (&Some(exp), 0, _) => exp.span, - (&None, 1, Some(stmt)) => stmt.span, - _ => return false, - } - } else { - expr.span - }; - - is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none() -} - fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) where 'b: 'a, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 0ec9387f9c4..866eaff5b1d 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::FormatExpn; +use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -14,7 +14,13 @@ use super::EXPECT_FUN_CALL; /// Checks for the `EXPECT_FUN_CALL` lint. #[allow(clippy::too_many_lines)] -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Span, name: &str, args: &[hir::Expr<'_>]) { +pub(super) fn check( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + method_span: Span, + name: &str, + args: &'tcx [hir::Expr<'tcx>], +) { // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or // `&str` fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { @@ -128,11 +134,12 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Spa let mut applicability = Applicability::MachineApplicable; //Special handling for `format!` as arg_root - if let Some(format_expn) = FormatExpn::parse(arg_root) { - let span = match *format_expn.format_args.value_args { - [] => format_expn.format_args.format_string_span, - [.., last] => format_expn.format_args.format_string_span.to(last.span), - }; + if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) { + if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { + return; + } + let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return }; + let span = format_args.inputs_span(); let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index fa7274990db..49d4b3a1850 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{higher, is_direct_expn_of}; +use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; @@ -34,26 +34,30 @@ declare_clippy_lint! { declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]); -const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"]; - impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - for dmn in &DEBUG_MACRO_NAMES { - if is_direct_expn_of(e.span, dmn).is_some() { - if let Some(macro_args) = higher::extract_assert_macro_args(e) { - for arg in macro_args { - let mut visitor = MutArgVisitor::new(cx); - visitor.visit_expr(arg); - if let Some(span) = visitor.expr_span() { - span_lint( - cx, - DEBUG_ASSERT_WITH_MUT_CALL, - span, - &format!("do not call a function with mutable arguments inside of `{}!`", dmn), - ); - } - } - } + let Some(macro_call) = root_macro_call_first_node(cx, e) else { return }; + let macro_name = cx.tcx.item_name(macro_call.def_id); + if !matches!( + macro_name.as_str(), + "debug_assert" | "debug_assert_eq" | "debug_assert_ne" + ) { + return; + } + let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else { return }; + for arg in [lhs, rhs] { + let mut visitor = MutArgVisitor::new(cx); + visitor.visit_expr(arg); + if let Some(span) = visitor.expr_span() { + span_lint( + cx, + DEBUG_ASSERT_WITH_MUT_CALL, + span, + &format!( + "do not call a function with mutable arguments inside of `{}!`", + macro_name + ), + ); } } } diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 8769c045214..b7a56970b33 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{find_macro_calls, is_expn_of, return_ty}; +use clippy_utils::visitors::expr_visitor_no_bodies; use rustc_hir as hir; -use rustc_hir::intravisit::FnKind; +use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; @@ -55,19 +57,19 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { } fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { - let mut panics = find_macro_calls( - &[ - "unimplemented", - "unreachable", - "panic", - "todo", - "assert", - "assert_eq", - "assert_ne", - ], - body, - ); - panics.retain(|span| is_expn_of(*span, "debug_assert").is_none()); + let mut panics = Vec::new(); + expr_visitor_no_bodies(|expr| { + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true }; + if matches!( + &*cx.tcx.item_name(macro_call.def_id).as_str(), + "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne" + ) { + panics.push(macro_call.span); + return false; + } + true + }) + .visit_expr(&body.value); if !panics.is_empty() { span_lint_and_then( cx, diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index edfac824ded..6ef6b9a20aa 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,10 +1,8 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expn_of, match_panic_call}; -use if_chain::if_chain; +use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -78,37 +76,37 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if match_panic_call(cx, expr).is_some() - && (is_expn_of(expr.span, "debug_assert").is_none() && is_expn_of(expr.span, "assert").is_none()) - { - let span = get_outer_span(expr); - if is_expn_of(expr.span, "unimplemented").is_some() { + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if is_panic(cx, macro_call.def_id) { + span_lint( + cx, + PANIC, + macro_call.span, + "`panic` should not be present in production code", + ); + return; + } + match cx.tcx.item_name(macro_call.def_id).as_str() { + "todo" => { + span_lint( + cx, + TODO, + macro_call.span, + "`todo` should not be present in production code", + ); + }, + "unimplemented" => { span_lint( cx, UNIMPLEMENTED, - span, + macro_call.span, "`unimplemented` should not be present in production code", ); - } else if is_expn_of(expr.span, "todo").is_some() { - span_lint(cx, TODO, span, "`todo` should not be present in production code"); - } else if is_expn_of(expr.span, "unreachable").is_some() { - span_lint(cx, UNREACHABLE, span, "usage of the `unreachable!` macro"); - } else if is_expn_of(expr.span, "panic").is_some() { - span_lint(cx, PANIC, span, "`panic` should not be present in production code"); - } - } - } -} - -fn get_outer_span(expr: &Expr<'_>) -> Span { - if_chain! { - if expr.span.from_expansion(); - let first = expr.span.ctxt().outer_expn_data().call_site; - if first.from_expansion(); - then { - first.ctxt().outer_expn_data().call_site - } else { - expr.span + }, + "unreachable" => { + span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); + }, + _ => {}, } } } diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index 6d9aff47421..1dd8895ebd0 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -1,35 +1,29 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::hygiene::{ExpnKind, MacroKind}; use super::UNIT_CMP; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if expr.span.from_expansion() { - if let Some(callee) = expr.span.source_callee() { - if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind { - if let ExprKind::Binary(ref cmp, left, _) = expr.kind { - let op = cmp.node; - if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { - let result = match symbol.as_str() { - "assert_eq" | "debug_assert_eq" => "succeed", - "assert_ne" | "debug_assert_ne" => "fail", - _ => return, - }; - span_lint( - cx, - UNIT_CMP, - expr.span, - &format!( - "`{}` of unit values detected. This will always {}", - symbol.as_str(), - result - ), - ); - } - } + if let Some(macro_call) = root_macro_call_first_node(cx, expr) { + let macro_name = cx.tcx.item_name(macro_call.def_id); + let result = match macro_name.as_str() { + "assert_eq" | "debug_assert_eq" => "succeed", + "assert_ne" | "debug_assert_ne" => "fail", + _ => return, + }; + let Some ((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return }; + if !cx.typeck_results().expr_ty(left).is_unit() { + return; } + span_lint( + cx, + UNIT_CMP, + macro_call.span, + &format!("`{}` of unit values detected. This will always {}", macro_name, result), + ); } return; } diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index e98dcd3cf98..165004e5b41 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,5 +1,6 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{ @@ -410,9 +411,13 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { } self.declared_lints.insert(item.ident.name, item.span); } - } else if is_expn_of(item.span, "impl_lint_pass").is_some() - || is_expn_of(item.span, "declare_lint_pass").is_some() - { + } else if let Some(macro_call) = root_macro_call_first_node(cx, item) { + if !matches!( + &*cx.tcx.item_name(macro_call.def_id).as_str(), + "impl_lint_pass" | "declare_lint_pass" + ) { + return; + } if let hir::ItemKind::Impl(hir::Impl { of_trait: None, items: impl_item_refs, diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 0ba0b59ed13..af1e2eb4dd1 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" publish = false [dependencies] +arrayvec = { version = "0.7", default-features = false } if_chain = "1.0" rustc-semver = "1.1" diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 8400bfbbd99..3d3180521ab 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -5,7 +5,6 @@ #![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)] use crate::{both, over}; -use if_chain::if_chain; use rustc_ast::ptr::P; use rustc_ast::{self as ast, *}; use rustc_span::symbol::Ident; @@ -679,34 +678,3 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { _ => false, } } - -/// Extract args from an assert-like macro. -/// -/// Currently working with: -/// - `assert_eq!` and `assert_ne!` -/// - `debug_assert_eq!` and `debug_assert_ne!` -/// -/// For example: -/// -/// `debug_assert_eq!(a, b)` will return Some([a, b]) -pub fn extract_assert_macro_args(mut expr: &Expr) -> Option<[&Expr; 2]> { - if_chain! { - if let ExprKind::If(_, ref block, _) = expr.kind; - if let StmtKind::Semi(ref e) = block.stmts.get(0)?.kind; - then { - expr = e; - } - } - if_chain! { - if let ExprKind::Block(ref block, _) = expr.kind; - if let StmtKind::Expr(ref expr) = block.stmts.get(0)?.kind; - if let ExprKind::Match(ref match_expr, _) = expr.kind; - if let ExprKind::Tup(ref tup) = match_expr.kind; - if let [a, b, ..] = tup.as_slice(); - if let (&ExprKind::AddrOf(_, _, ref a), &ExprKind::AddrOf(_, _, ref b)) = (&a.kind, &b.kind); - then { - return Some([&*a, &*b]); - } - } - None -} diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index c764c35d444..160a51740cd 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -3,15 +3,13 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::ty::is_type_diagnostic_item; -use crate::{is_expn_of, last_path_segment, match_def_path, paths}; +use crate::{is_expn_of, match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{self, LitKind}; use rustc_hir as hir; -use rustc_hir::{ - Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp, -}; +use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, symbol, ExpnKind, Span, Symbol}; +use rustc_span::{sym, symbol, Span}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`. @@ -428,293 +426,6 @@ pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind { } } -/// Extract args from an assert-like macro. -/// Currently working with: -/// - `assert!`, `assert_eq!` and `assert_ne!` -/// - `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` -/// For example: -/// `assert!(expr)` will return `Some([expr])` -/// `debug_assert_eq!(a, b)` will return `Some([a, b])` -pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option>> { - /// Try to match the AST for a pattern that contains a match, for example when two args are - /// compared - fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option>> { - if_chain! { - if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind; - if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind; - if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind; - if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind; - then { - return Some(vec![lhs, rhs]); - } - } - None - } - - if let ExprKind::Block(block, _) = e.kind { - if block.stmts.len() == 1 { - if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind { - // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`) - if_chain! { - if let Some(If { cond, .. }) = If::hir(matchexpr); - if let ExprKind::Unary(UnOp::Not, condition) = cond.kind; - then { - return Some(vec![condition]); - } - } - - // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`) - if_chain! { - if let ExprKind::Block(matchblock,_) = matchexpr.kind; - if let Some(matchblock_expr) = matchblock.expr; - then { - return ast_matchblock(matchblock_expr); - } - } - } - } else if let Some(matchblock_expr) = block.expr { - // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`) - return ast_matchblock(matchblock_expr); - } - } - None -} - -/// A parsed `format!` expansion -pub struct FormatExpn<'tcx> { - /// Span of `format!(..)` - pub call_site: Span, - /// Inner `format_args!` expansion - pub format_args: FormatArgsExpn<'tcx>, -} - -impl FormatExpn<'tcx> { - /// Parses an expanded `format!` invocation - pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { - if_chain! { - if let ExprKind::Block(block, _) = expr.kind; - if let [stmt] = block.stmts; - if let StmtKind::Local(local) = stmt.kind; - if let Some(init) = local.init; - if let ExprKind::Call(_, [format_args]) = init.kind; - let expn_data = expr.span.ctxt().outer_expn_data(); - if let ExpnKind::Macro(_, sym::format) = expn_data.kind; - if let Some(format_args) = FormatArgsExpn::parse(format_args); - then { - Some(FormatExpn { - call_site: expn_data.call_site, - format_args, - }) - } else { - None - } - } - } -} - -/// A parsed `format_args!` expansion -pub struct FormatArgsExpn<'tcx> { - /// Span of the first argument, the format string - pub format_string_span: Span, - /// Values passed after the format string - pub value_args: Vec<&'tcx Expr<'tcx>>, - - /// String literal expressions which represent the format string split by "{}" - pub format_string_parts: &'tcx [Expr<'tcx>], - /// Symbols corresponding to [`Self::format_string_parts`] - pub format_string_symbols: Vec, - /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)` - pub args: &'tcx [Expr<'tcx>], - /// The final argument passed to `Arguments::new_v1_formatted`, if applicable - pub fmt_expr: Option<&'tcx Expr<'tcx>>, -} - -impl FormatArgsExpn<'tcx> { - /// Parses an expanded `format_args!` or `format_args_nl!` invocation - pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { - if_chain! { - if let ExpnKind::Macro(_, name) = expr.span.ctxt().outer_expn_data().kind; - let name = name.as_str(); - if name.ends_with("format_args") || name.ends_with("format_args_nl"); - if let ExprKind::Call(_, args) = expr.kind; - if let Some((strs_ref, args, fmt_expr)) = match args { - // Arguments::new_v1 - [strs_ref, args] => Some((strs_ref, args, None)), - // Arguments::new_v1_formatted - [strs_ref, args, fmt_expr, _unsafe_arg] => Some((strs_ref, args, Some(fmt_expr))), - _ => None, - }; - if let ExprKind::AddrOf(BorrowKind::Ref, _, strs_arr) = strs_ref.kind; - if let ExprKind::Array(format_string_parts) = strs_arr.kind; - if let Some(format_string_symbols) = format_string_parts - .iter() - .map(|e| { - if let ExprKind::Lit(lit) = &e.kind { - if let LitKind::Str(symbol, _style) = lit.node { - return Some(symbol); - } - } - None - }) - .collect(); - if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args.kind; - if let ExprKind::Match(args, [arm], _) = args.kind; - if let ExprKind::Tup(value_args) = args.kind; - if let Some(value_args) = value_args - .iter() - .map(|e| match e.kind { - ExprKind::AddrOf(_, _, e) => Some(e), - _ => None, - }) - .collect(); - if let ExprKind::Array(args) = arm.body.kind; - then { - Some(FormatArgsExpn { - format_string_span: strs_ref.span, - value_args, - format_string_parts, - format_string_symbols, - args, - fmt_expr, - }) - } else { - None - } - } - } - - /// Returns a vector of `FormatArgsArg`. - pub fn args(&self) -> Option>> { - if let Some(expr) = self.fmt_expr { - if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; - if let ExprKind::Array(exprs) = expr.kind; - then { - exprs.iter().map(|fmt| { - if_chain! { - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = fmt.kind; - if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); - if let ExprKind::Lit(lit) = &position_field.expr.kind; - if let LitKind::Int(position, _) = lit.node; - if let Ok(i) = usize::try_from(position); - let arg = &self.args[i]; - if let ExprKind::Call(_, [arg_name, _]) = arg.kind; - if let ExprKind::Field(_, j) = arg_name.kind; - if let Ok(j) = j.name.as_str().parse::(); - then { - Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) }) - } else { - None - } - } - }).collect() - } else { - None - } - } - } else { - Some( - self.value_args - .iter() - .zip(self.args.iter()) - .map(|(value, arg)| FormatArgsArg { value, arg, fmt: None }) - .collect(), - ) - } - } -} - -/// Type representing a `FormatArgsExpn`'s format arguments -pub struct FormatArgsArg<'tcx> { - /// An element of `value_args` according to `position` - pub value: &'tcx Expr<'tcx>, - /// An element of `args` according to `position` - pub arg: &'tcx Expr<'tcx>, - /// An element of `fmt_expn` - pub fmt: Option<&'tcx Expr<'tcx>>, -} - -impl<'tcx> FormatArgsArg<'tcx> { - /// Returns true if any formatting parameters are used that would have an effect on strings, - /// like `{:+2}` instead of just `{}`. - pub fn has_string_formatting(&self) -> bool { - self.fmt.map_or(false, |fmt| { - // `!` because these conditions check that `self` is unformatted. - !if_chain! { - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = fmt.kind; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); - // struct `core::fmt::rt::v1::FormatSpec` - if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind; - let mut precision_found = false; - let mut width_found = false; - if subfields.iter().all(|field| { - match field.ident.name { - sym::precision => { - precision_found = true; - if let ExprKind::Path(ref precision_path) = field.expr.kind { - last_path_segment(precision_path).ident.name == sym::Implied - } else { - false - } - } - sym::width => { - width_found = true; - if let ExprKind::Path(ref width_qpath) = field.expr.kind { - last_path_segment(width_qpath).ident.name == sym::Implied - } else { - false - } - } - _ => true, - } - }); - if precision_found && width_found; - then { true } else { false } - } - }) - } - - /// Returns true if the argument is formatted using `Display::fmt`. - pub fn is_display(&self) -> bool { - if_chain! { - if let ExprKind::Call(_, [_, format_field]) = self.arg.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind; - if let [.., t, _] = path.segments; - if t.ident.name == sym::Display; - then { true } else { false } - } - } -} - -/// A parsed `panic!` expansion -pub struct PanicExpn<'tcx> { - /// Span of `panic!(..)` - pub call_site: Span, - /// Inner `format_args!` expansion - pub format_args: FormatArgsExpn<'tcx>, -} - -impl PanicExpn<'tcx> { - /// Parses an expanded `panic!` invocation - pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { - if_chain! { - if let ExprKind::Call(_, [format_args]) = expr.kind; - let expn_data = expr.span.ctxt().outer_expn_data(); - if let Some(format_args) = FormatArgsExpn::parse(format_args); - then { - Some(PanicExpn { - call_site: expn_data.call_site, - format_args, - }) - } else { - None - } - } - } -} - /// A parsed `Vec` initialization expression #[derive(Clone, Copy)] pub enum VecInitKind { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 54d470ca738..bbb70e3adb5 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -44,6 +44,7 @@ pub mod diagnostics; pub mod eager_or_lazy; pub mod higher; mod hir_utils; +pub mod macros; pub mod msrvs; pub mod numeric_literal; pub mod paths; @@ -1138,19 +1139,6 @@ pub fn contains_return(expr: &hir::Expr<'_>) -> bool { found } -/// Finds calls of the specified macros in a function body. -pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec { - let mut result = Vec::new(); - expr_visitor_no_bodies(|expr| { - if names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) { - result.push(expr.span); - } - true - }) - .visit_expr(&body.value); - result -} - /// Extends the span to the beginning of the spans line, incl. whitespaces. /// /// ```rust @@ -1679,32 +1667,6 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name) } -pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Call(func, [arg]) = expr.kind { - expr_path_res(cx, func) - .opt_def_id() - .map_or(false, |id| match_panic_def_id(cx, id)) - .then(|| arg) - } else { - None - } -} - -pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { - match_any_def_paths( - cx, - did, - &[ - &paths::BEGIN_PANIC, - &paths::PANIC_ANY, - &paths::PANICKING_PANIC, - &paths::PANICKING_PANIC_FMT, - &paths::PANICKING_PANIC_STR, - ], - ) - .is_some() -} - /// Returns the list of condition expressions and the list of blocks in a /// sequence of `if/else`. /// E.g., this returns `([a, b], [c, d, e])` for the expression diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs new file mode 100644 index 00000000000..2bf43aeb995 --- /dev/null +++ b/clippy_utils/src/macros.rs @@ -0,0 +1,539 @@ +#![allow(clippy::similar_names)] // `expr` and `expn` + +use crate::visitors::expr_visitor_no_bodies; + +use arrayvec::ArrayVec; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; +use rustc_lint::LateContext; +use rustc_span::def_id::DefId; +use rustc_span::hygiene::{MacroKind, SyntaxContext}; +use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol}; +use std::ops::ControlFlow; + +/// A macro call, like `vec![1, 2, 3]`. +/// +/// Use `tcx.item_name(macro_call.def_id)` to get the macro name. +/// Even better is to check if it is a diagnostic item. +/// +/// This structure is similar to `ExpnData` but it precludes desugaring expansions. +#[derive(Debug)] +pub struct MacroCall { + /// Macro `DefId` + pub def_id: DefId, + /// Kind of macro + pub kind: MacroKind, + /// The expansion produced by the macro call + pub expn: ExpnId, + /// Span of the macro call site + pub span: Span, +} + +impl MacroCall { + pub fn is_local(&self) -> bool { + span_is_local(self.span) + } +} + +/// Returns an iterator of expansions that created the given span +pub fn expn_backtrace(mut span: Span) -> impl Iterator { + std::iter::from_fn(move || { + let ctxt = span.ctxt(); + if ctxt == SyntaxContext::root() { + return None; + } + let expn = ctxt.outer_expn(); + let data = expn.expn_data(); + span = data.call_site; + Some((expn, data)) + }) +} + +/// Checks whether the span is from the root expansion or a locally defined macro +pub fn span_is_local(span: Span) -> bool { + !span.from_expansion() || expn_is_local(span.ctxt().outer_expn()) +} + +/// Checks whether the expansion is the root expansion or a locally defined macro +pub fn expn_is_local(expn: ExpnId) -> bool { + if expn == ExpnId::root() { + return true; + } + let data = expn.expn_data(); + let backtrace = expn_backtrace(data.call_site); + std::iter::once((expn, data)) + .chain(backtrace) + .find_map(|(_, data)| data.macro_def_id) + .map_or(true, DefId::is_local) +} + +/// Returns an iterator of macro expansions that created the given span. +/// Note that desugaring expansions are skipped. +pub fn macro_backtrace(span: Span) -> impl Iterator { + expn_backtrace(span).filter_map(|(expn, data)| match data { + ExpnData { + kind: ExpnKind::Macro(kind, _), + macro_def_id: Some(def_id), + call_site: span, + .. + } => Some(MacroCall { + def_id, + kind, + expn, + span, + }), + _ => None, + }) +} + +/// If the macro backtrace of `span` has a macro call at the root expansion +/// (i.e. not a nested macro call), returns `Some` with the `MacroCall` +pub fn root_macro_call(span: Span) -> Option { + macro_backtrace(span).last() +} + +/// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node" +/// produced by the macro call, as in [`first_node_in_macro`]. +pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option { + if first_node_in_macro(cx, node) != Some(ExpnId::root()) { + return None; + } + root_macro_call(node.span()) +} + +/// Like [`macro_backtrace`], but only returns macro calls where `node` is the "first node" of the +/// macro call, as in [`first_node_in_macro`]. +pub fn first_node_macro_backtrace(cx: &LateContext<'_>, node: &impl HirNode) -> impl Iterator { + let span = node.span(); + first_node_in_macro(cx, node) + .into_iter() + .flat_map(move |expn| macro_backtrace(span).take_while(move |macro_call| macro_call.expn != expn)) +} + +/// If `node` is the "first node" in a macro expansion, returns `Some` with the `ExpnId` of the +/// macro call site (i.e. the parent of the macro expansion). This generally means that `node` +/// is the outermost node of an entire macro expansion, but there are some caveats noted below. +/// This is useful for finding macro calls while visiting the HIR without processing the macro call +/// at every node within its expansion. +/// +/// If you already have immediate access to the parent node, it is simpler to +/// just check the context of that span directly (e.g. `parent.span.from_expansion()`). +/// +/// If a macro call is in statement position, it expands to one or more statements. +/// In that case, each statement *and* their immediate descendants will all yield `Some` +/// with the `ExpnId` of the containing block. +/// +/// A node may be the "first node" of multiple macro calls in a macro backtrace. +/// The expansion of the outermost macro call site is returned in such cases. +pub fn first_node_in_macro(cx: &LateContext<'_>, node: &impl HirNode) -> Option { + // get the macro expansion or return `None` if not found + // `macro_backtrace` importantly ignores desugaring expansions + let expn = macro_backtrace(node.span()).next()?.expn; + + // get the parent node, possibly skipping over a statement + // if the parent is not found, it is sensible to return `Some(root)` + let hir = cx.tcx.hir(); + let mut parent_iter = hir.parent_iter(node.hir_id()); + let (parent_id, _) = match parent_iter.next() { + None => return Some(ExpnId::root()), + Some((_, Node::Stmt(_))) => match parent_iter.next() { + None => return Some(ExpnId::root()), + Some(next) => next, + }, + Some(next) => next, + }; + + // get the macro expansion of the parent node + let parent_span = hir.span(parent_id); + let Some(parent_macro_call) = macro_backtrace(parent_span).next() else { + // the parent node is not in a macro + return Some(ExpnId::root()); + }; + + if parent_macro_call.expn.is_descendant_of(expn) { + // `node` is input to a macro call + return None; + } + + Some(parent_macro_call.expn) +} + +/* Specific Macro Utils */ + +/// Is `def_id` of `std::panic`, `core::panic` or any inner implementation macros +pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool { + let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false }; + matches!( + name.as_str(), + "core_panic_macro" + | "std_panic_macro" + | "core_panic_2015_macro" + | "std_panic_2015_macro" + | "core_panic_2021_macro" + ) +} + +pub enum PanicExpn<'a> { + /// No arguments - `panic!()` + Empty, + /// A string literal or any `&str` - `panic!("message")` or `panic!(message)` + Str(&'a Expr<'a>), + /// A single argument that implements `Display` - `panic!("{}", object)` + Display(&'a Expr<'a>), + /// Anything else - `panic!("error {}: {}", a, b)` + Format(FormatArgsExpn<'a>), +} + +impl<'a> PanicExpn<'a> { + pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option { + if !macro_backtrace(expr.span).any(|macro_call| is_panic(cx, macro_call.def_id)) { + return None; + } + let ExprKind::Call(callee, [arg]) = expr.kind else { return None }; + let ExprKind::Path(QPath::Resolved(_, path)) = callee.kind else { return None }; + let result = match path.segments.last().unwrap().ident.as_str() { + "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty, + "panic" | "panic_str" => Self::Str(arg), + "panic_display" => { + let ExprKind::AddrOf(_, _, e) = arg.kind else { return None }; + Self::Display(e) + }, + "panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?), + _ => return None, + }; + Some(result) + } +} + +/// Finds the arguments of an `assert!` or `debug_assert!` macro call within the macro expansion +pub fn find_assert_args<'a>( + cx: &LateContext<'_>, + expr: &'a Expr<'a>, + expn: ExpnId, +) -> Option<(&'a Expr<'a>, PanicExpn<'a>)> { + find_assert_args_inner(cx, expr, expn).map(|([e], p)| (e, p)) +} + +/// Finds the arguments of an `assert_eq!` or `debug_assert_eq!` macro call within the macro +/// expansion +pub fn find_assert_eq_args<'a>( + cx: &LateContext<'_>, + expr: &'a Expr<'a>, + expn: ExpnId, +) -> Option<(&'a Expr<'a>, &'a Expr<'a>, PanicExpn<'a>)> { + find_assert_args_inner(cx, expr, expn).map(|([a, b], p)| (a, b, p)) +} + +fn find_assert_args_inner<'a, const N: usize>( + cx: &LateContext<'_>, + expr: &'a Expr<'a>, + expn: ExpnId, +) -> Option<([&'a Expr<'a>; N], PanicExpn<'a>)> { + let macro_id = expn.expn_data().macro_def_id?; + let (expr, expn) = match cx.tcx.item_name(macro_id).as_str().strip_prefix("debug_") { + None => (expr, expn), + Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?, + }; + let mut args = ArrayVec::new(); + let mut panic_expn = None; + expr_visitor_no_bodies(|e| { + if args.is_full() { + if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() { + panic_expn = PanicExpn::parse(cx, e); + } + panic_expn.is_none() + } else if is_assert_arg(cx, e, expn) { + args.push(e); + false + } else { + true + } + }) + .visit_expr(expr); + let args = args.into_inner().ok()?; + // if no `panic!(..)` is found, use `PanicExpn::Empty` + // to indicate that the default assertion message is used + let panic_expn = panic_expn.unwrap_or(PanicExpn::Empty); + Some((args, panic_expn)) +} + +fn find_assert_within_debug_assert<'a>( + cx: &LateContext<'_>, + expr: &'a Expr<'a>, + expn: ExpnId, + assert_name: Symbol, +) -> Option<(&'a Expr<'a>, ExpnId)> { + let mut found = None; + expr_visitor_no_bodies(|e| { + if found.is_some() || !e.span.from_expansion() { + return false; + } + let e_expn = e.span.ctxt().outer_expn(); + if e_expn == expn { + return true; + } + if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) { + found = Some((e, e_expn)); + } + false + }) + .visit_expr(expr); + found +} + +fn is_assert_arg(cx: &LateContext<'_>, expr: &'a Expr<'a>, assert_expn: ExpnId) -> bool { + if !expr.span.from_expansion() { + return true; + } + let result = macro_backtrace(expr.span).try_for_each(|macro_call| { + if macro_call.expn == assert_expn { + ControlFlow::Break(false) + } else { + match cx.tcx.item_name(macro_call.def_id) { + // `cfg!(debug_assertions)` in `debug_assert!` + sym::cfg => ControlFlow::CONTINUE, + // assert!(other_macro!(..)) + _ => ControlFlow::Break(true), + } + } + }); + match result { + ControlFlow::Break(is_assert_arg) => is_assert_arg, + ControlFlow::Continue(()) => true, + } +} + +/// A parsed `format_args!` expansion +pub struct FormatArgsExpn<'tcx> { + /// Span of the first argument, the format string + pub format_string_span: Span, + /// The format string split by formatted args like `{..}` + pub format_string_parts: Vec, + /// Values passed after the format string + pub value_args: Vec<&'tcx Expr<'tcx>>, + /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`) + pub formatters: Vec<(usize, Symbol)>, + /// List of `fmt::v1::Argument { .. }` expressions. If this is empty, + /// then `formatters` represents the format args (`{..}`). + /// If this is non-empty, it represents the format args, and the `position` + /// parameters within the struct expressions are indexes of `formatters`. + pub specs: Vec<&'tcx Expr<'tcx>>, +} + +impl FormatArgsExpn<'tcx> { + /// Parses an expanded `format_args!` or `format_args_nl!` invocation + pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { + macro_backtrace(expr.span).find(|macro_call| { + matches!( + cx.tcx.item_name(macro_call.def_id), + sym::const_format_args | sym::format_args | sym::format_args_nl + ) + })?; + let mut format_string_span: Option = None; + let mut format_string_parts: Vec = Vec::new(); + let mut value_args: Vec<&Expr<'_>> = Vec::new(); + let mut formatters: Vec<(usize, Symbol)> = Vec::new(); + let mut specs: Vec<&Expr<'_>> = Vec::new(); + expr_visitor_no_bodies(|e| { + // if we're still inside of the macro definition... + if e.span.ctxt() == expr.span.ctxt() { + // ArgumnetV1::new(, ::fmt) + if_chain! { + if let ExprKind::Call(callee, [val, fmt_path]) = e.kind; + if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind; + if seg.ident.name == sym::new; + if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind; + if path.segments.last().unwrap().ident.name == sym::ArgumentV1; + if let ExprKind::Path(QPath::Resolved(_, path)) = fmt_path.kind; + if let [.., fmt_trait, _fmt] = path.segments; + then { + let val_idx = if_chain! { + if val.span.ctxt() == expr.span.ctxt(); + if let ExprKind::Field(_, field) = val.kind; + if let Ok(idx) = field.name.as_str().parse(); + then { + // tuple index + idx + } else { + // assume the value expression is passed directly + formatters.len() + } + }; + formatters.push((val_idx, fmt_trait.ident.name)); + } + } + if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind { + if path.segments.last().unwrap().ident.name == sym::Argument { + specs.push(e); + } + } + // walk through the macro expansion + return true; + } + // assume that the first expr with a differing context represents + // (and has the span of) the format string + if format_string_span.is_none() { + format_string_span = Some(e.span); + let span = e.span; + // walk the expr and collect string literals which are format string parts + expr_visitor_no_bodies(|e| { + if e.span.ctxt() != span.ctxt() { + // defensive check, probably doesn't happen + return false; + } + if let ExprKind::Lit(lit) = &e.kind { + if let LitKind::Str(symbol, _s) = lit.node { + format_string_parts.push(symbol); + } + } + true + }) + .visit_expr(e); + } else { + // assume that any further exprs with a differing context are value args + value_args.push(e); + } + // don't walk anything not from the macro expansion (e.a. inputs) + false + }) + .visit_expr(expr); + Some(FormatArgsExpn { + format_string_span: format_string_span?, + format_string_parts, + value_args, + formatters, + specs, + }) + } + + /// Finds a nested call to `format_args!` within a `format!`-like macro call + pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { + let mut format_args = None; + expr_visitor_no_bodies(|e| { + if format_args.is_some() { + return false; + } + let e_ctxt = e.span.ctxt(); + if e_ctxt == expr.span.ctxt() { + return true; + } + if e_ctxt.outer_expn().is_descendant_of(expn_id) { + format_args = FormatArgsExpn::parse(cx, e); + } + false + }) + .visit_expr(expr); + format_args + } + + /// Returns a vector of `FormatArgsArg`. + pub fn args(&self) -> Option>> { + if self.specs.is_empty() { + let args = std::iter::zip(&self.value_args, &self.formatters) + .map(|(value, &(_, format_trait))| FormatArgsArg { + value, + format_trait, + spec: None, + }) + .collect(); + return Some(args); + } + self.specs + .iter() + .map(|spec| { + if_chain! { + // struct `core::fmt::rt::v1::Argument` + if let ExprKind::Struct(_, fields, _) = spec.kind; + if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); + if let ExprKind::Lit(lit) = &position_field.expr.kind; + if let LitKind::Int(position, _) = lit.node; + if let Ok(i) = usize::try_from(position); + if let Some(&(j, format_trait)) = self.formatters.get(i); + then { + Some(FormatArgsArg { value: self.value_args[j], format_trait, spec: Some(spec) }) + } else { + None + } + } + }) + .collect() + } + + /// Span of all inputs + pub fn inputs_span(&self) -> Span { + match *self.value_args { + [] => self.format_string_span, + [.., last] => self.format_string_span.to(last.span), + } + } +} + +/// Type representing a `FormatArgsExpn`'s format arguments +pub struct FormatArgsArg<'tcx> { + /// An element of `value_args` according to `position` + pub value: &'tcx Expr<'tcx>, + /// An element of `args` according to `position` + pub format_trait: Symbol, + /// An element of `specs` + pub spec: Option<&'tcx Expr<'tcx>>, +} + +impl<'tcx> FormatArgsArg<'tcx> { + /// Returns true if any formatting parameters are used that would have an effect on strings, + /// like `{:+2}` instead of just `{}`. + pub fn has_string_formatting(&self) -> bool { + self.spec.map_or(false, |spec| { + // `!` because these conditions check that `self` is unformatted. + !if_chain! { + // struct `core::fmt::rt::v1::Argument` + if let ExprKind::Struct(_, fields, _) = spec.kind; + if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); + // struct `core::fmt::rt::v1::FormatSpec` + if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind; + if subfields.iter().all(|field| match field.ident.name { + sym::precision | sym::width => match field.expr.kind { + ExprKind::Path(QPath::Resolved(_, path)) => { + path.segments.last().unwrap().ident.name == sym::Implied + } + _ => false, + } + _ => true, + }); + then { true } else { false } + } + }) + } +} + +/// A node with a `HirId` and a `Span` +pub trait HirNode { + fn hir_id(&self) -> HirId; + fn span(&self) -> Span; +} + +macro_rules! impl_hir_node { + ($($t:ident),*) => { + $(impl HirNode for hir::$t<'_> { + fn hir_id(&self) -> HirId { + self.hir_id + } + fn span(&self) -> Span { + self.span + } + })* + }; +} + +impl_hir_node!(Expr, Pat); + +impl HirNode for hir::Item<'_> { + fn hir_id(&self) -> HirId { + self.hir_id() + } + + fn span(&self) -> Span { + self.span + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index aa3b3af2356..27db53a6e6d 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -25,7 +25,6 @@ pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"]; pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; -pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; /// Preferably use the diagnostic item `sym::Borrow` where possible pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; pub const BORROW_MUT_TRAIT: [&str; 3] = ["core", "borrow", "BorrowMut"]; @@ -110,10 +109,6 @@ pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"]; pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; -pub(super) const PANICKING_PANIC: [&str; 3] = ["core", "panicking", "panic"]; -pub(super) const PANICKING_PANIC_FMT: [&str; 3] = ["core", "panicking", "panic_fmt"]; -pub(super) const PANICKING_PANIC_STR: [&str; 3] = ["core", "panicking", "panic_str"]; -pub(super) const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"]; pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"]; diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index cb516d0f977..7477c01ca78 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -1,4 +1,3 @@ -//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843 #![allow(non_fmt_panics)] macro_rules! assert_const { diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index ec80ec702fb..e1f818814d5 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -1,75 +1,75 @@ error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:11:5 + --> $DIR/assertions_on_constants.rs:10:5 | LL | assert!(true); | ^^^^^^^^^^^^^ | = note: `-D clippy::assertions-on-constants` implied by `-D warnings` = help: remove it - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false)` should probably be replaced - --> $DIR/assertions_on_constants.rs:12:5 + --> $DIR/assertions_on_constants.rs:11:5 | LL | assert!(false); | ^^^^^^^^^^^^^^ | = help: use `panic!()` or `unreachable!()` - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:13:5 + --> $DIR/assertions_on_constants.rs:12:5 | LL | assert!(true, "true message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: remove it - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced - --> $DIR/assertions_on_constants.rs:14:5 +error: `assert!(false, ..)` should probably be replaced + --> $DIR/assertions_on_constants.rs:13:5 | LL | assert!(false, "false message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))` - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: use `panic!(..)` or `unreachable!(..)` + +error: `assert!(false, ..)` should probably be replaced + --> $DIR/assertions_on_constants.rs:16:5 + | +LL | assert!(false, "{}", msg.to_uppercase()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `panic!(..)` or `unreachable!(..)` error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:20:5 + --> $DIR/assertions_on_constants.rs:19:5 | LL | assert!(B); | ^^^^^^^^^^ | = help: remove it - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false)` should probably be replaced - --> $DIR/assertions_on_constants.rs:23:5 + --> $DIR/assertions_on_constants.rs:22:5 | LL | assert!(C); | ^^^^^^^^^^ | = help: use `panic!()` or `unreachable!()` - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced - --> $DIR/assertions_on_constants.rs:24:5 +error: `assert!(false, ..)` should probably be replaced + --> $DIR/assertions_on_constants.rs:23:5 | LL | assert!(C, "C message"); | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))` - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: use `panic!(..)` or `unreachable!(..)` error: `debug_assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:26:5 + --> $DIR/assertions_on_constants.rs:25:5 | LL | debug_assert!(true); | ^^^^^^^^^^^^^^^^^^^ | = help: remove it - = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/eq_op_macros.stderr b/tests/ui/eq_op_macros.stderr index 885415b42c7..cd9f1826e59 100644 --- a/tests/ui/eq_op_macros.stderr +++ b/tests/ui/eq_op_macros.stderr @@ -21,6 +21,28 @@ LL | assert_in_macro_def!(); | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) +error: identical args used in this `debug_assert_eq!` macro call + --> $DIR/eq_op_macros.rs:9:26 + | +LL | debug_assert_eq!(a, a); + | ^^^^ +... +LL | assert_in_macro_def!(); + | ---------------------- in this macro invocation + | + = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: identical args used in this `debug_assert_ne!` macro call + --> $DIR/eq_op_macros.rs:10:26 + | +LL | debug_assert_ne!(a, a); + | ^^^^ +... +LL | assert_in_macro_def!(); + | ---------------------- in this macro invocation + | + = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) + error: identical args used in this `assert_eq!` macro call --> $DIR/eq_op_macros.rs:22:16 | @@ -45,28 +67,6 @@ error: identical args used in this `assert_ne!` macro call LL | assert_ne!(a + 1, a + 1); | ^^^^^^^^^^^^ -error: identical args used in this `debug_assert_eq!` macro call - --> $DIR/eq_op_macros.rs:9:26 - | -LL | debug_assert_eq!(a, a); - | ^^^^ -... -LL | assert_in_macro_def!(); - | ---------------------- in this macro invocation - | - = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: identical args used in this `debug_assert_ne!` macro call - --> $DIR/eq_op_macros.rs:10:26 - | -LL | debug_assert_ne!(a, a); - | ^^^^ -... -LL | assert_in_macro_def!(); - | ---------------------- in this macro invocation - | - = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) - error: identical args used in this `debug_assert_eq!` macro call --> $DIR/eq_op_macros.rs:38:22 | diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr index 8bccbaefe23..91ebd695238 100644 --- a/tests/ui/missing_panics_doc.stderr +++ b/tests/ui/missing_panics_doc.stderr @@ -27,7 +27,6 @@ note: first possible panic found here | LL | panic!("This function panics") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:17:1 @@ -42,7 +41,6 @@ note: first possible panic found here | LL | todo!() | ^^^^^^^ - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:22:1 @@ -61,7 +59,6 @@ note: first possible panic found here | LL | panic!() | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:31:1 @@ -76,7 +73,6 @@ note: first possible panic found here | LL | if true { unreachable!() } else { panic!() } | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:36:1 @@ -92,7 +88,6 @@ note: first possible panic found here | LL | assert_eq!(x, 0); | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:42:1 @@ -108,7 +103,6 @@ note: first possible panic found here | LL | assert_ne!(x, 0); | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 7 previous errors diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index 78d09b8b210..561503ae54f 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -14,7 +14,6 @@ note: return Err() instead of panicking | LL | panic!("error"); | ^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:11:5 @@ -31,7 +30,6 @@ note: return Err() instead of panicking | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:16:5 @@ -48,7 +46,6 @@ note: return Err() instead of panicking | LL | unreachable!(); | ^^^^^^^^^^^^^^ - = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:21:5 @@ -65,7 +62,6 @@ note: return Err() instead of panicking | LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:52:1 @@ -82,7 +78,6 @@ note: return Err() instead of panicking | LL | panic!("error"); | ^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:67:1 @@ -99,7 +94,6 @@ note: return Err() instead of panicking | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr index 7501d6d85ed..b6aa005e7b5 100644 --- a/tests/ui/panic_in_result_fn_assertions.stderr +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -15,7 +15,6 @@ note: return Err() instead of panicking | LL | assert!(x == 5, "wrong argument"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn_assertions.rs:13:5 @@ -33,7 +32,6 @@ note: return Err() instead of panicking | LL | assert_eq!(x, 5); | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn_assertions.rs:19:5 @@ -51,7 +49,6 @@ note: return Err() instead of panicking | LL | assert_ne!(x, 1); | ^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 2b607ff5888..bfd1c7a3801 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -25,23 +25,18 @@ LL | todo!(); | ^^^^^^^ | = note: `-D clippy::todo` implied by `-D warnings` - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:17:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:18:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:24:5 @@ -50,23 +45,18 @@ LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unimplemented` implied by `-D warnings` - = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:25:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:26:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:32:5 @@ -75,23 +65,18 @@ LL | unreachable!(); | ^^^^^^^^^^^^^^ | = note: `-D clippy::unreachable` implied by `-D warnings` - = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:33:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:34:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:40:5 @@ -104,24 +89,18 @@ error: `todo` should not be present in production code | LL | todo!(); | ^^^^^^^ - | - = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:42:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:43:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 16 previous errors diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 2b5a7b348b9..824506a4257 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -33,8 +33,6 @@ LL | | }, LL | | } LL | | ); | |_____^ - | - = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: `debug_assert_eq` of unit values detected. This will always succeed --> $DIR/unit_cmp.rs:32:5 @@ -47,8 +45,6 @@ LL | | }, LL | | } LL | | ); | |_____^ - | - = note: this error originates in the macro `$crate::assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert_ne` of unit values detected. This will always fail --> $DIR/unit_cmp.rs:41:5 @@ -61,8 +57,6 @@ LL | | }, LL | | } LL | | ); | |_____^ - | - = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: `debug_assert_ne` of unit values detected. This will always fail --> $DIR/unit_cmp.rs:49:5 @@ -75,8 +69,6 @@ LL | | }, LL | | } LL | | ); | |_____^ - | - = note: this error originates in the macro `$crate::assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From a4ebf6f78e8a3f586251e7d0e4c72af51b436de5 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Thu, 30 Dec 2021 18:43:34 -0500 Subject: Change `unnecessary_to_owned` `into_iter` suggestions to `MaybeIncorrect` --- clippy_lints/src/methods/unnecessary_iter_cloned.rs | 17 ++++++++++++++--- clippy_lints/src/methods/unnecessary_to_owned.rs | 13 +++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 8300df03e99..4f589a6d318 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -18,7 +18,7 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol if let Some(callee_def_id) = fn_def_id(cx, parent); if is_into_iter(cx, callee_def_id); then { - check_for_loop_iter(cx, parent, method_name, receiver) + check_for_loop_iter(cx, parent, method_name, receiver, false) } else { false } @@ -34,6 +34,7 @@ pub fn check_for_loop_iter( expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>, + cloned_before_iter: bool, ) -> bool { if_chain! { if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent)); @@ -70,12 +71,22 @@ pub fn check_for_loop_iter( expr.span, &format!("unnecessary use of `{}`", method_name), |diag| { - diag.span_suggestion(expr.span, "use", snippet, Applicability::MachineApplicable); + // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to + // a `to_owned`-like function was removed, then the next suggestion may be + // incorrect. This is because the iterator that results from the call's removal + // could hold a reference to a resource that is used mutably. See + // https://github.com/rust-lang/rust-clippy/issues/8148. + let applicability = if cloned_before_iter { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + diag.span_suggestion(expr.span, "use", snippet, applicability); for addr_of_expr in addr_of_exprs { match addr_of_expr.kind { ExprKind::AddrOf(_, _, referent) => { let span = addr_of_expr.span.with_hi(referent.span.lo()); - diag.span_suggestion(span, "remove this `&`", String::new(), Applicability::MachineApplicable); + diag.span_suggestion(span, "remove this `&`", String::new(), applicability); } _ => unreachable!(), } diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index c48bacfce0d..7e17f163b21 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -187,7 +187,13 @@ fn check_into_iter_call_arg( if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { - if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver) { + if unnecessary_iter_cloned::check_for_loop_iter( + cx, + parent, + method_name, + receiver, + true, + ) { return true; } let cloned_or_copied = if is_copy(cx, item_ty) { @@ -195,6 +201,9 @@ fn check_into_iter_call_arg( } else { "cloned" }; + // The next suggestion may be incorrect because the removal of the `to_owned`-like + // function could cause the iterator to hold a reference to a resource that is used + // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. span_lint_and_sugg( cx, UNNECESSARY_TO_OWNED, @@ -202,7 +211,7 @@ fn check_into_iter_call_arg( &format!("unnecessary use of `{}`", method_name), "use", format!("{}.iter().{}()", receiver_snippet, cloned_or_copied), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); return true; } -- cgit 1.4.1-3-g733a5 From 366234a515ab6538c83e5b58481b2c45abd72d76 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sat, 8 Jan 2022 09:09:52 -0500 Subject: Add `unnecessary_to_owned` "Known problems" section --- clippy_lints/src/methods/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4e33b2ff14c..6572c7111b3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1895,6 +1895,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// The unnecessary calls result in useless allocations. /// + /// ### Known problems + /// `unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an + /// owned copy of a resource and the resource is later used mutably. See + /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148). + /// /// ### Example /// ```rust /// let path = std::path::Path::new("x"); -- cgit 1.4.1-3-g733a5 From 02ec39b2ff69ce3275724e234ebcb72d310766ca Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 11 Jan 2022 09:52:23 -0600 Subject: Stop using in_band_lifetimes --- clippy_lints/src/bool_assert_comparison.rs | 2 +- .../case_sensitive_file_extension_comparisons.rs | 2 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 2 +- clippy_lints/src/casts/cast_ref_to_mut.rs | 2 +- clippy_lints/src/casts/char_lit_as_u8.rs | 2 +- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/copies.rs | 14 +++----- clippy_lints/src/default.rs | 4 +-- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 10 +++--- clippy_lints/src/entry.rs | 10 +++--- clippy_lints/src/equatable_if_let.rs | 2 +- clippy_lints/src/erasing_op.rs | 10 ++++-- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/must_use.rs | 6 ++-- .../src/functions/not_unsafe_ptr_arg_deref.rs | 6 ++-- clippy_lints/src/functions/result_unit_err.rs | 6 ++-- clippy_lints/src/functions/too_many_arguments.rs | 12 +++---- clippy_lints/src/functions/too_many_lines.rs | 4 +-- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/implicit_return.rs | 4 +-- .../src/inconsistent_struct_constructor.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/lib.rs | 1 - clippy_lints/src/loops/empty_loop.rs | 2 +- clippy_lints/src/loops/explicit_into_iter_loop.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/loops/needless_collect.rs | 4 +-- clippy_lints/src/loops/never_loop.rs | 4 +-- clippy_lints/src/loops/while_let_loop.rs | 2 +- clippy_lints/src/loops/while_let_on_iterator.rs | 14 ++++---- clippy_lints/src/manual_assert.rs | 2 +- clippy_lints/src/manual_map.rs | 17 ++++++---- clippy_lints/src/manual_ok_or.rs | 2 +- clippy_lints/src/manual_unwrap_or.rs | 2 +- clippy_lints/src/match_str_case_mismatch.rs | 2 +- clippy_lints/src/matches.rs | 12 ++++--- clippy_lints/src/methods/expect_fun_call.rs | 2 +- .../src/methods/from_iter_instead_of_collect.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 4 +-- .../src/methods/unnecessary_iter_cloned.rs | 10 +++--- clippy_lints/src/methods/unnecessary_to_owned.rs | 29 ++++++++-------- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/no_effect.rs | 4 +-- clippy_lints/src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/octal_escapes.rs | 4 +-- clippy_lints/src/ptr_eq.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/return_self_not_must_use.rs | 2 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 7 ++-- clippy_lints/src/strings.rs | 4 +-- clippy_lints/src/strlen_on_c_strings.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 4 +-- clippy_lints/src/trailing_empty_array.rs | 2 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 4 +-- clippy_lints/src/undropped_manually_drops.rs | 2 +- clippy_lints/src/uninit_vec.rs | 4 +-- clippy_lints/src/unit_hash.rs | 2 +- .../src/utils/internal_lints/metadata_collector.rs | 12 +++---- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 13 +++++--- clippy_utils/src/lib.rs | 39 ++++++++++++---------- clippy_utils/src/macros.rs | 4 +-- clippy_utils/src/qualify_min_const_fn.rs | 25 ++++++++++---- clippy_utils/src/source.rs | 2 +- clippy_utils/src/sugg.rs | 4 +-- clippy_utils/src/ty.rs | 4 +-- clippy_utils/src/visitors.rs | 8 ++--- doc/common_tools_writing_lints.md | 2 +- 77 files changed, 216 insertions(+), 189 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index ea2cfb0bc08..c50e214be28 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -42,7 +42,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool { ) && !e.span.from_expansion() } -fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { +fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(e); cx.tcx diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index 3f286dd9e2f..e8f39cd3709 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -67,7 +67,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: & None } -impl LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons { +impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons { fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) { span_lint_and_help( diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 248b35b024e..b9de5510455 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::sym; use super::CAST_PTR_ALIGNMENT; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Cast(cast_expr, cast_to) = expr.kind { if is_hir_ty_cfg_dependant(cx, cast_to) { return; diff --git a/clippy_lints/src/casts/cast_ref_to_mut.rs b/clippy_lints/src/casts/cast_ref_to_mut.rs index d9bf1ea58b9..15f2f81f407 100644 --- a/clippy_lints/src/casts/cast_ref_to_mut.rs +++ b/clippy_lints/src/casts/cast_ref_to_mut.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; use super::CAST_REF_TO_MUT; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind; if let ExprKind::Cast(e, t) = &e.kind; diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index 099a0de881f..7cc406018db 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, UintTy}; use super::CHAR_LIT_AS_U8; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Cast(e, _) = &expr.kind; if let ExprKind::Lit(l) = &e.kind; diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 3132d3a5cf0..fb04f93fbcf 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -12,7 +12,7 @@ use rustc_semver::RustcVersion; use super::PTR_AS_PTR; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option) { if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) { return; } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index d07bc23235b..73ce656ad15 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -316,7 +316,7 @@ struct BlockEqual { /// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to /// abort any further processing and avoid duplicate lint triggers. -fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option { +fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option { let mut start_eq = usize::MAX; let mut end_eq = usize::MAX; let mut expr_eq = true; @@ -385,11 +385,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option< }) } -fn check_for_warn_of_moved_symbol( - cx: &LateContext<'tcx>, - symbols: &FxHashSet, - if_expr: &'tcx Expr<'_>, -) -> bool { +fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &FxHashSet, if_expr: &Expr<'_>) -> bool { get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| { let ignore_span = block.span.shrink_to_lo().to(if_expr.span); @@ -419,13 +415,13 @@ fn check_for_warn_of_moved_symbol( } fn emit_branches_sharing_code_lint( - cx: &LateContext<'tcx>, + cx: &LateContext<'_>, start_stmts: usize, end_stmts: usize, lint_end: bool, warn_about_moved_symbol: bool, - blocks: &[&Block<'tcx>], - if_expr: &'tcx Expr<'_>, + blocks: &[&Block<'_>], + if_expr: &Expr<'_>, ) { if start_stmts == 0 && !lint_end { return; diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index a0b137efe22..4274943a3d1 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -77,7 +77,7 @@ pub struct Default { impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]); -impl LateLintPass<'_> for Default { +impl<'tcx> LateLintPass<'tcx> for Default { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if !expr.span.from_expansion(); @@ -110,7 +110,7 @@ impl LateLintPass<'_> for Default { } #[allow(clippy::too_many_lines)] - fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { // start from the `let mut _ = _::default();` and look at all the following // statements, see if they re-assign the fields of the binding let stmts_head = match block.stmts { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 3573ea5f026..e5131c497ae 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -54,7 +54,7 @@ declare_clippy_lint! { declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); -impl LateLintPass<'_> for DefaultNumericFallback { +impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { let mut visitor = NumericFallbackVisitor::new(cx); visitor.visit_body(body); diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index fa2b348591b..bf077a212fd 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -355,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { } } -fn try_parse_ref_op( +fn try_parse_ref_op<'tcx>( tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'_>, expr: &'tcx Expr<'_>, @@ -387,7 +387,7 @@ fn try_parse_ref_op( // Checks whether the type for a deref call actually changed the type, not just the mutability of // the reference. -fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { +fn deref_method_same_type(result_ty: Ty<'_>, arg_ty: Ty<'_>) -> bool { match (result_ty.kind(), arg_ty.kind()) { (ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => TyS::same_type(result_ty, arg_ty), @@ -457,7 +457,7 @@ fn is_linted_explicit_deref_position(parent: Option>, child_id: HirId, } /// Adjustments are sometimes made in the parent block rather than the expression itself. -fn find_adjustments( +fn find_adjustments<'tcx>( tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'_>, expr: &'tcx Expr<'_>, @@ -499,7 +499,7 @@ fn find_adjustments( } #[allow(clippy::needless_pass_by_value)] -fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) { +fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) { match state { State::DerefMethod { ty_changed_count, @@ -568,7 +568,7 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat } impl Dereferencing { - fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) { + fn check_local_usage(&mut self, cx: &LateContext<'_>, e: &Expr<'_>, local: HirId) { if let Some(outer_pat) = self.ref_locals.get_mut(&local) { if let Some(pat) = outer_pat { // Check for auto-deref diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 3d92eb16870..3ce239273e2 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -233,7 +233,7 @@ struct ContainsExpr<'tcx> { key: &'tcx Expr<'tcx>, call_ctxt: SyntaxContext, } -fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> { +fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> { let mut negated = false; let expr = peel_hir_expr_while(expr, |e| match e.kind { ExprKind::Unary(UnOp::Not, e) => { @@ -280,7 +280,7 @@ struct InsertExpr<'tcx> { key: &'tcx Expr<'tcx>, value: &'tcx Expr<'tcx>, } -fn try_parse_insert(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { +fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { if let ExprKind::MethodCall(_, _, [map, key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) { @@ -301,7 +301,7 @@ enum Edit<'tcx> { /// An insertion into the map. Insertion(Insertion<'tcx>), } -impl Edit<'tcx> { +impl<'tcx> Edit<'tcx> { fn as_insertion(self) -> Option> { if let Self::Insertion(i) = self { Some(i) } else { None } } @@ -532,7 +532,7 @@ struct InsertSearchResults<'tcx> { allow_insert_closure: bool, is_single_insert: bool, } -impl InsertSearchResults<'tcx> { +impl<'tcx> InsertSearchResults<'tcx> { fn as_single_insertion(&self) -> Option> { self.is_single_insert.then(|| self.edits[0].as_insertion().unwrap()) } @@ -633,7 +633,7 @@ impl InsertSearchResults<'tcx> { } } -fn find_insert_calls( +fn find_insert_calls<'tcx>( cx: &LateContext<'tcx>, contains_expr: &ContainsExpr<'tcx>, expr: &'tcx Expr<'_>, diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 06d128f5527..cf47e581ccb 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { } } -fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool { +fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool { if let Some(def_id) = cx.tcx.lang_items().eq_trait() { implements_trait(cx, ty, def_id, &[other.into()]) } else { diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index bb6acd8c5dd..c1a84973c42 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -50,13 +50,19 @@ impl<'tcx> LateLintPass<'tcx> for ErasingOp { } } -fn different_types(tck: &TypeckResults<'tcx>, input: &'tcx Expr<'_>, output: &'tcx Expr<'_>) -> bool { +fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool { let input_ty = tck.expr_ty(input).peel_refs(); let output_ty = tck.expr_ty(output).peel_refs(); !same_type_and_consts(input_ty, output_ty) } -fn check(cx: &LateContext<'cx>, tck: &TypeckResults<'cx>, op: &Expr<'cx>, other: &Expr<'cx>, parent: &Expr<'cx>) { +fn check<'tcx>( + cx: &LateContext<'tcx>, + tck: &TypeckResults<'tcx>, + op: &Expr<'tcx>, + other: &Expr<'tcx>, + parent: &Expr<'tcx>, +) { if constant_simple(cx, tck, op) == Some(Constant::Int(0)) { if different_types(tck, other, parent) { return; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 866ff216f84..5ece2cc5ac4 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -53,7 +53,7 @@ impl FromOverInto { impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); -impl LateLintPass<'_> for FromOverInto { +impl<'tcx> LateLintPass<'tcx> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) { return; diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 73e800073b0..57b07513205 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]); -impl LateLintPass<'tcx> for FromStrRadix10 { +impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { if_chain! { if let ExprKind::Call(maybe_path, arguments) = &exp.kind; diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 77d08081c07..f2b4aefaead 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -18,7 +18,7 @@ use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; -pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { +pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = must_use_attr(attrs); if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind { @@ -40,7 +40,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { } } -pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { +pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -62,7 +62,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem< } } -pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { +pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind { let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index f83789bb219..6d829a18b2e 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -9,7 +9,7 @@ use clippy_utils::{iter_input_pats, path_to_local}; use super::NOT_UNSAFE_PTR_ARG_DEREF; -pub(super) fn check_fn( +pub(super) fn check_fn<'tcx>( cx: &LateContext<'tcx>, kind: intravisit::FnKind<'tcx>, decl: &'tcx hir::FnDecl<'tcx>, @@ -25,14 +25,14 @@ pub(super) fn check_fn( check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id)); } -pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { +pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind { let body = cx.tcx.hir().body(eid); check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id); } } -fn check_raw_ptr( +fn check_raw_ptr<'tcx>( cx: &LateContext<'tcx>, unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl<'tcx>, diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs index 71f6f87ae60..73f08a04989 100644 --- a/clippy_lints/src/functions/result_unit_err.rs +++ b/clippy_lints/src/functions/result_unit_err.rs @@ -13,7 +13,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use super::RESULT_UNIT_ERR; -pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { +pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind { let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -23,7 +23,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { } } -pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { +pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) { if let hir::ImplItemKind::Fn(ref sig, _) = item.kind { let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -33,7 +33,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem< } } -pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { +pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs index 63a14d8d4cd..3af960491ed 100644 --- a/clippy_lints/src/functions/too_many_arguments.rs +++ b/clippy_lints/src/functions/too_many_arguments.rs @@ -9,9 +9,9 @@ use clippy_utils::is_trait_impl_item; use super::TOO_MANY_ARGUMENTS; pub(super) fn check_fn( - cx: &LateContext<'tcx>, - kind: intravisit::FnKind<'tcx>, - decl: &'tcx hir::FnDecl<'_>, + cx: &LateContext<'_>, + kind: intravisit::FnKind<'_>, + decl: &hir::FnDecl<'_>, span: Span, hir_id: hir::HirId, too_many_arguments_threshold: u64, @@ -39,11 +39,7 @@ pub(super) fn check_fn( } } -pub(super) fn check_trait_item( - cx: &LateContext<'tcx>, - item: &'tcx hir::TraitItem<'_>, - too_many_arguments_threshold: u64, -) { +pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { // don't lint extern functions decls, it's not their fault if sig.header.abi == Abi::Rust { diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 65efbbab41a..54bdea7ea25 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -11,9 +11,9 @@ use super::TOO_MANY_LINES; pub(super) fn check_fn( cx: &LateContext<'_>, - kind: FnKind<'tcx>, + kind: FnKind<'_>, span: Span, - body: &'tcx hir::Body<'_>, + body: &hir::Body<'_>, too_many_lines_threshold: u64, ) { // Closures must be contained in a parent body, which will be checked for `too_many_lines`. diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 16e5c5ca603..9525c163ece 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -55,7 +55,7 @@ impl IfThenSomeElseNone { impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); -impl LateLintPass<'_> for IfThenSomeElseNone { +impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) { return; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 07caeada80d..d650d6e9a85 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -94,8 +94,8 @@ fn get_call_site(span: Span, ctxt: SyntaxContext) -> Option { } fn lint_implicit_returns( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, + cx: &LateContext<'_>, + expr: &Expr<'_>, // The context of the function body. ctxt: SyntaxContext, // Whether the expression is from a macro expansion. diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 1debdef9d86..9e03065e7fb 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -63,7 +63,7 @@ declare_clippy_lint! { declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]); -impl LateLintPass<'_> for InconsistentStructConstructor { +impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { if !expr.span.from_expansion(); diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 69f1c90beec..073313e2bad 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -69,7 +69,7 @@ impl IndexRefutableSlice { impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); -impl LateLintPass<'_> for IndexRefutableSlice { +impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 017a8a779d9..d3bdc819a9f 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]); -impl LateLintPass<'_> for IterNotReturningIterator { +impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { let name = item.ident.name.as_str(); if matches!(name, "iter" | "iter_mut") { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 20e6220ec7d..265c24b1c97 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -245,7 +245,7 @@ enum LenOutput<'tcx> { Option(DefId), Result(DefId, Ty<'tcx>), } -fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option> { +fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option> { match *sig.output().kind() { ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral), ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d765c2bcde..175a35e7994 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -4,7 +4,6 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(drain_filter)] -#![feature(in_band_lifetimes)] #![feature(iter_intersperse)] #![feature(let_else)] #![feature(once_cell)] diff --git a/clippy_lints/src/loops/empty_loop.rs b/clippy_lints/src/loops/empty_loop.rs index dda09fecdf9..823cf0f4322 100644 --- a/clippy_lints/src/loops/empty_loop.rs +++ b/clippy_lints/src/loops/empty_loop.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_in_panic_handler, is_no_std_crate}; use rustc_hir::{Block, Expr}; use rustc_lint::LateContext; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, loop_block: &Block<'_>) { if loop_block.stmts.is_empty() && loop_block.expr.is_none() && !is_in_panic_handler(cx, expr) { let msg = "empty `loop {}` wastes CPU cycles"; let help = if is_no_std_crate(cx) { diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index 1bab0d99b69..17246cc5426 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -8,7 +8,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::TyS; use rustc_span::symbol::sym; -pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) { let self_ty = cx.typeck_results().expr_ty(self_arg); let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); if !(TyS::same_type(self_ty, self_ty_adjusted) && is_trait_method(cx, call_expr, sym::IntoIterator)) { diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index c62fa5e998b..c439f701da1 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -203,7 +203,7 @@ fn build_manual_memcpy_suggestion<'tcx>( #[derive(Clone)] struct MinifyingSugg<'a>(Sugg<'a>); -impl Display for MinifyingSugg<'a> { +impl<'a> Display for MinifyingSugg<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index aedf0844937..37a57d8feb1 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -147,7 +147,7 @@ impl BreakAfterExprVisitor { } } -impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor { +impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index ba895f35faa..6248680aa62 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -339,8 +339,8 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>( } } -fn get_captured_ids(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>) -> HirIdSet { - fn get_captured_ids_recursive(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>, set: &mut HirIdSet) { +fn get_captured_ids(cx: &LateContext<'_>, ty: &'_ TyS<'_>) -> HirIdSet { + fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: &'_ TyS<'_>, set: &mut HirIdSet) { match ty.kind() { ty::Adt(_, generics) => { for generic in *generics { diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index a3aa6be6afd..bb1b3e2a1ec 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -10,8 +10,8 @@ use rustc_span::Span; use std::iter::{once, Iterator}; pub(super) fn check( - cx: &LateContext<'tcx>, - block: &'tcx Block<'_>, + cx: &LateContext<'_>, + block: &Block<'_>, loop_id: HirId, span: Span, for_loop: Option<&ForLoop<'_>>, diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index 4dcd5c87722..8f57df0be6b 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -7,7 +7,7 @@ use rustc_hir::{Block, Expr, ExprKind, MatchSource, Pat, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { // extract the expression from the first statement (if any) in a block let inner_stmt_expr = extract_expr_from_first_stmt(loop_block); // or extract the first expression (if any) from the block diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 942d6ca6b4a..750328d1d01 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -13,7 +13,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::{symbol::sym, Symbol}; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! { if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr); // check for `Some(..)` pattern @@ -191,7 +191,7 @@ fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fie /// Strips off all field and path expressions. This will return true if a field or path has been /// skipped. Used to skip them after failing to check for equality. -fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) { +fn skip_fields_and_path<'tcx>(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) { let mut e = expr; let e = loop { match e.kind { @@ -204,13 +204,13 @@ fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool } /// Checks if the given expression uses the iterator. -fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool { +fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool { struct V<'a, 'b, 'tcx> { cx: &'a LateContext<'tcx>, iter_expr: &'b IterExpr, uses_iter: bool, } - impl Visitor<'tcx> for V<'_, '_, 'tcx> { + impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> { type Map = ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None @@ -245,7 +245,7 @@ fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr } #[allow(clippy::too_many_lines)] -fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool { +fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool { struct AfterLoopVisitor<'a, 'b, 'tcx> { cx: &'a LateContext<'tcx>, iter_expr: &'b IterExpr, @@ -253,7 +253,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: after_loop: bool, used_iter: bool, } - impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> { + impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> { type Map = ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None @@ -292,7 +292,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: found_local: bool, used_after: bool, } - impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { + impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { type Map = ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index e3a34b22e32..26b53ab5d68 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]); -impl LateLintPass<'_> for ManualAssert { +impl<'tcx> LateLintPass<'tcx> for ManualAssert { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if_chain! { if let ExprKind::If(cond, then, None) = expr.kind; diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 34a70ca76c6..8475e367b09 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { declare_lint_pass!(ManualMap => [MANUAL_MAP]); -impl LateLintPass<'_> for ManualMap { +impl<'tcx> LateLintPass<'tcx> for ManualMap { #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) { @@ -219,7 +219,7 @@ impl LateLintPass<'_> for ManualMap { // Checks whether the expression could be passed as a function, or whether a closure is needed. // Returns the function to be passed to `map` if it exists. -fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { +fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { match expr.kind { ExprKind::Call(func, [arg]) if path_to_local_id(arg, binding) @@ -251,8 +251,13 @@ struct SomeExpr<'tcx> { // Try to parse into a recognized `Option` pattern. // i.e. `_`, `None`, `Some(..)`, or a reference to any of those. -fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option> { - fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxContext) -> Option> { +fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option> { + fn f<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + ref_count: usize, + ctxt: SyntaxContext, + ) -> Option> { match pat.kind { PatKind::Wild => Some(OptionPat::Wild), PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt), @@ -269,7 +274,7 @@ fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxCon } // Checks for an expression wrapped by the `Some` constructor. Returns the contained expression. -fn get_some_expr( +fn get_some_expr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, needs_unsafe_block: bool, @@ -306,6 +311,6 @@ fn get_some_expr( } // Checks for the `None` value. -fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { +fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) } diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index b60e2dc366b..bd083e3e9e2 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]); -impl LateLintPass<'_> for ManualOkOr { +impl<'tcx> LateLintPass<'tcx> for ManualOkOr { fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) { if in_external_macro(cx.sess(), scrutinee.span) { return; diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index aac3c6e0de2..b3a91d9f18f 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]); -impl LateLintPass<'_> for ManualUnwrapOr { +impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOr { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) { return; diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs index 2c0fc218ca0..1fc7eb72142 100644 --- a/clippy_lints/src/match_str_case_mismatch.rs +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -55,7 +55,7 @@ enum CaseMethod { AsciiUppercase, } -impl LateLintPass<'_> for MatchStrCaseMismatch { +impl<'tcx> LateLintPass<'tcx> for MatchStrCaseMismatch { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, expr.span); diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 0d693499bc6..66c1886710f 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -999,7 +999,7 @@ enum CommonPrefixSearcher<'a> { Path(&'a [PathSegment<'a>]), Mixed, } -impl CommonPrefixSearcher<'a> { +impl<'a> CommonPrefixSearcher<'a> { fn with_path(&mut self, path: &'a [PathSegment<'a>]) { match path { [path @ .., _] => self.with_prefix(path), @@ -1804,11 +1804,15 @@ mod redundant_pattern_match { /// Checks if the drop order for a type matters. Some std types implement drop solely to /// deallocate memory. For these types, and composites containing them, changing the drop order /// won't result in any observable side effects. - fn type_needs_ordered_drop(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + fn type_needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default()) } - fn type_needs_ordered_drop_inner(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { + fn type_needs_ordered_drop_inner<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + seen: &mut FxHashSet>, + ) -> bool { if !seen.insert(ty) { return false; } @@ -1870,7 +1874,7 @@ mod redundant_pattern_match { // Checks if there are any temporaries created in the given expression for which drop order // matters. - fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { struct V<'a, 'tcx> { cx: &'a LateContext<'tcx>, res: bool, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 866eaff5b1d..0f39470f342 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -14,7 +14,7 @@ use super::EXPECT_FUN_CALL; /// Checks for the `EXPECT_FUN_CALL` lint. #[allow(clippy::too_many_lines)] -pub(super) fn check( +pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_span: Span, diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 8ea9312c0f7..6436e28a63c 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp } } -fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { +fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> String { fn strip_angle_brackets(s: &str) -> Option<&str> { s.strip_prefix('<')?.strip_suffix('>') } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 70f20da1d6d..514bdadc442 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -124,7 +124,7 @@ struct IterUsage { } #[allow(clippy::too_many_lines)] -fn parse_iter_usage( +fn parse_iter_usage<'tcx>( cx: &LateContext<'tcx>, ctxt: SyntaxContext, mut iter: impl Iterator)>, @@ -281,7 +281,7 @@ pub(super) fn check_needless_splitn( } } -fn check_iter( +fn check_iter<'tcx>( cx: &LateContext<'tcx>, ctxt: SyntaxContext, mut iter: impl Iterator)>, diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 4f589a6d318..5999245ea7d 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -12,7 +12,7 @@ use rustc_span::{sym, Symbol}; use super::UNNECESSARY_TO_OWNED; -pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) -> bool { +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if_chain! { if let Some(parent) = get_parent_expr(cx, expr); if let Some(callee_def_id) = fn_def_id(cx, parent); @@ -30,10 +30,10 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol /// include this code directly is so that it can be called from /// `unnecessary_into_owned::check_into_iter_call_arg`. pub fn check_for_loop_iter( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, + cx: &LateContext<'_>, + expr: &Expr<'_>, method_name: Symbol, - receiver: &'tcx Expr<'tcx>, + receiver: &Expr<'_>, cloned_before_iter: bool, ) -> bool { if_chain! { @@ -101,7 +101,7 @@ pub fn check_for_loop_iter( /// The core logic of `check_for_loop_iter` above, this function wraps a use of /// `CloneOrCopyVisitor`. -fn clone_or_copy_needed( +fn clone_or_copy_needed<'tcx>( cx: &LateContext<'tcx>, pat: &Pat<'tcx>, body: &'tcx Expr<'tcx>, diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 7e17f163b21..e5b6d296b2d 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -16,7 +16,7 @@ use std::cmp::max; use super::UNNECESSARY_TO_OWNED; -pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) { +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let [receiver] = args; @@ -44,11 +44,11 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol /// call of a `to_owned`-like function is unnecessary. #[allow(clippy::too_many_lines)] fn check_addr_of_expr( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, + cx: &LateContext<'_>, + expr: &Expr<'_>, method_name: Symbol, method_def_id: DefId, - receiver: &'tcx Expr<'tcx>, + receiver: &Expr<'_>, ) -> bool { if_chain! { if let Some(parent) = get_parent_expr(cx, expr); @@ -171,12 +171,7 @@ fn check_addr_of_expr( /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. -fn check_into_iter_call_arg( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, - method_name: Symbol, - receiver: &'tcx Expr<'tcx>, -) -> bool { +fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if_chain! { if let Some(parent) = get_parent_expr(cx, expr); if let Some(callee_def_id) = fn_def_id(cx, parent); @@ -221,7 +216,7 @@ fn check_into_iter_call_arg( /// Checks whether `expr` is an argument in a function call and, if so, determines whether its call /// of a `to_owned`-like function is unnecessary. -fn check_other_call_arg( +fn check_other_call_arg<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, @@ -287,7 +282,7 @@ fn check_other_call_arg( /// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such /// expression found (if any) along with the immediately prior expression. -fn skip_addr_of_ancestors( +fn skip_addr_of_ancestors<'tcx>( cx: &LateContext<'tcx>, mut expr: &'tcx Expr<'tcx>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { @@ -303,7 +298,7 @@ fn skip_addr_of_ancestors( /// Checks whether an expression is a function or method call and, if so, returns its `DefId`, /// `Substs`, and arguments. -fn get_callee_substs_and_args( +fn get_callee_substs_and_args<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, ) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> { @@ -328,7 +323,7 @@ fn get_callee_substs_and_args( } /// Returns the `TraitPredicate`s and `ProjectionPredicate`s for a function's input type. -fn get_input_traits_and_projections( +fn get_input_traits_and_projections<'tcx>( cx: &LateContext<'tcx>, callee_def_id: DefId, input: Ty<'tcx>, @@ -368,7 +363,11 @@ fn get_input_traits_and_projections( } /// Composes two substitutions by applying the latter to the types of the former. -fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: SubstsRef<'tcx>) -> Vec> { +fn compose_substs<'tcx>( + cx: &LateContext<'tcx>, + left: &[GenericArg<'tcx>], + right: SubstsRef<'tcx>, +) -> Vec> { left.iter() .map(|arg| { if let GenericArgKind::Type(arg_ty) = arg.unpack() { diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 401dc27811d..21b3f81d5d9 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -717,7 +717,7 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) } } -fn check_binary( +fn check_binary<'a>( cx: &LateContext<'a>, expr: &Expr<'_>, cmp: &rustc_span::source_map::Spanned, diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 0c1da035173..19d58f7474b 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -48,7 +48,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]); -impl LateLintPass<'_> for NeedlessForEach { +impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { let expr = match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr, diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 094a3f111ba..9957afcbf04 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -330,7 +330,7 @@ fn check<'tcx>( Some(()) } -impl LateLintPass<'tcx> for NeedlessLateInit { +impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { let mut parents = cx.tcx.hir().parent_iter(local.hir_id); diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 9d5babc5de8..5bf8a1ba1ca 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { } } -fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> bool { +fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { if let StmtKind::Semi(expr) = stmt.kind { if has_no_effect(cx, expr) { span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); @@ -155,7 +155,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } } -fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { +fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if_chain! { if let StmtKind::Semi(expr) = stmt.kind; if let Some(reduced) = reduce_expression(cx, expr); diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 4b57dbc4c41..e46fee4cac5 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]); -impl LateLintPass<'_> for NonOctalUnixPermissions { +impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { ExprKind::MethodCall(path, _, [func, param], _) => { diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 9c971437645..e0da12f77fc 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]); impl EarlyLintPass for OctalEscapes { - fn check_expr(&mut self, cx: &EarlyContext<'tcx>, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if in_external_macro(cx.sess, expr.span) { return; } @@ -65,7 +65,7 @@ impl EarlyLintPass for OctalEscapes { } } -fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) { +fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { let contents = lit.symbol.as_str(); let mut iter = contents.char_indices().peekable(); let mut found = vec![]; diff --git a/clippy_lints/src/ptr_eq.rs b/clippy_lints/src/ptr_eq.rs index 3c126fc1ca6..2bec93ac606 100644 --- a/clippy_lints/src/ptr_eq.rs +++ b/clippy_lints/src/ptr_eq.rs @@ -39,7 +39,7 @@ declare_lint_pass!(PtrEq => [PTR_EQ]); static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; -impl LateLintPass<'_> for PtrEq { +impl<'tcx> LateLintPass<'tcx> for PtrEq { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.from_expansion() { return; diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index b2bd0103d11..7c88b42ea31 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -42,7 +42,7 @@ declare_clippy_lint! { declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]); -impl LateLintPass<'_> for RedundantSlicing { +impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.from_expansion() { return; diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 935bbc37d75..5dafd08cf3b 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]); -fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalDefId, span: Span, hir_id: HirId) { +fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) { if_chain! { // If it comes from an external macro, better ignore it. if !in_external_macro(cx.sess(), span); diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 0b3bbbc8155..729694da46d 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]); -impl LateLintPass<'_> for SemicolonIfNothingReturned { +impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if_chain! { if !block.span.from_expansion(); diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index df1e85afdd7..9b195f3c0a2 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); -fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option> { +fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option> { match expr.kind { ExprKind::Call(count_func, _func_args) => { if_chain! { @@ -64,7 +64,10 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) } } -fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { +fn get_pointee_ty_and_count_expr<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, +) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { const FUNCTIONS: [&[&str]; 8] = [ &paths::PTR_COPY_NONOVERLAPPING, &paths::PTR_COPY, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index ad8e72ad764..b4a71aefd43 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -381,7 +381,7 @@ declare_clippy_lint! { declare_lint_pass!(StrToString => [STR_TO_STRING]); -impl LateLintPass<'_> for StrToString { +impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; @@ -431,7 +431,7 @@ declare_clippy_lint! { declare_lint_pass!(StringToString => [STRING_TO_STRING]); -impl LateLintPass<'_> for StringToString { +impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind; diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index fee01fb0bd1..d6e948a7560 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]); -impl LateLintPass<'tcx> for StrlenOnCStrings { +impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if !expr.span.from_expansion(); diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index faf43fd9fc1..ca725918e87 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -355,7 +355,7 @@ struct BinaryOp<'exprs> { right: &'exprs Expr, } -impl BinaryOp<'exprs> { +impl<'exprs> BinaryOp<'exprs> { fn new(op: BinOpKind, span: Span, (left, right): (&'exprs Expr, &'exprs Expr)) -> Self { Self { op, span, left, right } } @@ -419,7 +419,7 @@ fn chained_binops(kind: &ExprKind) -> Option>> { } } -fn chained_binops_helper(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option>> { +fn chained_binops_helper<'expr>(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option>> { match (&left_outer.kind, &right_outer.kind) { ( ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e), diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 47c0a84cd46..bf1cbf4f692 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { } } -fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { +fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool { if_chain! { // First check if last field is an array if let ItemKind::Struct(data, _) = &item.kind; diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 3d3b4a6679d..697ed267e2f 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -113,8 +113,8 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks { } } -impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks { - type Map = Map<'hir>; +impl<'v> Visitor<'v> for UndocumentedUnsafeBlocks { + type Map = Map<'v>; fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index c58fa67a023..7557e14d11f 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]); -impl LateLintPass<'tcx> for UndroppedManuallyDrops { +impl<'tcx> LateLintPass<'tcx> for UndroppedManuallyDrops { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some([arg_0, ..]) = match_function_call(cx, expr, &paths::DROP) { let ty = cx.typeck_results().expr_ty(arg_0); diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 46cc76b150e..2ffaf24f942 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for UninitVec { } } -fn handle_uninit_vec_pair( +fn handle_uninit_vec_pair<'tcx>( cx: &LateContext<'tcx>, maybe_init_or_reserve: &'tcx Stmt<'tcx>, maybe_set_len: &'tcx Expr<'tcx>, @@ -196,7 +196,7 @@ fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_> } /// Returns self if the expression is `Vec::set_len()` -fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> { +fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> { // peel unsafe blocks in `unsafe { vec.set_len() }` let expr = peel_hir_expr_while(expr, |e| { if let ExprKind::Block(block, _) = e.kind { diff --git a/clippy_lints/src/unit_hash.rs b/clippy_lints/src/unit_hash.rs index 26b4e0f58a8..dcf8a9d7c84 100644 --- a/clippy_lints/src/unit_hash.rs +++ b/clippy_lints/src/unit_hash.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { } declare_lint_pass!(UnitHash => [UNIT_HASH]); -impl LateLintPass<'tcx> for UnitHash { +impl<'tcx> LateLintPass<'tcx> for UnitHash { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 02f5d45cc18..4e46d79dc08 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -577,7 +577,7 @@ fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String { fn get_lint_group_and_level_or_lint( cx: &LateContext<'_>, lint_name: &str, - item: &'hir Item<'_>, + item: &Item<'_>, ) -> Option<(String, &'static str)> { let result = cx .lint_store @@ -696,20 +696,20 @@ fn extract_emission_info<'hir>( } /// Resolves the possible lints that this expression could reference -fn resolve_lints(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec { +fn resolve_lints<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec { let mut resolver = LintResolver::new(cx); resolver.visit_expr(expr); resolver.lints } /// This function tries to resolve the linked applicability to the given expression. -fn resolve_applicability(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option { +fn resolve_applicability<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option { let mut resolver = ApplicabilityResolver::new(cx); resolver.visit_expr(expr); resolver.complete() } -fn check_is_multi_part(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool { +fn check_is_multi_part<'hir>(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool { if let ExprKind::Closure(_, _, body_id, _, _) = closure_expr.kind { let mut scanner = IsMultiSpanScanner::new(cx); intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body_id)); @@ -824,7 +824,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { } /// This returns the parent local node if the expression is a reference one -fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> { +fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> { if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { if let hir::def::Res::Local(local_hir) = path.res { return get_parent_local_hir_id(cx, local_hir); @@ -834,7 +834,7 @@ fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Opti None } -fn get_parent_local_hir_id(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { +fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { let map = cx.tcx.hir(); match map.find(map.get_parent_node(hir_id)) { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 1bc0eb6303c..43474da3450 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -77,7 +77,7 @@ impl VecPushSearcher { } } -impl LateLintPass<'_> for VecInitThenPush { +impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) { self.searcher = None; } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 5c024612f8e..34c5af848a6 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -223,7 +223,7 @@ pub fn constant_simple<'tcx>( constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) } -pub fn constant_full_int( +pub fn constant_full_int<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 61e529a6079..c3936ec95d4 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -45,7 +45,12 @@ impl ops::BitOrAssign for EagernessSuggestion { } /// Determine the eagerness of the given function call. -fn fn_eagerness(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, args: &'tcx [Expr<'_>]) -> EagernessSuggestion { +fn fn_eagerness<'tcx>( + cx: &LateContext<'tcx>, + fn_id: DefId, + name: Symbol, + args: &'tcx [Expr<'_>], +) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; let name = name.as_str(); @@ -92,7 +97,7 @@ fn fn_eagerness(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, args: &'tcx } #[allow(clippy::too_many_lines)] -fn expr_eagerness(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion { +fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion { struct V<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, eagerness: EagernessSuggestion, @@ -225,11 +230,11 @@ fn expr_eagerness(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggest } /// Whether the given expression should be changed to evaluate eagerly -pub fn switch_to_eager_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { +pub fn switch_to_eager_eval<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { expr_eagerness(cx, expr) == EagernessSuggestion::Eager } /// Whether the given expression should be changed to evaluate lazily -pub fn switch_to_lazy_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { +pub fn switch_to_lazy_eval<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { expr_eagerness(cx, expr) == EagernessSuggestion::Lazy } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 16bcffb8df9..9f2018385f3 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,6 +1,5 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(in_band_lifetimes)] #![feature(let_else)] #![feature(once_cell)] #![feature(rustc_private)] @@ -128,7 +127,7 @@ macro_rules! extract_msrv_attr { extract_msrv_attr!(@EarlyContext); }; (@$context:ident$(, $call:tt)?) => { - fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { use $crate::get_unique_inner_attr; match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") { Some(msrv_attr) => { @@ -277,7 +276,11 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { } /// Checks if the first type parameter is a lang item. -pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> { +pub fn is_ty_param_lang_item<'tcx>( + cx: &LateContext<'_>, + qpath: &QPath<'tcx>, + item: LangItem, +) -> Option<&'tcx hir::Ty<'tcx>> { let ty = get_qpath_generic_tys(qpath).next()?; if let TyKind::Path(qpath) = &ty.kind { @@ -293,7 +296,7 @@ pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: La } /// Checks if the first type parameter is a diagnostic item. -pub fn is_ty_param_diagnostic_item( +pub fn is_ty_param_diagnostic_item<'tcx>( cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: Symbol, @@ -370,7 +373,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { } } -pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> { +pub fn get_qpath_generics<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> { match path { QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args), QPath::TypeRelative(_, s) => s.args, @@ -378,7 +381,7 @@ pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> } } -pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator> { +pub fn get_qpath_generic_tys<'tcx>(path: &QPath<'tcx>) -> impl Iterator> { get_qpath_generics(path) .map_or([].as_ref(), |a| a.args) .iter() @@ -767,7 +770,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// /// Note that this check is not recursive, so passing the `if` expression will always return true /// even though sub-expressions might return false. -pub fn can_move_expr_to_closure_no_visit( +pub fn can_move_expr_to_closure_no_visit<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_ids: &[HirId], @@ -842,7 +845,7 @@ impl std::ops::BitOrAssign for CaptureKind { /// Note as this will walk up to parent expressions until the capture can be determined it should /// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or /// function argument (other than a receiver). -pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind { +pub fn capture_local_usage<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind { fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind { let mut capture = CaptureKind::Ref(Mutability::Not); pat.each_binding_or_first(&mut |_, id, span, _| match cx @@ -942,7 +945,7 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind /// Checks if the expression can be moved into a closure as is. This will return a list of captures /// if so, otherwise, `None`. -pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { +pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { struct V<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, // Stack of potential break targets contained in the expression. @@ -955,7 +958,7 @@ pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> /// mutable reference. captures: HirIdMap, } - impl Visitor<'tcx> for V<'_, 'tcx> { + impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { type Map = ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None @@ -1212,7 +1215,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio } /// Gets the loop or closure enclosing the given expression, if any. -pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { +pub fn get_enclosing_loop_or_closure<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { for (_, node) in tcx.hir().parent_iter(expr.hir_id) { match node { Node::Expr( @@ -1720,7 +1723,7 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool { } /// Peels away all the compiler generated code surrounding the body of an async function, -pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { +pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Call( _, &[ @@ -1824,7 +1827,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } /// Gets the node where an expression is either used, or it's type is unified with another branch. -pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option> { +pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option> { let mut child_id = expr.hir_id; let mut iter = tcx.hir().parent_iter(child_id); loop { @@ -2030,8 +2033,8 @@ where /// Peels off all references on the pattern. Returns the underlying pattern and the number of /// references removed. -pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) { - fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) { +pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) { + fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) { if let PatKind::Ref(pat, _) = pat.kind { peel(pat, count + 1) } else { @@ -2054,7 +2057,7 @@ pub fn peel_hir_expr_while<'tcx>( /// Peels off up to the given number of references on the expression. Returns the underlying /// expression and the number of references removed. -pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) { +pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) { let mut remaining = count; let e = peel_hir_expr_while(expr, |e| match e.kind { ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => { @@ -2068,7 +2071,7 @@ pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, /// Peels off all references on the expression. Returns the underlying expression and the number of /// references removed. -pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { +pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { let mut count = 0; let e = peel_hir_expr_while(expr, |e| match e.kind { ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => { @@ -2151,7 +2154,7 @@ impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> { static TEST_ITEM_NAMES_CACHE: SyncOnceCell>>> = SyncOnceCell::new(); -fn with_test_item_names(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { +fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); let mut map: MutexGuard<'_, FxHashMap>> = cache.lock().unwrap(); match map.entry(module) { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 2bf43aeb995..a3e336d701c 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -283,7 +283,7 @@ fn find_assert_within_debug_assert<'a>( found } -fn is_assert_arg(cx: &LateContext<'_>, expr: &'a Expr<'a>, assert_expn: ExpnId) -> bool { +fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> bool { if !expr.span.from_expansion() { return true; } @@ -322,7 +322,7 @@ pub struct FormatArgsExpn<'tcx> { pub specs: Vec<&'tcx Expr<'tcx>>, } -impl FormatArgsExpn<'tcx> { +impl<'tcx> FormatArgsExpn<'tcx> { /// Parses an expanded `format_args!` or `format_args_nl!` invocation pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { macro_backtrace(expr.span).find(|macro_call| { diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 1a4da1627b7..d6d43e93e7a 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -19,7 +19,7 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -85,7 +85,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&Ru Ok(()) } -fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { +fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { for arg in ty.walk(tcx) { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -133,7 +133,13 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { Ok(()) } -fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult { +fn check_rvalue<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: DefId, + rvalue: &Rvalue<'tcx>, + span: Span, +) -> McfResult { match rvalue { Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body), @@ -211,7 +217,12 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv } } -fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult { +fn check_statement<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: DefId, + statement: &Statement<'tcx>, +) -> McfResult { let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(box (place, rval)) => { @@ -240,7 +251,7 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen } } -fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -250,7 +261,7 @@ fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: & } } -fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { let mut cursor = place.projection.as_ref(); while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; @@ -275,7 +286,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t Ok(()) } -fn check_terminator( +fn check_terminator<'a, 'tcx>( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>, diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index d928317259d..dbad607c58e 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -281,7 +281,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>( /// correctly get a snippet of `vec![]`. /// /// This will also return whether or not the snippet is a macro call. -pub fn snippet_with_context( +pub fn snippet_with_context<'a>( cx: &LateContext<'_>, span: Span, outer: SyntaxContext, diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 92662c59226..87bc8232dde 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -461,7 +461,7 @@ impl Neg for Sugg<'_> { } } -impl Not for Sugg<'a> { +impl<'a> Not for Sugg<'a> { type Output = Sugg<'a>; fn not(self) -> Sugg<'a> { use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual}; @@ -846,7 +846,7 @@ struct DerefDelegate<'a, 'tcx> { applicability: Applicability, } -impl DerefDelegate<'_, 'tcx> { +impl<'tcx> DerefDelegate<'_, 'tcx> { /// build final suggestion: /// - create the ending part of suggestion /// - concatenate starting and ending parts diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 6d191d4a59b..72317447159 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -25,7 +25,7 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } /// Checks whether a type can be partially moved. -pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { +pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if has_drop(cx, ty) || is_copy(cx, ty) { return false; } @@ -366,7 +366,7 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { /// Returns `true` if types `a` and `b` are same types having same `Const` generic args, /// otherwise returns `false` -pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { +pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.kind(), &b.kind()) { (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => { if did_a != did_b { diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 4bfd3c64b9c..b60cd4736f3 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -173,7 +173,7 @@ pub trait Visitable<'tcx> { } macro_rules! visitable_ref { ($t:ident, $f:ident) => { - impl Visitable<'tcx> for &'tcx $t<'tcx> { + impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { fn visit>(self, visitor: &mut V) { visitor.$f(self); } @@ -217,7 +217,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { } /// Checks if the given local is used. -pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { +pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { let mut is_used = false; let mut visitor = expr_visitor(cx, |expr| { if !is_used { @@ -231,7 +231,7 @@ pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id } /// Checks if the given expression is a constant. -pub fn is_const_evaluatable(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { +pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { struct V<'a, 'tcx> { cx: &'a LateContext<'tcx>, is_const: bool, @@ -321,7 +321,7 @@ pub fn is_const_evaluatable(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { } /// Checks if the given expression performs an unsafe operation outside of an unsafe block. -pub fn is_expr_unsafe(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { +pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { struct V<'a, 'tcx> { cx: &'a LateContext<'tcx>, is_unsafe: bool, diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index c7e51d53f51..207b0be1548 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -60,7 +60,7 @@ Two noticeable items here: Starting with an `expr`, you can check whether it is calling a specific method `some_method`: ```rust -impl LateLintPass<'_> for MyStructLint { +impl<'tcx> LateLintPass<'tcx> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { // Check our expr is calling a method -- cgit 1.4.1-3-g733a5 From ad95279c34272949d6babc31d54209434a97f46e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 5 Jan 2022 18:27:10 -0500 Subject: Suggest deref when needed in `implicit_clone` --- clippy_lints/src/methods/implicit_clone.rs | 21 ++++++++---- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/implicit_clone.rs | 9 +++++ tests/ui/implicit_clone.stderr | 54 ++++++++++++++++++------------ 4 files changed, 58 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 90492ffda3c..865e7702b71 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,31 +1,40 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::ty::peel_mid_ty_refs; use clippy_utils::{is_diag_item_method, is_diag_trait_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::TyS; -use rustc_span::{sym, Span}; +use rustc_span::sym; use super::IMPLICIT_CLONE; -pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) { +pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if is_clone_like(cx, method_name, method_def_id); let return_type = cx.typeck_results().expr_ty(expr); - let input_type = cx.typeck_results().expr_ty(recv).peel_refs(); + let input_type = cx.typeck_results().expr_ty(recv); + let (input_type, ref_count) = peel_mid_ty_refs(input_type); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); if TyS::same_type(return_type, input_type); then { + let mut app = Applicability::MachineApplicable; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, IMPLICIT_CLONE, - span, + expr.span, &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name), "consider using", - "clone".to_string(), - Applicability::MachineApplicable + if ref_count > 1 { + format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip) + } else { + format!("{}.clone()", recv_snip) + }, + app, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8a2a468c852..ae5bfadbc5f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2342,7 +2342,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { - implicit_clone::check(cx, name, expr, recv, span); + implicit_clone::check(cx, name, expr, recv); }, ("unwrap", []) => match method_call!(recv) { Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index cef71cf79d7..639fecb8927 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -105,4 +105,13 @@ fn main() { let os_str = OsStr::new("foo"); let _ = os_str.to_owned(); let _ = os_str.to_os_string(); + + // issue #8227 + let pathbuf_ref = &pathbuf; + let pathbuf_ref = &pathbuf_ref; + let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf` + let _ = pathbuf_ref.to_path_buf(); + let pathbuf_ref = &pathbuf_ref; + let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf` + let _ = pathbuf_ref.to_path_buf(); } diff --git a/tests/ui/implicit_clone.stderr b/tests/ui/implicit_clone.stderr index e6f7527b672..0f412424190 100644 --- a/tests/ui/implicit_clone.stderr +++ b/tests/ui/implicit_clone.stderr @@ -1,64 +1,76 @@ error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:65:17 + --> $DIR/implicit_clone.rs:65:13 | LL | let _ = vec.to_owned(); - | ^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^ help: consider using: `vec.clone()` | = note: `-D clippy::implicit-clone` implied by `-D warnings` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type - --> $DIR/implicit_clone.rs:66:17 + --> $DIR/implicit_clone.rs:66:13 | LL | let _ = vec.to_vec(); - | ^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^ help: consider using: `vec.clone()` error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:70:21 + --> $DIR/implicit_clone.rs:70:13 | LL | let _ = vec_ref.to_owned(); - | ^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type - --> $DIR/implicit_clone.rs:71:21 + --> $DIR/implicit_clone.rs:71:13 | LL | let _ = vec_ref.to_vec(); - | ^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()` error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:83:17 + --> $DIR/implicit_clone.rs:83:13 | LL | let _ = str.to_owned(); - | ^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^ help: consider using: `str.clone()` error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:87:20 + --> $DIR/implicit_clone.rs:87:13 | LL | let _ = kitten.to_owned(); - | ^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^^ help: consider using: `kitten.clone()` error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:97:21 + --> $DIR/implicit_clone.rs:97:13 | LL | let _ = pathbuf.to_owned(); - | ^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> $DIR/implicit_clone.rs:98:21 + --> $DIR/implicit_clone.rs:98:13 | LL | let _ = pathbuf.to_path_buf(); - | ^^^^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()` error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:101:23 + --> $DIR/implicit_clone.rs:101:13 | LL | let _ = os_string.to_owned(); - | ^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()` error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type - --> $DIR/implicit_clone.rs:102:23 + --> $DIR/implicit_clone.rs:102:13 | LL | let _ = os_string.to_os_string(); - | ^^^^^^^^^^^^ help: consider using: `clone` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()` -error: aborting due to 10 previous errors +error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type + --> $DIR/implicit_clone.rs:113:13 + | +LL | let _ = pathbuf_ref.to_path_buf(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(*pathbuf_ref).clone()` + +error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type + --> $DIR/implicit_clone.rs:116:13 + | +LL | let _ = pathbuf_ref.to_path_buf(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()` + +error: aborting due to 12 previous errors -- cgit 1.4.1-3-g733a5 From ee84ac3396d9ea09c2160ff892cd297ef1b2ea70 Mon Sep 17 00:00:00 2001 From: Marek Downar Date: Sat, 15 Jan 2022 15:51:46 +0100 Subject: issue #8239: Printed hint for lint or_fun_call is cropped and does not show the solution --- clippy_lints/src/methods/or_fun_call.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 4e4653dadca..6fb67ff89c3 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -4,6 +4,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_mac use clippy_utils::ty::{implements_trait, match_type}; use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths}; use if_chain::if_chain; +use rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -52,16 +53,24 @@ pub(super) fn check<'tcx>( then { let mut applicability = Applicability::MachineApplicable; + let hint = ".unwrap_or_default()"; + let mut sugg: String = format!( + "{}{}", + snippet_with_applicability(cx, self_expr.span, "..", &mut applicability), + hint + ); + + if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES { + sugg = hint.to_string(); + } + span_lint_and_sugg( cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - format!( - "{}.unwrap_or_default()", - snippet_with_applicability(cx, self_expr.span, "..", &mut applicability) - ), + sugg, applicability, ); -- cgit 1.4.1-3-g733a5 From 49502727e7db97055d04c7f06e04b73b05fdb7e2 Mon Sep 17 00:00:00 2001 From: Marek Downar Date: Sat, 15 Jan 2022 22:19:01 +0100 Subject: issue #8239: fix to prev commit && 4 test cases --- clippy_lints/src/methods/or_fun_call.rs | 13 +++++--- tests/ui/or_fun_call.fixed | 48 +++++++++++++++++++++++++++++ tests/ui/or_fun_call.rs | 50 ++++++++++++++++++++++++++++++ tests/ui/or_fun_call.stderr | 54 ++++++++++++++++++++++++++++++++- 4 files changed, 160 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6fb67ff89c3..c35a2e57a66 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -24,6 +24,7 @@ pub(super) fn check<'tcx>( args: &'tcx [hir::Expr<'_>], ) { /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, name: &str, @@ -32,6 +33,7 @@ pub(super) fn check<'tcx>( arg: &hir::Expr<'_>, or_has_args: bool, span: Span, + method_span: Span, ) -> bool { let is_default_default = || is_trait_item(cx, fun, sym::Default); @@ -53,21 +55,24 @@ pub(super) fn check<'tcx>( then { let mut applicability = Applicability::MachineApplicable; - let hint = ".unwrap_or_default()"; + let hint = "unwrap_or_default()"; + let mut shrink = span; + let mut sugg: String = format!( - "{}{}", + "{}.{}", snippet_with_applicability(cx, self_expr.span, "..", &mut applicability), hint ); if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES { + shrink = method_span.with_hi(span.hi()); sugg = hint.to_string(); } span_lint_and_sugg( cx, OR_FUN_CALL, - span, + shrink, &format!("use of `{}` followed by a call to `{}`", name, path), "try this", sugg, @@ -173,7 +178,7 @@ pub(super) fn check<'tcx>( match inner_arg.kind { hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) { + if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span, method_span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span); } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 87cdb3ace47..fe8f5c9fc62 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -176,4 +176,52 @@ mod issue6675 { } } +mod issue8239 { + unsafe fn more_than_max_suggestion_highest_lines_0() { + let frames = Vec::new(); + frames + .iter() + .map(|f: &String| f.to_lowercase()) + .reduce(|mut acc, f| { + acc.push_str(&f); + acc + }) + .unwrap_or_default(); + } + + unsafe fn more_to_max_suggestion_highest_lines_1() { + let frames = Vec::new(); + let iter = frames.iter(); + iter.map(|f: &String| f.to_lowercase()) + .reduce(|mut acc, f| { + let _ = ""; + let _ = ""; + acc.push_str(&f); + acc + }) + .unwrap_or_default(); + } + + unsafe fn equal_to_max_suggestion_highest_lines() { + let frames = Vec::new(); + let iter = frames.iter(); + iter.map(|f: &String| f.to_lowercase()) + .reduce(|mut acc, f| { + let _ = ""; + acc.push_str(&f); + acc + }).unwrap_or_default(); + } + + unsafe fn less_than_max_suggestion_highest_lines() { + let frames = Vec::new(); + let iter = frames.iter(); + let map = iter.map(|f: &String| f.to_lowercase()); + map.reduce(|mut acc, f| { + acc.push_str(&f); + acc + }).unwrap_or_default(); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 3f69cef301c..a702d9dadd4 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -176,4 +176,54 @@ mod issue6675 { } } +mod issue8239 { + unsafe fn more_than_max_suggestion_highest_lines_0() { + let frames = Vec::new(); + frames + .iter() + .map(|f: &String| f.to_lowercase()) + .reduce(|mut acc, f| { + acc.push_str(&f); + acc + }) + .unwrap_or(String::new()); + } + + unsafe fn more_to_max_suggestion_highest_lines_1() { + let frames = Vec::new(); + let iter = frames.iter(); + iter.map(|f: &String| f.to_lowercase()) + .reduce(|mut acc, f| { + let _ = ""; + let _ = ""; + acc.push_str(&f); + acc + }) + .unwrap_or(String::new()); + } + + unsafe fn equal_to_max_suggestion_highest_lines() { + let frames = Vec::new(); + let iter = frames.iter(); + iter.map(|f: &String| f.to_lowercase()) + .reduce(|mut acc, f| { + let _ = ""; + acc.push_str(&f); + acc + }) + .unwrap_or(String::new()); + } + + unsafe fn less_than_max_suggestion_highest_lines() { + let frames = Vec::new(); + let iter = frames.iter(); + let map = iter.map(|f: &String| f.to_lowercase()); + map.reduce(|mut acc, f| { + acc.push_str(&f); + acc + }) + .unwrap_or(String::new()); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 9d0c42b10c2..549b00ae3c4 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -108,5 +108,57 @@ error: use of `unwrap_or` followed by a function call LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` -error: aborting due to 18 previous errors +error: use of `unwrap_or` followed by a call to `new` + --> $DIR/or_fun_call.rs:189:14 + | +LL | .unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + +error: use of `unwrap_or` followed by a call to `new` + --> $DIR/or_fun_call.rs:202:14 + | +LL | .unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + +error: use of `unwrap_or` followed by a call to `new` + --> $DIR/or_fun_call.rs:208:9 + | +LL | / iter.map(|f: &String| f.to_lowercase()) +LL | | .reduce(|mut acc, f| { +LL | | let _ = ""; +LL | | acc.push_str(&f); +LL | | acc +LL | | }) +LL | | .unwrap_or(String::new()); + | |_____________________________________^ + | +help: try this + | +LL ~ iter.map(|f: &String| f.to_lowercase()) +LL + .reduce(|mut acc, f| { +LL + let _ = ""; +LL + acc.push_str(&f); +LL + acc +LL ~ }).unwrap_or_default(); + | + +error: use of `unwrap_or` followed by a call to `new` + --> $DIR/or_fun_call.rs:221:9 + | +LL | / map.reduce(|mut acc, f| { +LL | | acc.push_str(&f); +LL | | acc +LL | | }) +LL | | .unwrap_or(String::new()); + | |_________________________________^ + | +help: try this + | +LL ~ map.reduce(|mut acc, f| { +LL + acc.push_str(&f); +LL + acc +LL ~ }).unwrap_or_default(); + | + +error: aborting due to 22 previous errors -- cgit 1.4.1-3-g733a5 From 1c9b31d3503e3c324ffc12f1fbf9bab5e318decb Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Thu, 30 Dec 2021 22:39:53 -0800 Subject: New line: cloned_next --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_perf.rs | 1 + clippy_lints/src/methods/iter_overeager_cloned.rs | 62 +++++++++++++++ clippy_lints/src/methods/mod.rs | 91 +++++++++++++++++++---- tests/ui/iter_overeager_cloned.fixed | 45 +++++++++++ tests/ui/iter_overeager_cloned.rs | 47 ++++++++++++ tests/ui/iter_overeager_cloned.stderr | 58 +++++++++++++++ 9 files changed, 292 insertions(+), 15 deletions(-) create mode 100644 clippy_lints/src/methods/iter_overeager_cloned.rs create mode 100644 tests/ui/iter_overeager_cloned.fixed create mode 100644 tests/ui/iter_overeager_cloned.rs create mode 100644 tests/ui/iter_overeager_cloned.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f4da9a3827..258a8256f53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3049,6 +3049,7 @@ Released 2018-09-13 [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero +[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 26fb4259952..eba51099496 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -156,6 +156,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::ITER_NEXT_SLICE), LintId::of(methods::ITER_NTH), LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_OVEREAGER_CLONED), LintId::of(methods::ITER_SKIP_NEXT), LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 746bdb19c3d..56146a0fd3a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -288,6 +288,7 @@ store.register_lints(&[ methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, + methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index f9ffd4cf829..c44ef124bfa 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -14,6 +14,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::ITER_NTH), + LintId::of(methods::ITER_OVEREAGER_CLONED), LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::SINGLE_CHAR_PATTERN), diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs new file mode 100644 index 00000000000..ca33bfc643d --- /dev/null +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -0,0 +1,62 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::{get_iterator_item_ty, is_copy}; +use itertools::Itertools; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use std::ops::Not; + +use super::ITER_OVEREAGER_CLONED; +use crate::redundant_clone::REDUNDANT_CLONE; + +/// lint overeager use of `cloned()` for `Iterator`s +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + name: &str, + map_arg: &[hir::Expr<'_>], +) { + // Check if it's iterator and get type associated with `Item`. + let inner_ty = match get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)) { + Some(ty) => ty, + _ => return, + }; + + match inner_ty.kind() { + ty::Ref(_, ty, _) if !is_copy(cx, ty) => {}, + _ => return, + }; + + let (lint, preserve_cloned) = match name { + "count" => (REDUNDANT_CLONE, false), + _ => (ITER_OVEREAGER_CLONED, true), + }; + let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default(); + let msg = format!( + "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead", + name, + wildcard_params, + name, + wildcard_params, + preserve_cloned.then(|| ".cloned()").unwrap_or_default(), + ); + + span_lint_and_sugg( + cx, + lint, + expr.span, + &msg, + "try this", + format!( + "{}.{}({}){}", + snippet(cx, recv.span, ".."), + name, + map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "), + preserve_cloned.then(|| ".cloned()").unwrap_or_default(), + ), + Applicability::MachineApplicable, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a3cfdd3d4ba..cff625112e5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -30,6 +30,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; +mod iter_overeager_cloned; mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; @@ -106,6 +107,41 @@ declare_clippy_lint! { "used `cloned` where `copied` could be used instead" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed. + /// + /// ### Why is this bad? + /// It's often inefficient to clone all elements of an iterator, when eventually, only some + /// of them will be consumed. + /// + /// ### Examples + /// ```rust + /// # let vec = vec!["string".to_string()]; + /// + /// // Bad + /// vec.iter().cloned().take(10); + /// + /// // Good + /// vec.iter().take(10).cloned(); + /// + /// // Bad + /// vec.iter().cloned().last(); + /// + /// // Good + /// vec.iter().last().cloned(); + /// + /// ``` + /// ### Known Problems + /// This `lint` removes the side of effect of cloning items in the iterator. + /// A code that relies on that side-effect could fail. + /// + #[clippy::version = "1.59.0"] + pub ITER_OVEREAGER_CLONED, + perf, + "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies" +} + declare_clippy_lint! { /// ### What it does /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be @@ -1950,6 +1986,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_COPY, CLONE_ON_REF_PTR, CLONE_DOUBLE_REF, + ITER_OVEREAGER_CLONED, CLONED_INSTEAD_OF_COPIED, FLAT_MAP_OPTION, INEFFICIENT_TO_STRING, @@ -2243,9 +2280,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, _ => {}, }, - ("count", []) => match method_call(recv) { - Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { - iter_count::check(cx, expr, recv2, name); + (name @ "count", args @ []) => match method_call(recv) { + Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + 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), _ => {}, @@ -2266,10 +2304,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio flat_map_identity::check(cx, expr, arg, span); flat_map_option::check(cx, expr, arg, span); }, - ("flatten", []) => { - if let Some(("map", [recv, map_arg], _)) = method_call(recv) { - map_flatten::check(cx, expr, recv, map_arg); - } + (name @ "flatten", args @ []) => match method_call(recv) { + Some(("map", [recv, map_arg], _)) => map_flatten::check(cx, expr, recv, map_arg), + Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + _ => {}, }, ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), ("for_each", [_]) => { @@ -2281,6 +2319,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), + ("last", args @ []) => { + if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let ("cloned", []) = (name2, args2) { + iter_overeager_cloned::check(cx, expr, recv2, name, args); + } + } + }, ("map", [m_arg]) => { if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { match (name, args) { @@ -2296,20 +2341,22 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio map_identity::check(cx, expr, recv, m_arg, span); }, ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), - ("next", []) => { - if let Some((name, [recv, args @ ..], _)) = method_call(recv) { - match (name, args) { - ("filter", [arg]) => filter_next::check(cx, expr, recv, arg), - ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv), - ("iter", []) => iter_next_slice::check(cx, expr, recv), - ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg), + (name @ "next", args @ []) => { + if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { + match (name2, args2) { + ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), + ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, 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), _ => {}, } } }, - ("nth", [n_arg]) => match method_call(recv) { + ("nth", args @ [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, recv2, name, args), 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), @@ -2320,6 +2367,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + ("skip", args) => { + if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let ("cloned", []) = (name2, args2) { + iter_overeager_cloned::check(cx, expr, recv2, name, args); + } + } + }, ("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); @@ -2337,6 +2391,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), + ("take", args @ [_arg]) => { + if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let ("cloned", []) = (name2, args2) { + iter_overeager_cloned::check(cx, expr, recv2, name, args); + } + } + }, ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed new file mode 100644 index 00000000000..a9041671101 --- /dev/null +++ b/tests/ui/iter_overeager_cloned.fixed @@ -0,0 +1,45 @@ +// run-rustfix +#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] + +fn main() { + let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; + + let _: Option = vec.iter().last().cloned(); + + let _: Option = vec.iter().chain(vec.iter()).next().cloned(); + + let _: usize = vec.iter().filter(|x| x == &"2").count(); + + let _: Vec<_> = vec.iter().take(2).cloned().collect(); + + let _: Vec<_> = vec.iter().skip(2).cloned().collect(); + + let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned(); + + let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] + .iter().flatten().cloned(); + + // Not implemented yet + let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); + + // Not implemented yet + let _ = vec.iter().cloned().map(|x| x.len()); + + // This would fail if changed. + let _ = vec.iter().cloned().map(|x| x + "2"); + + // Not implemented yet + let _ = vec.iter().cloned().find(|x| x == "2"); + + // Not implemented yet + let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); + + // Not implemented yet + let _ = vec.iter().cloned().all(|x| x.len() == 1); + + // Not implemented yet + let _ = vec.iter().cloned().any(|x| x.len() == 1); + + // Should probably stay as it is. + let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); +} diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs new file mode 100644 index 00000000000..dd04e33a4b3 --- /dev/null +++ b/tests/ui/iter_overeager_cloned.rs @@ -0,0 +1,47 @@ +// run-rustfix +#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] + +fn main() { + let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; + + let _: Option = vec.iter().cloned().last(); + + let _: Option = vec.iter().chain(vec.iter()).cloned().next(); + + let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); + + let _: Vec<_> = vec.iter().cloned().take(2).collect(); + + let _: Vec<_> = vec.iter().cloned().skip(2).collect(); + + let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); + + let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] + .iter() + .cloned() + .flatten(); + + // Not implemented yet + let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); + + // Not implemented yet + let _ = vec.iter().cloned().map(|x| x.len()); + + // This would fail if changed. + let _ = vec.iter().cloned().map(|x| x + "2"); + + // Not implemented yet + let _ = vec.iter().cloned().find(|x| x == "2"); + + // Not implemented yet + let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); + + // Not implemented yet + let _ = vec.iter().cloned().all(|x| x.len() == 1); + + // Not implemented yet + let _ = vec.iter().cloned().any(|x| x.len() == 1); + + // Should probably stay as it is. + let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); +} diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr new file mode 100644 index 00000000000..e36b0e36fbd --- /dev/null +++ b/tests/ui/iter_overeager_cloned.stderr @@ -0,0 +1,58 @@ +error: called `cloned().last()` on an `Iterator`. It may be more efficient to call `last().cloned()` instead + --> $DIR/iter_overeager_cloned.rs:7:29 + | +LL | let _: Option = vec.iter().cloned().last(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().last().cloned()` + | + = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings` + +error: called `cloned().next()` on an `Iterator`. It may be more efficient to call `next().cloned()` instead + --> $DIR/iter_overeager_cloned.rs:9:29 + | +LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().chain(vec.iter()).next().cloned()` + +error: called `cloned().count()` on an `Iterator`. It may be more efficient to call `count()` instead + --> $DIR/iter_overeager_cloned.rs:11:20 + | +LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").count()` + | + = note: `-D clippy::redundant-clone` implied by `-D warnings` + +error: called `cloned().take(...)` on an `Iterator`. It may be more efficient to call `take(...).cloned()` instead + --> $DIR/iter_overeager_cloned.rs:13:21 + | +LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().take(2).cloned()` + +error: called `cloned().skip(...)` on an `Iterator`. It may be more efficient to call `skip(...).cloned()` instead + --> $DIR/iter_overeager_cloned.rs:15:21 + | +LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().skip(2).cloned()` + +error: called `cloned().nth(...)` on an `Iterator`. It may be more efficient to call `nth(...).cloned()` instead + --> $DIR/iter_overeager_cloned.rs:17:13 + | +LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").nth(2).cloned()` + +error: called `cloned().flatten()` on an `Iterator`. It may be more efficient to call `flatten().cloned()` instead + --> $DIR/iter_overeager_cloned.rs:19:13 + | +LL | let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] + | _____________^ +LL | | .iter() +LL | | .cloned() +LL | | .flatten(); + | |__________________^ + | +help: try this + | +LL ~ let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] +LL ~ .iter().flatten().cloned(); + | + +error: aborting due to 7 previous errors + -- cgit 1.4.1-3-g733a5 From d48d247309f024b4d009a528e243e4567a98aa8e Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Sun, 16 Jan 2022 10:19:48 -0800 Subject: Fix clippy warnings --- clippy_lints/src/methods/mod.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cff625112e5..f9d8e03a499 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2319,7 +2319,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), - ("last", args @ []) => { + ("last" | "skip", args @ []) => { if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv2, name, args); @@ -2367,13 +2367,6 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, - ("skip", args) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { - if let ("cloned", []) = (name2, args2) { - iter_overeager_cloned::check(cx, expr, recv2, name, args); - } - } - }, ("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); -- cgit 1.4.1-3-g733a5 From 36396c6b972714bda6c25ab14a7a954136b8654f Mon Sep 17 00:00:00 2001 From: Piotr Mikulski Date: Sun, 16 Jan 2022 10:32:45 -0800 Subject: Fix tests --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f9d8e03a499..d75ab0c4b1b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2319,7 +2319,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), - ("last" | "skip", args @ []) => { + ("last", args @ []) | ("skip", args @ [_]) => { if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv2, name, args); -- cgit 1.4.1-3-g733a5 From 69d78ceeba0627d650d6058a456fdfb2df0eaa7f Mon Sep 17 00:00:00 2001 From: Marek Downar Date: Mon, 17 Jan 2022 12:34:03 +0100 Subject: removing unsafe from test fn's && renaming shrink to sugg_span --- clippy_lints/src/methods/or_fun_call.rs | 6 +++--- tests/ui/or_fun_call.fixed | 8 ++++---- tests/ui/or_fun_call.rs | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index c35a2e57a66..448dc4e6147 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( then { let mut applicability = Applicability::MachineApplicable; let hint = "unwrap_or_default()"; - let mut shrink = span; + let mut sugg_span = span; let mut sugg: String = format!( "{}.{}", @@ -65,14 +65,14 @@ pub(super) fn check<'tcx>( ); if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES { - shrink = method_span.with_hi(span.hi()); + sugg_span = method_span.with_hi(span.hi()); sugg = hint.to_string(); } span_lint_and_sugg( cx, OR_FUN_CALL, - shrink, + sugg_span, &format!("use of `{}` followed by a call to `{}`", name, path), "try this", sugg, diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index fe8f5c9fc62..3208048e0d5 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -177,7 +177,7 @@ mod issue6675 { } mod issue8239 { - unsafe fn more_than_max_suggestion_highest_lines_0() { + fn more_than_max_suggestion_highest_lines_0() { let frames = Vec::new(); frames .iter() @@ -189,7 +189,7 @@ mod issue8239 { .unwrap_or_default(); } - unsafe fn more_to_max_suggestion_highest_lines_1() { + fn more_to_max_suggestion_highest_lines_1() { let frames = Vec::new(); let iter = frames.iter(); iter.map(|f: &String| f.to_lowercase()) @@ -202,7 +202,7 @@ mod issue8239 { .unwrap_or_default(); } - unsafe fn equal_to_max_suggestion_highest_lines() { + fn equal_to_max_suggestion_highest_lines() { let frames = Vec::new(); let iter = frames.iter(); iter.map(|f: &String| f.to_lowercase()) @@ -213,7 +213,7 @@ mod issue8239 { }).unwrap_or_default(); } - unsafe fn less_than_max_suggestion_highest_lines() { + fn less_than_max_suggestion_highest_lines() { let frames = Vec::new(); let iter = frames.iter(); let map = iter.map(|f: &String| f.to_lowercase()); diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index a702d9dadd4..57ab5f03ee2 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -177,7 +177,7 @@ mod issue6675 { } mod issue8239 { - unsafe fn more_than_max_suggestion_highest_lines_0() { + fn more_than_max_suggestion_highest_lines_0() { let frames = Vec::new(); frames .iter() @@ -189,7 +189,7 @@ mod issue8239 { .unwrap_or(String::new()); } - unsafe fn more_to_max_suggestion_highest_lines_1() { + fn more_to_max_suggestion_highest_lines_1() { let frames = Vec::new(); let iter = frames.iter(); iter.map(|f: &String| f.to_lowercase()) @@ -202,7 +202,7 @@ mod issue8239 { .unwrap_or(String::new()); } - unsafe fn equal_to_max_suggestion_highest_lines() { + fn equal_to_max_suggestion_highest_lines() { let frames = Vec::new(); let iter = frames.iter(); iter.map(|f: &String| f.to_lowercase()) @@ -214,7 +214,7 @@ mod issue8239 { .unwrap_or(String::new()); } - unsafe fn less_than_max_suggestion_highest_lines() { + fn less_than_max_suggestion_highest_lines() { let frames = Vec::new(); let iter = frames.iter(); let map = iter.map(|f: &String| f.to_lowercase()); -- cgit 1.4.1-3-g733a5 From 23fd95a5e99acf35b471ca9b01230d7578bfac5f Mon Sep 17 00:00:00 2001 From: max <36980911+pr2502@users.noreply.github.com> Date: Sat, 8 Jan 2022 23:10:20 +0100 Subject: fix underflow in `check_manual_split_once` lint --- clippy_lints/src/methods/str_splitn.rs | 6 +++--- tests/ui/crashes/ice-8250.rs | 6 ++++++ tests/ui/crashes/ice-8250.stderr | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 tests/ui/crashes/ice-8250.rs create mode 100644 tests/ui/crashes/ice-8250.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 70f20da1d6d..e8a3562c393 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -45,16 +45,16 @@ pub(super) fn check_manual_split_once( IterUsageKind::Next | IterUsageKind::Second => { let self_deref = { let adjust = cx.typeck_results().expr_adjustments(self_arg); - if adjust.is_empty() { + if adjust.len() < 2 { String::new() } else if cx.typeck_results().expr_ty(self_arg).is_box() || adjust .iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box()) { - format!("&{}", "*".repeat(adjust.len() - 1)) + format!("&{}", "*".repeat(adjust.len().saturating_sub(1))) } else { - "*".repeat(adjust.len() - 2) + "*".repeat(adjust.len().saturating_sub(2)) } }; if matches!(usage.kind, IterUsageKind::Next) { diff --git a/tests/ui/crashes/ice-8250.rs b/tests/ui/crashes/ice-8250.rs new file mode 100644 index 00000000000..d9a5ee1162a --- /dev/null +++ b/tests/ui/crashes/ice-8250.rs @@ -0,0 +1,6 @@ +fn _f(s: &str) -> Option<()> { + let _ = s[1..].splitn(2, '.').next()?; + Some(()) +} + +fn main() {} diff --git a/tests/ui/crashes/ice-8250.stderr b/tests/ui/crashes/ice-8250.stderr new file mode 100644 index 00000000000..04ea4456656 --- /dev/null +++ b/tests/ui/crashes/ice-8250.stderr @@ -0,0 +1,18 @@ +error: manual implementation of `split_once` + --> $DIR/ice-8250.rs:2:13 + | +LL | let _ = s[1..].splitn(2, '.').next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split_once('.').map_or(s[1..], |x| x.0)` + | + = note: `-D clippy::manual-split-once` implied by `-D warnings` + +error: unnecessary use of `splitn` + --> $DIR/ice-8250.rs:2:13 + | +LL | let _ = s[1..].splitn(2, '.').next()?; + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split('.')` + | + = note: `-D clippy::needless-splitn` implied by `-D warnings` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 515ed80b9d63e20c196a7739118c2f316a097106 Mon Sep 17 00:00:00 2001 From: dswij Date: Tue, 25 Jan 2022 16:18:32 +0800 Subject: Update docs for `map_flatten` on `Option` --- clippy_lints/src/methods/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d75ab0c4b1b..45f2992df91 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -566,17 +566,20 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Readability, this can be written more concisely as - /// `_.flat_map(_)` + /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option` /// /// ### Example /// ```rust /// let vec = vec![vec![1]]; + /// let opt = Some(5); /// /// // Bad /// vec.iter().map(|x| x.iter()).flatten(); + /// opt.map(|x| Some(x * 2)).flatten(); /// /// // Good /// vec.iter().flat_map(|x| x.iter()); + /// opt.and_then(|x| Some(x * 2)); /// ``` #[clippy::version = "1.31.0"] pub MAP_FLATTEN, -- cgit 1.4.1-3-g733a5 From deadc255883a726abee105564bc9a0f65f01e62b Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 2 Nov 2021 09:43:31 -0500 Subject: Factor out differing_macro_contexts --- clippy_lints/src/blocks_in_if_conditions.rs | 6 +++--- clippy_lints/src/formatting.rs | 14 ++++++-------- clippy_lints/src/implicit_hasher.rs | 3 +-- clippy_lints/src/methods/option_map_unwrap_or.rs | 3 +-- clippy_lints/src/swap.rs | 4 ++-- clippy_lints/src/unwrap.rs | 7 ++++--- clippy_utils/src/hir_utils.rs | 3 +-- clippy_utils/src/lib.rs | 7 ------- doc/common_tools_writing_lints.md | 8 ++++++-- 9 files changed, 24 insertions(+), 31 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index c4956bacf43..4c4dd85d518 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::get_parent_expr; use clippy_utils::higher; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::{differing_macro_contexts, get_parent_expr}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { if let Some(ex) = &block.expr { // don't dig into the expression here, just suggest that they remove // the block - if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) { + if expr.span.from_expansion() || ex.span.from_expansion() { return; } let mut applicability = Applicability::MachineApplicable; @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { } } else { let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); - if span.from_expansion() || differing_macro_contexts(expr.span, span) { + if span.from_expansion() || expr.span.from_expansion() { return; } // move block higher diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index ae18f8081bc..57964b8d48e 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; -use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -135,7 +134,7 @@ impl EarlyLintPass for Formatting { /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind { - if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion() { + if !lhs.span.from_expansion() && !rhs.span.from_expansion() { let eq_span = lhs.span.between(rhs.span); if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { @@ -165,7 +164,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind; - if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion(); + if !lhs.span.from_expansion() && !rhs.span.from_expansion(); // span between BinOp LHS and RHS let binop_span = lhs.span.between(rhs.span); // if RHS is an UnOp @@ -206,8 +205,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { if let ExprKind::If(_, then, Some(else_)) = &expr.kind; if is_block(else_) || is_if(else_); - if !differing_macro_contexts(then.span, else_.span); - if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span); + if !then.span.from_expansion() && !else_.span.from_expansion(); + if !in_external_macro(cx.sess(), expr.span); // workaround for rust-lang/rust#43081 if expr.span.lo().0 != 0 && expr.span.hi().0 != 0; @@ -268,7 +267,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { for element in array { if_chain! { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span); + if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt(); let space_span = lhs.span.between(op.span); if let Some(space_snippet) = snippet_opt(cx, space_span); let lint_span = lhs.span.with_lo(lhs.span.hi()); @@ -291,8 +290,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { if_chain! { - if !differing_macro_contexts(first.span, second.span); - if !first.span.from_expansion(); + if !first.span.from_expansion() && !second.span.from_expansion(); if let ExprKind::If(cond_expr, ..) = &first.kind; if is_block(second) || is_if(second); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index eed25e9bc0e..3fb7e5dfd6c 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -17,7 +17,6 @@ use rustc_typeck::hir_ty_to_ty; use if_chain::if_chain; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::differing_macro_contexts; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { vis.visit_ty(impl_.self_ty); for target in &vis.found { - if differing_macro_contexts(item.span, target.span()) { + if item.span.ctxt() != target.span().ctxt() { return; } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 9c6f4211031..6c641af59f9 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; @@ -48,7 +47,7 @@ pub(super) fn check<'tcx>( } } - if differing_macro_contexts(unwrap_arg.span, map_span) { + if unwrap_arg.span.ctxt() != map_span.ctxt() { return; } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 4c10b12437d..1885f3ca414 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value, std_or_core}; +use clippy_utils::{can_mut_borrow_both, eq_expr_value, std_or_core}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; @@ -172,7 +172,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if_chain! { if let StmtKind::Semi(first) = w[0].kind; if let StmtKind::Semi(second) = w[1].kind; - if !differing_macro_contexts(first.span, second.span); + if first.span.ctxt() == second.span.ctxt(); if let ExprKind::Assign(lhs0, rhs0, _) = first.kind; if let ExprKind::Assign(lhs1, rhs1, _) = second.kind; if eq_expr_value(cx, lhs0, rhs1); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index e9840487013..9b9e25326f9 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated}; +use clippy_utils::{path_to_local, usage::is_potentially_mutated}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; @@ -238,8 +238,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { if let Some(unwrappable) = self.unwrappables.iter() .find(|u| u.local_id == id); // Span contexts should not differ with the conditional branch - if !differing_macro_contexts(unwrappable.branch.span, expr.span); - if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span); + let span_ctxt = expr.span.ctxt(); + if unwrappable.branch.span.ctxt() == span_ctxt; + if unwrappable.check.span.ctxt() == span_ctxt; then { if call_to_unwrap == unwrappable.safe_to_unwrap { let is_entire_condition = unwrappable.is_entire_condition; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index ed573ad9056..a2b10c12eb9 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,5 +1,4 @@ use crate::consts::{constant_context, constant_simple}; -use crate::differing_macro_contexts; use crate::source::snippet_opt; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -186,7 +185,7 @@ impl HirEqInterExpr<'_, '_, '_> { #[allow(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { - if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) { + if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() { return false; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index ed73364841c..f10f130bc32 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -134,13 +134,6 @@ macro_rules! extract_msrv_attr { }; } -/// Returns `true` if the two spans come from differing expansions (i.e., one is -/// from a macro and one isn't). -#[must_use] -pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { - rhs.ctxt() != lhs.ctxt() -} - /// If the given expression is a local binding, find the initializer expression. /// If that initializer expression is another local binding, find its initializer again. /// This process repeats as long as possible (but usually no more than once). Initializer diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index 6c8a3dc418b..36c454745ba 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -235,7 +235,11 @@ Use the following functions to deal with macros: assert_eq!(in_external_macro(cx.sess(), match_span), true); ``` -- `differing_macro_contexts()`: returns true if the two given spans are not from the same context +- `span.ctxt()`: the span's context represents whether it is from expansion, and if so, what expanded it + +One thing `SpanContext` is useful for is to check if two spans are in the same context. For example, +in `a == b`, `a` and `b` have the same context. In a `macro_rules!` with `a == $b`, `$b` is expanded to some +expression with a different context from `a`. ```rust macro_rules! m { @@ -252,7 +256,7 @@ Use the following functions to deal with macros: // These spans are not from the same context // x.is_some() is from inside the macro // x.unwrap() is from outside the macro - assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true); + assert_eq!(x_is_some_span.ctxt(), x_unwrap_span.ctxt()); ``` [TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html -- cgit 1.4.1-3-g733a5 From 98c6381a387ac05e27c03ccfc64146bf4934f5c8 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 6 Jan 2022 09:31:38 -0600 Subject: Factor out single_segment_path --- clippy_lints/src/loops/single_element_loop.rs | 24 ++++++++++-------------- clippy_lints/src/methods/chars_cmp.rs | 15 ++++++--------- clippy_lints/src/methods/option_map_or_none.rs | 13 ++++++------- clippy_lints/src/ranges.rs | 26 +++++++------------------- clippy_utils/src/lib.rs | 8 -------- 5 files changed, 29 insertions(+), 57 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 15f419e4410..36ecd83f7d6 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,10 +1,9 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::single_segment_path; -use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::source::{indent_of, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, Pat}; use rustc_lint::LateContext; pub(super) fn check<'tcx>( @@ -16,24 +15,21 @@ pub(super) fn check<'tcx>( ) { let arg_expr = match arg.kind { ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg, - ExprKind::MethodCall(method, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => { - &args[0] - }, + ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg, _ => return, }; if_chain! { - if let PatKind::Binding(.., target, _) = pat.kind; if let ExprKind::Array([arg_expression]) = arg_expr.kind; - if let ExprKind::Path(ref list_item) = arg_expression.kind; - if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name); if let ExprKind::Block(block, _) = body.kind; if !block.stmts.is_empty(); - then { - let mut block_str = snippet(cx, block.span, "..").into_owned(); + let mut applicability = Applicability::MachineApplicable; + let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); + let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability); + let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned(); block_str.remove(0); block_str.pop(); - + let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)); span_lint_and_sugg( cx, @@ -41,8 +37,8 @@ pub(super) fn check<'tcx>( expr.span, "for loop over a single element", "try", - format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str), - Applicability::MachineApplicable + format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str), + applicability, ) } } diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 514c4118765..2cf2c5641bf 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{method_chain_args, single_segment_path}; +use clippy_utils::{method_chain_args, path_def_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_lint::Lint; -use rustc_middle::ty; -use rustc_span::sym; +use rustc_middle::ty::{self, DefIdTree}; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. pub(super) fn check( @@ -19,11 +18,9 @@ pub(super) fn check( ) -> bool { if_chain! { if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Call(fun, arg_char) = info.other.kind; - if arg_char.len() == 1; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym::Some; + if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind; + if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id)); + if Some(id) == cx.tcx.lang_items().option_some_variant(); then { let mut applicability = Applicability::MachineApplicable; let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); @@ -42,7 +39,7 @@ pub(super) fn check( if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, - snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), + snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), applicability, ); diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 5e5c1038e82..bdf8cea1207 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, single_segment_path}; +use clippy_utils::{is_lang_ctor, path_def_id}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; +use rustc_middle::ty::DefIdTree; use rustc_span::symbol::sym; use super::OPTION_MAP_OR_NONE; @@ -76,13 +77,11 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind; let arg_snippet = snippet(cx, span, ".."); let body = cx.tcx.hir().body(id); - if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value); - if arg_char.len() == 1; - if let hir::ExprKind::Path(ref qpath) = func.kind; - if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym::Some; + if let Some((func, [arg_char])) = reduce_unit_expression(cx, &body.value); + if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id)); + if Some(id) == cx.tcx.lang_items().option_some_variant(); then { - let func_snippet = snippet(cx, arg_char[0].span, ".."); + let func_snippet = snippet(cx, arg_char.span, ".."); let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ `map(..)` instead"; return span_lint_and_sugg( diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 8065ed3ffc5..e213c208794 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -2,19 +2,18 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local}; use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::sym; -use rustc_span::symbol::Ident; use std::cmp::Ordering; declare_clippy_lint! { @@ -220,12 +219,12 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' _ => return, }; // value, name, order (higher/lower), inclusiveness - if let (Some((lval, lname, name_span, lval_span, lord, linc)), Some((rval, rname, _, rval_span, rord, rinc))) = + if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) = (check_range_bounds(cx, l), check_range_bounds(cx, r)) { // we only lint comparisons on the same name and with different // direction - if lname != rname || lord == rord { + if lid != rid || lord == rord { return; } let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval); @@ -293,7 +292,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' } } -fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> { +fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> { if let ExprKind::Binary(ref op, l, r) = ex.kind { let (inclusive, ordering) = match op.node { BinOpKind::Gt => (false, Ordering::Greater), @@ -302,11 +301,11 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, BinOpKind::Le => (true, Ordering::Less), _ => return None, }; - if let Some(id) = match_ident(l) { + if let Some(id) = path_to_local(l) { if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { return Some((c, id, l.span, r.span, ordering, inclusive)); } - } else if let Some(id) = match_ident(r) { + } else if let Some(id) = path_to_local(r) { if let Some((c, _)) = constant(cx, cx.typeck_results(), l) { return Some((c, id, r.span, l.span, ordering.reverse(), inclusive)); } @@ -315,17 +314,6 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, None } -fn match_ident(e: &Expr<'_>) -> Option { - if let ExprKind::Path(ref qpath) = e.kind { - if let Some(seg) = single_segment_path(qpath) { - if seg.args.is_none() { - return Some(seg.ident); - } - } - } - None -} - fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) { if_chain! { if path.ident.as_str() == "zip"; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f10f130bc32..3df7af601cf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -326,14 +326,6 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - match *path { - QPath::Resolved(_, path) => path.segments.get(0), - QPath::TypeRelative(_, seg) => Some(seg), - QPath::LangItem(..) => None, - } -} - /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. -- cgit 1.4.1-3-g733a5 From bd583d91a1bf3717f724a38531e142aa4a9ee6cc Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 6 Jan 2022 12:41:17 -0600 Subject: Factor out is_qpath_def_path --- clippy_lints/src/infinite_iter.rs | 12 ++--- clippy_lints/src/matches.rs | 62 ++++++++++++---------- .../src/methods/manual_saturating_arithmetic.rs | 8 +-- clippy_utils/src/lib.rs | 10 +--- 4 files changed, 44 insertions(+), 48 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 3008e86ef8b..b6badef02f5 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths}; +use clippy_utils::{get_trait_def_id, higher, match_def_path, path_def_id, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -167,13 +167,9 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), - ExprKind::Call(path, _) => { - if let ExprKind::Path(ref qpath) = path.kind { - is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into() - } else { - Finite - } - }, + ExprKind::Call(path, _) => path_def_id(cx, path) + .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT)) + .into(), ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(), _ => Finite, } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 2579404fb18..81ae4dacdf6 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1765,22 +1765,22 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; - use clippy_utils::higher; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type}; - use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths}; + use clippy_utils::{higher, match_def_path}; + use clippy_utils::{is_lang_ctor, is_trait_method, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; - use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; + use rustc_hir::LangItem::{OptionNone, PollPending}; use rustc_hir::{ intravisit::{walk_expr, Visitor}, Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp, }; use rustc_lint::LateContext; - use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; + use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; use rustc_span::sym; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -1956,28 +1956,31 @@ mod redundant_pattern_match { has_else: bool, ) { // also look inside refs - let mut kind = &let_pat.kind; // if we have &None for example, peel it so we can detect "if let None = x" - if let PatKind::Ref(inner, _mutability) = kind { - kind = &inner.kind; - } + let check_pat = match let_pat.kind { + PatKind::Ref(inner, _mutability) => inner, + _ => let_pat, + }; let op_ty = cx.typeck_results().expr_ty(let_expr); // Determine which function should be used, and the type contained by the corresponding // variant. - let (good_method, inner_ty) = match kind { - PatKind::TupleStruct(ref path, [sub_pat], _) => { + let (good_method, inner_ty) = match check_pat.kind { + PatKind::TupleStruct(ref qpath, [sub_pat], _) => { if let PatKind::Wild = sub_pat.kind { - if is_lang_ctor(cx, path, ResultOk) { + let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id); + let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return }; + let lang_items = cx.tcx.lang_items(); + if Some(id) == lang_items.result_ok_variant() { ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)) - } else if is_lang_ctor(cx, path, ResultErr) { + } else if Some(id) == lang_items.result_err_variant() { ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty)) - } else if is_lang_ctor(cx, path, OptionSome) { + } else if Some(id) == lang_items.option_some_variant() { ("is_some()", op_ty) - } else if is_lang_ctor(cx, path, PollReady) { + } else if Some(id) == lang_items.poll_ready_variant() { ("is_ready()", op_ty) - } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) { + } else if match_def_path(cx, id, &paths::IPADDR_V4) { ("is_ipv4()", op_ty) - } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) { + } else if match_def_path(cx, id, &paths::IPADDR_V6) { ("is_ipv6()", op_ty) } else { return; @@ -2177,17 +2180,22 @@ mod redundant_pattern_match { should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left) - && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right) - { - (&(*arms[0].body).kind, &(*arms[1].body).kind) - } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left) - && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right) - { - (&(*arms[1].body).kind, &(*arms[0].body).kind) - } else { - return None; - }; + let left_id = cx + .typeck_results() + .qpath_res(path_left, arms[0].pat.hir_id) + .opt_def_id()?; + let right_id = cx + .typeck_results() + .qpath_res(path_right, arms[1].pat.hir_id) + .opt_def_id()?; + let body_node_pair = + if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) { + (&(*arms[0].body).kind, &(*arms[1].body).kind) + } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) { + (&(*arms[1].body).kind, &(*arms[0].body).kind) + } else { + return None; + }; match body_node_pair { (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 4307cbf0050..0fe510beaa0 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_qpath_def_path; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, path_def_id}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -93,12 +93,12 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option, segments: &[&str]) -> bool { } } -/// Resolves the path to a `DefId` and checks if it matches the given path. -pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool { - cx.qpath_res(path, hir_id) - .opt_def_id() - .map_or(false, |id| match_def_path(cx, id, segments)) -} - /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. /// /// Please use `is_expr_diagnostic_item` if the target is a diagnostic item. @@ -1775,8 +1768,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool match expr.kind { ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), - ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY), - _ => false, + _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), } } -- cgit 1.4.1-3-g733a5 From 8ccd26462032427741f753424702e78e1050e96b Mon Sep 17 00:00:00 2001 From: tamaron Date: Sun, 30 Jan 2022 12:56:07 +0900 Subject: modify code --- clippy_lints/src/methods/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 18d4867b7eb..7847adce0f1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2402,10 +2402,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, - ("unwrap", []) => match method_call(recv) { - Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), - Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), - _ => unwrap_used::check(cx, expr, recv), + ("unwrap", []) => { + match method_call(recv) { + Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), + Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), + _ => {}, + } + unwrap_used::check(cx, expr, recv); }, ("unwrap_or", [u_arg]) => match method_call(recv) { Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { -- cgit 1.4.1-3-g733a5 From 1a2364e534b75377c9e5727b29dca5017596bb1f Mon Sep 17 00:00:00 2001 From: tamaron Date: Sun, 30 Jan 2022 14:59:25 +0900 Subject: fix code --- clippy_lints/src/methods/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7847adce0f1..5b4a152afd5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2404,8 +2404,12 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("unwrap", []) => { match method_call(recv) { - Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), - Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), + Some(("get", [recv, get_arg], _)) => { + get_unwrap::check(cx, expr, recv, get_arg, false); + }, + Some(("get_mut", [recv, get_arg], _)) => { + get_unwrap::check(cx, expr, recv, get_arg, true); + }, _ => {}, } unwrap_used::check(cx, expr, recv); -- cgit 1.4.1-3-g733a5 From 5faa7ebb709dfbd8d0b7274ffda05b08d70b8a3d Mon Sep 17 00:00:00 2001 From: dswij Date: Mon, 31 Jan 2022 13:35:14 +0800 Subject: Fix `chars_next_cmp` suggestion not escaped --- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 2 +- tests/ui/starts_ends_with.fixed | 10 ++++- tests/ui/starts_ends_with.rs | 10 ++++- tests/ui/starts_ends_with.stderr | 50 +++++++++++++++++------ 4 files changed, 56 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 4275857757f..a7c0e43923e 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, - c), + c.escape_default()), applicability, ); diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed index 7dfcf9c91e4..983fac7afe6 100644 --- a/tests/ui/starts_ends_with.fixed +++ b/tests/ui/starts_ends_with.fixed @@ -7,6 +7,10 @@ fn main() {} fn starts_with() { "".starts_with(' '); !"".starts_with(' '); + + // Ensure that suggestion is escaped correctly + "".starts_with('\n'); + !"".starts_with('\n'); } fn chars_cmp_with_unwrap() { @@ -31,7 +35,7 @@ fn chars_cmp_with_unwrap() { // !s.ends_with('o') // Nothing here } - if !s.ends_with('o') { + if !s.ends_with('\n') { // !s.ends_with('o') // Nothing here } @@ -43,4 +47,8 @@ fn ends_with() { !"".ends_with(' '); "".ends_with(' '); !"".ends_with(' '); + + // Ensure that suggestion is escaped correctly + "".ends_with('\n'); + !"".ends_with('\n'); } diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index e48a4246354..e3335dd2e2e 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -7,6 +7,10 @@ fn main() {} fn starts_with() { "".chars().next() == Some(' '); Some(' ') != "".chars().next(); + + // Ensure that suggestion is escaped correctly + "".chars().next() == Some('\n'); + Some('\n') != "".chars().next(); } fn chars_cmp_with_unwrap() { @@ -31,7 +35,7 @@ fn chars_cmp_with_unwrap() { // !s.ends_with('o') // Nothing here } - if s.chars().last().unwrap() != 'o' { + if s.chars().last().unwrap() != '\n' { // !s.ends_with('o') // Nothing here } @@ -43,4 +47,8 @@ fn ends_with() { Some(' ') != "".chars().last(); "".chars().next_back() == Some(' '); Some(' ') != "".chars().next_back(); + + // Ensure that suggestion is escaped correctly + "".chars().last() == Some('\n'); + Some('\n') != "".chars().last(); } diff --git a/tests/ui/starts_ends_with.stderr b/tests/ui/starts_ends_with.stderr index 7c726d0e010..2dd9f53b802 100644 --- a/tests/ui/starts_ends_with.stderr +++ b/tests/ui/starts_ends_with.stderr @@ -13,13 +13,25 @@ LL | Some(' ') != "".chars().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:14:8 + --> $DIR/starts_ends_with.rs:12:5 + | +LL | "".chars().next() == Some('/n'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with('/n')` + +error: you should use the `starts_with` method + --> $DIR/starts_ends_with.rs:13:5 + | +LL | Some('/n') != "".chars().next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with('/n')` + +error: you should use the `starts_with` method + --> $DIR/starts_ends_with.rs:18:8 | LL | if s.chars().next().unwrap() == 'f' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:18:8 + --> $DIR/starts_ends_with.rs:22:8 | LL | if s.chars().next_back().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` @@ -27,52 +39,64 @@ LL | if s.chars().next_back().unwrap() == 'o' { = note: `-D clippy::chars-last-cmp` implied by `-D warnings` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:22:8 + --> $DIR/starts_ends_with.rs:26:8 | LL | if s.chars().last().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:26:8 + --> $DIR/starts_ends_with.rs:30:8 | LL | if s.chars().next().unwrap() != 'f' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:30:8 + --> $DIR/starts_ends_with.rs:34:8 | LL | if s.chars().next_back().unwrap() != 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:34:8 + --> $DIR/starts_ends_with.rs:38:8 | -LL | if s.chars().last().unwrap() != 'o' { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` +LL | if s.chars().last().unwrap() != '/n' { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('/n')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:42:5 + --> $DIR/starts_ends_with.rs:46:5 | LL | "".chars().last() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:43:5 + --> $DIR/starts_ends_with.rs:47:5 | LL | Some(' ') != "".chars().last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:44:5 + --> $DIR/starts_ends_with.rs:48:5 | LL | "".chars().next_back() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:45:5 + --> $DIR/starts_ends_with.rs:49:5 | LL | Some(' ') != "".chars().next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` -error: aborting due to 12 previous errors +error: you should use the `ends_with` method + --> $DIR/starts_ends_with.rs:52:5 + | +LL | "".chars().last() == Some('/n'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with('/n')` + +error: you should use the `ends_with` method + --> $DIR/starts_ends_with.rs:53:5 + | +LL | Some('/n') != "".chars().last(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with('/n')` + +error: aborting due to 16 previous errors -- cgit 1.4.1-3-g733a5 From 4f96ca353ec2f48e02efe592dc9d7ebaa1e66f60 Mon Sep 17 00:00:00 2001 From: Jaeyong Sung Date: Sun, 13 Feb 2022 02:32:09 +0900 Subject: add only_used_in_recursion lint - fix code that have variables that is "only used in recursion" - add test --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/option_map_or_none.rs | 9 +- clippy_lints/src/only_used_in_recursion.rs | 563 +++++++++++++++++++++++++ clippy_lints/src/unnecessary_sort_by.rs | 45 +- tests/ui/only_used_in_recursion.rs | 73 ++++ tests/ui/only_used_in_recursion.stderr | 70 +++ 10 files changed, 732 insertions(+), 34 deletions(-) create mode 100644 clippy_lints/src/only_used_in_recursion.rs create mode 100644 tests/ui/only_used_in_recursion.rs create mode 100644 tests/ui/only_used_in_recursion.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index c9adf77c0d6..46f002aeeb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3349,6 +3349,7 @@ Released 2018-09-13 [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref [`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect +[`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index d93e34e76b4..7410d965ec1 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -226,6 +226,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(octal_escapes::OCTAL_ESCAPES), + LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index bd5ff613447..0cdf0cd1917 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -63,6 +63,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), LintId::of(no_effect::NO_EFFECT), LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index a80320a578f..431bd622702 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -388,6 +388,7 @@ store.register_lints(&[ non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY, nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, octal_escapes::OCTAL_ESCAPES, + only_used_in_recursion::ONLY_USED_IN_RECURSION, open_options::NONSENSICAL_OPEN_OPTIONS, option_env_unwrap::OPTION_ENV_UNWRAP, option_if_let_else::OPTION_IF_LET_ELSE, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0b07726519e..bd49ad0652c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -316,6 +316,7 @@ mod non_octal_unix_permissions; mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; mod octal_escapes; +mod only_used_in_recursion; mod open_options; mod option_env_unwrap; mod option_if_let_else; @@ -862,6 +863,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv))); store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); + store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index bdf8cea1207..2a5ab6e625c 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -14,10 +14,7 @@ use super::RESULT_MAP_OR_INTO_OPTION; // The expression inside a closure may or may not have surrounding braces // which causes problems when generating a suggestion. -fn reduce_unit_expression<'a>( - cx: &LateContext<'_>, - expr: &'a hir::Expr<'_>, -) -> Option<(&'a hir::Expr<'a>, &'a [hir::Expr<'a>])> { +fn reduce_unit_expression<'a>(expr: &'a hir::Expr<'_>) -> Option<(&'a hir::Expr<'a>, &'a [hir::Expr<'a>])> { match expr.kind { hir::ExprKind::Call(func, arg_char) => Some((func, arg_char)), hir::ExprKind::Block(block, _) => { @@ -25,7 +22,7 @@ fn reduce_unit_expression<'a>( (&[], Some(inner_expr)) => { // If block only contains an expression, // reduce `|x| { x + 1 }` to `|x| x + 1` - reduce_unit_expression(cx, inner_expr) + reduce_unit_expression(inner_expr) }, _ => None, } @@ -77,7 +74,7 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind; let arg_snippet = snippet(cx, span, ".."); let body = cx.tcx.hir().body(id); - if let Some((func, [arg_char])) = reduce_unit_expression(cx, &body.value); + if let Some((func, [arg_char])) = reduce_unit_expression(&body.value); if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id)); if Some(id) == cx.tcx.lang_items().option_some_variant(); then { diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs new file mode 100644 index 00000000000..ace00333bd1 --- /dev/null +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -0,0 +1,563 @@ +use std::collections::VecDeque; + +use clippy_utils::diagnostics::span_lint_and_sugg; +use itertools::{izip, Itertools}; +use rustc_ast::{walk_list, Label, Mutability}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::{ + Arm, Block, Body, Expr, ExprKind, Guard, HirId, Let, Local, Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, + UnOp, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::kw; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for arguments that is only used in recursion with no side-effects. + /// The arguments can be involved in calculations and assignments but as long as + /// the calculations have no side-effects (function calls or mutating dereference) + /// and the assigned variables are also only in recursion, it is useless. + /// + /// ### Why is this bad? + /// The could contain a useless calculation and can make function simpler. + /// + /// ### Known Issues + /// It could not catch the variable that has no side effects but only used in recursion. + /// + /// ### Example + /// ```rust + /// fn f(a: usize, b: usize) -> usize { + /// if a == 0 { + /// 1 + /// } else { + /// f(a - 1, b + 1) + /// } + /// } + /// # fn main() { + /// # print!("{}", f(1, 1)); + /// # } + /// ``` + /// Use instead: + /// ```rust + /// fn f(a: usize) -> usize { + /// if a == 0 { + /// 1 + /// } else { + /// f(a - 1) + /// } + /// } + /// # fn main() { + /// # print!("{}", f(1)); + /// # } + /// ``` + #[clippy::version = "1.60.0"] + pub ONLY_USED_IN_RECURSION, + complexity, + "default lint description" +} +declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]); + +impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + _: &'tcx rustc_hir::FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + _: Span, + _: HirId, + ) { + if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind { + let ty_res = cx.typeck_results(); + let param_span = body + .params + .iter() + .flat_map(|param| { + let mut v = Vec::new(); + param.pat.each_binding(|_, hir_id, span, ident| { + v.push((hir_id, span, ident)); + }); + v + }) + .skip(match kind { + FnKind::Method(..) => 1, + _ => 0, + }) + .filter(|(_, _, ident)| !ident.name.as_str().starts_with('_')) + .collect_vec(); + + let params = body.params.iter().map(|param| param.pat).collect(); + + let mut visitor = SideEffectVisit { + graph: FxHashMap::default(), + has_side_effect: FxHashSet::default(), + ret_vars: Vec::new(), + contains_side_effect: false, + break_vars: FxHashMap::default(), + params, + fn_ident: ident, + is_method: matches!(kind, FnKind::Method(..)), + ty_res, + ty_ctx: cx.tcx, + }; + + visitor.visit_expr(&body.value); + let vars = std::mem::take(&mut visitor.ret_vars); + visitor.add_side_effect(vars); + + let mut queue = visitor.has_side_effect.iter().copied().collect::>(); + + while let Some(id) = queue.pop_front() { + if let Some(next) = visitor.graph.get(&id) { + for i in next { + if !visitor.has_side_effect.contains(i) { + visitor.has_side_effect.insert(*i); + queue.push_back(*i); + } + } + } + } + + for (id, span, ident) in param_span { + if !visitor.has_side_effect.contains(&id) { + span_lint_and_sugg( + cx, + ONLY_USED_IN_RECURSION, + span, + "parameter is only used in recursion with no side-effects", + "if this is intentional, prefix with an underscore", + format!("_{}", ident.name.as_str()), + Applicability::MaybeIncorrect, + ); + } + } + } + } +} + +pub fn is_primitive(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, + ty::Ref(_, t, _) => is_primitive(t), + _ => false, + } +} + +pub fn is_array(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Array(..) | ty::Slice(..) => true, + ty::Ref(_, t, _) => is_array(t), + _ => false, + } +} + +pub struct SideEffectVisit<'tcx> { + graph: FxHashMap>, + has_side_effect: FxHashSet, + // bool for if the variable was dereferenced from mutable reference + ret_vars: Vec<(HirId, bool)>, + contains_side_effect: bool, + // break label + break_vars: FxHashMap>, + params: Vec<&'tcx Pat<'tcx>>, + fn_ident: Ident, + is_method: bool, + ty_res: &'tcx TypeckResults<'tcx>, + ty_ctx: TyCtxt<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> { + fn visit_block(&mut self, b: &'tcx Block<'tcx>) { + b.stmts.iter().for_each(|stmt| { + self.visit_stmt(stmt); + self.ret_vars.clear(); + }); + walk_list!(self, visit_expr, b.expr); + } + + fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { + match s.kind { + StmtKind::Local(Local { + pat, init: Some(init), .. + }) => { + self.visit_pat_expr(pat, init); + }, + StmtKind::Item(i) => { + let item = self.ty_ctx.hir().item(i); + self.visit_item(item); + }, + StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), + StmtKind::Local(_) => {}, + } + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + debug_assert!(self.ret_vars.is_empty()); + match ex.kind { + ExprKind::Array(exprs) | ExprKind::Tup(exprs) => { + self.ret_vars = exprs + .iter() + .flat_map(|expr| { + self.visit_expr(expr); + std::mem::take(&mut self.ret_vars) + }) + .collect(); + }, + ExprKind::Call(callee, args) => self.visit_fn(callee, args), + ExprKind::MethodCall(path, args, _) => self.visit_method_call(path, args), + ExprKind::Binary(_, lhs, rhs) => { + self.visit_bin_op(lhs, rhs); + }, + ExprKind::Unary(op, expr) => self.visit_un_op(op, expr), + ExprKind::Let(Let { pat, init, .. }) => self.visit_pat_expr(pat, init), + ExprKind::If(bind, then_expr, else_expr) => { + self.visit_if(bind, then_expr, else_expr); + }, + ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms), + ExprKind::Closure(_, _, body_id, _, _) => { + let body = self.ty_ctx.hir().body(body_id); + self.visit_body(body); + let vars = std::mem::take(&mut self.ret_vars); + self.add_side_effect(vars); + }, + ExprKind::Loop(block, label, _, _) | ExprKind::Block(block, label) => { + self.visit_block_label(block, label); + }, + ExprKind::Assign(bind, expr, _) => { + self.visit_assign(bind, expr); + }, + ExprKind::AssignOp(_, bind, expr) => { + self.visit_assign(bind, expr); + self.visit_bin_op(bind, expr); + }, + ExprKind::Field(expr, _) => { + self.visit_expr(expr); + if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) { + self.ret_vars.iter_mut().for_each(|(_, b)| *b = true); + } + }, + ExprKind::Index(expr, index) => { + self.visit_expr(expr); + let mut vars = std::mem::take(&mut self.ret_vars); + self.visit_expr(index); + self.ret_vars.append(&mut vars); + + if !is_array(self.ty_res.expr_ty(expr)) { + self.add_side_effect(self.ret_vars.clone()); + } else if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) { + self.ret_vars.iter_mut().for_each(|(_, b)| *b = true); + } + }, + ExprKind::Break(dest, Some(expr)) => { + self.visit_expr(expr); + if let Some(label) = dest.label { + self.break_vars + .entry(label.ident) + .or_insert(Vec::new()) + .append(&mut self.ret_vars); + } + self.contains_side_effect = true; + }, + ExprKind::Ret(Some(expr)) => { + self.visit_expr(expr); + let vars = std::mem::take(&mut self.ret_vars); + self.add_side_effect(vars); + self.contains_side_effect = true; + }, + ExprKind::Break(_, None) | ExprKind::Continue(_) | ExprKind::Ret(None) => { + self.contains_side_effect = true; + }, + ExprKind::Struct(_, exprs, expr) => { + let mut ret_vars = exprs + .iter() + .flat_map(|field| { + self.visit_expr(field.expr); + std::mem::take(&mut self.ret_vars) + }) + .collect(); + + walk_list!(self, visit_expr, expr); + self.ret_vars.append(&mut ret_vars); + }, + _ => walk_expr(self, ex), + } + } + + fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) { + if let Res::Local(id) = path.res { + self.ret_vars.push((id, false)); + } + } +} + +impl<'tcx> SideEffectVisit<'tcx> { + fn visit_assign(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) { + // Just support array and tuple unwrapping for now. + // + // ex) `(a, b) = (c, d);` + // The graph would look like this: + // a -> c + // b -> d + // + // This would minimize the connection of the side-effect graph. + match (&lhs.kind, &rhs.kind) { + (ExprKind::Array(lhs), ExprKind::Array(rhs)) | (ExprKind::Tup(lhs), ExprKind::Tup(rhs)) => { + // if not, it is a compile error + debug_assert!(lhs.len() == rhs.len()); + izip!(*lhs, *rhs).for_each(|(lhs, rhs)| self.visit_assign(lhs, rhs)); + }, + // in other assigns, we have to connect all each other + // because they can be connected somehow + _ => { + self.visit_expr(lhs); + let lhs_vars = std::mem::take(&mut self.ret_vars); + self.visit_expr(rhs); + let rhs_vars = std::mem::take(&mut self.ret_vars); + self.connect_assign(&lhs_vars, &rhs_vars); + }, + } + } + + fn visit_block_label(&mut self, block: &'tcx Block<'tcx>, label: Option(target_opt: Option>, source_opt: Option>) -> Option> { match (target_opt, source_opt) { - (Some(mut target), Some(mut source)) => { + (Some(mut target), Some(source)) => { target.reserve(source.len()); - for op in source.drain(..) { + for op in source { target.push(op); } Some(target) @@ -436,9 +436,9 @@ fn chained_binops_helper<'expr>(left_outer: &'expr Expr, right_outer: &'expr Exp chained_binops_helper(left_left, left_right), chained_binops_helper(right_left, right_right), ) { - (Some(mut left_ops), Some(mut right_ops)) => { + (Some(mut left_ops), Some(right_ops)) => { left_ops.reserve(right_ops.len()); - for op in right_ops.drain(..) { + for op in right_ops { left_ops.push(op); } Some(left_ops) diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 56633490eaa..a617422bbeb 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -473,7 +473,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { /// ``` fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) { if let Some(args) = match_lint_emission(cx, expr) { - let mut emission_info = extract_emission_info(cx, args); + let emission_info = extract_emission_info(cx, args); if emission_info.is_empty() { // See: // - src/misc.rs:734:9 @@ -483,7 +483,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { return; } - for (lint_name, applicability, is_multi_part) in emission_info.drain(..) { + for (lint_name, applicability, is_multi_part) in emission_info { let app_info = self.applicability_info.entry(lint_name).or_default(); app_info.applicability = applicability; app_info.is_multi_part_suggestion = is_multi_part; @@ -693,7 +693,7 @@ fn extract_emission_info<'hir>( } lints - .drain(..) + .into_iter() .map(|lint_name| (lint_name, applicability, multi_part)) .collect() } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 9654895060f..00594f4d42a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -74,6 +74,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { self.inter_expr().eq_expr(left, right) } + pub fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool { + self.inter_expr().eq_path(left, right) + } + pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool { self.inter_expr().eq_path_segment(left, right) } @@ -362,7 +366,7 @@ impl HirEqInterExpr<'_, '_, '_> { } } - fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool { + pub fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool { match (left.res, right.res) { (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r), (Res::Local(_), _) | (_, Res::Local(_)) => false, diff --git a/tests/ui/extend_with_drain.fixed b/tests/ui/extend_with_drain.fixed index e863870e7d6..71ebad24c16 100644 --- a/tests/ui/extend_with_drain.fixed +++ b/tests/ui/extend_with_drain.fixed @@ -1,11 +1,11 @@ // run-rustfix #![warn(clippy::extend_with_drain)] +#![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; fn main() { //gets linted let mut vec1 = vec![0u8; 1024]; let mut vec2: std::vec::Vec = Vec::new(); - vec2.append(&mut vec1); let mut vec3 = vec![0u8; 1024]; @@ -17,7 +17,7 @@ fn main() { vec11.append(&mut return_vector()); - //won't get linted it dosen't move the entire content of a vec into another + //won't get linted it doesn't move the entire content of a vec into another let mut test1 = vec![0u8, 10]; let mut test2: std::vec::Vec = Vec::new(); diff --git a/tests/ui/extend_with_drain.rs b/tests/ui/extend_with_drain.rs index dcb36b5951c..e9f011abb0e 100644 --- a/tests/ui/extend_with_drain.rs +++ b/tests/ui/extend_with_drain.rs @@ -1,11 +1,11 @@ // run-rustfix #![warn(clippy::extend_with_drain)] +#![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; fn main() { //gets linted let mut vec1 = vec![0u8; 1024]; let mut vec2: std::vec::Vec = Vec::new(); - vec2.extend(vec1.drain(..)); let mut vec3 = vec![0u8; 1024]; @@ -17,7 +17,7 @@ fn main() { vec11.extend(return_vector().drain(..)); - //won't get linted it dosen't move the entire content of a vec into another + //won't get linted it doesn't move the entire content of a vec into another let mut test1 = vec![0u8, 10]; let mut test2: std::vec::Vec = Vec::new(); diff --git a/tests/ui/iter_with_drain.fixed b/tests/ui/iter_with_drain.fixed new file mode 100644 index 00000000000..aea4dba9dd5 --- /dev/null +++ b/tests/ui/iter_with_drain.fixed @@ -0,0 +1,56 @@ +// run-rustfix +// will emits unused mut warnings after fixing +#![allow(unused_mut)] +// will emits needless collect warnings after fixing +#![allow(clippy::needless_collect)] +#![warn(clippy::iter_with_drain)] +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn full() { + let mut a = vec!["aaa".to_string(), "bbb".to_string()]; + let mut a: BinaryHeap<_> = a.into_iter().collect(); + let mut a: HashSet<_> = a.drain().collect(); + let mut a: VecDeque<_> = a.drain().collect(); + let mut a: Vec<_> = a.into_iter().collect(); + let mut a: HashMap<_, _> = a.into_iter().map(|x| (x.clone(), x)).collect(); + let _: Vec<(String, String)> = a.drain().collect(); +} + +fn closed() { + let mut a = vec!["aaa".to_string(), "bbb".to_string()]; + let mut a: BinaryHeap<_> = a.into_iter().collect(); + let mut a: HashSet<_> = a.drain().collect(); + let mut a: VecDeque<_> = a.drain().collect(); + let mut a: Vec<_> = a.into_iter().collect(); + let mut a: HashMap<_, _> = a.into_iter().map(|x| (x.clone(), x)).collect(); + let _: Vec<(String, String)> = a.drain().collect(); +} + +fn should_not_help() { + let mut a = vec!["aaa".to_string(), "bbb".to_string()]; + let mut a: BinaryHeap<_> = a.drain(1..).collect(); + let mut a: HashSet<_> = a.drain().collect(); + let mut a: VecDeque<_> = a.drain().collect(); + let mut a: Vec<_> = a.drain(..a.len() - 1).collect(); + let mut a: HashMap<_, _> = a.drain(1..a.len() - 1).map(|x| (x.clone(), x)).collect(); + let _: Vec<(String, String)> = a.drain().collect(); + + let mut b = vec!["aaa".to_string(), "bbb".to_string()]; + let _: Vec<_> = b.drain(0..a.len()).collect(); +} + +#[derive(Default)] +struct Bomb { + fire: Vec, +} + +fn should_not_help_0(bomb: &mut Bomb) { + let _: Vec = bomb.fire.drain(..).collect(); +} + +fn main() { + full(); + closed(); + should_not_help(); + should_not_help_0(&mut Bomb::default()); +} diff --git a/tests/ui/iter_with_drain.rs b/tests/ui/iter_with_drain.rs new file mode 100644 index 00000000000..271878cffb4 --- /dev/null +++ b/tests/ui/iter_with_drain.rs @@ -0,0 +1,56 @@ +// run-rustfix +// will emits unused mut warnings after fixing +#![allow(unused_mut)] +// will emits needless collect warnings after fixing +#![allow(clippy::needless_collect)] +#![warn(clippy::iter_with_drain)] +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn full() { + let mut a = vec!["aaa".to_string(), "bbb".to_string()]; + let mut a: BinaryHeap<_> = a.drain(..).collect(); + let mut a: HashSet<_> = a.drain().collect(); + let mut a: VecDeque<_> = a.drain().collect(); + let mut a: Vec<_> = a.drain(..).collect(); + let mut a: HashMap<_, _> = a.drain(..).map(|x| (x.clone(), x)).collect(); + let _: Vec<(String, String)> = a.drain().collect(); +} + +fn closed() { + let mut a = vec!["aaa".to_string(), "bbb".to_string()]; + let mut a: BinaryHeap<_> = a.drain(0..).collect(); + let mut a: HashSet<_> = a.drain().collect(); + let mut a: VecDeque<_> = a.drain().collect(); + let mut a: Vec<_> = a.drain(..a.len()).collect(); + let mut a: HashMap<_, _> = a.drain(0..a.len()).map(|x| (x.clone(), x)).collect(); + let _: Vec<(String, String)> = a.drain().collect(); +} + +fn should_not_help() { + let mut a = vec!["aaa".to_string(), "bbb".to_string()]; + let mut a: BinaryHeap<_> = a.drain(1..).collect(); + let mut a: HashSet<_> = a.drain().collect(); + let mut a: VecDeque<_> = a.drain().collect(); + let mut a: Vec<_> = a.drain(..a.len() - 1).collect(); + let mut a: HashMap<_, _> = a.drain(1..a.len() - 1).map(|x| (x.clone(), x)).collect(); + let _: Vec<(String, String)> = a.drain().collect(); + + let mut b = vec!["aaa".to_string(), "bbb".to_string()]; + let _: Vec<_> = b.drain(0..a.len()).collect(); +} + +#[derive(Default)] +struct Bomb { + fire: Vec, +} + +fn should_not_help_0(bomb: &mut Bomb) { + let _: Vec = bomb.fire.drain(..).collect(); +} + +fn main() { + full(); + closed(); + should_not_help(); + should_not_help_0(&mut Bomb::default()); +} diff --git a/tests/ui/iter_with_drain.stderr b/tests/ui/iter_with_drain.stderr new file mode 100644 index 00000000000..aa394439fa6 --- /dev/null +++ b/tests/ui/iter_with_drain.stderr @@ -0,0 +1,40 @@ +error: `drain(..)` used on a `Vec` + --> $DIR/iter_with_drain.rs:11:34 + | +LL | let mut a: BinaryHeap<_> = a.drain(..).collect(); + | ^^^^^^^^^ help: try this: `into_iter()` + | + = note: `-D clippy::iter-with-drain` implied by `-D warnings` + +error: `drain(..)` used on a `VecDeque` + --> $DIR/iter_with_drain.rs:14:27 + | +LL | let mut a: Vec<_> = a.drain(..).collect(); + | ^^^^^^^^^ help: try this: `into_iter()` + +error: `drain(..)` used on a `Vec` + --> $DIR/iter_with_drain.rs:15:34 + | +LL | let mut a: HashMap<_, _> = a.drain(..).map(|x| (x.clone(), x)).collect(); + | ^^^^^^^^^ help: try this: `into_iter()` + +error: `drain(..)` used on a `Vec` + --> $DIR/iter_with_drain.rs:21:34 + | +LL | let mut a: BinaryHeap<_> = a.drain(0..).collect(); + | ^^^^^^^^^^ help: try this: `into_iter()` + +error: `drain(..)` used on a `VecDeque` + --> $DIR/iter_with_drain.rs:24:27 + | +LL | let mut a: Vec<_> = a.drain(..a.len()).collect(); + | ^^^^^^^^^^^^^^^^ help: try this: `into_iter()` + +error: `drain(..)` used on a `Vec` + --> $DIR/iter_with_drain.rs:25:34 + | +LL | let mut a: HashMap<_, _> = a.drain(0..a.len()).map(|x| (x.clone(), x)).collect(); + | ^^^^^^^^^^^^^^^^^ help: try this: `into_iter()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index 19b253b0fe2..40d7791df28 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -1,7 +1,7 @@ // run-rustfix #![allow(unused_parens)] - +#![allow(clippy::iter_with_drain)] fn f() -> usize { 42 } diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index 7d034117547..a8ddd9b5f75 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -1,7 +1,7 @@ // run-rustfix #![allow(unused_parens)] - +#![allow(clippy::iter_with_drain)] fn f() -> usize { 42 } -- cgit 1.4.1-3-g733a5 From ce841fe73b1476f6d4ac1495f88a567c501d01a8 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sat, 5 Mar 2022 18:35:58 -0500 Subject: Format with `rustfmt_if_chain` --- clippy_lints/src/methods/unnecessary_to_owned.rs | 36 +++++++++--------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 7916fb8e3b4..cc9949b153f 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -114,7 +114,12 @@ fn check_addr_of_expr( parent.span, &format!("unnecessary use of `{}`", method_name), "use", - format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs), + format!( + "{:&>width$}{}", + "", + receiver_snippet, + width = n_target_refs - n_receiver_refs + ), Applicability::MachineApplicable, ); return true; @@ -182,20 +187,10 @@ fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { - if unnecessary_iter_cloned::check_for_loop_iter( - cx, - parent, - method_name, - receiver, - true, - ) { + if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } - let cloned_or_copied = if is_copy(cx, item_ty) { - "copied" - } else { - "cloned" - }; + let cloned_or_copied = if is_copy(cx, item_ty) { "copied" } else { "cloned" }; // The next suggestion may be incorrect because the removal of the `to_owned`-like // function could cause the iterator to hold a reference to a resource that is used // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. @@ -243,10 +238,11 @@ fn check_other_call_arg<'tcx>( if if trait_predicate.def_id() == deref_trait_id { if let [projection_predicate] = projection_predicates[..] { let normalized_ty = - cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); + cx.tcx + .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && get_associated_type(cx, receiver_ty, deref_trait_id, - "Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty) + && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") + .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty) } else { false } @@ -254,7 +250,7 @@ fn check_other_call_arg<'tcx>( let composed_substs = compose_substs( cx, &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], - call_substs + call_substs, ); implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) } else { @@ -339,11 +335,7 @@ fn get_input_traits_and_projections<'tcx>( if let Some(arg) = substs.iter().next(); if let GenericArgKind::Type(arg_ty) = arg.unpack(); if arg_ty == input; - then { - true - } else { - false - } + then { true } else { false } } }; match predicate.kind().skip_binder() { -- cgit 1.4.1-3-g733a5 From 1a95590faf2a81e7b7bae697c2209ba7607f0336 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sat, 5 Mar 2022 21:18:44 -0500 Subject: Fix #8507 --- clippy_lints/src/methods/unnecessary_to_owned.rs | 10 ++++- tests/ui/unnecessary_to_owned.fixed | 48 ++++++++++++++++++++++++ tests/ui/unnecessary_to_owned.rs | 48 ++++++++++++++++++++++++ tests/ui/unnecessary_to_owned.stderr | 8 +++- 4 files changed, 112 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index cc9949b153f..1555758fc4a 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,7 +2,9 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::ty::{ + contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs, +}; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; @@ -260,6 +262,12 @@ fn check_other_call_arg<'tcx>( // `Target = T`. if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); + // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then + // `T` must not be instantiated with a reference + // (https://github.com/rust-lang/rust-clippy/issues/8507). + if (n_refs == 0 && !receiver_ty.is_ref()) + || trait_predicate.def_id() != as_ref_trait_id + || !contains_ty(fn_sig.output(), input); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 720138db137..38ba41ac54e 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -212,3 +212,51 @@ fn get_file_path(_file_type: &FileType) -> Result(P); + + pub trait Abstracted {} + + impl

Abstracted for Opaque

{} + + fn build

(p: P) -> Opaque

+ where + P: AsRef, + { + Opaque(p) + } + + // Should not lint. + fn test_str(s: &str) -> Box { + Box::new(build(s.to_string())) + } + + // Should not lint. + fn test_x(x: super::X) -> Box { + Box::new(build(x)) + } + + #[derive(Clone, Copy)] + struct Y(&'static str); + + impl AsRef 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 { + Box::new(build(y)) + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 60b2e718f5d..15fb7ee83e3 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -212,3 +212,51 @@ fn get_file_path(_file_type: &FileType) -> Result(P); + + pub trait Abstracted {} + + impl

Abstracted for Opaque

{} + + fn build

(p: P) -> Opaque

+ where + P: AsRef, + { + Opaque(p) + } + + // Should not lint. + fn test_str(s: &str) -> Box { + Box::new(build(s.to_string())) + } + + // Should not lint. + fn test_x(x: super::X) -> Box { + Box::new(build(x)) + } + + #[derive(Clone, Copy)] + struct Y(&'static str); + + impl AsRef 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 { + Box::new(build(y.to_string())) + } +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 1dfc65e22e2..c53ce32be77 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -491,5 +491,11 @@ LL - let path = match get_file_path(&t) { LL + let path = match get_file_path(t) { | -error: aborting due to 76 previous errors +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:260:24 + | +LL | Box::new(build(y.to_string())) + | ^^^^^^^^^^^^^ help: use: `y` + +error: aborting due to 77 previous errors -- cgit 1.4.1-3-g733a5 From b981748036e3fbf3ab13a33c7eaab05735f86a4d Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 15 Mar 2022 09:46:49 +0100 Subject: Move iter_with_drain to nursery --- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.register_perf.rs | 1 - clippy_lints/src/methods/mod.rs | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 23bca5a0eab..814e898b5b2 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -166,7 +166,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::ITER_NTH_ZERO), LintId::of(methods::ITER_OVEREAGER_CLONED), LintId::of(methods::ITER_SKIP_NEXT), - LintId::of(methods::ITER_WITH_DRAIN), LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 8d4dde42bbe..c2fc67afba5 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -13,6 +13,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(future_not_send::FUTURE_NOT_SEND), LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutex_atomic::MUTEX_ATOMIC), diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index 6e9c0ee33a1..f2f5c988d8f 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -16,7 +16,6 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::ITER_NTH), LintId::of(methods::ITER_OVEREAGER_CLONED), - LintId::of(methods::ITER_WITH_DRAIN), LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::SINGLE_CHAR_PATTERN), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5edd22cd14c..aa9f86f292c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1140,7 +1140,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.61.0"] pub ITER_WITH_DRAIN, - perf, + nursery, "replace `.drain(..)` with `.into_iter()`" } -- cgit 1.4.1-3-g733a5 From 6a3dbe4798e3966b80b16373fda75f5e4dd91384 Mon Sep 17 00:00:00 2001 From: dswij Date: Tue, 15 Mar 2022 21:29:17 +0800 Subject: `unnecessary_lazy_eval` show suggestions on multiline lint --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 26 ++-- tests/ui/unnecessary_lazy_eval.fixed | 8 ++ tests/ui/unnecessary_lazy_eval.rs | 8 ++ tests/ui/unnecessary_lazy_eval.stderr | 145 +++++++++++++++++----- tests/ui/unnecessary_lazy_eval_unfixable.stderr | 12 +- 5 files changed, 148 insertions(+), 51 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 1e2765263c8..0dd41a4dacf 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{eager_or_lazy, usage}; @@ -48,20 +48,16 @@ pub(super) fn check<'tcx>( Applicability::MaybeIncorrect }; - span_lint_and_sugg( - cx, - UNNECESSARY_LAZY_EVALUATIONS, - expr.span, - msg, - &format!("use `{}` instead", simplify_using), - format!( - "{0}.{1}({2})", - snippet(cx, recv.span, ".."), - simplify_using, - snippet(cx, body_expr.span, ".."), - ), - applicability, - ); + if let hir::ExprKind::MethodCall(_, _, span) = expr.kind { + span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { + diag.span_suggestion( + span, + &format!("use `{}(..)` instead", simplify_using), + format!("{}({})", simplify_using, snippet(cx, body_expr.span, "..")), + applicability, + ); + }); + } } } } diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 4ba2a0a5dbc..65fcdc43061 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -115,6 +115,14 @@ fn main() { let _: Result = res.or(Ok(2)); let _: Result = res.or(Ok(astronomers_pi)); let _: Result = res.or(Ok(ext_str.some_field)); + let _: Result = res. + // some lines + // some lines + // some lines + // some lines + // some lines + // some lines + or(Ok(ext_str.some_field)); // neither bind_instead_of_map nor unnecessary_lazy_eval applies here let _: Result = res.and_then(|x| Err(x)); diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 466915217e4..206080ed69a 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -115,6 +115,14 @@ fn main() { let _: Result = res.or_else(|_| Ok(2)); let _: Result = res.or_else(|_| Ok(astronomers_pi)); let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + let _: Result = res. + // some lines + // some lines + // some lines + // some lines + // some lines + // some lines + or_else(|_| Ok(ext_str.some_field)); // neither bind_instead_of_map nor unnecessary_lazy_eval applies here let _: Result = res.and_then(|x| Err(x)); diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index cc94bd5cd9e..7e4dd7730e7 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -2,7 +2,9 @@ error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:35:13 | LL | let _ = opt.unwrap_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `opt.unwrap_or(2)` + | ^^^^-------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` @@ -10,187 +12,264 @@ error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)` + | ^^^^--------------------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)` + | ^^^^------------------------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:39:13 | LL | let _ = opt.and_then(|_| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `opt.and(ext_opt)` + | ^^^^--------------------- + | | + | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:40:13 | LL | let _ = opt.or_else(|| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `opt.or(ext_opt)` + | ^^^^------------------- + | | + | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:41:13 | LL | let _ = opt.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `opt.or(None)` + | ^^^^---------------- + | | + | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:42:13 | LL | let _ = opt.get_or_insert_with(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `get_or_insert` instead: `opt.get_or_insert(2)` + | ^^^^------------------------ + | | + | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:43:13 | LL | let _ = opt.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^ help: use `ok_or` instead: `opt.ok_or(2)` + | ^^^^---------------- + | | + | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:44:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))` + | ^^^^^^^^^^^^^^^^^------------------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:47:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Some(10).unwrap_or(2)` + | ^^^^^^^^^-------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = Some(10).and_then(|_| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `Some(10).and(ext_opt)` + | ^^^^^^^^^--------------------- + | | + | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:49:28 | LL | let _: Option = None.or_else(|| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `None.or(ext_opt)` + | ^^^^^------------------- + | | + | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = None.get_or_insert_with(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `get_or_insert` instead: `None.get_or_insert(2)` + | ^^^^^------------------------ + | | + | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:51:35 | LL | let _: Result = None.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^ help: use `ok_or` instead: `None.ok_or(2)` + | ^^^^^---------------- + | | + | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:52:28 | LL | let _: Option = None.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `None.or(None)` + | ^^^^^---------------- + | | + | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `deep.0.unwrap_or(2)` + | ^^^^^^^-------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = deep.0.and_then(|_| ext_opt); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `deep.0.and(ext_opt)` + | ^^^^^^^--------------------- + | | + | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = deep.0.or_else(|| None); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `deep.0.or(None)` + | ^^^^^^^---------------- + | | + | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `get_or_insert` instead: `deep.0.get_or_insert(2)` + | ^^^^^^^------------------------ + | | + | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:59:13 | LL | let _ = deep.0.ok_or_else(|| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `ok_or` instead: `deep.0.ok_or(2)` + | ^^^^^^^---------------- + | | + | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:79:28 | LL | let _: Option = None.or_else(|| Some(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `None.or(Some(3))` + | ^^^^^------------------- + | | + | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:80:13 | LL | let _ = deep.0.or_else(|| Some(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `deep.0.or(Some(3))` + | ^^^^^^^------------------- + | | + | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:81:13 | LL | let _ = opt.or_else(|| Some(3)); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `opt.or(Some(3))` + | ^^^^------------------- + | | + | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = res2.unwrap_or_else(|_| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `res2.unwrap_or(2)` + | ^^^^^--------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:88:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)` + | ^^^^^---------------------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)` + | ^^^^^-------------------------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:111:35 | LL | let _: Result = res.and_then(|_| Err(2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `res.and(Err(2))` + | ^^^^-------------------- + | | + | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:112:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `res.and(Err(astronomers_pi))` + | ^^^^--------------------------------- + | | + | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:113:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `and` instead: `res.and(Err(ext_str.some_field))` + | ^^^^------------------------------------- + | | + | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:115:35 | LL | let _: Result = res.or_else(|_| Ok(2)); - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `res.or(Ok(2))` + | ^^^^------------------ + | | + | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:116:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `res.or(Ok(astronomers_pi))` + | ^^^^------------------------------- + | | + | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval.rs:117:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `or` instead: `res.or(Ok(ext_str.some_field))` + | ^^^^----------------------------------- + | | + | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 32 previous errors +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval.rs:118:35 + | +LL | let _: Result = res. + | ___________________________________^ +LL | | // some lines +LL | | // some lines +LL | | // some lines +... | +LL | | // some lines +LL | | or_else(|_| Ok(ext_str.some_field)); + | |_________----------------------------------^ + | | + | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` + +error: aborting due to 33 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 75674b0a9d2..20acab6e844 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -2,7 +2,9 @@ error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 | LL | let _ = Ok(1).unwrap_or_else(|()| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | ^^^^^^---------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` @@ -10,13 +12,17 @@ error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | ^^^^^^------------------------ + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | ^^^^^^------------------------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From bd888d435423a47ce3bdbaec6c61a3cb093a7e18 Mon Sep 17 00:00:00 2001 From: dswij Date: Thu, 17 Mar 2022 14:33:09 +0800 Subject: Add some comments --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 0dd41a4dacf..2369be70812 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -48,6 +48,9 @@ pub(super) fn check<'tcx>( Applicability::MaybeIncorrect }; + // This is a duplicate of what's happening in clippy_lints::methods::method_call, + // which isn't ideal, We want to get the method call span, + // but prefer to avoid changing the signature of the function itself. if let hir::ExprKind::MethodCall(_, _, span) = expr.kind { span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( -- cgit 1.4.1-3-g733a5 From 34ad33c57aa9db1b0c8473925affef08fadc7b8a Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 18 Mar 2022 21:11:54 +0100 Subject: refactor: move into methods module --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 41 +++++++++++ clippy_lints/src/methods/or_then_unwrap.rs | 68 +++++++++++++++++++ clippy_lints/src/or_then_unwrap.rs | 102 ---------------------------- 7 files changed, 112 insertions(+), 107 deletions(-) create mode 100644 clippy_lints/src/methods/or_then_unwrap.rs delete mode 100644 clippy_lints/src/or_then_unwrap.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 9ff5f26c1fa..033efcb8a89 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -181,6 +181,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::OR_THEN_UNWRAP), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), @@ -238,7 +239,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(or_then_unwrap::OR_THEN_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 34d764e810d..a2ce69065f9 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -47,6 +47,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::OR_THEN_UNWRAP), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), @@ -66,7 +67,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(no_effect::NO_EFFECT), LintId::of(no_effect::UNNECESSARY_OPERATION), LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), - LintId::of(or_then_unwrap::OR_THEN_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 0b6e3c7e7df..ce5a1170504 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -319,6 +319,7 @@ store.register_lints(&[ methods::OPTION_FILTER_MAP, methods::OPTION_MAP_OR_NONE, methods::OR_FUN_CALL, + methods::OR_THEN_UNWRAP, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -404,7 +405,6 @@ store.register_lints(&[ open_options::NONSENSICAL_OPEN_OPTIONS, option_env_unwrap::OPTION_ENV_UNWRAP, option_if_let_else::OPTION_IF_LET_ELSE, - or_then_unwrap::OR_THEN_UNWRAP, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, panic_in_result_fn::PANIC_IN_RESULT_FN, panic_unimplemented::PANIC, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fdab58935ef..504235d0d1e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -322,7 +322,6 @@ mod only_used_in_recursion; mod open_options; mod option_env_unwrap; mod option_if_let_else; -mod or_then_unwrap; mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; @@ -867,7 +866,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ignore_publish: cargo_ignore_publish, }) }); - store.register_late_pass(|| Box::new(or_then_unwrap::OrThenUnwrap)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index aa9f86f292c..1e76428858b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod option_as_ref_deref; mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; +mod or_then_unwrap; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -778,6 +779,42 @@ declare_clippy_lint! { "using any `*or` method with a function call, which suggests `*or_else`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.or(…).unwrap()` calls to Options and Results. + /// + /// ### Why is this bad? + /// You should use `.unwrap_or(…)` instead for clarity. + /// + /// ### Example + /// ```rust + /// # let fallback = "fallback"; + /// // Result + /// # type Error = &'static str; + /// # let result: Result<&str, Error> = Err("error"); + /// let value = result.or::(Ok(fallback)).unwrap(); + /// + /// // Option + /// # let option: Option<&str> = None; + /// let value = option.or(Some(fallback)).unwrap(); + /// ``` + /// Use instead: + /// ```rust + /// # let fallback = "fallback"; + /// // Result + /// # let result: Result<&str, &str> = Err("error"); + /// let value = result.unwrap_or(fallback); + /// + /// // Option + /// # let option: Option<&str> = None; + /// let value = option.unwrap_or(fallback); + /// ``` + #[clippy::version = "1.61.0"] + pub OR_THEN_UNWRAP, + complexity, + "checks for `.or(…).unwrap()` calls to Options and Results." +} + declare_clippy_lint! { /// ### What it does /// Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`, @@ -2039,6 +2076,7 @@ impl_lint_pass!(Methods => [ OPTION_MAP_OR_NONE, BIND_INSTEAD_OF_MAP, OR_FUN_CALL, + OR_THEN_UNWRAP, EXPECT_FUN_CALL, CHARS_NEXT_CMP, CHARS_LAST_CMP, @@ -2474,6 +2512,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio Some(("get_mut", [recv, get_arg], _)) => { get_unwrap::check(cx, expr, recv, get_arg, true); }, + Some(("or", [recv, or_arg], or_span)) => { + or_then_unwrap::check(cx, expr, recv, or_arg, or_span); + }, _ => {}, } unwrap_used::check(cx, expr, recv); diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs new file mode 100644 index 00000000000..02fa5887f67 --- /dev/null +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -0,0 +1,68 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::{sym, Span}; + +use super::OR_THEN_UNWRAP; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + unwrap_expr: &Expr<'_>, + recv: &'tcx Expr<'tcx>, + or_arg: &'tcx Expr<'_>, + or_span: Span, +) { + let ty = cx.typeck_results().expr_ty(recv); // get type of x (we later check if it's Option or Result) + let title; + + if is_type_diagnostic_item(cx, ty, sym::Option) { + title = ".or(Some(…)).unwrap() found"; + if !is(or_arg, "Some") { + return; + } + } else if is_type_diagnostic_item(cx, ty, sym::Result) { + title = ".or(Ok(…)).unwrap() found"; + if !is(or_arg, "Ok") { + return; + } + } else { + // Someone has implemented a struct with .or(...).unwrap() chaining, + // but it's not an Option or a Result, so bail + return; + } + + let unwrap_span = if let ExprKind::MethodCall(_, _, span) = unwrap_expr.kind { + span + } else { + // unreachable. but fallback to ident's span ("()" are missing) + unwrap_expr.span + }; + + span_lint_and_help( + cx, + OR_THEN_UNWRAP, + or_span.to(unwrap_span), + title, + None, + "use `unwrap_or()` instead", + ); +} + +/// is expr a Call to name? +/// name might be "Some", "Ok", "Err", etc. +fn is<'a>(expr: &Expr<'a>, name: &str) -> bool { + if_chain! { + if let ExprKind::Call(some_expr, _some_args) = expr.kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = &some_expr.kind; + if let Some(path_segment) = path.segments.first(); + if path_segment.ident.name.as_str() == name; + then { + true + } + else { + false + } + } +} diff --git a/clippy_lints/src/or_then_unwrap.rs b/clippy_lints/src/or_then_unwrap.rs deleted file mode 100644 index d467fbdfe02..00000000000 --- a/clippy_lints/src/or_then_unwrap.rs +++ /dev/null @@ -1,102 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `.or(…).unwrap()` calls to Options and Results. - /// - /// ### Why is this bad? - /// You should use `.unwrap_or(…)` instead for clarity. - /// - /// ### Example - /// ```rust - /// # let fallback = "fallback"; - /// // Result - /// # type Error = &'static str; - /// # let result: Result<&str, Error> = Err("error"); - /// let value = result.or::(Ok(fallback)).unwrap(); - /// - /// // Option - /// # let option: Option<&str> = None; - /// let value = option.or(Some(fallback)).unwrap(); - /// ``` - /// Use instead: - /// ```rust - /// # let fallback = "fallback"; - /// // Result - /// # let result: Result<&str, &str> = Err("error"); - /// let value = result.unwrap_or(fallback); - /// - /// // Option - /// # let option: Option<&str> = None; - /// let value = option.unwrap_or(fallback); - /// ``` - #[clippy::version = "1.61.0"] - pub OR_THEN_UNWRAP, - complexity, - "checks for `.or(…).unwrap()` calls to Options and Results." -} -declare_lint_pass!(OrThenUnwrap => [OR_THEN_UNWRAP]); - -impl<'tcx> LateLintPass<'tcx> for OrThenUnwrap { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // look for x.or().unwrap() - if_chain! { - if let ExprKind::MethodCall(path, [unwrap_self], unwrap_span) = &expr.kind; - if path.ident.name == sym::unwrap; - if let ExprKind::MethodCall(caller_path, [or_self, or_arg], or_span) = &unwrap_self.kind; - if caller_path.ident.name == sym::or; - then { - let ty = cx.typeck_results().expr_ty(or_self); // get type of x (we later check if it's Option or Result) - let title; - - if is_type_diagnostic_item(cx, ty, sym::Option) { - title = ".or(Some(…)).unwrap() found"; - if !is(or_arg, "Some") { - return; - } - } else if is_type_diagnostic_item(cx, ty, sym::Result) { - title = ".or(Ok(…)).unwrap() found"; - if !is(or_arg, "Ok") { - return; - } - } else { - // Someone has implemented a struct with .or(...).unwrap() chaining, - // but it's not an Option or a Result, so bail - return; - } - - span_lint_and_help( - cx, - OR_THEN_UNWRAP, - or_span.to(*unwrap_span), - title, - None, - "use `unwrap_or()` instead" - ); - } - } - } -} - -/// is expr a Call to name? -/// name might be "Some", "Ok", "Err", etc. -fn is<'a>(expr: &Expr<'a>, name: &str) -> bool { - if_chain! { - if let ExprKind::Call(some_expr, _some_args) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = &some_expr.kind; - if let Some(path_segment) = path.segments.first(); - if path_segment.ident.name.as_str() == name; - then { - true - } - else { - false - } - } -} -- cgit 1.4.1-3-g733a5 From f00e844a1f3b7e6d8a5d84e90baa37b0cebeac67 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 18 Mar 2022 22:44:56 +0100 Subject: feat: use span_lint_and_sugg --- clippy_lints/src/methods/or_then_unwrap.rs | 10 ++++++---- tests/ui/or_then_unwrap.stderr | 7 ++----- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 02fa5887f67..578f898da78 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -1,6 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::{sym, Span}; @@ -40,13 +41,14 @@ pub(super) fn check<'tcx>( unwrap_expr.span }; - span_lint_and_help( + span_lint_and_sugg( cx, OR_THEN_UNWRAP, or_span.to(unwrap_span), title, - None, - "use `unwrap_or()` instead", + "try this", + "unwrap_or(...)".into(), + Applicability::HasPlaceholders, ); } diff --git a/tests/ui/or_then_unwrap.stderr b/tests/ui/or_then_unwrap.stderr index fdd718b3580..7eade84bd65 100644 --- a/tests/ui/or_then_unwrap.stderr +++ b/tests/ui/or_then_unwrap.stderr @@ -2,18 +2,15 @@ error: .or(Some(…)).unwrap() found --> $DIR/or_then_unwrap.rs:22:20 | LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or(...)` | = note: `-D clippy::or-then-unwrap` implied by `-D warnings` - = help: use `unwrap_or()` instead error: .or(Ok(…)).unwrap() found --> $DIR/or_then_unwrap.rs:25:20 | LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use `unwrap_or()` instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or(...)` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 895de1f13e78de456d5ecbdca3c87526c4dbbef2 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 18 Mar 2022 23:18:36 +0100 Subject: feat: make fixable --- clippy_lints/src/methods/or_then_unwrap.rs | 30 +++++++++++++------ tests/ui/or_then_unwrap.fixed | 48 ++++++++++++++++++++++++++++++ tests/ui/or_then_unwrap.rs | 2 ++ tests/ui/or_then_unwrap.stderr | 8 ++--- 4 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 tests/ui/or_then_unwrap.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 578f898da78..4e2dcf67231 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; @@ -17,15 +18,20 @@ pub(super) fn check<'tcx>( ) { let ty = cx.typeck_results().expr_ty(recv); // get type of x (we later check if it's Option or Result) let title; + let or_arg_content: Span; if is_type_diagnostic_item(cx, ty, sym::Option) { title = ".or(Some(…)).unwrap() found"; - if !is(or_arg, "Some") { + if let Some(content) = get_content_if_is(or_arg, "Some") { + or_arg_content = content; + } else { return; } } else if is_type_diagnostic_item(cx, ty, sym::Result) { title = ".or(Ok(…)).unwrap() found"; - if !is(or_arg, "Ok") { + if let Some(content) = get_content_if_is(or_arg, "Ok") { + or_arg_content = content; + } else { return; } } else { @@ -41,30 +47,36 @@ pub(super) fn check<'tcx>( unwrap_expr.span }; + let mut applicability = Applicability::MachineApplicable; + let suggestion = format!( + "unwrap_or({})", + snippet_with_applicability(cx, or_arg_content, "..", &mut applicability) + ); + span_lint_and_sugg( cx, OR_THEN_UNWRAP, or_span.to(unwrap_span), title, "try this", - "unwrap_or(...)".into(), - Applicability::HasPlaceholders, + suggestion, + applicability, ); } -/// is expr a Call to name? +/// is expr a Call to name? if so, return what it's wrapping /// name might be "Some", "Ok", "Err", etc. -fn is<'a>(expr: &Expr<'a>, name: &str) -> bool { +fn get_content_if_is<'a>(expr: &Expr<'a>, name: &str) -> Option { if_chain! { - if let ExprKind::Call(some_expr, _some_args) = expr.kind; + if let ExprKind::Call(some_expr, [arg]) = expr.kind; if let ExprKind::Path(QPath::Resolved(_, path)) = &some_expr.kind; if let Some(path_segment) = path.segments.first(); if path_segment.ident.name.as_str() == name; then { - true + Some(arg.span) } else { - false + None } } } diff --git a/tests/ui/or_then_unwrap.fixed b/tests/ui/or_then_unwrap.fixed new file mode 100644 index 00000000000..b1e69ce2d26 --- /dev/null +++ b/tests/ui/or_then_unwrap.fixed @@ -0,0 +1,48 @@ +// run-rustfix + +#![warn(clippy::or_then_unwrap)] +#![allow(clippy::map_identity)] + +struct SomeStruct {} +impl SomeStruct { + fn or(self, _: Option) -> Self { + self + } + fn unwrap(&self) {} +} + +struct SomeOtherStruct {} +impl SomeOtherStruct { + fn or(self) -> Self { + self + } + fn unwrap(&self) {} +} + +fn main() { + let option: Option<&str> = None; + let _ = option.unwrap_or("fallback"); // should trigger lint + + let result: Result<&str, &str> = Err("Error"); + let _ = result.unwrap_or("fallback"); // should trigger lint + + // Not Option/Result + let instance = SomeStruct {}; + let _ = instance.or(Some(SomeStruct {})).unwrap(); // should not trigger lint + + // or takes no argument + let instance = SomeOtherStruct {}; + let _ = instance.or().unwrap(); // should not trigger lint and should not panic + + // None in or + let option: Option<&str> = None; + let _ = option.or(None).unwrap(); // should not trigger lint + + // Not Err in or + let result: Result<&str, &str> = Err("Error"); + let _ = result.or::<&str>(Err("Other Error")).unwrap(); // should not trigger lint + + // other function between + let option: Option<&str> = None; + let _ = option.or(Some("fallback")).map(|v| v).unwrap(); // should not trigger lint +} diff --git a/tests/ui/or_then_unwrap.rs b/tests/ui/or_then_unwrap.rs index 8d7e50ad405..dc66e86be6f 100644 --- a/tests/ui/or_then_unwrap.rs +++ b/tests/ui/or_then_unwrap.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity)] diff --git a/tests/ui/or_then_unwrap.stderr b/tests/ui/or_then_unwrap.stderr index 7eade84bd65..301a54530cf 100644 --- a/tests/ui/or_then_unwrap.stderr +++ b/tests/ui/or_then_unwrap.stderr @@ -1,16 +1,16 @@ error: .or(Some(…)).unwrap() found - --> $DIR/or_then_unwrap.rs:22:20 + --> $DIR/or_then_unwrap.rs:24:20 | LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or(...)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` | = note: `-D clippy::or-then-unwrap` implied by `-D warnings` error: .or(Ok(…)).unwrap() found - --> $DIR/or_then_unwrap.rs:25:20 + --> $DIR/or_then_unwrap.rs:27:20 | LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or(...)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 0f83753934b84efb6b3263270f625f0f44c208f2 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Sun, 20 Mar 2022 23:43:17 +0100 Subject: feat: change error message --- clippy_lints/src/methods/or_then_unwrap.rs | 4 ++-- tests/ui/or_then_unwrap.stderr | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 4e2dcf67231..a0f6d80c19b 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -21,14 +21,14 @@ pub(super) fn check<'tcx>( let or_arg_content: Span; if is_type_diagnostic_item(cx, ty, sym::Option) { - title = ".or(Some(…)).unwrap() found"; + title = "found `.or(Some(…)).unwrap()`"; if let Some(content) = get_content_if_is(or_arg, "Some") { or_arg_content = content; } else { return; } } else if is_type_diagnostic_item(cx, ty, sym::Result) { - title = ".or(Ok(…)).unwrap() found"; + title = "found `.or(Ok(…)).unwrap()`"; if let Some(content) = get_content_if_is(or_arg, "Ok") { or_arg_content = content; } else { diff --git a/tests/ui/or_then_unwrap.stderr b/tests/ui/or_then_unwrap.stderr index 6b32634defd..da88154c59f 100644 --- a/tests/ui/or_then_unwrap.stderr +++ b/tests/ui/or_then_unwrap.stderr @@ -1,4 +1,4 @@ -error: .or(Some(…)).unwrap() found +error: found `.or(Some(…)).unwrap()` --> $DIR/or_then_unwrap.rs:24:20 | LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint @@ -6,13 +6,13 @@ LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint | = note: `-D clippy::or-then-unwrap` implied by `-D warnings` -error: .or(Ok(…)).unwrap() found +error: found `.or(Ok(…)).unwrap()` --> $DIR/or_then_unwrap.rs:27:20 | LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` -error: .or(Some(…)).unwrap() found +error: found `.or(Some(…)).unwrap()` --> $DIR/or_then_unwrap.rs:31:31 | LL | let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint -- cgit 1.4.1-3-g733a5 From 4580c8a9b7f61d2e9968ae1aaab08cfa2a5eb221 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Sun, 20 Mar 2022 23:54:04 +0100 Subject: refactor: use is_lang_ctor() --- clippy_lints/src/methods/or_then_unwrap.rs | 31 ++++++++++++------------------ 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index a0f6d80c19b..28b1bfe8fb5 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -1,9 +1,8 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; +use clippy_utils::{diagnostics::span_lint_and_sugg, is_lang_ctor}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{lang_items::LangItem, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::{sym, Span}; @@ -22,14 +21,14 @@ pub(super) fn check<'tcx>( if is_type_diagnostic_item(cx, ty, sym::Option) { title = "found `.or(Some(…)).unwrap()`"; - if let Some(content) = get_content_if_is(or_arg, "Some") { + if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) { or_arg_content = content; } else { return; } } else if is_type_diagnostic_item(cx, ty, sym::Result) { title = "found `.or(Ok(…)).unwrap()`"; - if let Some(content) = get_content_if_is(or_arg, "Ok") { + if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) { or_arg_content = content; } else { return; @@ -64,19 +63,13 @@ pub(super) fn check<'tcx>( ); } -/// is expr a Call to name? if so, return what it's wrapping -/// name might be "Some", "Ok", "Err", etc. -fn get_content_if_is<'a>(expr: &Expr<'a>, name: &str) -> Option { - if_chain! { - if let ExprKind::Call(some_expr, [arg]) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = &some_expr.kind; - if let Some(path_segment) = path.segments.first(); - if path_segment.ident.name.as_str() == name; - then { - Some(arg.span) - } - else { - None - } +fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option { + if let ExprKind::Call(some_expr, [arg]) = expr.kind + && let ExprKind::Path(qpath) = &some_expr.kind + && is_lang_ctor(cx, qpath, item) + { + Some(arg.span) + } else { + None } } -- cgit 1.4.1-3-g733a5 From 765cce11b10eabe667b42df1a9a878fe38b713ce Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Mon, 21 Mar 2022 00:04:37 +0100 Subject: refactor: remove need for MethodCall matching --- clippy_lints/src/methods/or_then_unwrap.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 28b1bfe8fb5..be5768c3545 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -39,13 +39,6 @@ pub(super) fn check<'tcx>( return; } - let unwrap_span = if let ExprKind::MethodCall(_, _, span) = unwrap_expr.kind { - span - } else { - // unreachable. but fallback to ident's span ("()" are missing) - unwrap_expr.span - }; - let mut applicability = Applicability::MachineApplicable; let suggestion = format!( "unwrap_or({})", @@ -55,7 +48,7 @@ pub(super) fn check<'tcx>( span_lint_and_sugg( cx, OR_THEN_UNWRAP, - or_span.to(unwrap_span), + unwrap_expr.span.with_lo(or_span.lo()), title, "try this", suggestion, -- cgit 1.4.1-3-g733a5 From 5b6295d663fe5f2cc825f8a74578b0afab58c560 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Mon, 21 Mar 2022 14:11:22 +0800 Subject: allowing [`map_flatten`] to split long suggestions add new function `span_lint_and_sugg_` for edges in `clippy_utils::diagnostics` --- clippy_lints/src/methods/map_flatten.rs | 118 +++++++++---------- clippy_lints/src/methods/mod.rs | 2 +- .../src/utils/internal_lints/metadata_collector.rs | 3 +- clippy_utils/src/diagnostics.rs | 86 +++++++++++++- tests/ui/map_flatten.fixed | 31 ----- tests/ui/map_flatten.rs | 74 +++++++----- tests/ui/map_flatten.stderr | 125 +++++++++++++++------ tests/ui/map_flatten_fixable.fixed | 31 +++++ tests/ui/map_flatten_fixable.rs | 31 +++++ tests/ui/map_flatten_fixable.stderr | 80 +++++++++++++ 10 files changed, 426 insertions(+), 155 deletions(-) delete mode 100644 tests/ui/map_flatten.fixed create mode 100644 tests/ui/map_flatten_fixable.fixed create mode 100644 tests/ui/map_flatten_fixable.rs create mode 100644 tests/ui/map_flatten_fixable.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index e1212c31cfb..f447940ea3b 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -1,83 +1,73 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_sugg_for_edges; use clippy_utils::is_trait_method; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; +use rustc_span::{symbol::sym, Span}; use super::MAP_FLATTEN; /// lint use of `map().flatten()` for `Iterators` and 'Options' -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - recv: &'tcx hir::Expr<'_>, - map_arg: &'tcx hir::Expr<'_>, -) { - // lint if caller of `.map().flatten()` is an Iterator - if is_trait_method(cx, expr, sym::Iterator) { - let map_closure_ty = cx.typeck_results().expr_ty(map_arg); - let is_map_to_option = match map_closure_ty.kind() { - ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { - let map_closure_sig = match map_closure_ty.kind() { - ty::Closure(_, substs) => substs.as_closure().sig(), - _ => map_closure_ty.fn_sig(cx.tcx), - }; - let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output()); - is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option) - }, - _ => false, - }; - - let method_to_use = if is_map_to_option { - // `(...).map(...)` has type `impl Iterator> - "filter_map" - } else { - // `(...).map(...)` has type `impl Iterator> - "flat_map" - }; - let func_snippet = snippet(cx, map_arg.span, ".."); - let hint = format!(".{0}({1})", method_to_use, func_snippet); - span_lint_and_sugg( +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) { + if let Some((caller_ty_name, method_to_use)) = try_get_caller_ty_name_and_method_name(cx, expr, recv, map_arg) { + let mut applicability = Applicability::MachineApplicable; + let help_msgs = [ + &format!("try replacing `map` with `{}`", method_to_use), + "and remove the `.flatten()`", + ]; + let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability); + span_lint_and_sugg_for_edges( cx, MAP_FLATTEN, - expr.span.with_lo(recv.span.hi()), - "called `map(..).flatten()` on an `Iterator`", - &format!("try using `{}` instead", method_to_use), - hint, - Applicability::MachineApplicable, + expr.span.with_lo(map_span.lo()), + &format!("called `map(..).flatten()` on `{}`", caller_ty_name), + &help_msgs, + format!("{}({})", method_to_use, closure_snippet), + applicability, ); } +} - // lint if caller of `.map().flatten()` is an Option or Result - let caller_type = match cx.typeck_results().expr_ty(recv).kind() { - ty::Adt(adt, _) => { +fn try_get_caller_ty_name_and_method_name( + cx: &LateContext<'_>, + expr: &Expr<'_>, + caller_expr: &Expr<'_>, + map_arg: &Expr<'_>, +) -> Option<(&'static str, &'static str)> { + if is_trait_method(cx, expr, sym::Iterator) { + if is_map_to_option(cx, map_arg) { + // `(...).map(...)` has type `impl Iterator> + Some(("Iterator", "filter_map")) + } else { + // `(...).map(...)` has type `impl Iterator> + Some(("Iterator", "flat_map")) + } + } else { + if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(caller_expr).kind() { if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) { - "Option" + return Some(("Option", "and_then")); } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) { - "Result" - } else { - return; + return Some(("Result", "and_then")); } - }, - _ => { - return; - }, - }; + } + None + } +} - let func_snippet = snippet(cx, map_arg.span, ".."); - let hint = format!(".and_then({})", func_snippet); - let lint_info = format!("called `map(..).flatten()` on an `{}`", caller_type); - span_lint_and_sugg( - cx, - MAP_FLATTEN, - expr.span.with_lo(recv.span.hi()), - &lint_info, - "try using `and_then` instead", - hint, - Applicability::MachineApplicable, - ); +fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool { + let map_closure_ty = cx.typeck_results().expr_ty(map_arg); + match map_closure_ty.kind() { + ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => { + let map_closure_sig = match map_closure_ty.kind() { + ty::Closure(_, substs) => substs.as_closure().sig(), + _ => map_closure_ty.fn_sig(cx.tcx), + }; + let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output()); + is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option) + }, + _ => false, + } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index aa9f86f292c..822f40179ee 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2377,7 +2377,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio flat_map_option::check(cx, expr, arg, span); }, (name @ "flatten", args @ []) => match method_call(recv) { - Some(("map", [recv, map_arg], _)) => map_flatten::check(cx, expr, recv, map_arg), + 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, recv2, name, args), _ => {}, }, diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index a617422bbeb..b3fad6ce7b6 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -85,7 +85,7 @@ macro_rules! CONFIGURATION_VALUE_TEMPLATE { }; } -const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ +const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [ &["clippy_utils", "diagnostics", "span_lint"], &["clippy_utils", "diagnostics", "span_lint_and_help"], &["clippy_utils", "diagnostics", "span_lint_and_note"], @@ -93,6 +93,7 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ &["clippy_utils", "diagnostics", "span_lint_and_sugg"], &["clippy_utils", "diagnostics", "span_lint_and_then"], &["clippy_utils", "diagnostics", "span_lint_hir_and_then"], + &["clippy_utils", "diagnostics", "span_lint_and_sugg_for_edges"], ]; const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [ ("span_suggestion", false), diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index a927788e6a4..625a53899df 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -8,7 +8,7 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::source_map::{MultiSpan, Span}; @@ -213,6 +213,90 @@ pub fn span_lint_and_sugg<'a, T: LintContext>( }); } +/// Like [`span_lint_and_sugg`] with a focus on the edges. The output will either +/// emit single span or multispan suggestion depending on the number of its lines. +/// +/// If the given suggestion string has more lines than the maximum display length defined by +/// [`MAX_SUGGESTION_HIGHLIGHT_LINES`][`rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES`], +/// this function will split the suggestion and span to showcase the change for the top and +/// bottom edge of the code. For normal suggestions, in one display window, the help message +/// will be combined with a colon. +/// +/// Multipart suggestions like the one being created here currently cannot be +/// applied by rustfix (See [rustfix#141](https://github.com/rust-lang/rustfix/issues/141)). +/// Testing rustfix with this lint emission function might require a file with +/// suggestions that can be fixed and those that can't. See +/// [clippy#8520](https://github.com/rust-lang/rust-clippy/pull/8520/files) for +/// an example and of this. +/// +/// # Example for a long suggestion +/// +/// ```text +/// error: called `map(..).flatten()` on `Option` +/// --> $DIR/map_flatten.rs:8:10 +/// | +/// LL | .map(|x| { +/// | __________^ +/// LL | | if x <= 5 { +/// LL | | Some(x) +/// LL | | } else { +/// ... | +/// LL | | }) +/// LL | | .flatten(); +/// | |__________________^ +/// | +/// = note: `-D clippy::map-flatten` implied by `-D warnings` +/// help: try replacing `map` with `and_then` +/// | +/// LL ~ .and_then(|x| { +/// LL + if x <= 5 { +/// LL + Some(x) +/// | +/// help: and remove the `.flatten()` +/// | +/// LL + None +/// LL + } +/// LL ~ }); +/// | +/// ``` +pub fn span_lint_and_sugg_for_edges( + cx: &LateContext<'_>, + lint: &'static Lint, + sp: Span, + msg: &str, + helps: &[&str; 2], + sugg: String, + applicability: Applicability, +) { + span_lint_and_then(cx, lint, sp, msg, |diag| { + let sugg_lines_count = sugg.lines().count(); + if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES { + let sm = cx.sess().source_map(); + if let (Ok(line_upper), Ok(line_bottom)) = (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi())) { + let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2; + let span_upper = sm.span_until_char(sp.with_hi(line_upper.sf.lines[line_upper.line + split_idx]), '\n'); + let span_bottom = sp.with_lo(line_bottom.sf.lines[line_bottom.line - split_idx]); + + let sugg_lines_vec = sugg.lines().collect::>(); + let sugg_upper = sugg_lines_vec[..split_idx].join("\n"); + let sugg_bottom = sugg_lines_vec[sugg_lines_count - split_idx..].join("\n"); + + diag.span_suggestion(span_upper, helps[0], sugg_upper, applicability); + diag.span_suggestion(span_bottom, helps[1], sugg_bottom, applicability); + + return; + } + } + diag.span_suggestion_with_style( + sp, + &helps.join(", "), + sugg, + applicability, + rustc_errors::SuggestionStyle::ShowAlways, + ); + }); +} + /// Create a suggestion made from several `span → replacement`. /// /// Note: in the JSON format (used by `compiletest_rs`), the help message will diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed deleted file mode 100644 index fec3a95edd6..00000000000 --- a/tests/ui/map_flatten.fixed +++ /dev/null @@ -1,31 +0,0 @@ -// run-rustfix - -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::map_identity)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::unnecessary_wraps)] -#![feature(result_flattening)] - -fn main() { - // mapping to Option on Iterator - fn option_id(x: i8) -> Option { - Some(x) - } - let option_id_ref: fn(i8) -> Option = option_id; - let option_id_closure = |x| Some(x); - let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect(); - let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect(); - let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect(); - let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); - - // mapping to Iterator on Iterator - let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); - - // mapping to Option on Option - let _: Option<_> = (Some(Some(1))).and_then(|x| x); - - // mapping to Result on Result - let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x); -} diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index aa1f76e335a..7d47ee09dc1 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -1,31 +1,55 @@ -// run-rustfix - -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::map_identity)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::unnecessary_wraps)] +#![warn(clippy::map_flatten)] #![feature(result_flattening)] -fn main() { - // mapping to Option on Iterator - fn option_id(x: i8) -> Option { - Some(x) - } - let option_id_ref: fn(i8) -> Option = option_id; - let option_id_closure = |x| Some(x); - let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); - let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); - let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); - let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); +// issue #8506, multi-line +#[rustfmt::skip] +fn long_span() { + let _: Option = Some(1) + .map(|x| { + if x <= 5 { + Some(x) + } else { + None + } + }) + .flatten(); - // mapping to Iterator on Iterator - let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + let _: Result = Ok(1) + .map(|x| { + if x == 1 { + Ok(x) + } else { + Err(0) + } + }) + .flatten(); - // mapping to Option on Option - let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); + let result: Result = Ok(2); + fn do_something() { } + let _: Result = result + .map(|res| { + if res > 0 { + do_something(); + Ok(res) + } else { + Err(0) + } + }) + .flatten(); + + let _: Vec<_> = vec![5_i8; 6] + .into_iter() + .map(|some_value| { + if some_value > 3 { + Some(some_value) + } else { + None + } + }) + .flatten() + .collect(); +} - // mapping to Result on Result - let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); +fn main() { + long_span(); } diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index bcd2047e6fa..c9c60df838f 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,46 +1,107 @@ -error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:18:46 +error: called `map(..).flatten()` on `Option` + --> $DIR/map_flatten.rs:8:10 | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` +LL | .map(|x| { + | __________^ +LL | | if x <= 5 { +LL | | Some(x) +LL | | } else { +... | +LL | | }) +LL | | .flatten(); + | |__________________^ | = note: `-D clippy::map-flatten` implied by `-D warnings` - -error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:19:46 +help: try replacing `map` with `and_then` | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` - -error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:20:46 +LL ~ .and_then(|x| { +LL + if x <= 5 { +LL + Some(x) | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` - -error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:21:46 +help: and remove the `.flatten()` + | +LL + None +LL + } +LL ~ }); | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` -error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:24:46 +error: called `map(..).flatten()` on `Result` + --> $DIR/map_flatten.rs:18:10 + | +LL | .map(|x| { + | __________^ +LL | | if x == 1 { +LL | | Ok(x) +LL | | } else { +... | +LL | | }) +LL | | .flatten(); + | |__________________^ + | +help: try replacing `map` with `and_then` + | +LL ~ .and_then(|x| { +LL + if x == 1 { +LL + Ok(x) + | +help: and remove the `.flatten()` + | +LL + Err(0) +LL + } +LL ~ }); | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` -error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:27:39 +error: called `map(..).flatten()` on `Result` + --> $DIR/map_flatten.rs:30:10 + | +LL | .map(|res| { + | __________^ +LL | | if res > 0 { +LL | | do_something(); +LL | | Ok(res) +... | +LL | | }) +LL | | .flatten(); + | |__________________^ + | +help: try replacing `map` with `and_then` + | +LL ~ .and_then(|res| { +LL + if res > 0 { +LL + do_something(); + | +help: and remove the `.flatten()` + | +LL + Err(0) +LL + } +LL ~ }); | -LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` -error: called `map(..).flatten()` on an `Result` - --> $DIR/map_flatten.rs:30:41 +error: called `map(..).flatten()` on `Iterator` + --> $DIR/map_flatten.rs:42:10 + | +LL | .map(|some_value| { + | __________^ +LL | | if some_value > 3 { +LL | | Some(some_value) +LL | | } else { +... | +LL | | }) +LL | | .flatten() + | |__________________^ + | +help: try replacing `map` with `filter_map` + | +LL ~ .filter_map(|some_value| { +LL + if some_value > 3 { +LL + Some(some_value) + | +help: and remove the `.flatten()` + | +LL + None +LL + } +LL + }) | -LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed new file mode 100644 index 00000000000..fec3a95edd6 --- /dev/null +++ b/tests/ui/map_flatten_fixable.fixed @@ -0,0 +1,31 @@ +// run-rustfix + +#![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] +#![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::map_identity)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::unnecessary_wraps)] +#![feature(result_flattening)] + +fn main() { + // mapping to Option on Iterator + fn option_id(x: i8) -> Option { + Some(x) + } + let option_id_ref: fn(i8) -> Option = option_id; + let option_id_closure = |x| Some(x); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); + + // mapping to Iterator on Iterator + let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); + + // mapping to Option on Option + let _: Option<_> = (Some(Some(1))).and_then(|x| x); + + // mapping to Result on Result + let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x); +} diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs new file mode 100644 index 00000000000..aa1f76e335a --- /dev/null +++ b/tests/ui/map_flatten_fixable.rs @@ -0,0 +1,31 @@ +// run-rustfix + +#![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] +#![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::map_identity)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::unnecessary_wraps)] +#![feature(result_flattening)] + +fn main() { + // mapping to Option on Iterator + fn option_id(x: i8) -> Option { + Some(x) + } + let option_id_ref: fn(i8) -> Option = option_id; + let option_id_closure = |x| Some(x); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); + let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + + // mapping to Iterator on Iterator + let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + + // mapping to Option on Option + let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); + + // mapping to Result on Result + let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); +} diff --git a/tests/ui/map_flatten_fixable.stderr b/tests/ui/map_flatten_fixable.stderr new file mode 100644 index 00000000000..c91c73846b6 --- /dev/null +++ b/tests/ui/map_flatten_fixable.stderr @@ -0,0 +1,80 @@ +error: called `map(..).flatten()` on `Iterator` + --> $DIR/map_flatten_fixable.rs:18:47 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::map-flatten` implied by `-D warnings` +help: try replacing `map` with `filter_map`, and remove the `.flatten()` + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect(); + | ~~~~~~~~~~~~~~~~~~~~~ + +error: called `map(..).flatten()` on `Iterator` + --> $DIR/map_flatten_fixable.rs:19:47 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try replacing `map` with `filter_map`, and remove the `.flatten()` + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: called `map(..).flatten()` on `Iterator` + --> $DIR/map_flatten_fixable.rs:20:47 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try replacing `map` with `filter_map`, and remove the `.flatten()` + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: called `map(..).flatten()` on `Iterator` + --> $DIR/map_flatten_fixable.rs:21:47 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try replacing `map` with `filter_map`, and remove the `.flatten()` + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: called `map(..).flatten()` on `Iterator` + --> $DIR/map_flatten_fixable.rs:24:47 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try replacing `map` with `flat_map`, and remove the `.flatten()` + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); + | ~~~~~~~~~~~~~~~~~~ + +error: called `map(..).flatten()` on `Option` + --> $DIR/map_flatten_fixable.rs:27:40 + | +LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try replacing `map` with `and_then`, and remove the `.flatten()` + | +LL | let _: Option<_> = (Some(Some(1))).and_then(|x| x); + | ~~~~~~~~~~~~~~~ + +error: called `map(..).flatten()` on `Result` + --> $DIR/map_flatten_fixable.rs:30:42 + | +LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try replacing `map` with `and_then`, and remove the `.flatten()` + | +LL | let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x); + | ~~~~~~~~~~~~~~~ + +error: aborting due to 7 previous errors + -- cgit 1.4.1-3-g733a5 From b60a7fb7b67566c611cfd0de94f76c5596a4915d Mon Sep 17 00:00:00 2001 From: Yoav Lavi Date: Thu, 24 Mar 2022 13:18:18 +0100 Subject: `unnecessary_join` lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/methods/mod.rs | 36 ++++++++++++++++++++++++ clippy_lints/src/methods/unnecessary_join.rs | 41 ++++++++++++++++++++++++++++ tests/ui/unnecessary_join.fixed | 35 ++++++++++++++++++++++++ tests/ui/unnecessary_join.rs | 37 +++++++++++++++++++++++++ tests/ui/unnecessary_join.stderr | 20 ++++++++++++++ 8 files changed, 172 insertions(+) create mode 100644 clippy_lints/src/methods/unnecessary_join.rs create mode 100644 tests/ui/unnecessary_join.fixed create mode 100644 tests/ui/unnecessary_join.rs create mode 100644 tests/ui/unnecessary_join.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index dc83de66554..88f71931d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3508,6 +3508,7 @@ Released 2018-09-13 [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold +[`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 65ad64f1901..21f1ef562b5 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -334,6 +334,7 @@ store.register_lints(&[ methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FIND_MAP, methods::UNNECESSARY_FOLD, + methods::UNNECESSARY_JOIN, methods::UNNECESSARY_LAZY_EVALUATIONS, methods::UNNECESSARY_TO_OWNED, methods::UNWRAP_OR_ELSE_DEFAULT, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 00d30513181..eb6534cb8ca 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -63,6 +63,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(methods::UNNECESSARY_JOIN), LintId::of(misc::FLOAT_CMP), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mut_mut::MUT_MUT), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c586a0444f0..9d4e1fa3994 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -60,6 +60,7 @@ mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; +mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_to_owned; mod unwrap_or_else_default; @@ -2049,6 +2050,35 @@ declare_clippy_lint! { "unnecessary calls to `to_owned`-like functions" } +declare_clippy_lint! { + /// ### What it does + /// Checks for use of `.collect::>().join("")` on iterators. + /// + /// ### Why is this bad? + /// `.collect::()` is more concise and usually more performant + /// + /// ### Example + /// ```rust + /// let vector = vec!["hello", "world"]; + /// let output = vector.iter().map(|item| item.to_uppercase()).collect::>().join(""); + /// println!("{}", output); + /// ``` + /// The correct use would be: + /// ```rust + /// let vector = vec!["hello", "world"]; + /// let output = vector.iter().map(|item| item.to_uppercase()).collect::(); + /// println!("{}", output); + /// ``` + /// ### Known problems + /// While `.collect::()` is more performant in most cases, there are cases where + /// using `.collect::()` over `.collect::>().join("")` + /// will prevent loop unrolling and will result in a negative performance impact. + #[clippy::version = "1.61.0"] + pub UNNECESSARY_JOIN, + pedantic, + "using `.collect::>().join(\"\")` on an iterator" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2134,6 +2164,7 @@ impl_lint_pass!(Methods => [ MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN, UNNECESSARY_TO_OWNED, + UNNECESSARY_JOIN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2429,6 +2460,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), + ("join", [join_arg]) => { + if let Some(("collect", _, span)) = method_call(recv) { + unnecessary_join::check(cx, expr, recv, join_arg, span); + } + }, ("last", args @ []) | ("skip", args @ [_]) => { if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { diff --git a/clippy_lints/src/methods/unnecessary_join.rs b/clippy_lints/src/methods/unnecessary_join.rs new file mode 100644 index 00000000000..973b8a7e6bf --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_join.rs @@ -0,0 +1,41 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item}; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{Ref, Slice}; +use rustc_span::{sym, Span}; + +use super::UNNECESSARY_JOIN; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + join_self_arg: &'tcx Expr<'tcx>, + join_arg: &'tcx Expr<'tcx>, + span: Span, +) { + let applicability = Applicability::MachineApplicable; + let collect_output_adjusted_type = cx.typeck_results().expr_ty_adjusted(join_self_arg); + if_chain! { + // the turbofish for collect is ::> + if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind(); + if let Slice(slice) = ref_type.kind(); + if is_type_diagnostic_item(cx, *slice, sym::String); + // the argument for join is "" + if let ExprKind::Lit(spanned) = &join_arg.kind; + if let LitKind::Str(symbol, _) = spanned.node; + if symbol.is_empty(); + then { + span_lint_and_sugg( + cx, + UNNECESSARY_JOIN, + span.with_hi(expr.span.hi()), + r#"called `.collect>().join("")` on an iterator"#, + "try using", + "collect::()".to_owned(), + applicability, + ); + } + } +} diff --git a/tests/ui/unnecessary_join.fixed b/tests/ui/unnecessary_join.fixed new file mode 100644 index 00000000000..7e12c6ae4be --- /dev/null +++ b/tests/ui/unnecessary_join.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::unnecessary_join)] + +fn main() { + // should be linted + let vector = vec!["hello", "world"]; + let output = vector + .iter() + .map(|item| item.to_uppercase()) + .collect::(); + println!("{}", output); + + // should be linted + let vector = vec!["hello", "world"]; + let output = vector + .iter() + .map(|item| item.to_uppercase()) + .collect::(); + println!("{}", output); + + // should not be linted + let vector = vec!["hello", "world"]; + let output = vector + .iter() + .map(|item| item.to_uppercase()) + .collect::>() + .join("\n"); + println!("{}", output); + + // should not be linted + let vector = vec!["hello", "world"]; + let output = vector.iter().map(|item| item.to_uppercase()).collect::(); + println!("{}", output); +} diff --git a/tests/ui/unnecessary_join.rs b/tests/ui/unnecessary_join.rs new file mode 100644 index 00000000000..0a21656a755 --- /dev/null +++ b/tests/ui/unnecessary_join.rs @@ -0,0 +1,37 @@ +// run-rustfix + +#![warn(clippy::unnecessary_join)] + +fn main() { + // should be linted + let vector = vec!["hello", "world"]; + let output = vector + .iter() + .map(|item| item.to_uppercase()) + .collect::>() + .join(""); + println!("{}", output); + + // should be linted + let vector = vec!["hello", "world"]; + let output = vector + .iter() + .map(|item| item.to_uppercase()) + .collect::>() + .join(""); + println!("{}", output); + + // should not be linted + let vector = vec!["hello", "world"]; + let output = vector + .iter() + .map(|item| item.to_uppercase()) + .collect::>() + .join("\n"); + println!("{}", output); + + // should not be linted + let vector = vec!["hello", "world"]; + let output = vector.iter().map(|item| item.to_uppercase()).collect::(); + println!("{}", output); +} diff --git a/tests/ui/unnecessary_join.stderr b/tests/ui/unnecessary_join.stderr new file mode 100644 index 00000000000..0b14b143aff --- /dev/null +++ b/tests/ui/unnecessary_join.stderr @@ -0,0 +1,20 @@ +error: called `.collect>().join("")` on an iterator + --> $DIR/unnecessary_join.rs:11:10 + | +LL | .collect::>() + | __________^ +LL | | .join(""); + | |_________________^ help: try using: `collect::()` + | + = note: `-D clippy::unnecessary-join` implied by `-D warnings` + +error: called `.collect>().join("")` on an iterator + --> $DIR/unnecessary_join.rs:20:10 + | +LL | .collect::>() + | __________^ +LL | | .join(""); + | |_________________^ help: try using: `collect::()` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From c22b7b8814e459d985c8ab337d933a4ae4feecea Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 29 Mar 2022 21:51:37 +0900 Subject: Fix ICE for `iter_overeager_cloned` --- clippy_lints/src/methods/iter_overeager_cloned.rs | 16 ++++++++++++---- tests/ui/iter_overeager_cloned.fixed | 6 ++++++ tests/ui/iter_overeager_cloned.rs | 6 ++++++ tests/ui/iter_overeager_cloned.stderr | 14 +++++++------- 4 files changed, 31 insertions(+), 11 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index b93f1399eae..54c9ca435a4 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::{get_iterator_item_ty, is_copy}; +use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy}; use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_span::sym; use std::ops::Not; use super::ITER_OVEREAGER_CLONED; @@ -20,9 +21,16 @@ pub(super) fn check<'tcx>( map_arg: &[hir::Expr<'_>], ) { // Check if it's iterator and get type associated with `Item`. - let inner_ty = match get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)) { - Some(ty) => ty, - _ => return, + let inner_ty = if_chain! { + if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + let recv_ty = cx.typeck_results().expr_ty(recv); + if implements_trait(cx, recv_ty, iterator_trait_id, &[]); + if let Some(inner_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)); + then { + inner_ty + } else { + return; + } }; match inner_ty.kind() { diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index a9041671101..56761ebbcb8 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] +#![allow(dead_code)] fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; @@ -43,3 +44,8 @@ fn main() { // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); } + +// #8527 +fn cloned_flatten(x: Option<&Option>) -> Option { + x.cloned().flatten() +} diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index dd04e33a4b3..98321d889b5 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] +#![allow(dead_code)] fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; @@ -45,3 +46,8 @@ fn main() { // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); } + +// #8527 +fn cloned_flatten(x: Option<&Option>) -> Option { + x.cloned().flatten() +} diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index e36b0e36fbd..0582700fd16 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -1,5 +1,5 @@ error: called `cloned().last()` on an `Iterator`. It may be more efficient to call `last().cloned()` instead - --> $DIR/iter_overeager_cloned.rs:7:29 + --> $DIR/iter_overeager_cloned.rs:8:29 | LL | let _: Option = vec.iter().cloned().last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().last().cloned()` @@ -7,13 +7,13 @@ LL | let _: Option = vec.iter().cloned().last(); = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings` error: called `cloned().next()` on an `Iterator`. It may be more efficient to call `next().cloned()` instead - --> $DIR/iter_overeager_cloned.rs:9:29 + --> $DIR/iter_overeager_cloned.rs:10:29 | LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().chain(vec.iter()).next().cloned()` error: called `cloned().count()` on an `Iterator`. It may be more efficient to call `count()` instead - --> $DIR/iter_overeager_cloned.rs:11:20 + --> $DIR/iter_overeager_cloned.rs:12:20 | LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").count()` @@ -21,25 +21,25 @@ LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); = note: `-D clippy::redundant-clone` implied by `-D warnings` error: called `cloned().take(...)` on an `Iterator`. It may be more efficient to call `take(...).cloned()` instead - --> $DIR/iter_overeager_cloned.rs:13:21 + --> $DIR/iter_overeager_cloned.rs:14:21 | LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().take(2).cloned()` error: called `cloned().skip(...)` on an `Iterator`. It may be more efficient to call `skip(...).cloned()` instead - --> $DIR/iter_overeager_cloned.rs:15:21 + --> $DIR/iter_overeager_cloned.rs:16:21 | LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().skip(2).cloned()` error: called `cloned().nth(...)` on an `Iterator`. It may be more efficient to call `nth(...).cloned()` instead - --> $DIR/iter_overeager_cloned.rs:17:13 + --> $DIR/iter_overeager_cloned.rs:18:13 | LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").nth(2).cloned()` error: called `cloned().flatten()` on an `Iterator`. It may be more efficient to call `flatten().cloned()` instead - --> $DIR/iter_overeager_cloned.rs:19:13 + --> $DIR/iter_overeager_cloned.rs:20:13 | LL | let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] | _____________^ -- cgit 1.4.1-3-g733a5 From 1582e7bf88175f7362f5bd12ad5835dcdfb58473 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 8 Feb 2022 16:51:02 +0530 Subject: fix mispelling in diagnostic message of bytes_nth --- clippy_lints/src/methods/bytes_nth.rs | 2 +- tests/ui/bytes_nth.stderr | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 76eaedea8a0..44857d61fef 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, expr.span, - &format!("called `.byte().nth()` on a `{}`", caller_type), + &format!("called `.bytes().nth()` on a `{}`", caller_type), "try", format!( "{}.as_bytes().get({})", diff --git a/tests/ui/bytes_nth.stderr b/tests/ui/bytes_nth.stderr index 536decf5e7f..5641d798853 100644 --- a/tests/ui/bytes_nth.stderr +++ b/tests/ui/bytes_nth.stderr @@ -1,4 +1,4 @@ -error: called `.byte().nth()` on a `String` +error: called `.bytes().nth()` on a `String` --> $DIR/bytes_nth.rs:8:5 | LL | s.bytes().nth(3); @@ -6,13 +6,13 @@ LL | s.bytes().nth(3); | = note: `-D clippy::bytes-nth` implied by `-D warnings` -error: called `.byte().nth()` on a `String` +error: called `.bytes().nth()` on a `String` --> $DIR/bytes_nth.rs:9:14 | LL | let _ = &s.bytes().nth(3); | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` -error: called `.byte().nth()` on a `str` +error: called `.bytes().nth()` on a `str` --> $DIR/bytes_nth.rs:10:5 | LL | s[..].bytes().nth(3); -- cgit 1.4.1-3-g733a5 From 1ad6442e919315144c476b522ed9a43579a319e5 Mon Sep 17 00:00:00 2001 From: Yoav Lavi Date: Wed, 6 Apr 2022 15:59:38 +0200 Subject: update unnecessary_join documentation --- clippy_lints/src/methods/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 021337280d1..b5a9af8c3bb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2055,7 +2055,7 @@ declare_clippy_lint! { /// Checks for use of `.collect::>().join("")` on iterators. /// /// ### Why is this bad? - /// `.collect::()` is more concise and usually more performant + /// `.collect::()` is more concise and might be more performant /// /// ### Example /// ```rust @@ -2070,9 +2070,12 @@ declare_clippy_lint! { /// println!("{}", output); /// ``` /// ### Known problems - /// While `.collect::()` is more performant in most cases, there are cases where + /// While `.collect::()` is sometimes more performant, there are cases where /// using `.collect::()` over `.collect::>().join("")` /// will prevent loop unrolling and will result in a negative performance impact. + /// + /// Additionlly, differences have been observed between aarch64 and x86_64 assembly output, + /// with aarch64 tending to producing faster assembly in more cases when using `.collect::()` #[clippy::version = "1.61.0"] pub UNNECESSARY_JOIN, pedantic, -- cgit 1.4.1-3-g733a5 From cebe575aad4cc24401d676299e31126ea3af26f6 Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Tue, 29 Mar 2022 19:19:16 +0200 Subject: Add .err().expect() lint --- clippy_lints/src/methods/err_expect.rs | 59 ++++++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 28 ++++++++++++++++ clippy_lints/src/utils/conf.rs | 2 +- clippy_utils/src/msrvs.rs | 2 +- tests/ui/err_expect.fixed | 14 ++++++++ tests/ui/err_expect.rs | 14 ++++++++ tests/ui/err_expect.stderr | 10 ++++++ tests/ui/min_rust_version_attr.rs | 6 ++++ tests/ui/min_rust_version_attr.stderr | 8 ++--- 9 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 clippy_lints/src/methods/err_expect.rs create mode 100644 tests/ui/err_expect.fixed create mode 100644 tests/ui/err_expect.rs create mode 100644 tests/ui/err_expect.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs new file mode 100644 index 00000000000..887f5c1cb3b --- /dev/null +++ b/clippy_lints/src/methods/err_expect.rs @@ -0,0 +1,59 @@ +use super::ERR_EXPECT; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::implements_trait; +use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item}; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_middle::ty::Ty; +use rustc_semver::RustcVersion; +use rustc_span::{sym, Span}; + +pub(super) fn check( + cx: &LateContext<'_>, + _expr: &rustc_hir::Expr<'_>, + recv: &rustc_hir::Expr<'_>, + msrv: Option<&RustcVersion>, + expect_span: Span, + err_span: Span, +) { + if_chain! { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); + // Test the version to make sure the lint can be showed (expect_err has been introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) + if meets_msrv(msrv, &msrvs::EXPECT_ERR); + + // Grabs the `Result` type + let result_type = cx.typeck_results().expr_ty(recv); + // Tests if the T type in a `Result` is not None + if let Some(data_type) = get_data_type(cx, result_type); + // Tests if the T type in a `Result` implements debug + if has_debug_impl(data_type, cx); + + then { + span_lint_and_sugg( + cx, + ERR_EXPECT, + err_span.to(expect_span), + "called `.err().expect()` on a `Result` value", + "try", + "expect_err".to_string(), + Applicability::MachineApplicable + ); + } + }; +} + +/// Given a `Result` type, return its data (`T`). +fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { + match ty.kind() { + ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().next(), + _ => None, + } +} + +/// Given a type, very if the Debug trait has been impl'd +fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { + cx.tcx + .get_diagnostic_item(sym::Debug) + .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b5a9af8c3bb..4475f8eaf59 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod chars_next_cmp_with_unwrap; mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; +mod err_expect; mod expect_fun_call; mod expect_used; mod extend_with_drain; @@ -362,6 +363,29 @@ declare_clippy_lint! { "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.err().expect()` calls on the `Result` type. + /// + /// ### Why is this bad? + /// `.expect_err()` can be called directly to avoid the extra type conversion from `ok()`. + /// + /// ### Example + /// ```should_panic + /// let x: Result = Ok(10); + /// x.err().expect("Testing err().expect()"); + /// ``` + /// Use instead: + /// ```should_panic + /// let x: Result = Ok(10); + /// x.expect_err("Testing expect_err"); + /// ``` + #[clippy::version = "1.61.0"] + pub ERR_EXPECT, + style, + r#"using `.err().expect("")` when `.expect_err("")` can be used"# +} + declare_clippy_lint! { /// ### What it does /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and @@ -2168,6 +2192,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_SPLITN, UNNECESSARY_TO_OWNED, UNNECESSARY_JOIN, + ERR_EXPECT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2431,8 +2456,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("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, msrv, span, err_span), _ => expect_used::check(cx, expr, recv), }, + ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); @@ -2574,6 +2601,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); }, }, + _ => {}, } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 680b2eb1da7..0bb818e2079 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -156,7 +156,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, EXPECT_ERR. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index fce93153d96..12191109b8c 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -30,6 +30,6 @@ msrv_aliases! { 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,28,0 { FROM_BOOL } - 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST } + 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } } diff --git a/tests/ui/err_expect.fixed b/tests/ui/err_expect.fixed new file mode 100644 index 00000000000..7e18d70bae4 --- /dev/null +++ b/tests/ui/err_expect.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +struct MyTypeNonDebug; + +#[derive(Debug)] +struct MyTypeDebug; + +fn main() { + let test_debug: Result = Ok(MyTypeDebug); + test_debug.expect_err("Testing debug type"); + + let test_non_debug: Result = Ok(MyTypeNonDebug); + test_non_debug.err().expect("Testing non debug type"); +} diff --git a/tests/ui/err_expect.rs b/tests/ui/err_expect.rs new file mode 100644 index 00000000000..bf8c3c9fb8c --- /dev/null +++ b/tests/ui/err_expect.rs @@ -0,0 +1,14 @@ +// run-rustfix + +struct MyTypeNonDebug; + +#[derive(Debug)] +struct MyTypeDebug; + +fn main() { + let test_debug: Result = Ok(MyTypeDebug); + test_debug.err().expect("Testing debug type"); + + let test_non_debug: Result = Ok(MyTypeNonDebug); + test_non_debug.err().expect("Testing non debug type"); +} diff --git a/tests/ui/err_expect.stderr b/tests/ui/err_expect.stderr new file mode 100644 index 00000000000..ffd97e00a5c --- /dev/null +++ b/tests/ui/err_expect.stderr @@ -0,0 +1,10 @@ +error: called `.err().expect()` on a `Result` value + --> $DIR/err_expect.rs:10:16 + | +LL | test_debug.err().expect("Testing debug type"); + | ^^^^^^^^^^^^ help: try: `expect_err` + | + = note: `-D clippy::err-expect` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 72e9bf9eb36..7666d01ffe1 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -145,6 +145,11 @@ fn int_from_bool() -> u8 { true as u8 } +fn err_expect() { + let x: Result = Ok(10); + x.err().expect("Testing expect_err"); +} + fn main() { filter_map_next(); checked_conversion(); @@ -162,6 +167,7 @@ fn main() { missing_const_for_fn(); unnest_or_patterns(); int_from_bool(); + err_expect(); } mod just_under_msrv { diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 6b3fdb0844b..9ed6308f115 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -1,12 +1,12 @@ error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:186:24 + --> $DIR/min_rust_version_attr.rs:192:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:185:9 + --> $DIR/min_rust_version_attr.rs:191:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,13 +17,13 @@ LL ~ assert_eq!(.to_uppercase(), "WORLD!"); | error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:198:24 + --> $DIR/min_rust_version_attr.rs:204:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:197:9 + --> $DIR/min_rust_version_attr.rs:203:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From a7125b0393c70c3d25feb7e063c312463694a1f6 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Wed, 6 Apr 2022 19:24:49 +0200 Subject: Fix mistakes in documentation : - err() was meant to be employed instead of ok() - wraps comment --- clippy_lints/src/methods/err_expect.rs | 3 ++- clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 887f5c1cb3b..be9d4ad94fb 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -19,7 +19,8 @@ pub(super) fn check( ) { if_chain! { if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - // Test the version to make sure the lint can be showed (expect_err has been introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) + // Test the version to make sure the lint can be showed (expect_err has been + // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) if meets_msrv(msrv, &msrvs::EXPECT_ERR); // Grabs the `Result` type diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4475f8eaf59..c5c871c9d29 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -368,7 +368,7 @@ declare_clippy_lint! { /// Checks for `.err().expect()` calls on the `Result` type. /// /// ### Why is this bad? - /// `.expect_err()` can be called directly to avoid the extra type conversion from `ok()`. + /// `.expect_err()` can be called directly to avoid the extra type conversion from `err()`. /// /// ### Example /// ```should_panic -- cgit 1.4.1-3-g733a5 From 182b7c38d7a55bb6f9f238085c6bebf7d28367eb Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 6 Apr 2022 15:35:49 +0100 Subject: Fix `as_deref_mut` false positives in `needless_option_as_deref` Also moves the lint to the methods directory --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 29 ++++++++++ .../src/methods/needless_option_as_deref.rs | 37 ++++++++++++ clippy_lints/src/needless_option_as_deref.rs | 65 ---------------------- tests/ui/needless_option_as_deref.fixed | 30 +++++++++- tests/ui/needless_option_as_deref.rs | 30 +++++++++- tests/ui/needless_option_as_deref.stderr | 12 +++- 10 files changed, 136 insertions(+), 75 deletions(-) create mode 100644 clippy_lints/src/methods/needless_option_as_deref.rs delete mode 100644 clippy_lints/src/needless_option_as_deref.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1fb3ca1fd9b..341c7e397d3 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -176,6 +176,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OK_EXPECT), @@ -225,7 +226,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(needless_bool::NEEDLESS_BOOL), LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), LintId::of(needless_late_init::NEEDLESS_LATE_INIT), - LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), LintId::of(needless_update::NEEDLESS_UPDATE), LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index a2ce69065f9..10369a855ae 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -44,6 +44,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), @@ -60,7 +61,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(needless_bool::BOOL_COMPARISON), LintId::of(needless_bool::NEEDLESS_BOOL), LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), LintId::of(needless_update::NEEDLESS_UPDATE), LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index bba3cae45f5..e5f5c6cd31c 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -315,6 +315,7 @@ store.register_lints(&[ methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::NEEDLESS_OPTION_AS_DEREF, methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, @@ -386,7 +387,6 @@ store.register_lints(&[ needless_continue::NEEDLESS_CONTINUE, needless_for_each::NEEDLESS_FOR_EACH, needless_late_init::NEEDLESS_LATE_INIT, - needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF, needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, needless_question_mark::NEEDLESS_QUESTION_MARK, needless_update::NEEDLESS_UPDATE, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8dab039f24f..a9a77f5ae04 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -308,7 +308,6 @@ mod needless_borrowed_ref; mod needless_continue; mod needless_for_each; mod needless_late_init; -mod needless_option_as_deref; mod needless_pass_by_value; mod needless_question_mark; mod needless_update; @@ -536,7 +535,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(ptr::Ptr)); store.register_late_pass(|| Box::new(ptr_eq::PtrEq)); store.register_late_pass(|| Box::new(needless_bool::NeedlessBool)); - store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref)); store.register_late_pass(|| Box::new(needless_bool::BoolComparison)); store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach)); store.register_late_pass(|| Box::new(misc::MiscLints)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c5c871c9d29..4a2bcca13b4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -41,6 +41,7 @@ mod map_collect_result_unit; mod map_flatten; mod map_identity; mod map_unwrap_or; +mod needless_option_as_deref; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -2106,6 +2107,30 @@ declare_clippy_lint! { "using `.collect::>().join(\"\")` on an iterator" } +declare_clippy_lint! { + /// ### What it does + /// Checks for no-op uses of `Option::{as_deref, as_deref_mut}`, + /// for example, `Option<&T>::as_deref()` returns the same type. + /// + /// ### Why is this bad? + /// Redundant code and improving readability. + /// + /// ### Example + /// ```rust + /// let a = Some(&1); + /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> + /// ``` + /// Could be written as: + /// ```rust + /// let a = Some(&1); + /// let b = a; + /// ``` + #[clippy::version = "1.57.0"] + pub NEEDLESS_OPTION_AS_DEREF, + complexity, + "no-op use of `deref` or `deref_mut` method to `Option`." +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2193,6 +2218,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_TO_OWNED, UNNECESSARY_JOIN, ERR_EXPECT, + NEEDLESS_OPTION_AS_DEREF, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2425,6 +2451,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, + ("as_deref" | "as_deref_mut", []) => { + needless_option_as_deref::check(cx, expr, recv, name); + }, ("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), diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs new file mode 100644 index 00000000000..7030baf19ff --- /dev/null +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::path_res; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::usage::local_used_after_expr; +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::NEEDLESS_OPTION_AS_DEREF; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) { + let typeck = cx.typeck_results(); + let outer_ty = typeck.expr_ty(expr); + + if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) { + if name == "as_deref_mut" && recv.is_syntactic_place_expr() { + let Res::Local(binding_id) = path_res(cx, recv) else { return }; + + if local_used_after_expr(cx, binding_id, recv) { + return; + } + } + + span_lint_and_sugg( + cx, + NEEDLESS_OPTION_AS_DEREF, + expr.span, + "derefed type is same as origin", + "try this", + snippet_opt(cx, recv.span).unwrap(), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/needless_option_as_deref.rs b/clippy_lints/src/needless_option_as_deref.rs deleted file mode 100644 index 9d3d7d1f24c..00000000000 --- a/clippy_lints/src/needless_option_as_deref.rs +++ /dev/null @@ -1,65 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; -use clippy_utils::ty::is_type_diagnostic_item; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for no-op uses of Option::{as_deref,as_deref_mut}, - /// for example, `Option<&T>::as_deref()` returns the same type. - /// - /// ### Why is this bad? - /// Redundant code and improving readability. - /// - /// ### Example - /// ```rust - /// let a = Some(&1); - /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> - /// ``` - /// Could be written as: - /// ```rust - /// let a = Some(&1); - /// let b = a; - /// ``` - #[clippy::version = "1.57.0"] - pub NEEDLESS_OPTION_AS_DEREF, - complexity, - "no-op use of `deref` or `deref_mut` method to `Option`." -} - -declare_lint_pass!(OptionNeedlessDeref=> [ - NEEDLESS_OPTION_AS_DEREF, -]); - -impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - let typeck = cx.typeck_results(); - let outer_ty = typeck.expr_ty(expr); - - if_chain! { - if is_type_diagnostic_item(cx,outer_ty,sym::Option); - if let ExprKind::MethodCall(path, [sub_expr], _) = expr.kind; - let symbol = path.ident.as_str(); - if symbol == "as_deref" || symbol == "as_deref_mut"; - if outer_ty == typeck.expr_ty(sub_expr); - then{ - span_lint_and_sugg( - cx, - NEEDLESS_OPTION_AS_DEREF, - expr.span, - "derefed type is same as origin", - "try this", - snippet_opt(cx,sub_expr.span).unwrap(), - Applicability::MachineApplicable - ); - } - } - } -} diff --git a/tests/ui/needless_option_as_deref.fixed b/tests/ui/needless_option_as_deref.fixed index d721452ae88..c09b07db3dc 100644 --- a/tests/ui/needless_option_as_deref.fixed +++ b/tests/ui/needless_option_as_deref.fixed @@ -1,13 +1,41 @@ // run-rustfix -#[warn(clippy::needless_option_as_deref)] +#![allow(unused)] +#![warn(clippy::needless_option_as_deref)] fn main() { // should lint let _: Option<&usize> = Some(&1); let _: Option<&mut usize> = Some(&mut 1); + let mut y = 0; + let mut x = Some(&mut y); + let _ = x; + // should not lint let _ = Some(Box::new(1)).as_deref(); let _ = Some(Box::new(1)).as_deref_mut(); + + // #7846 + let mut i = 0; + let mut opt_vec = vec![Some(&mut i)]; + opt_vec[0].as_deref_mut().unwrap(); + + let mut i = 0; + let x = &mut Some(&mut i); + (*x).as_deref_mut(); + + // #8047 + let mut y = 0; + let mut x = Some(&mut y); + x.as_deref_mut(); + dbg!(x); +} + +struct S<'a> { + opt: Option<&'a mut usize>, +} + +fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> { + s.opt.as_deref_mut() } diff --git a/tests/ui/needless_option_as_deref.rs b/tests/ui/needless_option_as_deref.rs index bb15512adf6..c3ba27ecccf 100644 --- a/tests/ui/needless_option_as_deref.rs +++ b/tests/ui/needless_option_as_deref.rs @@ -1,13 +1,41 @@ // run-rustfix -#[warn(clippy::needless_option_as_deref)] +#![allow(unused)] +#![warn(clippy::needless_option_as_deref)] fn main() { // should lint let _: Option<&usize> = Some(&1).as_deref(); let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); + let mut y = 0; + let mut x = Some(&mut y); + let _ = x.as_deref_mut(); + // should not lint let _ = Some(Box::new(1)).as_deref(); let _ = Some(Box::new(1)).as_deref_mut(); + + // #7846 + let mut i = 0; + let mut opt_vec = vec![Some(&mut i)]; + opt_vec[0].as_deref_mut().unwrap(); + + let mut i = 0; + let x = &mut Some(&mut i); + (*x).as_deref_mut(); + + // #8047 + let mut y = 0; + let mut x = Some(&mut y); + x.as_deref_mut(); + dbg!(x); +} + +struct S<'a> { + opt: Option<&'a mut usize>, +} + +fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> { + s.opt.as_deref_mut() } diff --git a/tests/ui/needless_option_as_deref.stderr b/tests/ui/needless_option_as_deref.stderr index 5dd507b4a71..bc07db5b38e 100644 --- a/tests/ui/needless_option_as_deref.stderr +++ b/tests/ui/needless_option_as_deref.stderr @@ -1,5 +1,5 @@ error: derefed type is same as origin - --> $DIR/needless_option_as_deref.rs:7:29 + --> $DIR/needless_option_as_deref.rs:8:29 | LL | let _: Option<&usize> = Some(&1).as_deref(); | ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)` @@ -7,10 +7,16 @@ LL | let _: Option<&usize> = Some(&1).as_deref(); = note: `-D clippy::needless-option-as-deref` implied by `-D warnings` error: derefed type is same as origin - --> $DIR/needless_option_as_deref.rs:8:33 + --> $DIR/needless_option_as_deref.rs:9:33 | LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)` -error: aborting due to 2 previous errors +error: derefed type is same as origin + --> $DIR/needless_option_as_deref.rs:13:13 + | +LL | let _ = x.as_deref_mut(); + | ^^^^^^^^^^^^^^^^ help: try this: `x` + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 06cfeb90c156d70c2318774081b37db809f6d840 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 2 Apr 2022 15:01:07 -0600 Subject: New lint `is_digit_ascii_radix` --- CHANGELOG.md | 1 + .../case_sensitive_file_extension_comparisons.rs | 4 +- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/methods/is_digit_ascii_radix.rs | 50 ++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 33 ++++++++++++++ clippy_lints/src/misc_early/mod.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 2 +- clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/numeric_literal.rs | 2 +- tests/ui/is_digit_ascii_radix.fixed | 18 ++++++++ tests/ui/is_digit_ascii_radix.rs | 18 ++++++++ tests/ui/is_digit_ascii_radix.stderr | 22 ++++++++++ tests/ui/to_digit_is_some.fixed | 4 +- tests/ui/to_digit_is_some.rs | 4 +- tests/ui/to_digit_is_some.stderr | 8 ++-- 18 files changed, 160 insertions(+), 14 deletions(-) create mode 100644 clippy_lints/src/methods/is_digit_ascii_radix.rs create mode 100644 tests/ui/is_digit_ascii_radix.fixed create mode 100644 tests/ui/is_digit_ascii_radix.rs create mode 100644 tests/ui/is_digit_ascii_radix.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index b4097ea86a5..c5c93b11327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3356,6 +3356,7 @@ Released 2018-09-13 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters +[`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index df780747a0c..e3e31c5863e 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -43,8 +43,8 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: & if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind; if (2..=6).contains(&ext_literal.as_str().len()); if ext_literal.as_str().starts_with('.'); - if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_digit(10)) - || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_digit(10)); + if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) + || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); then { let mut ty = ctx.typeck_results().expr_ty(obj); ty = match ty.kind() { diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 28d0c75fde6..e72031e4877 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -739,7 +739,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok). /// Plurals are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { - if s.starts_with(|c: char| c.is_digit(10)) { + if s.starts_with(|c: char| c.is_ascii_digit()) { return false; } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 14ca93b5f3c..aa8e3b535b1 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -165,6 +165,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::FLAT_MAP_IDENTITY), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::IS_DIGIT_ASCII_RADIX), LintId::of(methods::ITERATOR_STEP_BY_ZERO), LintId::of(methods::ITER_CLONED_COLLECT), LintId::of(methods::ITER_COUNT), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 532590aaa5a..7436f31125b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -302,6 +302,7 @@ store.register_lints(&[ methods::INEFFICIENT_TO_STRING, methods::INSPECT_FOR_EACH, methods::INTO_ITER_ON_REF, + methods::IS_DIGIT_ASCII_RADIX, methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 3114afac886..2d98802cb14 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -61,6 +61,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::ERR_EXPECT), LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::IS_DIGIT_ASCII_RADIX), LintId::of(methods::ITER_CLONED_COLLECT), LintId::of(methods::ITER_NEXT_SLICE), LintId::of(methods::ITER_NTH_ZERO), diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs new file mode 100644 index 00000000000..ad333df2f2d --- /dev/null +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -0,0 +1,50 @@ +//! Lint for `c.is_digit(10)` + +use super::IS_DIGIT_ASCII_RADIX; +use clippy_utils::{ + consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, meets_msrv, msrvs, + source::snippet_with_applicability, +}; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_semver::RustcVersion; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + self_arg: &'tcx Expr<'_>, + radix: &'tcx Expr<'_>, + msrv: Option<&RustcVersion>, +) { + if !meets_msrv(msrv, &msrvs::IS_ASCII_DIGIT) { + return; + } + + if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_char() { + return; + } + + if let Some(radix_val) = constant_full_int(cx, cx.typeck_results(), radix) { + let (num, replacement) = match radix_val { + FullInt::S(10) | FullInt::U(10) => (10, "is_ascii_digit"), + FullInt::S(16) | FullInt::U(16) => (16, "is_ascii_hexdigit"), + _ => return, + }; + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + IS_DIGIT_ASCII_RADIX, + expr.span, + &format!("use of `char::is_digit` with literal radix of {}", num), + "try", + format!( + "{}.{}()", + snippet_with_applicability(cx, self_arg.span, "..", &mut applicability), + replacement + ), + applicability, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 70d021a1668..6a7841a90df 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -26,6 +26,7 @@ mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; mod into_iter_on_ref; +mod is_digit_ascii_radix; mod iter_cloned_collect; mod iter_count; mod iter_next_slice; @@ -2131,6 +2132,36 @@ declare_clippy_lint! { "no-op use of `deref` or `deref_mut` method to `Option`." } +declare_clippy_lint! { + /// ### What it does + /// Finds usages of [`char::is_digit`] + /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that + /// can be replaced with [`is_ascii_digit`] + /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or + /// [`is_ascii_hexdigit`] + /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit). + /// + /// ### Why is this bad? + /// `is_digit(..)` is slower and requires specifying the radix. + /// + /// ### Example + /// ```rust + /// let c: char = '6'; + /// c.is_digit(10); + /// c.is_digit(16); + /// ``` + /// Use instead: + /// ```rust + /// let c: char = '6'; + /// c.is_ascii_digit(); + /// c.is_ascii_hexdigit(); + /// ``` + #[clippy::version = "1.61.0"] + pub IS_DIGIT_ASCII_RADIX, + style, + "use of `char::is_digit(..)` with literal radix of 10 or 16" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2219,6 +2250,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_JOIN, ERR_EXPECT, NEEDLESS_OPTION_AS_DEREF, + IS_DIGIT_ASCII_RADIX, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2516,6 +2548,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), ("is_file", []) => filetype_is_file::check(cx, expr, recv), + ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), ("join", [join_arg]) => { diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index d955fad7d41..6860b60acbd 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -361,7 +361,7 @@ impl MiscEarlyLints { // See for a regression. // FIXME: Find a better way to detect those cases. let lit_snip = match snippet_opt(cx, lit.span) { - Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip, + Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip, _ => return, }; diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 0d0c88b02c7..e3bc40c4b49 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { if interned_name.chars().any(char::is_uppercase) { return; } - if interned_name.chars().all(|c| c.is_digit(10) || c == '_') { + if interned_name.chars().all(|c| c.is_ascii_digit() || c == '_') { span_lint( self.0.cx, JUST_UNDERSCORES_AND_DIGITS, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 0424e067202..134fd1ce505 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -32,4 +32,5 @@ msrv_aliases! { 1,28,0 { FROM_BOOL } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } + 1,24,0 { IS_ASCII_DIGIT } } diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index 908ff822712..b92d42e8323 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -57,7 +57,7 @@ impl<'a> NumericLiteral<'a> { .trim_start() .chars() .next() - .map_or(false, |c| c.is_digit(10)) + .map_or(false, |c| c.is_ascii_digit()) { let (unsuffixed, suffix) = split_suffix(src, lit_kind); let float = matches!(lit_kind, LitKind::Float(..)); diff --git a/tests/ui/is_digit_ascii_radix.fixed b/tests/ui/is_digit_ascii_radix.fixed new file mode 100644 index 00000000000..c0ba647d707 --- /dev/null +++ b/tests/ui/is_digit_ascii_radix.fixed @@ -0,0 +1,18 @@ +// run-rustfix + +#![warn(clippy::is_digit_ascii_radix)] + +const TEN: u32 = 10; + +fn main() { + let c: char = '6'; + + // Should trigger the lint. + let _ = c.is_ascii_digit(); + let _ = c.is_ascii_hexdigit(); + let _ = c.is_ascii_hexdigit(); + + // Should not trigger the lint. + let _ = c.is_digit(11); + let _ = c.is_digit(TEN); +} diff --git a/tests/ui/is_digit_ascii_radix.rs b/tests/ui/is_digit_ascii_radix.rs new file mode 100644 index 00000000000..68e3f3243d9 --- /dev/null +++ b/tests/ui/is_digit_ascii_radix.rs @@ -0,0 +1,18 @@ +// run-rustfix + +#![warn(clippy::is_digit_ascii_radix)] + +const TEN: u32 = 10; + +fn main() { + let c: char = '6'; + + // Should trigger the lint. + let _ = c.is_digit(10); + let _ = c.is_digit(16); + let _ = c.is_digit(0x10); + + // Should not trigger the lint. + let _ = c.is_digit(11); + let _ = c.is_digit(TEN); +} diff --git a/tests/ui/is_digit_ascii_radix.stderr b/tests/ui/is_digit_ascii_radix.stderr new file mode 100644 index 00000000000..dc5cb2913ae --- /dev/null +++ b/tests/ui/is_digit_ascii_radix.stderr @@ -0,0 +1,22 @@ +error: use of `char::is_digit` with literal radix of 10 + --> $DIR/is_digit_ascii_radix.rs:11:13 + | +LL | let _ = c.is_digit(10); + | ^^^^^^^^^^^^^^ help: try: `c.is_ascii_digit()` + | + = note: `-D clippy::is-digit-ascii-radix` implied by `-D warnings` + +error: use of `char::is_digit` with literal radix of 16 + --> $DIR/is_digit_ascii_radix.rs:12:13 + | +LL | let _ = c.is_digit(16); + | ^^^^^^^^^^^^^^ help: try: `c.is_ascii_hexdigit()` + +error: use of `char::is_digit` with literal radix of 16 + --> $DIR/is_digit_ascii_radix.rs:13:13 + | +LL | let _ = c.is_digit(0x10); + | ^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_hexdigit()` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed index 19184df0bec..3c5e9642714 100644 --- a/tests/ui/to_digit_is_some.fixed +++ b/tests/ui/to_digit_is_some.fixed @@ -6,6 +6,6 @@ fn main() { let c = 'x'; let d = &c; - let _ = d.is_digit(10); - let _ = char::is_digit(c, 10); + let _ = d.is_digit(8); + let _ = char::is_digit(c, 8); } diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs index 45a6728ebf5..4f247c06cee 100644 --- a/tests/ui/to_digit_is_some.rs +++ b/tests/ui/to_digit_is_some.rs @@ -6,6 +6,6 @@ fn main() { let c = 'x'; let d = &c; - let _ = d.to_digit(10).is_some(); - let _ = char::to_digit(c, 10).is_some(); + let _ = d.to_digit(8).is_some(); + let _ = char::to_digit(c, 8).is_some(); } diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr index 177d3ccd3e2..10a1b393a39 100644 --- a/tests/ui/to_digit_is_some.stderr +++ b/tests/ui/to_digit_is_some.stderr @@ -1,16 +1,16 @@ error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:9:13 | -LL | let _ = d.to_digit(10).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(10)` +LL | let _ = d.to_digit(8).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(8)` | = note: `-D clippy::to-digit-is-some` implied by `-D warnings` error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:10:13 | -LL | let _ = char::to_digit(c, 10).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 10)` +LL | let _ = char::to_digit(c, 8).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 8)` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 744b0ff9035298a8f62accf7f48701fa56d2df49 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 8 Apr 2022 23:15:18 -0400 Subject: Don't lint `iter_with_drain` on references --- clippy_lints/src/methods/iter_with_drain.rs | 91 +++++++++++------------------ tests/ui/iter_with_drain.fixed | 9 +++ tests/ui/iter_with_drain.rs | 9 +++ 3 files changed, 51 insertions(+), 58 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 958c3773087..152072e09c7 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,72 +1,47 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::Range; use clippy_utils::is_integer_const; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{ - higher::{self, Range}, - SpanlessEq, -}; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; use rustc_span::Span; use super::ITER_WITH_DRAIN; -const DRAIN_TYPES: &[Symbol] = &[sym::Vec, sym::VecDeque]; - pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { - let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if let Some(drained_type) = DRAIN_TYPES.iter().find(|&&sym| is_type_diagnostic_item(cx, ty, sym)) { - // Refuse to emit `into_iter` suggestion on draining struct fields due - // to the strong possibility of processing unmovable field. - if let ExprKind::Field(..) = recv.kind { - return; - } + if !matches!(recv.kind, ExprKind::Field(..)) + && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) + && matches!(ty_name, sym::Vec | sym::VecDeque) + && let Some(range) = Range::hir(arg) + && is_full_range(cx, recv, range) + { + span_lint_and_sugg( + cx, + ITER_WITH_DRAIN, + span.with_hi(expr.span.hi()), + &format!("`drain(..)` used on a `{}`", ty_name), + "try this", + "into_iter()".to_string(), + Applicability::MaybeIncorrect, + ); + }; +} - if let Some(range) = higher::Range::hir(arg) { - let left_full = match range { - Range { start: Some(start), .. } if is_integer_const(cx, start, 0) => true, - Range { start: None, .. } => true, - _ => false, - }; - let full = left_full - && match range { - Range { - end: Some(end), - limits: RangeLimits::HalfOpen, - .. - } => { - // `x.drain(..x.len())` call - if_chain! { - if let ExprKind::MethodCall(len_path, len_args, _) = end.kind; - if len_path.ident.name == sym::len && len_args.len() == 1; - if let ExprKind::Path(QPath::Resolved(_, drain_path)) = recv.kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind; - if SpanlessEq::new(cx).eq_path(drain_path, len_path); - then { true } - else { false } - } - }, - Range { - end: None, - limits: RangeLimits::HalfOpen, - .. - } => true, - _ => false, - }; - if full { - span_lint_and_sugg( - cx, - ITER_WITH_DRAIN, - span.with_hi(expr.span.hi()), - &format!("`drain(..)` used on a `{}`", drained_type), - "try this", - "into_iter()".to_string(), - Applicability::MaybeIncorrect, - ); +fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { + range.start.map_or(true, |e| is_integer_const(cx, e, 0)) + && range.end.map_or(true, |e| { + if range.limits == RangeLimits::HalfOpen + && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind + && let ExprKind::MethodCall(name, [self_arg], _) = e.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false } - } - } + }) } diff --git a/tests/ui/iter_with_drain.fixed b/tests/ui/iter_with_drain.fixed index aea4dba9dd5..0330d554926 100644 --- a/tests/ui/iter_with_drain.fixed +++ b/tests/ui/iter_with_drain.fixed @@ -39,6 +39,15 @@ fn should_not_help() { let _: Vec<_> = b.drain(0..a.len()).collect(); } +fn _closed_range(mut x: Vec) { + let _: Vec = x.drain(0..=x.len()).collect(); +} + +fn _with_mut(x: &mut Vec, y: &mut VecDeque) { + let _: Vec = x.drain(..).collect(); + let _: Vec = y.drain(..).collect(); +} + #[derive(Default)] struct Bomb { fire: Vec, diff --git a/tests/ui/iter_with_drain.rs b/tests/ui/iter_with_drain.rs index 271878cffb4..993936fb8de 100644 --- a/tests/ui/iter_with_drain.rs +++ b/tests/ui/iter_with_drain.rs @@ -39,6 +39,15 @@ fn should_not_help() { let _: Vec<_> = b.drain(0..a.len()).collect(); } +fn _closed_range(mut x: Vec) { + let _: Vec = x.drain(0..=x.len()).collect(); +} + +fn _with_mut(x: &mut Vec, y: &mut VecDeque) { + let _: Vec = x.drain(..).collect(); + let _: Vec = y.drain(..).collect(); +} + #[derive(Default)] struct Bomb { fire: Vec, -- cgit 1.4.1-3-g733a5 From 6fba89751bfacf59109d37331ec79a8f87ee0aaf Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 4 Apr 2022 16:30:38 +0100 Subject: Remove overlap between `manual_split_once` and `needless_splitn` Also fixes some incorrect suggestions for rsplitn --- clippy_lints/src/methods/mod.rs | 7 +- clippy_lints/src/methods/str_splitn.rs | 246 ++++++++++----------------------- tests/ui/crashes/ice-8250.stderr | 10 +- tests/ui/manual_split_once.fixed | 21 ++- tests/ui/manual_split_once.rs | 21 ++- tests/ui/manual_split_once.stderr | 86 +++++------- tests/ui/needless_splitn.fixed | 20 +++ tests/ui/needless_splitn.rs | 20 +++ tests/ui/needless_splitn.stderr | 44 +++++- 9 files changed, 216 insertions(+), 259 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 021337280d1..7047aa4c69b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2516,12 +2516,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("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); - if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) { - str_splitn::check_manual_split_once(cx, name, expr, recv, pat_arg); - } - if count >= 2 { - str_splitn::check_needless_splitn(cx, name, expr, recv, pat_arg, count); - } + str_splitn::check(cx, name, expr, recv, pat_arg, count, msrv); } }, ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 8125930b304..6eaa9eb2ef0 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -1,36 +1,77 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::{is_diag_item_method, match_def_path, paths}; +use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_middle::ty; +use rustc_semver::RustcVersion; use rustc_span::{symbol::sym, Span, SyntaxContext}; -use super::MANUAL_SPLIT_ONCE; +use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; -pub(super) fn check_manual_split_once( +pub(super) fn check( cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>, + count: u128, + msrv: Option<&RustcVersion>, ) { - if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { + if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { return; } let ctxt = expr.span.ctxt(); - let (method_name, msg, reverse) = if method_name == "splitn" { - ("split_once", "manual implementation of `split_once`", false) - } else { - ("rsplit_once", "manual implementation of `rsplit_once`", true) + let Some(usage) = parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id)) else { return }; + + let needless = match usage.kind { + IterUsageKind::Nth(n) => count > n + 1, + IterUsageKind::NextTuple => count > 2, }; - let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) { - Some(x) => x, - None => return, + + if needless { + let mut app = Applicability::MachineApplicable; + let (r, message) = if method_name == "splitn" { + ("", "unnecessary use of `splitn`") + } else { + ("r", "unnecessary use of `rsplitn`") + }; + + span_lint_and_sugg( + cx, + NEEDLESS_SPLITN, + expr.span, + message, + "try this", + format!( + "{}.{r}split({})", + snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0, + snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0, + ), + app, + ); + } else if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) { + check_manual_split_once(cx, method_name, expr, self_arg, pat_arg, &usage); + } +} + +fn check_manual_split_once( + cx: &LateContext<'_>, + method_name: &str, + expr: &Expr<'_>, + self_arg: &Expr<'_>, + pat_arg: &Expr<'_>, + usage: &IterUsage, +) { + let ctxt = expr.span.ctxt(); + let (msg, reverse) = if method_name == "splitn" { + ("manual implementation of `split_once`", false) + } else { + ("manual implementation of `rsplit_once`", true) }; let mut app = Applicability::MachineApplicable; @@ -39,77 +80,36 @@ pub(super) fn check_manual_split_once( let sugg = match usage.kind { IterUsageKind::NextTuple => { - format!("{}.{}({})", self_snip, method_name, pat_snip) - }, - IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip), - IterUsageKind::Next | IterUsageKind::Second => { - let self_deref = { - let adjust = cx.typeck_results().expr_adjustments(self_arg); - if adjust.len() < 2 { - String::new() - } else if cx.typeck_results().expr_ty(self_arg).is_box() - || adjust - .iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box()) - { - format!("&{}", "*".repeat(adjust.len().saturating_sub(1))) - } else { - "*".repeat(adjust.len().saturating_sub(2)) - } - }; - if matches!(usage.kind, IterUsageKind::Next) { - match usage.unwrap_kind { - Some(UnwrapKind::Unwrap) => { - if reverse { - format!("{}.{}({}).unwrap().0", self_snip, method_name, pat_snip) - } else { - format!( - "{}.{}({}).map_or({}{}, |x| x.0)", - self_snip, method_name, pat_snip, self_deref, &self_snip - ) - } - }, - Some(UnwrapKind::QuestionMark) => { - format!( - "{}.{}({}).map_or({}{}, |x| x.0)", - self_snip, method_name, pat_snip, self_deref, &self_snip - ) - }, - None => { - format!( - "Some({}.{}({}).map_or({}{}, |x| x.0))", - &self_snip, method_name, pat_snip, self_deref, &self_snip - ) - }, - } + if reverse { + format!("{self_snip}.rsplit_once({pat_snip}).map(|(x, y)| (y, x))") } else { - match usage.unwrap_kind { - Some(UnwrapKind::Unwrap) => { - if reverse { - // In this case, no better suggestion is offered. - return; - } - format!("{}.{}({}).unwrap().1", self_snip, method_name, pat_snip) - }, - Some(UnwrapKind::QuestionMark) => { - format!("{}.{}({})?.1", self_snip, method_name, pat_snip) - }, - None => { - format!("{}.{}({}).map(|x| x.1)", self_snip, method_name, pat_snip) - }, - } + format!("{self_snip}.split_once({pat_snip})") } }, + IterUsageKind::Nth(1) => { + let (r, field) = if reverse { ("r", 0) } else { ("", 1) }; + + match usage.unwrap_kind { + Some(UnwrapKind::Unwrap) => { + format!("{self_snip}.{r}split_once({pat_snip}).unwrap().{field}") + }, + Some(UnwrapKind::QuestionMark) => { + format!("{self_snip}.{r}split_once({pat_snip})?.{field}") + }, + None => { + format!("{self_snip}.{r}split_once({pat_snip}).map(|x| x.{field})") + }, + } + }, + IterUsageKind::Nth(_) => return, }; span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); } enum IterUsageKind { - Next, - Second, + Nth(u128), NextTuple, - RNextTuple, } enum UnwrapKind { @@ -128,7 +128,6 @@ fn parse_iter_usage<'tcx>( cx: &LateContext<'tcx>, ctxt: SyntaxContext, mut iter: impl Iterator)>, - reverse: bool, ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { @@ -141,13 +140,7 @@ fn parse_iter_usage<'tcx>( let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; match (name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if reverse { - (IterUsageKind::Second, e.span) - } else { - (IterUsageKind::Next, e.span) - } - }, + ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), ("next_tuple", []) => { return if_chain! { if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); @@ -157,7 +150,7 @@ fn parse_iter_usage<'tcx>( if subs.len() == 2; then { Some(IterUsage { - kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple }, + kind: IterUsageKind::NextTuple, span: e.span, unwrap_kind: None }) @@ -185,11 +178,7 @@ fn parse_iter_usage<'tcx>( } } }; - match if reverse { idx ^ 1 } else { idx } { - 0 => (IterUsageKind::Next, span), - 1 => (IterUsageKind::Second, span), - _ => return None, - } + (IterUsageKind::Nth(idx), span) } else { return None; } @@ -238,86 +227,3 @@ fn parse_iter_usage<'tcx>( span, }) } - -use super::NEEDLESS_SPLITN; - -pub(super) fn check_needless_splitn( - cx: &LateContext<'_>, - method_name: &str, - expr: &Expr<'_>, - self_arg: &Expr<'_>, - pat_arg: &Expr<'_>, - count: u128, -) { - if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { - return; - } - let ctxt = expr.span.ctxt(); - let mut app = Applicability::MachineApplicable; - let (reverse, message) = if method_name == "splitn" { - (false, "unnecessary use of `splitn`") - } else { - (true, "unnecessary use of `rsplitn`") - }; - if_chain! { - if count >= 2; - if check_iter(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), count); - then { - span_lint_and_sugg( - cx, - NEEDLESS_SPLITN, - expr.span, - message, - "try this", - format!( - "{}.{}({})", - snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0, - if reverse {"rsplit"} else {"split"}, - snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0 - ), - app, - ); - } - } -} - -fn check_iter<'tcx>( - cx: &LateContext<'tcx>, - ctxt: SyntaxContext, - mut iter: impl Iterator)>, - count: u128, -) -> bool { - match iter.next() { - Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind { - (name, args) - } else { - return false; - }; - if_chain! { - if let Some(did) = cx.typeck_results().type_dependent_def_id(e.hir_id); - if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - then { - match (name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - return true; - }, - ("next_tuple", []) if count > 2 => { - return true; - }, - ("nth", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { - if count > idx + 1 { - return true; - } - } - }, - _ => return false, - } - } - } - }, - _ => return false, - }; - false -} diff --git a/tests/ui/crashes/ice-8250.stderr b/tests/ui/crashes/ice-8250.stderr index 04ea4456656..8ed8f3b3a06 100644 --- a/tests/ui/crashes/ice-8250.stderr +++ b/tests/ui/crashes/ice-8250.stderr @@ -1,11 +1,3 @@ -error: manual implementation of `split_once` - --> $DIR/ice-8250.rs:2:13 - | -LL | let _ = s[1..].splitn(2, '.').next()?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split_once('.').map_or(s[1..], |x| x.0)` - | - = note: `-D clippy::manual-split-once` implied by `-D warnings` - error: unnecessary use of `splitn` --> $DIR/ice-8250.rs:2:13 | @@ -14,5 +6,5 @@ LL | let _ = s[1..].splitn(2, '.').next()?; | = note: `-D clippy::needless-splitn` implied by `-D warnings` -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed index d5113df569a..8621ddc7467 100644 --- a/tests/ui/manual_split_once.fixed +++ b/tests/ui/manual_split_once.fixed @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![warn(clippy::manual_split_once)] -#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::needless_splitn)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] extern crate itertools; @@ -10,27 +10,25 @@ extern crate itertools; use itertools::Itertools; fn main() { - let _ = Some("key=value".split_once('=').map_or("key=value", |x| x.0)); let _ = "key=value".splitn(2, '=').nth(2); - let _ = "key=value".split_once('=').map_or("key=value", |x| x.0); - let _ = "key=value".split_once('=').map_or("key=value", |x| x.0); let _ = "key=value".split_once('=').unwrap().1; let _ = "key=value".split_once('=').unwrap().1; let (_, _) = "key=value".split_once('=').unwrap(); let s = String::from("key=value"); - let _ = s.split_once('=').map_or(&*s, |x| x.0); + let _ = s.split_once('=').unwrap().1; let s = Box::::from("key=value"); - let _ = s.split_once('=').map_or(&*s, |x| x.0); + let _ = s.split_once('=').unwrap().1; let s = &"key=value"; - let _ = s.split_once('=').map_or(*s, |x| x.0); + let _ = s.split_once('=').unwrap().1; fn _f(s: &str) -> Option<&str> { - let _ = s.split_once("key=value").map_or(s, |x| x.0); - let _ = s.split_once("key=value")?.1; - let _ = s.split_once("key=value")?.1; + let _ = s.split_once('=')?.1; + let _ = s.split_once('=')?.1; + let _ = s.rsplit_once('=')?.0; + let _ = s.rsplit_once('=')?.0; None } @@ -38,10 +36,9 @@ fn main() { let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); // `rsplitn` gives the results in the reverse order of `rsplit_once` - let _ = "key=value".rsplitn(2, '=').next().unwrap(); let _ = "key=value".rsplit_once('=').unwrap().0; - let _ = "key=value".rsplit_once('=').map(|x| x.1); let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); + let _ = s.rsplit_once('=').map(|x| x.0); } fn _msrv_1_51() { diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index 80e02952dbd..c8a1d7b91e5 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![warn(clippy::manual_split_once)] -#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::needless_splitn)] +#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] extern crate itertools; @@ -10,27 +10,25 @@ extern crate itertools; use itertools::Itertools; fn main() { - let _ = "key=value".splitn(2, '=').next(); let _ = "key=value".splitn(2, '=').nth(2); - let _ = "key=value".splitn(2, '=').next().unwrap(); - let _ = "key=value".splitn(2, '=').nth(0).unwrap(); let _ = "key=value".splitn(2, '=').nth(1).unwrap(); let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); let s = String::from("key=value"); - let _ = s.splitn(2, '=').next().unwrap(); + let _ = s.splitn(2, '=').nth(1).unwrap(); let s = Box::::from("key=value"); - let _ = s.splitn(2, '=').nth(0).unwrap(); + let _ = s.splitn(2, '=').nth(1).unwrap(); let s = &"key=value"; - let _ = s.splitn(2, '=').skip(0).next().unwrap(); + let _ = s.splitn(2, '=').skip(1).next().unwrap(); fn _f(s: &str) -> Option<&str> { - let _ = s.splitn(2, "key=value").next()?; - let _ = s.splitn(2, "key=value").nth(1)?; - let _ = s.splitn(2, "key=value").skip(1).next()?; + let _ = s.splitn(2, '=').nth(1)?; + let _ = s.splitn(2, '=').skip(1).next()?; + let _ = s.rsplitn(2, '=').nth(1)?; + let _ = s.rsplitn(2, '=').skip(1).next()?; None } @@ -38,10 +36,9 @@ fn main() { let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap(); // `rsplitn` gives the results in the reverse order of `rsplit_once` - let _ = "key=value".rsplitn(2, '=').next().unwrap(); let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); - let _ = "key=value".rsplitn(2, '=').nth(0); let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); + let _ = s.rsplitn(2, '=').nth(1); } fn _msrv_1_51() { diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index af9c7a2d41b..9635e6c5e4b 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -1,100 +1,88 @@ error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:13:13 + --> $DIR/manual_split_once.rs:14:13 | -LL | let _ = "key=value".splitn(2, '=').next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some("key=value".split_once('=').map_or("key=value", |x| x.0))` +LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` | = note: `-D clippy::manual-split-once` implied by `-D warnings` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:15:13 | -LL | let _ = "key=value".splitn(2, '=').next().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').map_or("key=value", |x| x.0)` - -error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:16:13 - | -LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').map_or("key=value", |x| x.0)` - -error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:17:13 - | -LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` - -error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:18:13 - | LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:19:18 + --> $DIR/manual_split_once.rs:16:18 | LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=')` +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:19:13 + | +LL | let _ = s.splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1` + error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:22:13 | -LL | let _ = s.splitn(2, '=').next().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(&*s, |x| x.0)` +LL | let _ = s.splitn(2, '=').nth(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:25:13 | -LL | let _ = s.splitn(2, '=').nth(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(&*s, |x| x.0)` +LL | let _ = s.splitn(2, '=').skip(1).next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:28:13 + --> $DIR/manual_split_once.rs:28:17 | -LL | let _ = s.splitn(2, '=').skip(0).next().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').map_or(*s, |x| x.0)` +LL | let _ = s.splitn(2, '=').nth(1)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1` error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:31:17 + --> $DIR/manual_split_once.rs:29:17 | -LL | let _ = s.splitn(2, "key=value").next()?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value").map_or(s, |x| x.0)` +LL | let _ = s.splitn(2, '=').skip(1).next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1` -error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:32:17 +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:30:17 | -LL | let _ = s.splitn(2, "key=value").nth(1)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` +LL | let _ = s.rsplitn(2, '=').nth(1)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0` -error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:33:17 +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:31:17 | -LL | let _ = s.splitn(2, "key=value").skip(1).next()?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1` +LL | let _ = s.rsplitn(2, '=').skip(1).next()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> $DIR/manual_split_once.rs:42:13 + --> $DIR/manual_split_once.rs:39:13 | LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().0` error: manual implementation of `rsplit_once` - --> $DIR/manual_split_once.rs:43:13 + --> $DIR/manual_split_once.rs:40:18 | -LL | let _ = "key=value".rsplitn(2, '=').nth(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|x| x.1)` +LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` error: manual implementation of `rsplit_once` - --> $DIR/manual_split_once.rs:44:18 + --> $DIR/manual_split_once.rs:41:13 | -LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` +LL | let _ = s.rsplitn(2, '=').nth(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)` error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:55:13 + --> $DIR/manual_split_once.rs:52:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` -error: aborting due to 16 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/needless_splitn.fixed b/tests/ui/needless_splitn.fixed index f6a4b2f17d3..61f5fc4e679 100644 --- a/tests/ui/needless_splitn.fixed +++ b/tests/ui/needless_splitn.fixed @@ -24,4 +24,24 @@ fn main() { let _ = str.rsplitn(2, '=').nth(1); let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap(); let (_, _) = str.rsplit('=').next_tuple().unwrap(); + + let _ = str.split('=').next(); + let _ = str.split('=').nth(3); + let _ = str.splitn(5, '=').nth(4); + let _ = str.splitn(5, '=').nth(5); +} + +fn _question_mark(s: &str) -> Option<()> { + let _ = s.split('=').next()?; + let _ = s.split('=').nth(0)?; + let _ = s.rsplit('=').next()?; + let _ = s.rsplit('=').nth(0)?; + + Some(()) +} + +fn _test_msrv() { + #![clippy::msrv = "1.51"] + // `manual_split_once` MSRV shouldn't apply to `needless_splitn` + let _ = "key=value".split('=').nth(0).unwrap(); } diff --git a/tests/ui/needless_splitn.rs b/tests/ui/needless_splitn.rs index 6ba32255bb2..71d9a7077fa 100644 --- a/tests/ui/needless_splitn.rs +++ b/tests/ui/needless_splitn.rs @@ -24,4 +24,24 @@ fn main() { let _ = str.rsplitn(2, '=').nth(1); let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap(); let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); + + let _ = str.splitn(5, '=').next(); + let _ = str.splitn(5, '=').nth(3); + let _ = str.splitn(5, '=').nth(4); + let _ = str.splitn(5, '=').nth(5); +} + +fn _question_mark(s: &str) -> Option<()> { + let _ = s.splitn(2, '=').next()?; + let _ = s.splitn(2, '=').nth(0)?; + let _ = s.rsplitn(2, '=').next()?; + let _ = s.rsplitn(2, '=').nth(0)?; + + Some(()) +} + +fn _test_msrv() { + #![clippy::msrv = "1.51"] + // `manual_split_once` MSRV shouldn't apply to `needless_splitn` + let _ = "key=value".splitn(2, '=').nth(0).unwrap(); } diff --git a/tests/ui/needless_splitn.stderr b/tests/ui/needless_splitn.stderr index 66de2256554..f112b29e7f2 100644 --- a/tests/ui/needless_splitn.stderr +++ b/tests/ui/needless_splitn.stderr @@ -36,5 +36,47 @@ error: unnecessary use of `rsplitn` LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` -error: aborting due to 6 previous errors +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:28:13 + | +LL | let _ = str.splitn(5, '=').next(); + | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:29:13 + | +LL | let _ = str.splitn(5, '=').nth(3); + | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:35:13 + | +LL | let _ = s.splitn(2, '=').next()?; + | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')` + +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:36:13 + | +LL | let _ = s.splitn(2, '=').nth(0)?; + | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')` + +error: unnecessary use of `rsplitn` + --> $DIR/needless_splitn.rs:37:13 + | +LL | let _ = s.rsplitn(2, '=').next()?; + | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')` + +error: unnecessary use of `rsplitn` + --> $DIR/needless_splitn.rs:38:13 + | +LL | let _ = s.rsplitn(2, '=').nth(0)?; + | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')` + +error: unnecessary use of `splitn` + --> $DIR/needless_splitn.rs:46:13 + | +LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split('=')` + +error: aborting due to 13 previous errors -- cgit 1.4.1-3-g733a5 From dfdc5ad7d8f5d3787406a00bab2d1e049a57d1e2 Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Tue, 12 Apr 2022 22:55:48 +0900 Subject: fix unnecessary_to_owned about msrv --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 23 ++- tests/ui/unnecessary_to_owned.fixed | 12 ++ tests/ui/unnecessary_to_owned.rs | 12 ++ tests/ui/unnecessary_to_owned.stderr | 176 ++++++++++++----------- 5 files changed, 138 insertions(+), 87 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 56a8782cee4..e2abce86791 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2254,7 +2254,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { single_char_add_str::check(cx, expr, args); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args); single_char_pattern::check(cx, expr, method_call.ident.name, args); - unnecessary_to_owned::check(cx, expr, method_call.ident.name, args); + unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.as_ref()); }, hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 1555758fc4a..02b882e8b55 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -5,6 +5,8 @@ use clippy_utils::source::snippet_opt; use clippy_utils::ty::{ contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs, }; +use clippy_utils::{meets_msrv, msrvs}; + use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; @@ -13,12 +15,19 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; use std::cmp::max; use super::UNNECESSARY_TO_OWNED; -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) { +pub fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + method_name: Symbol, + args: &'tcx [Expr<'tcx>], + msrv: Option<&RustcVersion>, +) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let [receiver] = args; @@ -33,7 +42,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) { return; } - if check_into_iter_call_arg(cx, expr, method_name, receiver) { + if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { return; } check_other_call_arg(cx, expr, method_name, receiver); @@ -178,7 +187,13 @@ fn check_addr_of_expr( /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. -fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { +fn check_into_iter_call_arg( + cx: &LateContext<'_>, + expr: &Expr<'_>, + method_name: Symbol, + receiver: &Expr<'_>, + msrv: Option<&RustcVersion>, +) -> bool { if_chain! { if let Some(parent) = get_parent_expr(cx, expr); if let Some(callee_def_id) = fn_def_id(cx, parent); @@ -192,7 +207,7 @@ fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } - let cloned_or_copied = if is_copy(cx, item_ty) { "copied" } else { "cloned" }; + let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" }; // The next suggestion may be incorrect because the removal of the `to_owned`-like // function could cause the iterator to hold a reference to a resource that is used // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 38ba41ac54e..7455e22d49b 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -2,6 +2,7 @@ #![allow(clippy::ptr_arg)] #![warn(clippy::unnecessary_to_owned)] +#![feature(custom_inner_attributes)] use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; @@ -213,6 +214,17 @@ fn get_file_path(_file_type: &FileType) -> Result Result $DIR/unnecessary_to_owned.rs:150:64 + --> $DIR/unnecessary_to_owned.rs:151:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:150:20 + --> $DIR/unnecessary_to_owned.rs:151:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:151:40 + --> $DIR/unnecessary_to_owned.rs:152:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:151:21 + --> $DIR/unnecessary_to_owned.rs:152:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:152:48 + --> $DIR/unnecessary_to_owned.rs:153:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:152:19 + --> $DIR/unnecessary_to_owned.rs:153:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:153:35 + --> $DIR/unnecessary_to_owned.rs:154:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:153:18 + --> $DIR/unnecessary_to_owned.rs:154:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:59:36 + --> $DIR/unnecessary_to_owned.rs:60:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -56,427 +56,427 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:60:19 + --> $DIR/unnecessary_to_owned.rs:61:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> $DIR/unnecessary_to_owned.rs:62:20 + --> $DIR/unnecessary_to_owned.rs:63:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:63:38 + --> $DIR/unnecessary_to_owned.rs:64:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:64:20 + --> $DIR/unnecessary_to_owned.rs:65:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> $DIR/unnecessary_to_owned.rs:66:18 + --> $DIR/unnecessary_to_owned.rs:67:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:67:34 + --> $DIR/unnecessary_to_owned.rs:68:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:68:18 + --> $DIR/unnecessary_to_owned.rs:69:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:70:17 + --> $DIR/unnecessary_to_owned.rs:71:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:71:30 + --> $DIR/unnecessary_to_owned.rs:72:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:72:17 + --> $DIR/unnecessary_to_owned.rs:73:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:73:17 + --> $DIR/unnecessary_to_owned.rs:74:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:75:19 + --> $DIR/unnecessary_to_owned.rs:76:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:76:36 + --> $DIR/unnecessary_to_owned.rs:77:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:77:19 + --> $DIR/unnecessary_to_owned.rs:78:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:78:19 + --> $DIR/unnecessary_to_owned.rs:79:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:79:19 + --> $DIR/unnecessary_to_owned.rs:80:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:80:19 + --> $DIR/unnecessary_to_owned.rs:81:19 | LL | require_slice(&x_ref.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:82:42 + --> $DIR/unnecessary_to_owned.rs:83:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:83:15 + --> $DIR/unnecessary_to_owned.rs:84:15 | LL | require_x(&x_ref.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:85:25 + --> $DIR/unnecessary_to_owned.rs:86:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:86:26 + --> $DIR/unnecessary_to_owned.rs:87:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:87:24 + --> $DIR/unnecessary_to_owned.rs:88:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:88:23 + --> $DIR/unnecessary_to_owned.rs:89:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:89:25 + --> $DIR/unnecessary_to_owned.rs:90:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:91:30 + --> $DIR/unnecessary_to_owned.rs:92:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:92:31 + --> $DIR/unnecessary_to_owned.rs:93:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:93:29 + --> $DIR/unnecessary_to_owned.rs:94:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:94:28 + --> $DIR/unnecessary_to_owned.rs:95:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:95:30 + --> $DIR/unnecessary_to_owned.rs:96:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:97:29 + --> $DIR/unnecessary_to_owned.rs:98:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:97:43 + --> $DIR/unnecessary_to_owned.rs:98:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:98:29 + --> $DIR/unnecessary_to_owned.rs:99:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:98:47 + --> $DIR/unnecessary_to_owned.rs:99:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:100:26 + --> $DIR/unnecessary_to_owned.rs:101:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:101:27 + --> $DIR/unnecessary_to_owned.rs:102:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:102:25 + --> $DIR/unnecessary_to_owned.rs:103:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:103:24 + --> $DIR/unnecessary_to_owned.rs:104:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:104:24 + --> $DIR/unnecessary_to_owned.rs:105:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:105:26 + --> $DIR/unnecessary_to_owned.rs:106:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:106:26 + --> $DIR/unnecessary_to_owned.rs:107:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:107:26 + --> $DIR/unnecessary_to_owned.rs:108:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:109:31 + --> $DIR/unnecessary_to_owned.rs:110:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:110:32 + --> $DIR/unnecessary_to_owned.rs:111:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:111:30 + --> $DIR/unnecessary_to_owned.rs:112:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:112:29 + --> $DIR/unnecessary_to_owned.rs:113:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:113:29 + --> $DIR/unnecessary_to_owned.rs:114:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:114:31 + --> $DIR/unnecessary_to_owned.rs:115:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:115:31 + --> $DIR/unnecessary_to_owned.rs:116:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:31 + --> $DIR/unnecessary_to_owned.rs:117:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:30 + --> $DIR/unnecessary_to_owned.rs:119:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:44 + --> $DIR/unnecessary_to_owned.rs:119:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:30 + --> $DIR/unnecessary_to_owned.rs:120:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:44 + --> $DIR/unnecessary_to_owned.rs:120:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:120:30 + --> $DIR/unnecessary_to_owned.rs:121:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:120:44 + --> $DIR/unnecessary_to_owned.rs:121:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:121:30 + --> $DIR/unnecessary_to_owned.rs:122:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:121:48 + --> $DIR/unnecessary_to_owned.rs:122:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:122:30 + --> $DIR/unnecessary_to_owned.rs:123:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:122:52 + --> $DIR/unnecessary_to_owned.rs:123:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:123:30 + --> $DIR/unnecessary_to_owned.rs:124:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:123:48 + --> $DIR/unnecessary_to_owned.rs:124:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:125:20 + --> $DIR/unnecessary_to_owned.rs:126:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:127:13 + --> $DIR/unnecessary_to_owned.rs:128:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:128:13 + --> $DIR/unnecessary_to_owned.rs:129:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:129:13 + --> $DIR/unnecessary_to_owned.rs:130:13 | LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:130:13 + --> $DIR/unnecessary_to_owned.rs:131:13 | LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:132:13 + --> $DIR/unnecessary_to_owned.rs:133:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:133:13 + --> $DIR/unnecessary_to_owned.rs:134:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:134:13 + --> $DIR/unnecessary_to_owned.rs:135:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:135:13 + --> $DIR/unnecessary_to_owned.rs:136:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:196:14 + --> $DIR/unnecessary_to_owned.rs:197:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -491,11 +491,23 @@ LL - let path = match get_file_path(&t) { LL + let path = match get_file_path(t) { | +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:220:14 + | +LL | let _ = &["x"][..].to_vec().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` + +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:225:14 + | +LL | let _ = &["x"][..].to_vec().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` + error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:260:24 + --> $DIR/unnecessary_to_owned.rs:272:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` -error: aborting due to 77 previous errors +error: aborting due to 79 previous errors -- cgit 1.4.1-3-g733a5 From 262b35ea2c4dd9a16c28bf40cb5c124f664ce96c Mon Sep 17 00:00:00 2001 From: infrandomness Date: Fri, 8 Apr 2022 20:07:19 +0200 Subject: Introduce option_take_on_temporary lints This lint checks if Option::take() is used on a temporary value (a value that is not of type &mut Option and that is not a Place expression) to suggest omitting take() --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 + clippy_lints/src/methods/mod.rs | 21 +++++++++++++++++++++ clippy_lints/src/methods/needless_option_take.rs | 23 +++++++++++++++++++++++ tests/ui/needless_option_take.fixed | 15 +++++++++++++++ tests/ui/needless_option_take.rs | 5 +++++ tests/ui/needless_option_take.stderr | 10 ++++++++++ 10 files changed, 79 insertions(+) create mode 100644 clippy_lints/src/methods/needless_option_take.rs create mode 100644 tests/ui/needless_option_take.fixed create mode 100644 tests/ui/needless_option_take.rs create mode 100644 tests/ui/needless_option_take.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 858547c84c1..d4096ca89df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3473,6 +3473,7 @@ Released 2018-09-13 [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes [`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref +[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 52c440de9dd..84e3176c003 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -183,6 +183,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), + LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OK_EXPECT), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 10369a855ae..2f6ebd445eb 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -45,6 +45,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), + LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index cfaa6871b50..aa9435f3b59 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -322,6 +322,7 @@ store.register_lints(&[ methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, methods::NEEDLESS_OPTION_AS_DEREF, + methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 82f45b5fd58..6588ca4a4a7 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -22,6 +22,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(methods::OPTION_TAKE_ON_TEMPORARY), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(octal_escapes::OCTAL_ESCAPES), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 82f4769a699..3d4c193691a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -43,6 +43,7 @@ mod map_flatten; mod map_identity; mod map_unwrap_or; mod needless_option_as_deref; +mod needless_option_take; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -2162,6 +2163,24 @@ declare_clippy_lint! { "use of `char::is_digit(..)` with literal radix of 10 or 16" } +declare_clippy_lint! { + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "1.61.0"] + pub NEEDLESS_OPTION_TAKE, + suspicious, + "using `.as_ref().take()` on a temporary value" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2251,6 +2270,7 @@ impl_lint_pass!(Methods => [ ERR_EXPECT, NEEDLESS_OPTION_AS_DEREF, IS_DIGIT_ASCII_RADIX, + NEEDLESS_OPTION_TAKE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2623,6 +2643,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio } } }, + ("take", []) => needless_option_take::check(cx, expr, recv), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs new file mode 100644 index 00000000000..b3696273e1d --- /dev/null +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -0,0 +1,23 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym::Result as sym_result; + +use super::NEEDLESS_OPTION_TAKE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if_chain! { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym_result); + let result_type = cx.typeck_results().expr_ty(recv); + + then { + span_lint( + cx, + NEEDLESS_OPTION_TAKE, + expr.span, + "Format test" + ); + } + }; +} diff --git a/tests/ui/needless_option_take.fixed b/tests/ui/needless_option_take.fixed new file mode 100644 index 00000000000..29691e81666 --- /dev/null +++ b/tests/ui/needless_option_take.fixed @@ -0,0 +1,15 @@ +// run-rustfix + +fn main() { + println!("Testing non erroneous option_take_on_temporary"); + let mut option = Some(1); + let _ = Box::new(move || option.take().unwrap()); + + println!("Testing non erroneous option_take_on_temporary"); + let x = Some(3); + x.as_ref(); + + println!("Testing erroneous option_take_on_temporary"); + let x = Some(3); + x.as_ref(); +} diff --git a/tests/ui/needless_option_take.rs b/tests/ui/needless_option_take.rs new file mode 100644 index 00000000000..2b32b9467f5 --- /dev/null +++ b/tests/ui/needless_option_take.rs @@ -0,0 +1,5 @@ +fn main() { + println!("Testing option_take_on_temporary"); + let x = Some(3); + let y = x.as_ref().take(); +} diff --git a/tests/ui/needless_option_take.stderr b/tests/ui/needless_option_take.stderr new file mode 100644 index 00000000000..cb3bf015b36 --- /dev/null +++ b/tests/ui/needless_option_take.stderr @@ -0,0 +1,10 @@ +error: called `Option::take()` on a temporary value + --> $DIR/needless_option_take.rs:14:5 + | +LL | x.as_ref().take(); + | ^^^^^^^^^^^^^^^^^ help: try: `x.as_ref()` + | + = note: `-D clippy::needless-option-take` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From ee9281d7a241c448f6bcbbb6cb8bdf8b17251a92 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Fri, 8 Apr 2022 21:27:01 +0200 Subject: Implement checks to the expression The implemented checks are for checking if the expression is either of type `Option` and isn't a syntactical place --- clippy_lints/src/methods/needless_option_take.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index b3696273e1d..27ef9009328 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -2,15 +2,17 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::sym::Result as sym_result; +use rustc_span::sym; use super::NEEDLESS_OPTION_TAKE; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { - if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym_result); - let result_type = cx.typeck_results().expr_ty(recv); - +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _recv: &'tcx Expr<'_>) { + // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place + if is_expr_option(cx, expr) && !expr.is_syntactic_place_expr() { + span_lint(cx, OPTION_TAKE_ON_TEMPORARY, expr.span, "Format test"); + } + /* if_chain! { + is_expr_option(cx, expr); then { span_lint( cx, @@ -19,5 +21,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' "Format test" ); } - }; + };*/ +} + +fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let expr_type = cx.typeck_results().expr_ty(expr); + is_type_diagnostic_item(cx, expr_type, sym::Option) } -- cgit 1.4.1-3-g733a5 From f8f144117da48b52f2c65292402dedcb1c59d9c1 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Fri, 8 Apr 2022 21:54:44 +0200 Subject: Swap span_lint for span_lint_and_sugg This implements a machine applicable suggestion to any matched usage of `.as_ref().take()`` --- clippy_lints/src/methods/needless_option_take.rs | 31 +++++++++++++----------- tests/ui/needless_option_take.rs | 2 ++ tests/ui/option_take_on_temporary.fixed | 7 ++++++ 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 tests/ui/option_take_on_temporary.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index 27ef9009328..57a43ff606a 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -1,27 +1,30 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_span::sym; use super::NEEDLESS_OPTION_TAKE; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _recv: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place if is_expr_option(cx, expr) && !expr.is_syntactic_place_expr() { - span_lint(cx, OPTION_TAKE_ON_TEMPORARY, expr.span, "Format test"); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + NEEDLESS_OPTION_TAKE, + expr.span, + "Called `Option::take()` on a temporary value", + "try", + format!( + "{}", + snippet_with_applicability(cx, recv.span, "..", &mut applicability) + ), + applicability, + ); } - /* if_chain! { - is_expr_option(cx, expr); - then { - span_lint( - cx, - NEEDLESS_OPTION_TAKE, - expr.span, - "Format test" - ); - } - };*/ } fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/tests/ui/needless_option_take.rs b/tests/ui/needless_option_take.rs index 2b32b9467f5..eb57ffeab45 100644 --- a/tests/ui/needless_option_take.rs +++ b/tests/ui/needless_option_take.rs @@ -1,3 +1,5 @@ +// run-rustfix + fn main() { println!("Testing option_take_on_temporary"); let x = Some(3); diff --git a/tests/ui/option_take_on_temporary.fixed b/tests/ui/option_take_on_temporary.fixed new file mode 100644 index 00000000000..9b4ca5a4ad1 --- /dev/null +++ b/tests/ui/option_take_on_temporary.fixed @@ -0,0 +1,7 @@ +// run-rustfix + +fn main() { + println!("Testing option_take_on_temporary"); + let x = Some(3); + let y = x.as_ref(); +} -- cgit 1.4.1-3-g733a5 From cf83e18106160382cd86cc8b35add250373491b6 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Fri, 8 Apr 2022 21:59:59 +0200 Subject: Swap the category of the lint This changes the lint from the suspicious category to the complexity category --- clippy_lints/src/lib.register_suspicious.rs | 1 - clippy_lints/src/methods/mod.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 6588ca4a4a7..82f45b5fd58 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -22,7 +22,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(methods::OPTION_TAKE_ON_TEMPORARY), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(octal_escapes::OCTAL_ESCAPES), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3d4c193691a..36844b3609b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2177,7 +2177,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.61.0"] pub NEEDLESS_OPTION_TAKE, - suspicious, + complexity, "using `.as_ref().take()` on a temporary value" } -- cgit 1.4.1-3-g733a5 From b52bc9b96bb3b22b4ab4a793e3706e7a9b718952 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 10 Apr 2022 10:59:43 +0200 Subject: Swap type checked expression Instead of type checking the entire expression (causing a false positive), only type check for a subset of the expression (the receiver of the matched function: `take()`) --- clippy_lints/src/methods/needless_option_take.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index 57a43ff606a..297d83e9e37 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -10,7 +10,7 @@ use super::NEEDLESS_OPTION_TAKE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place - if is_expr_option(cx, expr) && !expr.is_syntactic_place_expr() { + if is_expr_option(cx, recv) && !recv.is_syntactic_place_expr() { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, -- cgit 1.4.1-3-g733a5 From 76268c0d5590ca06129722fed4afb306a847caab Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 10 Apr 2022 23:42:33 +0200 Subject: Introduce new lint check This checks if the expression has one of `core`, `option`, `Option` or `as_ref` in its path, this avoids false positives --- clippy_lints/src/methods/needless_option_take.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index 297d83e9e37..5596515637e 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::match_def_path; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -10,7 +11,7 @@ use super::NEEDLESS_OPTION_TAKE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place - if is_expr_option(cx, recv) && !recv.is_syntactic_place_expr() { + if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) && has_expr_as_ref_path(cx, recv) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -31,3 +32,10 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_type = cx.typeck_results().expr_ty(expr); is_type_diagnostic_item(cx, expr_type, sym::Option) } + +fn has_expr_as_ref_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(ref_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + return match_def_path(cx, ref_id, &["core", "option", "Option", "as_ref"]); + } + false +} -- cgit 1.4.1-3-g733a5 From 822993675ff45d5b4b2f0a310c65d4abd1aef20a Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 11 Apr 2022 17:15:53 +0200 Subject: Modify lint description --- clippy_lints/src/methods/needless_option_take.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/needless_option_take.rs b/clippy_lints/src/methods/needless_option_take.rs index 5596515637e..829c118d291 100644 --- a/clippy_lints/src/methods/needless_option_take.rs +++ b/clippy_lints/src/methods/needless_option_take.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' cx, NEEDLESS_OPTION_TAKE, expr.span, - "Called `Option::take()` on a temporary value", + "called `Option::take()` on a temporary value", "try", format!( "{}", -- cgit 1.4.1-3-g733a5 From 2903b56f177b2b23db62d6bf2d500837d704fb4e Mon Sep 17 00:00:00 2001 From: infrandomness Date: Tue, 12 Apr 2022 19:34:55 +0200 Subject: Add tests and docs This adds test to make sure correct behavior of lint - The first test's option variable is not a temporary variable - The second test does not make usage of `take()` - The third test makes usage of `take()` and uses a temporary variable --- clippy_lints/src/methods/mod.rs | 6 ++++-- tests/ui/needless_option_take.rs | 10 +++++++++- tests/ui/option_take_on_temporary.fixed | 10 +++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 36844b3609b..48fa30ba929 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2169,11 +2169,13 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // example code where clippy issues a warning + /// let x = Some(3); + /// x.as_ref().take(); /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// let x = Some(3); + /// x.as_ref(); /// ``` #[clippy::version = "1.61.0"] pub NEEDLESS_OPTION_TAKE, diff --git a/tests/ui/needless_option_take.rs b/tests/ui/needless_option_take.rs index 27cc9a2e61e..9f4109eb463 100644 --- a/tests/ui/needless_option_take.rs +++ b/tests/ui/needless_option_take.rs @@ -1,7 +1,15 @@ // run-rustfix fn main() { - println!("Testing option_take_on_temporary"); + println!("Testing non erroneous option_take_on_temporary"); + let mut option = Some(1); + let _ = Box::new(move || option.take().unwrap()); + + println!("Testing non erroneous option_take_on_temporary"); + let x = Some(3); + x.as_ref(); + + println!("Testing erroneous option_take_on_temporary"); let x = Some(3); x.as_ref().take(); } diff --git a/tests/ui/option_take_on_temporary.fixed b/tests/ui/option_take_on_temporary.fixed index 7e293076682..29691e81666 100644 --- a/tests/ui/option_take_on_temporary.fixed +++ b/tests/ui/option_take_on_temporary.fixed @@ -1,7 +1,15 @@ // run-rustfix fn main() { - println!("Testing option_take_on_temporary"); + println!("Testing non erroneous option_take_on_temporary"); + let mut option = Some(1); + let _ = Box::new(move || option.take().unwrap()); + + println!("Testing non erroneous option_take_on_temporary"); + let x = Some(3); + x.as_ref(); + + println!("Testing erroneous option_take_on_temporary"); let x = Some(3); x.as_ref(); } -- cgit 1.4.1-3-g733a5 From 29ef80c78a0f9c58607944e50d3240eee2b7cdc7 Mon Sep 17 00:00:00 2001 From: whodi Date: Fri, 15 Apr 2022 14:25:55 -0400 Subject: adding spell checking --- .github/ISSUE_TEMPLATE/blank_issue.yml | 2 +- .github/ISSUE_TEMPLATE/false_negative.yml | 2 +- .github/ISSUE_TEMPLATE/false_positive.yml | 2 +- .github/workflows/clippy.yml | 4 ++-- clippy_dev/src/setup/git_hook.rs | 2 +- clippy_dev/src/setup/mod.rs | 4 ++-- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/empty_structs_with_brackets.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/match_result_ok.rs | 4 ++-- clippy_lints/src/matches/match_same_arms.rs | 4 ++-- clippy_lints/src/matches/mod.rs | 4 ++-- clippy_lints/src/matches/needless_match.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/needless_bitwise_bool.rs | 4 ++-- clippy_lints/src/needless_late_init.rs | 6 +++--- clippy_lints/src/octal_escapes.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 8 ++++---- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/transmute/utils.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 4 ++-- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 6 +++--- clippy_utils/src/macros.rs | 2 +- clippy_utils/src/source.rs | 2 +- tests/lint_message_convention.rs | 2 +- tests/ui/auxiliary/proc_macro_derive.rs | 2 +- 31 files changed, 46 insertions(+), 46 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/.github/ISSUE_TEMPLATE/blank_issue.yml b/.github/ISSUE_TEMPLATE/blank_issue.yml index d610e8c7bc4..89884bfc859 100644 --- a/.github/ISSUE_TEMPLATE/blank_issue.yml +++ b/.github/ISSUE_TEMPLATE/blank_issue.yml @@ -9,7 +9,7 @@ body: attributes: label: Description description: > - Please provide a discription of the issue, along with any information + Please provide a description of the issue, along with any information you feel relevant to replicate it. validations: required: true diff --git a/.github/ISSUE_TEMPLATE/false_negative.yml b/.github/ISSUE_TEMPLATE/false_negative.yml index 9357ccc4f4e..25e436d30b9 100644 --- a/.github/ISSUE_TEMPLATE/false_negative.yml +++ b/.github/ISSUE_TEMPLATE/false_negative.yml @@ -23,7 +23,7 @@ body: id: reproducer attributes: label: Reproducer - description: Please provide the code and steps to repoduce the bug + description: Please provide the code and steps to reproduce the bug value: | I tried this code: diff --git a/.github/ISSUE_TEMPLATE/false_positive.yml b/.github/ISSUE_TEMPLATE/false_positive.yml index b7dd400ee73..561b65c93a7 100644 --- a/.github/ISSUE_TEMPLATE/false_positive.yml +++ b/.github/ISSUE_TEMPLATE/false_positive.yml @@ -24,7 +24,7 @@ body: attributes: label: Reproducer description: > - Please provide the code and steps to repoduce the bug together with the + Please provide the code and steps to reproduce the bug together with the output from Clippy. value: | I tried this code: diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index cd83bc9642b..4292949a02d 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -6,14 +6,14 @@ on: branches-ignore: - auto - try - # Don't run Clippy tests, when only textfiles were modified + # Don't run Clippy tests, when only text files were modified paths-ignore: - 'COPYRIGHT' - 'LICENSE-*' - '**.md' - '**.txt' pull_request: - # Don't run Clippy tests, when only textfiles were modified + # Don't run Clippy tests, when only text files were modified paths-ignore: - 'COPYRIGHT' - 'LICENSE-*' diff --git a/clippy_dev/src/setup/git_hook.rs b/clippy_dev/src/setup/git_hook.rs index 3fbb77d5923..ad4b96f7ff3 100644 --- a/clippy_dev/src/setup/git_hook.rs +++ b/clippy_dev/src/setup/git_hook.rs @@ -18,7 +18,7 @@ pub fn install_hook(force_override: bool) { // So a little bit of a funny story. Git on unix requires the pre-commit file // to have the `execute` permission to be set. The Rust functions for modifying - // these flags doesn't seem to work when executed with normal user permissions. + // these flags doesn't seem to work when executed with normal user permissions. // // However, there is a little hack that is also being used by Rust itself in their // setup script. Git saves the `execute` flag when syncing files. This means diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs index a1e4dd103b8..f691ae4fa45 100644 --- a/clippy_dev/src/setup/mod.rs +++ b/clippy_dev/src/setup/mod.rs @@ -7,7 +7,7 @@ use std::path::Path; const CLIPPY_DEV_DIR: &str = "clippy_dev"; /// This function verifies that the tool is being executed in the clippy directory. -/// This is useful to ensure that setups only modify Clippys resources. The verification +/// This is useful to ensure that setups only modify Clippy's resources. The verification /// is done by checking that `clippy_dev` is a sub directory of the current directory. /// /// It will print an error message and return `false` if the directory could not be @@ -17,7 +17,7 @@ fn verify_inside_clippy_dir() -> bool { if path.exists() && path.is_dir() { true } else { - eprintln!("error: unable to verify that the working directory is clippys directory"); + eprintln!("error: unable to verify that the working directory is clippy's directory"); false } } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 55c1f085657..f05315a7d0c 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -270,7 +270,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Casting a function pointer to an integer can have surprising results and can occur - /// accidentally if parantheses are omitted from a function call. If you aren't doing anything + /// accidentally if parentheses are omitted from a function call. If you aren't doing anything /// low-level with function pointers then you can opt-out of casting functions to integers in /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function /// pointer casts in your code. diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index fdeac8d8255..8430e7b4c82 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -66,7 +66,7 @@ fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Spa } // there might still be field declarations hidden from the AST - // (conditionaly compiled code using #[cfg(..)]) + // (conditionally compiled code using #[cfg(..)]) let Some(braces_span_str) = snippet_opt(cx, braces_span) else { return false; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 6b62748ffef..8a84513b779 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -116,7 +116,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap LateLintPass<'tcx> for MatchResultOk { if_chain! { if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation - if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; + if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized; if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result); if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index b8591fe0db0..9b7344fb8b0 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { .map(|a| NormalizedPat::from_pat(cx, &arena, a.pat)) .collect(); - // The furthast forwards a pattern can move without semantic changes + // The furthest forwards a pattern can move without semantic changes let forwards_blocking_idxs: Vec<_> = normalized_pats .iter() .enumerate() @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { }) .collect(); - // The furthast backwards a pattern can move without semantic changes + // The furthest backwards a pattern can move without semantic changes let backwards_blocking_idxs: Vec<_> = normalized_pats .iter() .enumerate() diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 854cf06ed81..401ecef460c 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -7,7 +7,7 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{Span, SpanData, SyntaxContext}; -mod infalliable_detructuring_match; +mod infallible_destructuring_match; mod match_as_ref; mod match_bool; mod match_like_matches; @@ -694,7 +694,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { - self.infallible_destructuring_match_linted |= infalliable_detructuring_match::check(cx, local); + self.infallible_destructuring_match_linted |= infallible_destructuring_match::check(cx, local); } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index d6c8e472552..0abe6ddda65 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -118,7 +118,7 @@ fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { } /// Manually check for coercion casting by checking if the type of the match operand or let expr -/// differs with the assigned local variable or the funtion return type. +/// differs with the assigned local variable or the function return type. fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool { if let Some(p_node) = get_parent_node(cx.tcx, p_expr.hir_id) { match p_node { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f1a74220e68..70a2aaf78a0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1266,7 +1266,7 @@ declare_clippy_lint! { #[clippy::version = "1.55.0"] pub EXTEND_WITH_DRAIN, perf, - "using vec.append(&mut vec) to move the full range of a vecor to another" + "using vec.append(&mut vec) to move the full range of a vector to another" } declare_clippy_lint! { @@ -2100,7 +2100,7 @@ declare_clippy_lint! { /// using `.collect::()` over `.collect::>().join("")` /// will prevent loop unrolling and will result in a negative performance impact. /// - /// Additionlly, differences have been observed between aarch64 and x86_64 assembly output, + /// Additionally, differences have been observed between aarch64 and x86_64 assembly output, /// with aarch64 tending to producing faster assembly in more cases when using `.collect::()` #[clippy::version = "1.61.0"] pub UNNECESSARY_JOIN, diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index ac2f16b49e3..6e6ad1ebbce 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -44,7 +44,7 @@ declare_clippy_lint! { /// pub struct PubBaz; /// impl PubBaz { /// fn private() {} // ok - /// pub fn not_ptrivate() {} // missing #[inline] + /// pub fn not_private() {} // missing #[inline] /// } /// /// impl Bar for PubBaz { diff --git a/clippy_lints/src/needless_bitwise_bool.rs b/clippy_lints/src/needless_bitwise_bool.rs index a8a8d174a82..95395e2e136 100644 --- a/clippy_lints/src/needless_bitwise_bool.rs +++ b/clippy_lints/src/needless_bitwise_bool.rs @@ -53,7 +53,7 @@ fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { false } -fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn suggesstion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let ExprKind::Binary(ref op, left, right) = expr.kind { if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) { let op_snippet = match op.node { @@ -75,7 +75,7 @@ impl LateLintPass<'_> for NeedlessBitwiseBool { expr.span, "use of bitwise operator instead of lazy operator between booleans", |diag| { - if let Some(sugg) = suggession_snippet(cx, expr) { + if let Some(sugg) = suggesstion_snippet(cx, expr) { diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable); } }, diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 9957afcbf04..bbcf7e9e378 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -240,7 +240,7 @@ fn check<'tcx>( cx, NEEDLESS_LATE_INIT, local_stmt.span, - "unneeded late initalization", + "unneeded late initialization", |diag| { diag.tool_only_span_suggestion( local_stmt.span, @@ -265,7 +265,7 @@ fn check<'tcx>( cx, NEEDLESS_LATE_INIT, local_stmt.span, - "unneeded late initalization", + "unneeded late initialization", |diag| { diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability); @@ -296,7 +296,7 @@ fn check<'tcx>( cx, NEEDLESS_LATE_INIT, local_stmt.span, - "unneeded late initalization", + "unneeded late initialization", |diag| { diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability); diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index c19cea66104..e8532db4f71 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// /// ### Known problems /// The actual meaning can be the intended one. `\x00` can be used in these - /// cases to be unambigious. + /// cases to be unambiguous. /// /// The lint does not trigger for format strings in `print!()`, `write!()` /// and friends since the string is already preprocessed when Clippy lints diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index c9f807f2aa3..ea5a8f0858b 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -78,7 +78,7 @@ fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { /// A struct containing information about occurrences of the /// `if let Some(..) = .. else` construct that this lint detects. -struct OptionIfLetElseOccurence { +struct OptionIfLetElseOccurrence { option: String, method_sugg: String, some_expr: String, @@ -100,9 +100,9 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo } /// If this expression is the option if let/else construct we're detecting, then -/// this function returns an `OptionIfLetElseOccurence` struct with details if +/// this function returns an `OptionIfLetElseOccurrence` struct with details if /// this construct is found, or None if this construct is not found. -fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { +fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if_chain! { if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly if !in_constant(cx, expr.hir_id); @@ -154,7 +154,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> } } } - Some(OptionIfLetElseOccurence { + Some(OptionIfLetElseOccurrence { option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), method_sugg: method_sugg.to_string(), some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")), diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index b5dd27ff80d..c4c1aa11004 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -550,7 +550,7 @@ fn ident_difference_expr_with_base_location( // IdentIter, then the output of this function will be almost always be correct // in practice. // - // If it turns out that problematic cases are more prelavent than we assume, + // If it turns out that problematic cases are more prevalent than we assume, // then we should be able to change this function to do the correct traversal, // without needing to change the rest of the code. diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 0e07a0b0392..0cbf5ccefa6 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -87,7 +87,7 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> let res = check.do_check(&fn_ctxt); // do_check's documentation says that it might return Ok and create - // errors in the fcx instead of returing Err in some cases. Those cases + // errors in the fcx instead of returning Err in some cases. Those cases // should be filtered out before getting here. assert!( !fn_ctxt.errors_reported_since_creation(), diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 67cc8913318..b1b2addb9a1 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -432,7 +432,7 @@ impl Types { fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, context: CheckTyContext) { // Ignore functions in trait implementations as they are usually forced by the trait definition. // - // FIXME: idially we would like to warn *if the compicated type can be simplified*, but it's hard to + // FIXME: ideally we would like to warn *if the complicated type can be simplified*, but it's hard to // check. if context.is_in_trait_impl { return; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 790ffe618d7..ae431aac83b 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// *disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*. /// /// ### Why is this bad? - /// In the example above, `Some` is repeated, which unncessarily complicates the pattern. + /// In the example above, `Some` is repeated, which unnecessarily complicates the pattern. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f8e1021af0e..138f8bccb3f 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// ### Known problems /// - Unaddressed false negative in fn bodies of trait implementations - /// - False positive with assotiated types in traits (#4140) + /// - False positive with associated types in traits (#4140) /// /// ### Example /// ```rust diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index d23c85c033b..ff5be825b78 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -70,7 +70,7 @@ macro_rules! bind { }; } -/// Transforms the given `Option` varibles into `OptionPat>`. +/// Transforms the given `Option` variables into `OptionPat>`. /// This displays as `Some($name)` or `None` when printed. The name of the inner binding /// is set to the name of the variable passed to the macro. macro_rules! opt_bind { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 25d74b8c499..0e8f40e9210 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -292,7 +292,7 @@ declare_clippy_lint! { /// Checks for unnecessary conversion from Symbol to a string. /// /// ### Why is this bad? - /// It's faster use symbols directly intead of strings. + /// It's faster use symbols directly instead of strings. /// /// ### Example /// Bad: @@ -823,7 +823,7 @@ fn suggest_note( cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.span, - "this call is collspible", + "this call is collapsible", "collapse into", format!( "span_lint_and_note({}, {}, {}, {}, {}, {})", diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index ca03b8010dd..526bb2f7e06 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -117,7 +117,7 @@ const APPLICABILITY_NAME_INDEX: usize = 2; /// This applicability will be set for unresolved applicability values. const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved"; /// The version that will be displayed if none has been defined -const VERION_DEFAULT_STR: &str = "Unknown"; +const VERSION_DEFAULT_STR: &str = "Unknown"; declare_clippy_lint! { /// ### What it does @@ -571,7 +571,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option { fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String { extract_clippy_version_value(cx, item).map_or_else( - || VERION_DEFAULT_STR.to_string(), + || VERSION_DEFAULT_STR.to_string(), |version| version.as_str().to_string(), ) } @@ -872,7 +872,7 @@ impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> { self.suggestion_count += 2; } - /// Checks if the suggestions include multiple spanns + /// Checks if the suggestions include multiple spans fn is_multi_part(&self) -> bool { self.suggestion_count > 1 } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index e7d4c5a4952..a268e339bb1 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -367,7 +367,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { expr_visitor_no_bodies(|e| { // if we're still inside of the macro definition... if e.span.ctxt() == expr.span.ctxt() { - // ArgumnetV1::new_() + // ArgumentV1::new_() if_chain! { if let ExprKind::Call(callee, [val]) = e.kind; if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index beed7326803..c69a3d8d2a1 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -108,7 +108,7 @@ pub fn is_present_in_source(cx: &T, span: Span) -> bool { true } -/// Returns the positon just before rarrow +/// Returns the position just before rarrow /// /// ```rust,ignore /// fn into(self) -> () {} diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index dc82ba891fb..dd1d4412036 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -66,7 +66,7 @@ fn lint_message_convention() { // make sure that lint messages: // * are not capitalized - // * don't have puncuation at the end of the last sentence + // * don't have punctuation at the end of the last sentence // these directories have interesting tests let test_dirs = ["ui", "ui-cargo", "ui-internal", "ui-toml"] diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 4b7b7fec78f..ed7b17651e6 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -13,7 +13,7 @@ use proc_macro::{quote, TokenStream}; #[proc_macro_derive(DeriveSomething)] pub fn derive(_: TokenStream) -> TokenStream { - // Shound not trigger `used_underscore_binding` + // Should not trigger `used_underscore_binding` let _inside_derive = 1; assert_eq!(_inside_derive, _inside_derive); -- cgit 1.4.1-3-g733a5 From 4424aa444c2b24c3728e3f09d85bd9b69f57a48d Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 18 Apr 2022 13:28:23 +0100 Subject: `manual_split_once`: lint manual iteration of `SplitN` --- clippy_lints/src/methods/mod.rs | 22 +++- clippy_lints/src/methods/str_splitn.rs | 223 ++++++++++++++++++++++++++++----- tests/ui/manual_split_once.fixed | 96 +++++++++++++- tests/ui/manual_split_once.rs | 96 +++++++++++++- tests/ui/manual_split_once.stderr | 129 ++++++++++++++++++- 5 files changed, 527 insertions(+), 39 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 23266739645..7a1bf36489a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2009,13 +2009,27 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// // Bad - /// let (key, value) = _.splitn(2, '=').next_tuple()?; - /// let value = _.splitn(2, '=').nth(1)?; + /// let s = "key=value=add"; + /// let (key, value) = s.splitn(2, '=').next_tuple()?; + /// let value = s.splitn(2, '=').nth(1)?; /// + /// let mut parts = s.splitn(2, '='); + /// let key = parts.next()?; + /// let value = parts.next()?; + /// ``` + /// Use instead: + /// ```rust,ignore /// // Good - /// let (key, value) = _.split_once('=')?; - /// let value = _.split_once('=')?.1; + /// let s = "key=value=add"; + /// let (key, value) = s.split_once('=')?; + /// let value = s.split_once('=')?.1; + /// + /// let (key, value) = s.split_once('=')?; /// ``` + /// + /// ### Limitations + /// The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()` + /// in two separate `let` statements that immediately follow the `splitn()` #[clippy::version = "1.57.0"] pub MANUAL_SPLIT_ONCE, complexity, diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 6eaa9eb2ef0..52891eeed06 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -1,14 +1,19 @@ use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; -use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::usage::local_used_after_expr; +use clippy_utils::visitors::expr_visitor; +use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{ + BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, +}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_semver::RustcVersion; -use rustc_span::{symbol::sym, Span, SyntaxContext}; +use rustc_span::{sym, Span, Symbol, SyntaxContext}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; @@ -25,40 +30,41 @@ pub(super) fn check( return; } - let ctxt = expr.span.ctxt(); - let Some(usage) = parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id)) else { return }; - - let needless = match usage.kind { + let needless = |usage_kind| match usage_kind { IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::NextTuple => count > 2, }; + let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE); - if needless { - let mut app = Applicability::MachineApplicable; - let (r, message) = if method_name == "splitn" { - ("", "unnecessary use of `splitn`") - } else { - ("r", "unnecessary use of `rsplitn`") - }; - - span_lint_and_sugg( - cx, - NEEDLESS_SPLITN, - expr.span, - message, - "try this", - format!( - "{}.{r}split({})", - snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0, - snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0, - ), - app, - ); - } else if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) { - check_manual_split_once(cx, method_name, expr, self_arg, pat_arg, &usage); + match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) { + Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), + Some(usage) if manual => check_manual_split_once(cx, method_name, expr, self_arg, pat_arg, &usage), + None if manual => { + check_manual_split_once_indirect(cx, method_name, expr, self_arg, pat_arg); + }, + _ => {}, } } +fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) { + let mut app = Applicability::MachineApplicable; + let r = if method_name == "splitn" { "" } else { "r" }; + + span_lint_and_sugg( + cx, + NEEDLESS_SPLITN, + expr.span, + &format!("unnecessary use of `{r}splitn`"), + "try this", + format!( + "{}.{r}split({})", + snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut app).0, + snippet_with_context(cx, pat_arg.span, expr.span.ctxt(), "..", &mut app).0, + ), + app, + ); +} + fn check_manual_split_once( cx: &LateContext<'_>, method_name: &str, @@ -107,16 +113,171 @@ fn check_manual_split_once( span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); } +/// checks for +/// +/// ``` +/// let mut iter = "a.b.c".splitn(2, '.'); +/// let a = iter.next(); +/// let b = iter.next(); +/// ``` +fn check_manual_split_once_indirect( + cx: &LateContext<'_>, + method_name: &str, + expr: &Expr<'_>, + self_arg: &Expr<'_>, + pat_arg: &Expr<'_>, +) -> Option<()> { + let ctxt = expr.span.ctxt(); + let mut parents = cx.tcx.hir().parent_iter(expr.hir_id); + if let (_, Node::Local(local)) = parents.next()? + && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind + && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? + && let (_, Node::Block(enclosing_block)) = parents.next()? + + && let mut stmts = enclosing_block + .stmts + .iter() + .skip_while(|stmt| stmt.hir_id != iter_stmt_id) + .skip(1) + + && let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? + && let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? + && first.unwrap_kind == second.unwrap_kind + && first.name != second.name + && !local_used_after_expr(cx, iter_binding_id, second.init_expr) + { + let (r, lhs, rhs) = if method_name == "splitn" { + ("", first.name, second.name) + } else { + ("r", second.name, first.name) + }; + let msg = format!("manual implementation of `{r}split_once`"); + + let mut app = Applicability::MachineApplicable; + let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; + let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; + + span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| { + diag.span_label(first.span, "first usage here"); + diag.span_label(second.span, "second usage here"); + + let unwrap = match first.unwrap_kind { + UnwrapKind::Unwrap => ".unwrap()", + UnwrapKind::QuestionMark => "?", + }; + diag.span_suggestion_verbose( + local.span, + &format!("try `{r}split_once`"), + format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"), + app, + ); + + let remove_msg = format!("remove the `{iter_ident}` usages"); + diag.span_suggestion( + first.span, + &remove_msg, + String::new(), + app, + ); + diag.span_suggestion( + second.span, + &remove_msg, + String::new(), + app, + ); + }); + } + + Some(()) +} + +#[derive(Debug)] +struct IndirectUsage<'a> { + name: Symbol, + span: Span, + init_expr: &'a Expr<'a>, + unwrap_kind: UnwrapKind, +} + +/// returns `Some(IndirectUsage)` for e.g. +/// +/// ```ignore +/// let name = binding.next()?; +/// let name = binding.next().unwrap(); +/// ``` +fn indirect_usage<'tcx>( + cx: &LateContext<'tcx>, + stmt: &Stmt<'tcx>, + binding: HirId, + ctxt: SyntaxContext, +) -> Option> { + if let StmtKind::Local(Local { + pat: + Pat { + kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None), + .. + }, + init: Some(init_expr), + hir_id: local_hir_id, + .. + }) = stmt.kind + { + let mut path_to_binding = None; + expr_visitor(cx, |expr| { + if path_to_local_id(expr, binding) { + path_to_binding = Some(expr); + } + + path_to_binding.is_none() + }) + .visit_expr(init_expr); + + let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id); + let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?; + + let (parent_id, _) = parents.find(|(_, node)| { + !matches!( + node, + Node::Expr(Expr { + kind: ExprKind::Match(.., MatchSource::TryDesugar), + .. + }) + ) + })?; + + if let IterUsage { + kind: IterUsageKind::Nth(0), + unwrap_kind: Some(unwrap_kind), + .. + } = iter_usage + { + if parent_id == *local_hir_id { + return Some(IndirectUsage { + name: ident.name, + span: stmt.span, + init_expr, + unwrap_kind, + }); + } + } + } + + None +} + +#[derive(Debug, Clone, Copy)] enum IterUsageKind { Nth(u128), NextTuple, } +#[derive(Debug, PartialEq)] enum UnwrapKind { Unwrap, QuestionMark, } +#[derive(Debug)] struct IterUsage { kind: IterUsageKind, unwrap_kind: Option, diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed index bffc7b9b631..c7ca770434a 100644 --- a/tests/ui/manual_split_once.fixed +++ b/tests/ui/manual_split_once.fixed @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![warn(clippy::manual_split_once)] -#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] +#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] extern crate itertools; @@ -41,13 +41,107 @@ fn main() { let _ = s.rsplit_once('=').map(|x| x.0); } +fn indirect() -> Option<()> { + let (l, r) = "a.b.c".split_once('.').unwrap(); + + + + let (l, r) = "a.b.c".split_once('.')?; + + + + let (l, r) = "a.b.c".rsplit_once('.').unwrap(); + + + + let (l, r) = "a.b.c".rsplit_once('.')?; + + + + // could lint, currently doesn't + + let mut iter = "a.b.c".splitn(2, '.'); + let other = 1; + let l = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let mut mut_binding = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let tuple = (iter.next()?, iter.next()?); + + // should not lint + + let mut missing_unwrap = "a.b.c".splitn(2, '.'); + let l = missing_unwrap.next(); + let r = missing_unwrap.next(); + + let mut mixed_unrap = "a.b.c".splitn(2, '.'); + let unwrap = mixed_unrap.next().unwrap(); + let question_mark = mixed_unrap.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let same_name = iter.next()?; + let same_name = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let shadows_existing = "d"; + let shadows_existing = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let becomes_shadowed = iter.next()?; + let becomes_shadowed = "d"; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + let r = iter.next()?; + let third_usage = iter.next()?; + + let mut n_three = "a.b.c".splitn(3, '.'); + let l = n_three.next()?; + let r = n_three.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + { + let in_block = iter.next()?; + } + let r = iter.next()?; + + let mut lacks_binding = "a.b.c".splitn(2, '.'); + let _ = lacks_binding.next()?; + let r = lacks_binding.next()?; + + let mut mapped = "a.b.c".splitn(2, '.').map(|_| "~"); + let l = iter.next()?; + let r = iter.next()?; + + let mut assigned = ""; + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + assigned = iter.next()?; + + None +} + fn _msrv_1_51() { #![clippy::msrv = "1.51"] // `str::split_once` was stabilized in 1.52. Do not lint this let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + + let mut iter = "a.b.c".splitn(2, '.'); + let a = iter.next().unwrap(); + let b = iter.next().unwrap(); } fn _msrv_1_52() { #![clippy::msrv = "1.52"] let _ = "key=value".split_once('=').unwrap().1; + + let (a, b) = "a.b.c".split_once('.').unwrap(); + + } diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index 147be7c7ab1..ee2848a251e 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![warn(clippy::manual_split_once)] -#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)] +#![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] extern crate itertools; @@ -41,13 +41,107 @@ fn main() { let _ = s.rsplitn(2, '=').nth(1); } +fn indirect() -> Option<()> { + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next().unwrap(); + let r = iter.next().unwrap(); + + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".rsplitn(2, '.'); + let r = iter.next().unwrap(); + let l = iter.next().unwrap(); + + let mut iter = "a.b.c".rsplitn(2, '.'); + let r = iter.next()?; + let l = iter.next()?; + + // could lint, currently doesn't + + let mut iter = "a.b.c".splitn(2, '.'); + let other = 1; + let l = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let mut mut_binding = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let tuple = (iter.next()?, iter.next()?); + + // should not lint + + let mut missing_unwrap = "a.b.c".splitn(2, '.'); + let l = missing_unwrap.next(); + let r = missing_unwrap.next(); + + let mut mixed_unrap = "a.b.c".splitn(2, '.'); + let unwrap = mixed_unrap.next().unwrap(); + let question_mark = mixed_unrap.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let same_name = iter.next()?; + let same_name = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let shadows_existing = "d"; + let shadows_existing = iter.next()?; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let becomes_shadowed = iter.next()?; + let becomes_shadowed = "d"; + let r = iter.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + let r = iter.next()?; + let third_usage = iter.next()?; + + let mut n_three = "a.b.c".splitn(3, '.'); + let l = n_three.next()?; + let r = n_three.next()?; + + let mut iter = "a.b.c".splitn(2, '.'); + { + let in_block = iter.next()?; + } + let r = iter.next()?; + + let mut lacks_binding = "a.b.c".splitn(2, '.'); + let _ = lacks_binding.next()?; + let r = lacks_binding.next()?; + + let mut mapped = "a.b.c".splitn(2, '.').map(|_| "~"); + let l = iter.next()?; + let r = iter.next()?; + + let mut assigned = ""; + let mut iter = "a.b.c".splitn(2, '.'); + let l = iter.next()?; + assigned = iter.next()?; + + None +} + fn _msrv_1_51() { #![clippy::msrv = "1.51"] // `str::split_once` was stabilized in 1.52. Do not lint this let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + + let mut iter = "a.b.c".splitn(2, '.'); + let a = iter.next().unwrap(); + let b = iter.next().unwrap(); } fn _msrv_1_52() { #![clippy::msrv = "1.52"] let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + + let mut iter = "a.b.c".splitn(2, '.'); + let a = iter.next().unwrap(); + let b = iter.next().unwrap(); } diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index 9635e6c5e4b..2563a6904b7 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -79,10 +79,135 @@ LL | let _ = s.rsplitn(2, '=').nth(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)` error: manual implementation of `split_once` - --> $DIR/manual_split_once.rs:52:13 + --> $DIR/manual_split_once.rs:45:5 + | +LL | let mut iter = "a.b.c".splitn(2, '.'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let l = iter.next().unwrap(); + | ----------------------------- first usage here +LL | let r = iter.next().unwrap(); + | ----------------------------- second usage here + | +help: try `split_once` + | +LL | let (l, r) = "a.b.c".split_once('.').unwrap(); + | +help: remove the `iter` usages + | +LL - let l = iter.next().unwrap(); +LL + + | +help: remove the `iter` usages + | +LL - let r = iter.next().unwrap(); +LL + + | + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:49:5 + | +LL | let mut iter = "a.b.c".splitn(2, '.'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let l = iter.next()?; + | --------------------- first usage here +LL | let r = iter.next()?; + | --------------------- second usage here + | +help: try `split_once` + | +LL | let (l, r) = "a.b.c".split_once('.')?; + | +help: remove the `iter` usages + | +LL - let l = iter.next()?; +LL + + | +help: remove the `iter` usages + | +LL - let r = iter.next()?; +LL + + | + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:53:5 + | +LL | let mut iter = "a.b.c".rsplitn(2, '.'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let r = iter.next().unwrap(); + | ----------------------------- first usage here +LL | let l = iter.next().unwrap(); + | ----------------------------- second usage here + | +help: try `rsplit_once` + | +LL | let (l, r) = "a.b.c".rsplit_once('.').unwrap(); + | +help: remove the `iter` usages + | +LL - let r = iter.next().unwrap(); +LL + + | +help: remove the `iter` usages + | +LL - let l = iter.next().unwrap(); +LL + + | + +error: manual implementation of `rsplit_once` + --> $DIR/manual_split_once.rs:57:5 + | +LL | let mut iter = "a.b.c".rsplitn(2, '.'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let r = iter.next()?; + | --------------------- first usage here +LL | let l = iter.next()?; + | --------------------- second usage here + | +help: try `rsplit_once` + | +LL | let (l, r) = "a.b.c".rsplit_once('.')?; + | +help: remove the `iter` usages + | +LL - let r = iter.next()?; +LL + + | +help: remove the `iter` usages + | +LL - let l = iter.next()?; +LL + + | + +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:142:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` -error: aborting due to 14 previous errors +error: manual implementation of `split_once` + --> $DIR/manual_split_once.rs:144:5 + | +LL | let mut iter = "a.b.c".splitn(2, '.'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let a = iter.next().unwrap(); + | ----------------------------- first usage here +LL | let b = iter.next().unwrap(); + | ----------------------------- second usage here + | +help: try `split_once` + | +LL | let (a, b) = "a.b.c".split_once('.').unwrap(); + | +help: remove the `iter` usages + | +LL - let a = iter.next().unwrap(); +LL + + | +help: remove the `iter` usages + | +LL - let b = iter.next().unwrap(); +LL + + | + +error: aborting due to 19 previous errors -- cgit 1.4.1-3-g733a5 From 51db157fb4c44212fec54d61af19f80bd4335286 Mon Sep 17 00:00:00 2001 From: tamaron Date: Sat, 23 Apr 2022 22:45:26 +0900 Subject: fix --- clippy_lints/src/methods/mod.rs | 18 +++++++++--------- clippy_lints/src/methods/wrong_self_convention.rs | 2 +- tests/ui/wrong_self_convention.rs | 5 ----- tests/ui/wrong_self_convention.stderr | 18 +++++------------- tests/ui/wrong_self_convention2.rs | 10 ++++++++++ 5 files changed, 25 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7a1bf36489a..f3be71f6b8b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -296,15 +296,15 @@ declare_clippy_lint! { /// Checks for methods with certain name prefixes and which /// doesn't match how self is taken. The actual rules are: /// - /// |Prefix |Postfix |`self` taken | `self` type | - /// |-------|------------|-----------------------|--------------| - /// |`as_` | none |`&self` or `&mut self` | any | - /// |`from_`| none | none | any | - /// |`into_`| none |`self` | any | - /// |`is_` | none |`&self` or none | any | - /// |`to_` | `_mut` |`&mut self` | any | - /// |`to_` | not `_mut` |`self` | `Copy` | - /// |`to_` | not `_mut` |`&self` | not `Copy` | + /// |Prefix |Postfix |`self` taken | `self` type | + /// |-------|------------|-------------------------------|--------------| + /// |`as_` | none |`&self` or `&mut self` | any | + /// |`from_`| none | none | any | + /// |`into_`| none |`self` | any | + /// |`is_` | none |`&mut self` or `&self` or none | any | + /// |`to_` | `_mut` |`&mut self` | any | + /// |`to_` | not `_mut` |`self` | `Copy` | + /// |`to_` | not `_mut` |`&self` | not `Copy` | /// /// Note: Clippy doesn't trigger methods with `to_` prefix in: /// - Traits definition. diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index aecfea9c141..4b368d3ffae 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -14,7 +14,7 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ (&[Convention::StartsWith("as_")], &[SelfKind::Ref, SelfKind::RefMut]), (&[Convention::StartsWith("from_")], &[SelfKind::No]), (&[Convention::StartsWith("into_")], &[SelfKind::Value]), - (&[Convention::StartsWith("is_")], &[SelfKind::Ref, SelfKind::No]), + (&[Convention::StartsWith("is_")], &[SelfKind::RefMut, SelfKind::Ref, SelfKind::No]), (&[Convention::Eq("to_mut")], &[SelfKind::RefMut]), (&[Convention::StartsWith("to_"), Convention::EndsWith("_mut")], &[SelfKind::RefMut]), diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index f8fee4b3ab2..e3cc90ee222 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -193,11 +193,6 @@ pub mod issue8142 { struct S; impl S { - // Should lint: is_ methods should only take &self, or no self at all. - fn is_still_buggy(&mut self) -> bool { - false - } - // Should not lint: "no self at all" is allowed. fn is_forty_two(x: u32) -> bool { x == 42 diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 5493a99572e..2e7ee51d7e1 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -31,7 +31,7 @@ LL | fn into_i32(&self) {} | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take `self` by reference or no `self` +error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:38:15 | LL | fn is_i32(self) {} @@ -71,7 +71,7 @@ LL | pub fn into_i64(&self) {} | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take `self` by reference or no `self` +error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn is_i64(self) {} @@ -111,7 +111,7 @@ LL | fn into_i32_ref(&self) {} | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take `self` by reference or no `self` +error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:98:19 | LL | fn is_i32(self) {} @@ -143,7 +143,7 @@ LL | fn into_i32_ref(&self); | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take `self` by reference or no `self` +error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` --> $DIR/wrong_self_convention.rs:122:19 | LL | fn is_i32(self); @@ -191,13 +191,5 @@ LL | fn to_u64(self) -> u64 { | = help: consider choosing a less ambiguous name -error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:197:27 - | -LL | fn is_still_buggy(&mut self) -> bool { - | ^^^^^^^^^ - | - = help: consider choosing a less ambiguous name - -error: aborting due to 25 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index a8fe8331133..0dcf4743e8b 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -104,3 +104,13 @@ mod issue4546 { pub fn to_other_thingy(self: Pin<&Self>) {} } } + +mod issue_8480_8513 { + struct Cat(String); + + impl Cat { + fn is_animal(&mut self) -> bool { + todo!(); + } + } +} -- cgit 1.4.1-3-g733a5 From 91a822c16228c57bf57961271ecb2d0d28112fa4 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Thu, 5 May 2022 21:39:54 -0400 Subject: Address `unnecessary_to_owned` false positive --- clippy_lints/src/methods/unnecessary_to_owned.rs | 38 +++++++++------ tests/ui/recursive_format_impl.stderr | 11 +---- tests/ui/unnecessary_to_owned.fixed | 61 +++++++++++++++++++++++- tests/ui/unnecessary_to_owned.rs | 61 +++++++++++++++++++++++- tests/ui/unnecessary_to_owned.stderr | 34 ++++++------- 5 files changed, 160 insertions(+), 45 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 02b882e8b55..1f426979c4a 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -65,13 +65,12 @@ fn check_addr_of_expr( if let Some(parent) = get_parent_expr(cx, expr); if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind; let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::>(); - if let Some(target_ty) = match adjustments[..] - { + if let // For matching uses of `Cow::from` [ Adjustment { kind: Adjust::Deref(None), - .. + target: referent_ty, }, Adjustment { kind: Adjust::Borrow(_), @@ -82,7 +81,7 @@ fn check_addr_of_expr( | [ Adjustment { kind: Adjust::Deref(None), - .. + target: referent_ty, }, Adjustment { kind: Adjust::Borrow(_), @@ -97,7 +96,7 @@ fn check_addr_of_expr( | [ Adjustment { kind: Adjust::Deref(None), - .. + target: referent_ty, }, Adjustment { kind: Adjust::Deref(Some(OverloadedDeref { .. })), @@ -107,17 +106,24 @@ fn check_addr_of_expr( kind: Adjust::Borrow(_), target: target_ty, }, - ] => Some(target_ty), - _ => None, - }; + ] = adjustments[..]; let receiver_ty = cx.typeck_results().expr_ty(receiver); - // Only flag cases where the receiver is copyable or the method is `Cow::into_owned`. This - // restriction is to ensure there is not overlap between `redundant_clone` and this lint. - if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id); + let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty); + let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); + // Only flag cases satisfying at least one of the following three conditions: + // * the referent and receiver types are distinct + // * the referent/receiver type is a copyable array + // * the method is `Cow::into_owned` + // This restriction is to ensure there is no overlap between `redundant_clone` and this + // lint. It also avoids the following false positive: + // https://github.com/rust-lang/rust-clippy/issues/8759 + // Arrays are a bit of a corner case. Non-copyable arrays are handled by + // `redundant_clone`, but copyable arrays are not. + if *referent_ty != receiver_ty + || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) + || is_cow_into_owned(cx, method_name, method_def_id); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { - let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty); - let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( cx, @@ -207,7 +213,11 @@ fn check_into_iter_call_arg( if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } - let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" }; + let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { + "copied" + } else { + "cloned" + }; // The next suggestion may be incorrect because the removal of the `to_owned`-like // function could cause the iterator to hold a reference to a resource that is used // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. diff --git a/tests/ui/recursive_format_impl.stderr b/tests/ui/recursive_format_impl.stderr index 6171696ed69..1a717ac92d8 100644 --- a/tests/ui/recursive_format_impl.stderr +++ b/tests/ui/recursive_format_impl.stderr @@ -6,15 +6,6 @@ LL | write!(f, "{}", self.to_string()) | = note: `-D clippy::recursive-format-impl` implied by `-D warnings` -error: unnecessary use of `to_string` - --> $DIR/recursive_format_impl.rs:61:50 - | -LL | Self::E(string) => write!(f, "E {}", string.to_string()), - | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` - = note: this error originates in the macro `$crate::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) - error: using `self` as `Display` in `impl Display` will cause infinite recursion --> $DIR/recursive_format_impl.rs:73:9 | @@ -87,5 +78,5 @@ LL | write!(f, "{}", &&**&&*self) | = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 7455e22d49b..f4f76cd3dd4 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -78,10 +78,10 @@ fn main() { require_slice(array.as_ref()); require_slice(array_ref.as_ref()); require_slice(slice); - require_slice(x_ref); + require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. require_x(&Cow::::Owned(x.clone())); - require_x(x_ref); + require_x(&x_ref.to_owned()); // No longer flagged because of #8759. require_deref_c_str(c_str); require_deref_os_str(os_str); @@ -152,6 +152,7 @@ fn main() { require_os_str(&OsString::from("x")); require_path(&std::path::PathBuf::from("x")); require_str(&String::from("x")); + require_slice(&[String::from("x")]); } fn require_c_str(_: &CStr) {} @@ -272,3 +273,59 @@ mod issue_8507 { Box::new(build(y)) } } + +// 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()); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index bbcd00ad220..fe09a489ab0 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -78,10 +78,10 @@ fn main() { require_slice(&array.to_owned()); require_slice(&array_ref.to_owned()); require_slice(&slice.to_owned()); - require_slice(&x_ref.to_owned()); + require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. require_x(&Cow::::Owned(x.clone()).into_owned()); - require_x(&x_ref.to_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()); @@ -152,6 +152,7 @@ fn main() { 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) {} @@ -272,3 +273,59 @@ mod issue_8507 { 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()); + } +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index f9713559e4f..af7e7b41fb0 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -47,6 +47,18 @@ note: this value is dropped without further use LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ +error: redundant clone + --> $DIR/unnecessary_to_owned.rs:155:39 + | +LL | require_slice(&[String::from("x")].to_owned()); + | ^^^^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/unnecessary_to_owned.rs:155:20 + | +LL | require_slice(&[String::from("x")].to_owned()); + | ^^^^^^^^^^^^^^^^^^^ + error: unnecessary use of `into_owned` --> $DIR/unnecessary_to_owned.rs:60:36 | @@ -151,24 +163,12 @@ error: unnecessary use of `to_owned` LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` -error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:81:19 - | -LL | require_slice(&x_ref.to_owned()); - | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` - error: unnecessary use of `into_owned` --> $DIR/unnecessary_to_owned.rs:83:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this -error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:84:15 - | -LL | require_x(&x_ref.to_owned()); - | ^^^^^^^^^^^^^^^^^ help: use: `x_ref` - error: unnecessary use of `to_owned` --> $DIR/unnecessary_to_owned.rs:86:25 | @@ -476,7 +476,7 @@ LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owne | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:197:14 + --> $DIR/unnecessary_to_owned.rs:198:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -492,22 +492,22 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:220:14 + --> $DIR/unnecessary_to_owned.rs:221:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:225:14 + --> $DIR/unnecessary_to_owned.rs:226:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:272:24 + --> $DIR/unnecessary_to_owned.rs:273:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` -error: aborting due to 79 previous errors +error: aborting due to 78 previous errors -- cgit 1.4.1-3-g733a5 From bdfea1c095d0a98e759eeb680d34d2d6da51132c Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sun, 8 May 2022 07:13:14 -0400 Subject: Pass msrvs by copy --- clippy_lints/src/approx_const.rs | 4 +--- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/borrow_as_ptr.rs | 2 +- clippy_lints/src/casts/cast_abs_to_unsigned.rs | 4 ++-- clippy_lints/src/casts/cast_lossless.rs | 6 +++--- clippy_lints/src/casts/cast_slice_different_sizes.rs | 4 ++-- clippy_lints/src/casts/mod.rs | 10 +++++----- clippy_lints/src/casts/ptr_as_ptr.rs | 4 ++-- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 4 ++-- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_clone.rs | 2 +- clippy_lints/src/matches/mod.rs | 4 ++-- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/cloned_instead_of_copied.rs | 6 +++--- clippy_lints/src/methods/err_expect.rs | 4 ++-- clippy_lints/src/methods/filter_map_next.rs | 4 ++-- clippy_lints/src/methods/is_digit_ascii_radix.rs | 4 ++-- clippy_lints/src/methods/map_unwrap_or.rs | 4 ++-- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/methods/option_as_ref_deref.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 4 ++-- clippy_lints/src/methods/unnecessary_to_owned.rs | 6 +++--- clippy_lints/src/missing_const_for_fn.rs | 4 ++-- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 8 ++++---- clippy_lints/src/use_self.rs | 6 +++--- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/qualify_min_const_fn.rs | 8 ++++---- doc/adding_lints.md | 2 +- 36 files changed, 70 insertions(+), 72 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index e109ee0009e..da1b646f477 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -87,9 +87,7 @@ impl ApproxConstant { let s = s.as_str(); if s.parse::().is_ok() { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { - if is_approx_const(constant, s, min_digits) - && msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv)) - { + if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) { span_lint_and_help( cx, APPROX_CONSTANT, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 30dde2f0ef0..3de91f3d24a 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -613,7 +613,7 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option) { if_chain! { - if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES); + if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES); // check cfg_attr if attr.has_name(sym::cfg_attr); if let Some(items) = attr.meta_item_list(); diff --git a/clippy_lints/src/borrow_as_ptr.rs b/clippy_lints/src/borrow_as_ptr.rs index 9f8eb488c29..0993adbae2e 100644 --- a/clippy_lints/src/borrow_as_ptr.rs +++ b/clippy_lints/src/borrow_as_ptr.rs @@ -57,7 +57,7 @@ impl BorrowAsPtr { impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) { + if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { return; } diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index e9b0f1f672d..6bac6bf83f8 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -16,10 +16,10 @@ pub(super) fn check( cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, - msrv: &Option, + msrv: Option, ) { if_chain! { - if meets_msrv(msrv.as_ref(), &msrvs::UNSIGNED_ABS); + if meets_msrv(msrv, msrvs::UNSIGNED_ABS); if cast_from.is_integral(); if cast_to.is_integral(); if cast_from.is_signed(); diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 7717c1e9e31..938458e30ca 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -16,7 +16,7 @@ pub(super) fn check( cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, - msrv: &Option, + msrv: Option, ) { if !should_lint(cx, expr, cast_from, cast_to, msrv) { return; @@ -68,7 +68,7 @@ fn should_lint( expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, - msrv: &Option, + msrv: Option, ) -> bool { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). if in_constant(cx, expr.hir_id) { @@ -95,7 +95,7 @@ fn should_lint( }; !is_isize_or_usize(cast_from) && from_nbits < to_nbits }, - (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv.as_ref(), &msrvs::FROM_BOOL) => true, + (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true, (_, _) => { matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) }, diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 2238668abca..bb09a6708a0 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -8,9 +8,9 @@ use rustc_semver::RustcVersion; use super::CAST_SLICE_DIFFERENT_SIZES; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Option) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option) { // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist - if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) { + if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) { return; } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 9c3ebbe035b..108e119c104 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -532,7 +532,7 @@ impl_lint_pass!(Casts => [ impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !in_external_macro(cx.sess(), expr.span) { - ptr_as_ptr::check(cx, expr, &self.msrv); + ptr_as_ptr::check(cx, expr, self.msrv); } if expr.span.from_expansion() { @@ -562,9 +562,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); - cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); + cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); + cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); cast_enum_constructor::check(cx, expr, cast_expr, cast_from); } } @@ -572,8 +572,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_ref_to_mut::check(cx, expr); cast_ptr_alignment::check(cx, expr); char_lit_as_u8::check(cx, expr); - ptr_as_ptr::check(cx, expr, &self.msrv); - cast_slice_different_sizes::check(cx, expr, &self.msrv); + ptr_as_ptr::check(cx, expr, self.msrv); + cast_slice_different_sizes::check(cx, expr, self.msrv); } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index fb04f93fbcf..46d45d09661 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -12,8 +12,8 @@ use rustc_semver::RustcVersion; use super::PTR_AS_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option) { - if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option) { + if !meets_msrv(msrv, msrvs::POINTER_CAST) { return; } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 31cc3698592..e23428e216d 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -57,7 +57,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) { + if !meets_msrv(self.msrv, msrvs::TRY_FROM) { return; } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index c2f52605151..5d25c1d0634 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -55,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); impl<'tcx> LateLintPass<'tcx> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) { + if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) { return; } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 9525c163ece..b8d227855d9 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -57,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) { + if !meets_msrv(self.msrv, msrvs::BOOL_THEN) { return; } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 8a84513b779..07b0604f78d 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr); if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id); - if meets_msrv(self.msrv.as_ref(), &msrvs::SLICE_PATTERNS); + if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS); let found_slices = find_slice_values(cx, let_pat); if !found_slices.is_empty(); diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index ac3d9447b6b..60bbcde4f1d 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]); impl<'tcx> LateLintPass<'tcx> for ManualBits { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) { + if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) { return; } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index b8d620d8171..14f39067299 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -98,7 +98,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustiveStruct { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { + if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) { return; } @@ -150,7 +150,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { + if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) { return; } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index aacabf303a7..dfb3efc4e28 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -68,7 +68,7 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { + if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) { return; } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index ceb66947d02..a13d191375b 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -144,7 +144,7 @@ impl MapClone { fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { let mut applicability = Applicability::MachineApplicable; - let (message, sugg_method) = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) { + let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) { ("you are using an explicit closure for copying elements", "copied") } else { ("you are using an explicit closure for cloning elements", "cloned") diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 401ecef460c..3d8391bce2b 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } if !contains_cfg_arm(cx, expr, ex, arms) { if source == MatchSource::Normal { - if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) + if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) { match_same_arms::check(cx, arms); @@ -685,7 +685,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { match_wild_err_arm::check(cx, ex, arms); wild_in_or_pats::check(cx, arms); } else { - if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { + if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) { match_like_matches::check(cx, expr); } redundant_pattern_match::check(cx, expr); diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 054937e3e36..41073d40f3d 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); - if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) { + if meets_msrv(self.msrv, msrvs::MEM_TAKE) { check_replace_with_default(cx, src, dest, expr.span); } } diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index 6d30bb5a278..e9aeab2d5b6 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -10,16 +10,16 @@ use rustc_span::{sym, Span}; use super::CLONED_INSTEAD_OF_COPIED; -pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) => { subst.type_at(0) }, - _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => { + _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => { match get_iterator_item_ty(cx, recv_ty) { // ::Item Some(ty) => ty, diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index be9d4ad94fb..570a1b87358 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -13,7 +13,7 @@ pub(super) fn check( cx: &LateContext<'_>, _expr: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>, - msrv: Option<&RustcVersion>, + msrv: Option, expect_span: Span, err_span: Span, ) { @@ -21,7 +21,7 @@ pub(super) fn check( if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); // Test the version to make sure the lint can be showed (expect_err has been // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) - if meets_msrv(msrv, &msrvs::EXPECT_ERR); + if meets_msrv(msrv, msrvs::EXPECT_ERR); // Grabs the `Result` type let result_type = cx.typeck_results().expr_ty(recv); diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index f0d69a1f42e..38ec4d8e3ab 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -14,10 +14,10 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - msrv: Option<&RustcVersion>, + msrv: Option, ) { if is_trait_method(cx, expr, sym::Iterator) { - if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) { + if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) { return; } diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index ad333df2f2d..aa176dcc8b4 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -15,9 +15,9 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'_>, self_arg: &'tcx Expr<'_>, radix: &'tcx Expr<'_>, - msrv: Option<&RustcVersion>, + msrv: Option, ) { - if !meets_msrv(msrv, &msrvs::IS_ASCII_DIGIT) { + if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) { return; } diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 9ec84e76519..4a8e7ce4ddb 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -19,13 +19,13 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>, - msrv: Option<&RustcVersion>, + msrv: Option, ) -> bool { // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) { + if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) { return false; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f3be71f6b8b..5b073f6f3b8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2306,7 +2306,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - check_methods(cx, expr, self.msrv.as_ref()); + check_methods(cx, expr, self.msrv); match expr.kind { hir::ExprKind::Call(func, args) => { @@ -2322,7 +2322,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { single_char_add_str::check(cx, expr, args); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args); single_char_pattern::check(cx, expr, method_call.ident.name, args); - unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.as_ref()); + unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv); }, hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { @@ -2506,7 +2506,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } #[allow(clippy::too_many_lines)] -fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) { +fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option) { if let Some((name, [recv, args @ ..], span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { @@ -2534,7 +2534,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); }, Some(("take", [take_self_arg, take_arg], _)) => { - if meets_msrv(msrv, &msrvs::STR_REPEAT) { + if meets_msrv(msrv, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index ba2d2914315..b50a173d835 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -19,9 +19,9 @@ pub(super) fn check<'tcx>( as_ref_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, is_mut: bool, - msrv: Option<&RustcVersion>, + msrv: Option, ) { - if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) { + if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) { return; } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 52891eeed06..fc375763542 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -24,7 +24,7 @@ pub(super) fn check( self_arg: &Expr<'_>, pat_arg: &Expr<'_>, count: u128, - msrv: Option<&RustcVersion>, + msrv: Option, ) { if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { return; @@ -34,7 +34,7 @@ pub(super) fn check( IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::NextTuple => count > 2, }; - let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE); + let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE); match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) { Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 1f426979c4a..97c4feb3122 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -26,7 +26,7 @@ pub fn check<'tcx>( expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>], - msrv: Option<&RustcVersion>, + msrv: Option, ) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); @@ -198,7 +198,7 @@ fn check_into_iter_call_arg( expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>, - msrv: Option<&RustcVersion>, + msrv: Option, ) -> bool { if_chain! { if let Some(parent) = get_parent_expr(cx, expr); @@ -213,7 +213,7 @@ fn check_into_iter_call_arg( if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } - let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { + let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 06209bfe7b0..16d65966c10 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, hir_id: HirId, ) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) { + if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) { return; } @@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { + if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { cx.tcx.sess.span_err(span, err.as_ref()); } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index f26f3650cb3..a47dc26f603 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_range_zip_with_len(cx, path, args, expr.span); }, ExprKind::Binary(ref op, l, r) => { - if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) { + if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { check_possible_range_contains(cx, op.node, l, r, expr); } }, diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 40a62fd6d20..40b03068f6c 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -51,7 +51,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) { + if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) { return; } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index ea5064217ab..2d26c49252f 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -99,7 +99,7 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) { + if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) { return; } diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index ae431aac83b..04e2f301bfd 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -61,13 +61,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]); impl EarlyLintPass for UnnestedOrPatterns { fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { - if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { + if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &a.pat); } } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { + if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { if let ast::ExprKind::Let(pat, _, _) = &e.kind { lint_unnested_or_patterns(cx, pat); } @@ -75,13 +75,13 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { - if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { + if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &p.pat); } } fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { - if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { + if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &l.pat); } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 138f8bccb3f..66f7748e9e0 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { if_chain! { if !hir_ty.span.from_expansion(); - if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); + if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, in_body, @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if !expr.span.from_expansion(); - if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); + if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id); then {} else { return; } @@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { if_chain! { if !pat.span.from_expansion(); - if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); + if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind; if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _)); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 7d46952d971..ed511004ea0 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -117,8 +117,8 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Opt None } -pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { - msrv.map_or(true, |msrv| msrv.meets(*lint_msrv)) +pub fn meets_msrv(msrv: Option, lint_msrv: RustcVersion) -> bool { + msrv.map_or(true, |msrv| msrv.meets(lint_msrv)) } #[macro_export] diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 75808b1b174..6a8ed4e7bd7 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -19,7 +19,7 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -269,7 +269,7 @@ fn check_terminator<'a, 'tcx>( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>, - msrv: Option<&RustcVersion>, + msrv: Option, ) -> McfResult { let span = terminator.source_info.span; match &terminator.kind { @@ -353,7 +353,7 @@ fn check_terminator<'a, 'tcx>( } } -fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool { +fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option) -> bool { tcx.is_const_fn(def_id) && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level { @@ -362,7 +362,7 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> b // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. crate::meets_msrv( msrv, - &RustcVersion::parse(since.as_str()) + RustcVersion::parse(since.as_str()) .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"), ) } else { diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 307cf2f3a90..5607e2264a6 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -432,7 +432,7 @@ The project's MSRV can then be matched against the feature MSRV in the LintPass using the `meets_msrv` utility function. ``` rust -if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { +if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) { return; } ``` -- cgit 1.4.1-3-g733a5 From 597f61bbe3a861c3d77b784cc701e6a975fbe842 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sun, 8 May 2022 06:44:58 -0400 Subject: Optionally allow `expect` and `unwrap` in tests --- clippy_lints/src/lib.rs | 11 +- clippy_lints/src/methods/expect_used.rs | 7 +- clippy_lints/src/methods/mod.rs | 368 +++++++++++---------- clippy_lints/src/methods/unwrap_used.rs | 7 +- clippy_lints/src/utils/conf.rs | 8 + tests/ui-toml/expect_used/clippy.toml | 1 + tests/ui-toml/expect_used/expect_used.rs | 29 ++ tests/ui-toml/expect_used/expect_used.stderr | 19 ++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui-toml/unwrap_used/clippy.toml | 1 + tests/ui-toml/unwrap_used/unwrap_used.rs | 74 +++++ tests/ui-toml/unwrap_used/unwrap_used.stderr | 197 +++++++++++ 12 files changed, 543 insertions(+), 181 deletions(-) create mode 100644 tests/ui-toml/expect_used/clippy.toml create mode 100644 tests/ui-toml/expect_used/expect_used.rs create mode 100644 tests/ui-toml/expect_used/expect_used.stderr create mode 100644 tests/ui-toml/unwrap_used/clippy.toml create mode 100644 tests/ui-toml/unwrap_used/unwrap_used.rs create mode 100644 tests/ui-toml/unwrap_used/unwrap_used.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3bb821a1482..6970757b56d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -582,8 +582,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; + let allow_expect_in_tests = conf.allow_expect_in_tests; + let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv))); - store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv))); + store.register_late_pass(move || { + Box::new(methods::Methods::new( + avoid_breaking_exported_api, + msrv, + allow_expect_in_tests, + allow_unwrap_in_tests, + )) + }); store.register_late_pass(move || Box::new(matches::Matches::new(msrv))); store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv))); store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 55be513c5bb..fbc3348f185 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_in_test_function; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; @@ -7,7 +8,7 @@ use rustc_span::sym; use super::EXPECT_USED; /// lint use of `expect()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { @@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr None }; + if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { + return; + } + if let Some((lint, kind, none_value)) = mess { span_lint_and_help( cx, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5b073f6f3b8..e452614ce17 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2200,14 +2200,23 @@ declare_clippy_lint! { pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, + allow_expect_in_tests: bool, + allow_unwrap_in_tests: bool, } impl Methods { #[must_use] - pub fn new(avoid_breaking_exported_api: bool, msrv: Option) -> Self { + pub fn new( + avoid_breaking_exported_api: bool, + msrv: Option, + allow_expect_in_tests: bool, + allow_unwrap_in_tests: bool, + ) -> Self { Self { avoid_breaking_exported_api, msrv, + allow_expect_in_tests, + allow_unwrap_in_tests, } } } @@ -2306,7 +2315,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - check_methods(cx, expr, self.msrv); + self.check_methods(cx, expr); match expr.kind { hir::ExprKind::Call(func, args) => { @@ -2505,196 +2514,201 @@ impl<'tcx> LateLintPass<'tcx> for Methods { extract_msrv_attr!(LateContext); } -#[allow(clippy::too_many_lines)] -fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option) { - if let Some((name, [recv, args @ ..], span)) = method_call(expr) { - match (name, args) { - ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { - zst_offset::check(cx, expr, recv); - }, - ("and_then", [arg]) => { - let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); - let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); - if !biom_option_linted && !biom_result_linted { - unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); - } - }, - ("as_deref" | "as_deref_mut", []) => { - needless_option_as_deref::check(cx, expr, recv, name); - }, - ("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, msrv), - ("collect", []) => match method_call(recv) { - Some((name @ ("cloned" | "copied"), [recv2], _)) => { - iter_cloned_collect::check(cx, name, expr, recv2); +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) { + match (name, args) { + ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { + zst_offset::check(cx, expr, recv); + }, + ("and_then", [arg]) => { + let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); + let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); + if !biom_option_linted && !biom_result_linted { + unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); + } + }, + ("as_deref" | "as_deref_mut", []) => { + needless_option_as_deref::check(cx, expr, recv, name); + }, + ("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); + } + }, + _ => {}, + }, + (name @ "count", args @ []) => match method_call(recv) { + Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + 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), + _ => {}, + }, + ("drain", [arg]) => { + iter_with_drain::check(cx, expr, recv, span, arg); + }, + ("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), + _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests), + }, + ("extend", [arg]) => { + string_extend_chars::check(cx, expr, recv, arg); + extend_with_drain::check(cx, expr, recv, arg); + }, + ("filter_map", [arg]) => { + unnecessary_filter_map::check(cx, expr, arg, name); + filter_map_identity::check(cx, expr, arg, span); + }, + ("find_map", [arg]) => { + unnecessary_filter_map::check(cx, expr, arg, name); }, - Some(("map", [m_recv, m_arg], _)) => { - map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); + ("flat_map", [arg]) => { + flat_map_identity::check(cx, expr, arg, span); + flat_map_option::check(cx, expr, arg, span); }, - Some(("take", [take_self_arg, take_arg], _)) => { - if meets_msrv(msrv, msrvs::STR_REPEAT) { - manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); + (name @ "flatten", args @ []) => 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, recv2, name, args), + _ => {}, + }, + ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), + ("for_each", [_]) => { + if let Some(("inspect", [_, _], span2)) = method_call(recv) { + inspect_for_each::check(cx, expr, span2); } }, - _ => {}, - }, - (name @ "count", args @ []) => match method_call(recv) { - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args), - Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { - iter_count::check(cx, expr, recv2, name2); + ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), + ("is_file", []) => filetype_is_file::check(cx, expr, recv), + ("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), + ("join", [join_arg]) => { + if let Some(("collect", _, span)) = method_call(recv) { + unnecessary_join::check(cx, expr, recv, join_arg, span); + } }, - Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), - _ => {}, - }, - ("drain", [arg]) => { - iter_with_drain::check(cx, expr, recv, span, arg); - }, - ("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, msrv, span, err_span), - _ => expect_used::check(cx, expr, recv), - }, - ("extend", [arg]) => { - string_extend_chars::check(cx, expr, recv, arg); - extend_with_drain::check(cx, expr, recv, arg); - }, - ("filter_map", [arg]) => { - unnecessary_filter_map::check(cx, expr, arg, name); - filter_map_identity::check(cx, expr, arg, span); - }, - ("find_map", [arg]) => { - unnecessary_filter_map::check(cx, expr, arg, name); - }, - ("flat_map", [arg]) => { - flat_map_identity::check(cx, expr, arg, span); - flat_map_option::check(cx, expr, arg, span); - }, - (name @ "flatten", args @ []) => 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, recv2, name, args), - _ => {}, - }, - ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), - ("for_each", [_]) => { - if let Some(("inspect", [_, _], span2)) = method_call(recv) { - inspect_for_each::check(cx, expr, span2); - } - }, - ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), - ("is_file", []) => filetype_is_file::check(cx, expr, recv), - ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, msrv), - ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), - ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), - ("join", [join_arg]) => { - if let Some(("collect", _, span)) = method_call(recv) { - unnecessary_join::check(cx, expr, recv, join_arg, span); - } - }, - ("last", args @ []) | ("skip", args @ [_]) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { - if let ("cloned", []) = (name2, args2) { - iter_overeager_cloned::check(cx, expr, recv2, name, args); + ("last", args @ []) | ("skip", args @ [_]) => { + if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let ("cloned", []) = (name2, args2) { + iter_overeager_cloned::check(cx, expr, recv2, name, args); + } } - } - }, - (name @ ("map" | "map_err"), [m_arg]) => { - 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, msrv), - ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv), - ("filter", [f_arg]) => { - filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); - }, - ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true), - _ => {}, + }, + (name @ ("map" | "map_err"), [m_arg]) => { + 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), + ("filter", [f_arg]) => { + filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); + }, + ("find", [f_arg]) => { + filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true); + }, + _ => {}, + } } - } - map_identity::check(cx, expr, recv, m_arg, name, span); - }, - ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), - (name @ "next", args @ []) => { - if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { - match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args), - ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), - ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, 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), - _ => {}, + map_identity::check(cx, expr, recv, m_arg, name, span); + }, + ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), + (name @ "next", args @ []) => { + if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { + match (name2, args2) { + ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), + ("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), + _ => {}, + } } - } - }, - ("nth", args @ [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, recv2, name, args), - 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"), - ("or_else", [arg]) => { - if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) { - unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); - } - }, - ("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, msrv); - } - }, - ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { - suspicious_splitn::check(cx, name, expr, recv, count); - } - }, - ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("take", args @ [_arg]) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { - if let ("cloned", []) = (name2, args2) { - iter_overeager_cloned::check(cx, expr, recv2, name, args); + }, + ("nth", args @ [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, recv2, name, args), + 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"), + ("or_else", [arg]) => { + if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) { + unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } - } - }, - ("take", []) => needless_option_take::check(cx, expr, recv), - ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { - implicit_clone::check(cx, name, expr, recv); - }, - ("unwrap", []) => { - match method_call(recv) { - Some(("get", [recv, get_arg], _)) => { - get_unwrap::check(cx, expr, recv, get_arg, false); - }, - Some(("get_mut", [recv, get_arg], _)) => { - get_unwrap::check(cx, expr, recv, get_arg, true); + }, + ("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); + } + }, + ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { + if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + suspicious_splitn::check(cx, name, expr, recv, count); + } + }, + ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), + ("take", args @ [_arg]) => { + if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let ("cloned", []) = (name2, args2) { + iter_overeager_cloned::check(cx, expr, recv2, name, args); + } + } + }, + ("take", []) => needless_option_take::check(cx, expr, recv), + ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { + implicit_clone::check(cx, name, expr, recv); + }, + ("unwrap", []) => { + match method_call(recv) { + Some(("get", [recv, get_arg], _)) => { + get_unwrap::check(cx, expr, recv, get_arg, false); + }, + Some(("get_mut", [recv, get_arg], _)) => { + get_unwrap::check(cx, expr, recv, get_arg, true); + }, + Some(("or", [recv, or_arg], or_span)) => { + or_then_unwrap::check(cx, expr, recv, or_arg, or_span); + }, + _ => {}, + } + unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests); + }, + ("unwrap_or", [u_arg]) => match method_call(recv) { + Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { + manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, - Some(("or", [recv, or_arg], or_span)) => { - or_then_unwrap::check(cx, expr, recv, or_arg, or_span); + Some(("map", [m_recv, m_arg], span)) => { + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, _ => {}, - } - unwrap_used::check(cx, expr, recv); - }, - ("unwrap_or", [u_arg]) => match method_call(recv) { - 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)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); + ("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) => {}, + _ => { + unwrap_or_else_default::check(cx, expr, recv, u_arg); + unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); + }, }, _ => {}, - }, - ("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, msrv) => {}, - _ => { - unwrap_or_else_default::check(cx, expr, recv, u_arg); - unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); - }, - }, - _ => {}, + } } } } diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 44676d78c60..5c761014927 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_in_test_function; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; @@ -7,7 +8,7 @@ use rustc_span::sym; use super::UNWRAP_USED; /// lint use of `unwrap()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { @@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr None }; + if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { + return; + } + if let Some((lint, kind, none_value)) = mess { span_lint_and_help( cx, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 74b0168a179..bdcd76d153f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -316,6 +316,14 @@ define_Conf! { /// /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes (max_include_file_size: u64 = 1_000_000), + /// Lint: EXPECT_USED. + /// + /// Whether `expect` should be allowed in test functions + (allow_expect_in_tests: bool = false), + /// Lint: UNWRAP_USED. + /// + /// Whether `unwrap` should be allowed in test functions + (allow_unwrap_in_tests: bool = false), } /// Search for the configuration file. diff --git a/tests/ui-toml/expect_used/clippy.toml b/tests/ui-toml/expect_used/clippy.toml new file mode 100644 index 00000000000..6933b816419 --- /dev/null +++ b/tests/ui-toml/expect_used/clippy.toml @@ -0,0 +1 @@ +allow-expect-in-tests = true diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs new file mode 100644 index 00000000000..22dcd3ae9d6 --- /dev/null +++ b/tests/ui-toml/expect_used/expect_used.rs @@ -0,0 +1,29 @@ +// compile-flags: --test +#![warn(clippy::expect_used)] + +fn expect_option() { + let opt = Some(0); + let _ = opt.expect(""); +} + +fn expect_result() { + let res: Result = Ok(0); + let _ = res.expect(""); +} + +fn main() { + expect_option(); + expect_result(); +} + +#[test] +fn test_expect_option() { + let opt = Some(0); + let _ = opt.expect(""); +} + +#[test] +fn test_expect_result() { + let res: Result = Ok(0); + let _ = res.expect(""); +} diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr new file mode 100644 index 00000000000..9cb2199ed21 --- /dev/null +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -0,0 +1,19 @@ +error: used `expect()` on `an Option` value + --> $DIR/expect_used.rs:6:13 + | +LL | let _ = opt.expect(""); + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::expect-used` implied by `-D warnings` + = help: if this value is an `None`, it will panic + +error: used `expect()` on `a Result` value + --> $DIR/expect_used.rs:11:13 + | +LL | let _ = res.expect(""); + | ^^^^^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 8701809b4da..65277dd03e8 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `max-suggested-slice-pattern-length`, `await-holding-invalid-types`, `max-include-file-size`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `max-suggested-slice-pattern-length`, `await-holding-invalid-types`, `max-include-file-size`, `allow-expect-in-tests`, `allow-unwrap-in-tests`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui-toml/unwrap_used/clippy.toml b/tests/ui-toml/unwrap_used/clippy.toml new file mode 100644 index 00000000000..154626ef4e8 --- /dev/null +++ b/tests/ui-toml/unwrap_used/clippy.toml @@ -0,0 +1 @@ +allow-unwrap-in-tests = true diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs new file mode 100644 index 00000000000..a639de07971 --- /dev/null +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -0,0 +1,74 @@ +// compile-flags: --test + +#![allow(unused_mut, clippy::from_iter_instead_of_collect)] +#![warn(clippy::unwrap_used)] +#![deny(clippy::get_unwrap)] + +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::collections::VecDeque; +use std::iter::FromIterator; + +struct GetFalsePositive { + arr: [u32; 3], +} + +impl GetFalsePositive { + fn get(&self, pos: usize) -> Option<&u32> { + self.arr.get(pos) + } + fn get_mut(&mut self, pos: usize) -> Option<&mut u32> { + self.arr.get_mut(pos) + } +} + +fn main() { + let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); + let mut some_slice = &mut [0, 1, 2, 3]; + let mut some_vec = vec![0, 1, 2, 3]; + let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect(); + let mut some_hashmap: HashMap = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]); + let mut some_btreemap: BTreeMap = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]); + let mut false_positive = GetFalsePositive { arr: [0, 1, 2] }; + + { + // Test `get().unwrap()` + let _ = boxed_slice.get(1).unwrap(); + let _ = some_slice.get(0).unwrap(); + let _ = some_vec.get(0).unwrap(); + let _ = some_vecdeque.get(0).unwrap(); + let _ = some_hashmap.get(&1).unwrap(); + let _ = some_btreemap.get(&1).unwrap(); + #[allow(clippy::unwrap_used)] + let _ = false_positive.get(0).unwrap(); + // Test with deref + let _: u8 = *boxed_slice.get(1).unwrap(); + } + + { + // Test `get_mut().unwrap()` + *boxed_slice.get_mut(0).unwrap() = 1; + *some_slice.get_mut(0).unwrap() = 1; + *some_vec.get_mut(0).unwrap() = 1; + *some_vecdeque.get_mut(0).unwrap() = 1; + // Check false positives + #[allow(clippy::unwrap_used)] + { + *some_hashmap.get_mut(&1).unwrap() = 'b'; + *some_btreemap.get_mut(&1).unwrap() = 'b'; + *false_positive.get_mut(0).unwrap() = 1; + } + } + + { + // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()` + let _ = some_vec.get(0..1).unwrap().to_vec(); + let _ = some_vec.get_mut(0..1).unwrap().to_vec(); + } +} + +#[test] +fn test() { + let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); + let _ = boxed_slice.get(1).unwrap(); +} diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr new file mode 100644 index 00000000000..6c3adc5395f --- /dev/null +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -0,0 +1,197 @@ +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:36:17 + | +LL | let _ = boxed_slice.get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` + | +note: the lint level is defined here + --> $DIR/unwrap_used.rs:5:9 + | +LL | #![deny(clippy::get_unwrap)] + | ^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:36:17 + | +LL | let _ = boxed_slice.get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:37:17 + | +LL | let _ = some_slice.get(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:37:17 + | +LL | let _ = some_slice.get(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:38:17 + | +LL | let _ = some_vec.get(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:38:17 + | +LL | let _ = some_vec.get(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:39:17 + | +LL | let _ = some_vecdeque.get(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:39:17 + | +LL | let _ = some_vecdeque.get(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:40:17 + | +LL | let _ = some_hashmap.get(&1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:40:17 + | +LL | let _ = some_hashmap.get(&1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:41:17 + | +LL | let _ = some_btreemap.get(&1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:41:17 + | +LL | let _ = some_btreemap.get(&1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:45:21 + | +LL | let _: u8 = *boxed_slice.get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:45:22 + | +LL | let _: u8 = *boxed_slice.get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:50:9 + | +LL | *boxed_slice.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:50:10 + | +LL | *boxed_slice.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:51:9 + | +LL | *some_slice.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:51:10 + | +LL | *some_slice.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:52:9 + | +LL | *some_vec.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:52:10 + | +LL | *some_vec.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:53:9 + | +LL | *some_vecdeque.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:53:10 + | +LL | *some_vecdeque.get_mut(0).unwrap() = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:65:17 + | +LL | let _ = some_vec.get(0..1).unwrap().to_vec(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:65:17 + | +LL | let _ = some_vec.get(0..1).unwrap().to_vec(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:66:17 + | +LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` + +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_used.rs:66:17 + | +LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:73:13 + | +LL | let _ = boxed_slice.get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` + +error: aborting due to 27 previous errors + -- cgit 1.4.1-3-g733a5 From fe84ff336055412f0df8a2e625eaf46c6701e574 Mon Sep 17 00:00:00 2001 From: nsunderland1 Date: Fri, 6 May 2022 00:10:11 -0700 Subject: New lint: [`derive_partial_eq_without_eq`] --- CHANGELOG.md | 1 + clippy_dev/src/update_lints.rs | 6 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/derive.rs | 72 ++++++++++++++++++- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/loops/utils.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_utils/src/numeric_literal.rs | 2 +- tests/ui/absurd-extreme-comparisons.rs | 2 +- tests/ui/assign_ops2.rs | 2 +- tests/ui/cmp_owned/asymmetric_partial_eq.fixed | 2 +- tests/ui/cmp_owned/asymmetric_partial_eq.rs | 2 +- tests/ui/cmp_owned/with_suggestion.fixed | 4 +- tests/ui/cmp_owned/with_suggestion.rs | 4 +- tests/ui/cmp_owned/without_suggestion.rs | 4 +- tests/ui/crashes/ice-6254.rs | 1 + tests/ui/crashes/ice-6254.stderr | 2 +- tests/ui/derive_hash_xor_eq.rs | 2 + tests/ui/derive_hash_xor_eq.stderr | 16 ++--- tests/ui/derive_partial_eq_without_eq.fixed | 98 ++++++++++++++++++++++++++ tests/ui/derive_partial_eq_without_eq.rs | 98 ++++++++++++++++++++++++++ tests/ui/derive_partial_eq_without_eq.stderr | 46 ++++++++++++ tests/ui/equatable_if_let.fixed | 2 +- tests/ui/equatable_if_let.rs | 2 +- tests/ui/unit_cmp.rs | 6 +- tests/ui/unit_cmp.stderr | 12 ++-- 29 files changed, 359 insertions(+), 38 deletions(-) create mode 100644 tests/ui/derive_partial_eq_without_eq.fixed create mode 100644 tests/ui/derive_partial_eq_without_eq.rs create mode 100644 tests/ui/derive_partial_eq_without_eq.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 751f9fccd88..0608c360d30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3350,6 +3350,7 @@ Released 2018-09-13 [`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord +[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 1a6a4336da2..e9cc4f29943 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -17,7 +17,7 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum UpdateMode { Check, Change, @@ -372,7 +372,7 @@ fn exit_with_failure() { } /// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] struct Lint { name: String, group: String, @@ -414,7 +414,7 @@ impl Lint { } } -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] struct DeprecatedLint { name: String, reason: String, diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index e23428e216d..28c77ea40ef 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -123,7 +123,7 @@ struct Conversion<'a> { } /// The kind of conversion that is checked -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum ConversionType { SignedToUnsigned, SignedToSigned, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 557e101494e..a4757ebd8c7 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,8 +1,9 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::paths; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{is_automatically_derived, is_lint_allowed, match_def_path}; use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::{ BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety, @@ -156,11 +157,44 @@ declare_clippy_lint! { "deriving `serde::Deserialize` on a type that has methods using `unsafe`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for types that derive `PartialEq` and could implement `Eq`. + /// + /// ### Why is this bad? + /// If a type `T` derives `PartialEq` and all of its members implement `Eq`, + /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used + /// in APIs that require `Eq` types. It also allows structs containing `T` to derive + /// `Eq` themselves. + /// + /// ### Example + /// ```rust + /// #[derive(PartialEq)] + /// struct Foo { + /// i_am_eq: i32, + /// i_am_eq_too: Vec, + /// } + /// ``` + /// Use instead: + /// ```rust + /// #[derive(PartialEq, Eq)] + /// struct Foo { + /// i_am_eq: i32, + /// i_am_eq_too: Vec, + /// } + /// ``` + #[clippy::version = "1.62.0"] + pub DERIVE_PARTIAL_EQ_WITHOUT_EQ, + style, + "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`" +} + declare_lint_pass!(Derive => [ EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ, DERIVE_ORD_XOR_PARTIAL_ORD, - UNSAFE_DERIVE_DESERIALIZE + UNSAFE_DERIVE_DESERIALIZE, + DERIVE_PARTIAL_EQ_WITHOUT_EQ ]); impl<'tcx> LateLintPass<'tcx> for Derive { @@ -179,6 +213,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { if is_automatically_derived { check_unsafe_derive_deserialize(cx, item, trait_ref, ty); + check_partial_eq_without_eq(cx, item.span, trait_ref, ty); } else { check_copy_clone(cx, item, trait_ref, ty); } @@ -419,3 +454,36 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { self.cx.tcx.hir() } } + +/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint. +fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) { + if_chain! { + if let ty::Adt(adt, substs) = ty.kind(); + if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq); + if let Some(def_id) = trait_ref.trait_def_id(); + if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); + if !implements_trait(cx, ty, eq_trait_def_id, substs); + then { + // If all of our fields implement `Eq`, we can implement `Eq` too + for variant in adt.variants() { + for field in &variant.fields { + let ty = field.ty(cx.tcx, substs); + + if !implements_trait(cx, ty, eq_trait_def_id, substs) { + return; + } + } + } + + span_lint_and_sugg( + cx, + DERIVE_PARTIAL_EQ_WITHOUT_EQ, + span.ctxt().outer_expn_data().call_site, + "you are deriving `PartialEq` and can implement `Eq`", + "consider deriving `Eq` as well", + "PartialEq, Eq".to_string(), + Applicability::MachineApplicable, + ) + } + } +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index e68718f9fdf..0f43b320f76 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -46,6 +46,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(derivable_impls::DERIVABLE_IMPLS), LintId::of(derive::DERIVE_HASH_XOR_EQ), LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 5768edc5018..4e302b10a0f 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -113,6 +113,7 @@ store.register_lints(&[ derivable_impls::DERIVABLE_IMPLS, derive::DERIVE_HASH_XOR_EQ, derive::DERIVE_ORD_XOR_PARTIAL_ORD, + derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, derive::UNSAFE_DERIVE_DESERIALIZE, disallowed_methods::DISALLOWED_METHODS, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index d183c0449cd..62f26d821a0 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -16,6 +16,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(comparison_chain::COMPARISON_CHAIN), LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(dereference::NEEDLESS_BORROW), + LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 772d251b620..4801a84eb92 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -13,7 +13,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_typeck::hir_ty_to_ty; use std::iter::Iterator; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] enum IncrementVisitorVarState { Initial, // Not examined yet IncrOnce, // Incremented exactly once, may be a loop counter diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e452614ce17..cfeee4d0c70 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2835,7 +2835,7 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ]; -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] enum SelfKind { Value, Ref, diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index fc375763542..90651a6ba04 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -271,7 +271,7 @@ enum IterUsageKind { NextTuple, } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] enum UnwrapKind { Unwrap, QuestionMark, diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index b92d42e8323..3fb5415ce02 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::{Lit, LitFloatType, LitIntType, LitKind}; use std::iter; -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Radix { Binary, Octal, diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs index d205b383d1f..f682b280c1b 100644 --- a/tests/ui/absurd-extreme-comparisons.rs +++ b/tests/ui/absurd-extreme-comparisons.rs @@ -37,7 +37,7 @@ fn main() { use std::cmp::{Ordering, PartialEq, PartialOrd}; -#[derive(PartialEq, PartialOrd)] +#[derive(PartialEq, Eq, PartialOrd)] pub struct U(u64); impl PartialEq for U { diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index 4703a8c7777..f6d3a8fa3f0 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -24,7 +24,7 @@ fn main() { use std::ops::{Mul, MulAssign}; -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Wrap(i64); impl Mul for Wrap { diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed index 3305ac9bf8b..abd059c2308 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, clippy::redundant_clone)] // See #5700 +#![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. macro_rules! impl_types { diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/tests/ui/cmp_owned/asymmetric_partial_eq.rs index 88bc2f51dd6..020ef5f840b 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.rs +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, clippy::redundant_clone)] // See #5700 +#![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. macro_rules! impl_types { diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index 05fb96339e3..b28c4378e33 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -45,7 +45,7 @@ impl ToOwned for Foo { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct Bar; impl PartialEq for Bar { @@ -61,7 +61,7 @@ impl std::borrow::Borrow for Bar { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct Baz; impl ToOwned for Baz { diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index 0a02825ed82..c1089010fe1 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -45,7 +45,7 @@ impl ToOwned for Foo { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct Bar; impl PartialEq for Bar { @@ -61,7 +61,7 @@ impl std::borrow::Borrow for Bar { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct Baz; impl ToOwned for Baz { diff --git a/tests/ui/cmp_owned/without_suggestion.rs b/tests/ui/cmp_owned/without_suggestion.rs index f44a3901fb4..738d082339a 100644 --- a/tests/ui/cmp_owned/without_suggestion.rs +++ b/tests/ui/cmp_owned/without_suggestion.rs @@ -26,7 +26,7 @@ impl ToOwned for Foo { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct Baz; impl ToOwned for Baz { @@ -36,7 +36,7 @@ impl ToOwned for Baz { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] struct Bar; impl PartialEq for Bar { diff --git a/tests/ui/crashes/ice-6254.rs b/tests/ui/crashes/ice-6254.rs index c19eca43884..a2a60a16915 100644 --- a/tests/ui/crashes/ice-6254.rs +++ b/tests/ui/crashes/ice-6254.rs @@ -2,6 +2,7 @@ // panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', // compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5 +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(PartialEq)] struct Foo(i32); const FOO_REF_REF: &&Foo = &&Foo(42); diff --git a/tests/ui/crashes/ice-6254.stderr b/tests/ui/crashes/ice-6254.stderr index 95ebf23d818..f37ab2e9b0c 100644 --- a/tests/ui/crashes/ice-6254.stderr +++ b/tests/ui/crashes/ice-6254.stderr @@ -1,5 +1,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/ice-6254.rs:12:9 + --> $DIR/ice-6254.rs:13:9 | LL | FOO_REF_REF => {}, | ^^^^^^^^^^^ diff --git a/tests/ui/derive_hash_xor_eq.rs b/tests/ui/derive_hash_xor_eq.rs index 10abe22d53e..813ddc56646 100644 --- a/tests/ui/derive_hash_xor_eq.rs +++ b/tests/ui/derive_hash_xor_eq.rs @@ -1,3 +1,5 @@ +#![allow(clippy::derive_partial_eq_without_eq)] + #[derive(PartialEq, Hash)] struct Foo; diff --git a/tests/ui/derive_hash_xor_eq.stderr b/tests/ui/derive_hash_xor_eq.stderr index b383072ca4d..e5184bd1407 100644 --- a/tests/ui/derive_hash_xor_eq.stderr +++ b/tests/ui/derive_hash_xor_eq.stderr @@ -1,12 +1,12 @@ error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive_hash_xor_eq.rs:10:10 + --> $DIR/derive_hash_xor_eq.rs:12:10 | LL | #[derive(Hash)] | ^^^^ | = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:13:1 + --> $DIR/derive_hash_xor_eq.rs:15:1 | LL | / impl PartialEq for Bar { LL | | fn eq(&self, _: &Bar) -> bool { @@ -17,13 +17,13 @@ LL | | } = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive_hash_xor_eq.rs:19:10 + --> $DIR/derive_hash_xor_eq.rs:21:10 | LL | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:22:1 + --> $DIR/derive_hash_xor_eq.rs:24:1 | LL | / impl PartialEq for Baz { LL | | fn eq(&self, _: &Baz) -> bool { @@ -34,7 +34,7 @@ LL | | } = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive_hash_xor_eq.rs:31:1 + --> $DIR/derive_hash_xor_eq.rs:33:1 | LL | / impl std::hash::Hash for Bah { LL | | fn hash(&self, _: &mut H) {} @@ -42,14 +42,14 @@ LL | | } | |_^ | note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:28:10 + --> $DIR/derive_hash_xor_eq.rs:30:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive_hash_xor_eq.rs:49:5 + --> $DIR/derive_hash_xor_eq.rs:51:5 | LL | / impl Hash for Foo3 { LL | | fn hash(&self, _: &mut H) {} @@ -57,7 +57,7 @@ LL | | } | |_____^ | note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:46:14 + --> $DIR/derive_hash_xor_eq.rs:48:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed new file mode 100644 index 00000000000..7d4d1b3b649 --- /dev/null +++ b/tests/ui/derive_partial_eq_without_eq.fixed @@ -0,0 +1,98 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::derive_partial_eq_without_eq)] + +// Don't warn on structs that aren't PartialEq +struct NotPartialEq { + foo: u32, + bar: String, +} + +// Eq can be derived but is missing +#[derive(Debug, PartialEq, Eq)] +struct MissingEq { + foo: u32, + bar: String, +} + +// Eq is derived +#[derive(PartialEq, Eq)] +struct NotMissingEq { + foo: u32, + bar: String, +} + +// Eq is manually implemented +#[derive(PartialEq)] +struct ManualEqImpl { + foo: u32, + bar: String, +} + +impl Eq for ManualEqImpl {} + +// Cannot be Eq because f32 isn't Eq +#[derive(PartialEq)] +struct CannotBeEq { + foo: u32, + bar: f32, +} + +// Don't warn if PartialEq is manually implemented +struct ManualPartialEqImpl { + foo: u32, + bar: String, +} + +impl PartialEq for ManualPartialEqImpl { + fn eq(&self, other: &Self) -> bool { + self.foo == other.foo && self.bar == other.bar + } +} + +// Generic fields should be properly checked for Eq-ness +#[derive(PartialEq)] +struct GenericNotEq { + foo: T, + bar: U, +} + +#[derive(PartialEq, Eq)] +struct GenericEq { + foo: T, + bar: U, +} + +#[derive(PartialEq, Eq)] +struct TupleStruct(u32); + +#[derive(PartialEq, Eq)] +struct GenericTupleStruct(T); + +#[derive(PartialEq)] +struct TupleStructNotEq(f32); + +#[derive(PartialEq, Eq)] +enum Enum { + Foo(u32), + Bar { a: String, b: () }, +} + +#[derive(PartialEq, Eq)] +enum GenericEnum { + Foo(T), + Bar { a: U, b: V }, +} + +#[derive(PartialEq)] +enum EnumNotEq { + Foo(u32), + Bar { a: String, b: f32 }, +} + +// Ensure that rustfix works properly when `PartialEq` has other derives on either side +#[derive(Debug, PartialEq, Eq, Clone)] +struct RustFixWithOtherDerives; + +fn main() {} diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs new file mode 100644 index 00000000000..ab4e1df1ca4 --- /dev/null +++ b/tests/ui/derive_partial_eq_without_eq.rs @@ -0,0 +1,98 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::derive_partial_eq_without_eq)] + +// Don't warn on structs that aren't PartialEq +struct NotPartialEq { + foo: u32, + bar: String, +} + +// Eq can be derived but is missing +#[derive(Debug, PartialEq)] +struct MissingEq { + foo: u32, + bar: String, +} + +// Eq is derived +#[derive(PartialEq, Eq)] +struct NotMissingEq { + foo: u32, + bar: String, +} + +// Eq is manually implemented +#[derive(PartialEq)] +struct ManualEqImpl { + foo: u32, + bar: String, +} + +impl Eq for ManualEqImpl {} + +// Cannot be Eq because f32 isn't Eq +#[derive(PartialEq)] +struct CannotBeEq { + foo: u32, + bar: f32, +} + +// Don't warn if PartialEq is manually implemented +struct ManualPartialEqImpl { + foo: u32, + bar: String, +} + +impl PartialEq for ManualPartialEqImpl { + fn eq(&self, other: &Self) -> bool { + self.foo == other.foo && self.bar == other.bar + } +} + +// Generic fields should be properly checked for Eq-ness +#[derive(PartialEq)] +struct GenericNotEq { + foo: T, + bar: U, +} + +#[derive(PartialEq)] +struct GenericEq { + foo: T, + bar: U, +} + +#[derive(PartialEq)] +struct TupleStruct(u32); + +#[derive(PartialEq)] +struct GenericTupleStruct(T); + +#[derive(PartialEq)] +struct TupleStructNotEq(f32); + +#[derive(PartialEq)] +enum Enum { + Foo(u32), + Bar { a: String, b: () }, +} + +#[derive(PartialEq)] +enum GenericEnum { + Foo(T), + Bar { a: U, b: V }, +} + +#[derive(PartialEq)] +enum EnumNotEq { + Foo(u32), + Bar { a: String, b: f32 }, +} + +// Ensure that rustfix works properly when `PartialEq` has other derives on either side +#[derive(Debug, PartialEq, Clone)] +struct RustFixWithOtherDerives; + +fn main() {} diff --git a/tests/ui/derive_partial_eq_without_eq.stderr b/tests/ui/derive_partial_eq_without_eq.stderr new file mode 100644 index 00000000000..bf55165890a --- /dev/null +++ b/tests/ui/derive_partial_eq_without_eq.stderr @@ -0,0 +1,46 @@ +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:13:17 + | +LL | #[derive(Debug, PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + | + = note: `-D clippy::derive-partial-eq-without-eq` implied by `-D warnings` + +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:61:10 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:67:10 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:70:10 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:76:10 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:82:10 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: you are deriving `PartialEq` and can implement `Eq` + --> $DIR/derive_partial_eq_without_eq.rs:95:17 + | +LL | #[derive(Debug, PartialEq, Clone)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 88918d9671e..47bf25e409b 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, dead_code)] +#![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] use std::cmp::Ordering; diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 9a7ab75ef45..d498bca2455 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, dead_code)] +#![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] use std::cmp::Ordering; diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index 8d3a4eed82e..3d271104361 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -1,5 +1,9 @@ #![warn(clippy::unit_cmp)] -#![allow(clippy::no_effect, clippy::unnecessary_operation)] +#![allow( + clippy::no_effect, + clippy::unnecessary_operation, + clippy::derive_partial_eq_without_eq +)] #[derive(PartialEq)] pub struct ContainsUnit(()); // should be fine diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 824506a4257..41cf19ae685 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -1,5 +1,5 @@ error: ==-comparison of unit values detected. This will always be true - --> $DIR/unit_cmp.rs:12:8 + --> $DIR/unit_cmp.rs:16:8 | LL | if { | ________^ @@ -12,7 +12,7 @@ LL | | } {} = note: `-D clippy::unit-cmp` implied by `-D warnings` error: >-comparison of unit values detected. This will always be false - --> $DIR/unit_cmp.rs:18:8 + --> $DIR/unit_cmp.rs:22:8 | LL | if { | ________^ @@ -23,7 +23,7 @@ LL | | } {} | |_____^ error: `assert_eq` of unit values detected. This will always succeed - --> $DIR/unit_cmp.rs:24:5 + --> $DIR/unit_cmp.rs:28:5 | LL | / assert_eq!( LL | | { @@ -35,7 +35,7 @@ LL | | ); | |_____^ error: `debug_assert_eq` of unit values detected. This will always succeed - --> $DIR/unit_cmp.rs:32:5 + --> $DIR/unit_cmp.rs:36:5 | LL | / debug_assert_eq!( LL | | { @@ -47,7 +47,7 @@ LL | | ); | |_____^ error: `assert_ne` of unit values detected. This will always fail - --> $DIR/unit_cmp.rs:41:5 + --> $DIR/unit_cmp.rs:45:5 | LL | / assert_ne!( LL | | { @@ -59,7 +59,7 @@ LL | | ); | |_____^ error: `debug_assert_ne` of unit values detected. This will always fail - --> $DIR/unit_cmp.rs:49:5 + --> $DIR/unit_cmp.rs:53:5 | LL | / debug_assert_ne!( LL | | { -- cgit 1.4.1-3-g733a5 From ae0216d55700274166a853cee1daba59196d4bff Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Wed, 11 May 2022 01:03:52 +0900 Subject: Use the traits added to the Rust 2021 Edition prelude Follow up https://github.com/rust-lang/rust/pull/96861. This PR uses the traits added to the Rust 2021 Edition prelude. > The `TryInto`, `TryFrom` and `FromIterator` traits are now part of the prelude. https://doc.rust-lang.org/edition-guide/rust-2021/prelude.html --- clippy_lints/src/checked_conversions.rs | 1 - clippy_lints/src/enum_clike.rs | 1 - clippy_lints/src/excessive_bools.rs | 2 - clippy_lints/src/fallible_impl_from.rs | 1 - clippy_lints/src/index_refutable_slice.rs | 1 - clippy_lints/src/methods/mod.rs | 2 - clippy_lints/src/redundant_clone.rs | 1 - clippy_lints/src/regex.rs | 1 - clippy_lints/src/tabs_in_doc_comments.rs | 1 - clippy_utils/src/consts.rs | 1 - clippy_utils/src/sugg.rs | 1 - tests/ui-toml/unwrap_used/unwrap_used.rs | 1 - tests/ui-toml/unwrap_used/unwrap_used.stderr | 54 +++++++++++----------- .../proc_macro_suspicious_else_formatting.rs | 1 - tests/ui/checked_conversions.fixed | 2 - tests/ui/checked_conversions.rs | 2 - tests/ui/checked_conversions.stderr | 32 ++++++------- tests/ui/crashes/auxiliary/proc_macro_crash.rs | 1 - tests/ui/from_iter_instead_of_collect.fixed | 1 - tests/ui/from_iter_instead_of_collect.rs | 1 - tests/ui/from_iter_instead_of_collect.stderr | 30 ++++++------ tests/ui/get_unwrap.fixed | 1 - tests/ui/get_unwrap.rs | 1 - tests/ui/get_unwrap.stderr | 52 ++++++++++----------- tests/ui/infinite_iter.rs | 1 - tests/ui/infinite_iter.stderr | 2 +- tests/ui/manual_str_repeat.fixed | 2 +- tests/ui/manual_str_repeat.rs | 2 +- tests/ui/map_err.rs | 1 - tests/ui/map_err.stderr | 2 +- tests/ui/methods.rs | 1 - tests/ui/methods.stderr | 4 +- tests/ui/useless_conversion_try.rs | 2 - tests/ui/useless_conversion_try.stderr | 18 ++++---- 34 files changed, 99 insertions(+), 128 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 28c77ea40ef..7eeaaa01921 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -30,7 +30,6 @@ declare_clippy_lint! { /// Could be written: /// /// ```rust - /// # use std::convert::TryFrom; /// # let foo = 1; /// # let _ = /// i32::try_from(foo).is_ok() diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 43b405c9a8e..10be245b362 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -8,7 +8,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, IntTy, UintTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use std::convert::TryFrom; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 245a4fc12fd..7a81fb37e84 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -4,8 +4,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use std::convert::TryInto; - declare_clippy_lint! { /// ### What it does /// Checks for excessive diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 088d9996516..9f868df3ad0 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -32,7 +32,6 @@ declare_clippy_lint! { /// // Good /// struct Foo(i32); /// - /// use std::convert::TryFrom; /// impl TryFrom for Foo { /// type Error = (); /// fn try_from(s: String) -> Result { diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 07b0604f78d..9ce5b8e17a9 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -14,7 +14,6 @@ use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::Ident, Span}; -use std::convert::TryInto; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cfeee4d0c70..3e07961fcb3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1776,8 +1776,6 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// use std::iter::FromIterator; - /// /// let five_fives = std::iter::repeat(5).take(5); /// /// let v = Vec::from_iter(five_fives); diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 954e702a1f8..9904617353f 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -19,7 +19,6 @@ use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, Ge use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::sym; -use std::convert::TryFrom; use std::ops::ControlFlow; macro_rules! unwrap_or_continue { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 78ca7622f4a..67129299e2f 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -7,7 +7,6 @@ use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; -use std::convert::TryFrom; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index 15543b6a262..e223aea297f 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -4,7 +4,6 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; -use std::convert::TryFrom; declare_clippy_lint! { /// ### What it does diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 720dfe72237..75fab624fda 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -13,7 +13,6 @@ use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; use std::cmp::Ordering::{self, Equal}; -use std::convert::TryInto; use std::hash::{Hash, Hasher}; use std::iter; diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 855d3657dd4..1de73a80ad2 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -17,7 +17,6 @@ use rustc_middle::ty; use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext}; use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use std::borrow::Cow; -use std::convert::TryInto; use std::fmt::{Display, Write as _}; use std::iter; use std::ops::{Add, Neg, Not, Sub}; diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index a639de07971..74d0d7c2650 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -7,7 +7,6 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::VecDeque; -use std::iter::FromIterator; struct GetFalsePositive { arr: [u32; 3], diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 6c3adc5395f..6bcfa0a8b56 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -1,5 +1,5 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:36:17 + --> $DIR/unwrap_used.rs:35:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` @@ -11,7 +11,7 @@ LL | #![deny(clippy::get_unwrap)] | ^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:36:17 + --> $DIR/unwrap_used.rs:35:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,13 +20,13 @@ LL | let _ = boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:37:17 + --> $DIR/unwrap_used.rs:36:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:37:17 + --> $DIR/unwrap_used.rs:36:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,13 +34,13 @@ LL | let _ = some_slice.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:38:17 + --> $DIR/unwrap_used.rs:37:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:38:17 + --> $DIR/unwrap_used.rs:37:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,13 +48,13 @@ LL | let _ = some_vec.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:39:17 + --> $DIR/unwrap_used.rs:38:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:39:17 + --> $DIR/unwrap_used.rs:38:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,13 +62,13 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:40:17 + --> $DIR/unwrap_used.rs:39:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:40:17 + --> $DIR/unwrap_used.rs:39:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,13 +76,13 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:41:17 + --> $DIR/unwrap_used.rs:40:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:41:17 + --> $DIR/unwrap_used.rs:40:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,13 +90,13 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:45:21 + --> $DIR/unwrap_used.rs:44:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:45:22 + --> $DIR/unwrap_used.rs:44:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,13 +104,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:50:9 + --> $DIR/unwrap_used.rs:49:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:50:10 + --> $DIR/unwrap_used.rs:49:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,13 +118,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:51:9 + --> $DIR/unwrap_used.rs:50:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:51:10 + --> $DIR/unwrap_used.rs:50:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,13 +132,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:52:9 + --> $DIR/unwrap_used.rs:51:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:52:10 + --> $DIR/unwrap_used.rs:51:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,13 +146,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:53:9 + --> $DIR/unwrap_used.rs:52:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:53:10 + --> $DIR/unwrap_used.rs:52:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,13 +160,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:65:17 + --> $DIR/unwrap_used.rs:64:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:65:17 + --> $DIR/unwrap_used.rs:64:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,13 +174,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:66:17 + --> $DIR/unwrap_used.rs:65:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_used.rs:66:17 + --> $DIR/unwrap_used.rs:65:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:73:13 + --> $DIR/unwrap_used.rs:72:13 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` diff --git a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index 26c88489b03..a2ef0fe827c 100644 --- a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -5,7 +5,6 @@ extern crate proc_macro; use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree}; -use std::iter::FromIterator; fn read_ident(iter: &mut token_stream::IntoIter) -> Ident { match iter.next() { diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index 12290db3dcf..0983d393b56 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -7,8 +7,6 @@ )] #![warn(clippy::checked_conversions)] -use std::convert::TryFrom; - // Positive tests // Signed to unsigned diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 895a301e821..7d26ace47fd 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -7,8 +7,6 @@ )] #![warn(clippy::checked_conversions)] -use std::convert::TryFrom; - // Positive tests // Signed to unsigned diff --git a/tests/ui/checked_conversions.stderr b/tests/ui/checked_conversions.stderr index 18518def0ac..2e518040561 100644 --- a/tests/ui/checked_conversions.stderr +++ b/tests/ui/checked_conversions.stderr @@ -1,5 +1,5 @@ error: checked cast can be simplified - --> $DIR/checked_conversions.rs:17:13 + --> $DIR/checked_conversions.rs:15:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` @@ -7,91 +7,91 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; = note: `-D clippy::checked-conversions` implied by `-D warnings` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:18:13 + --> $DIR/checked_conversions.rs:16:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:22:13 + --> $DIR/checked_conversions.rs:20:13 | LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:23:13 + --> $DIR/checked_conversions.rs:21:13 | LL | let _ = value <= i64::from(u16::MAX) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:27:13 + --> $DIR/checked_conversions.rs:25:13 | LL | let _ = value <= (u8::max_value() as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:28:13 + --> $DIR/checked_conversions.rs:26:13 | LL | let _ = value <= (u8::MAX as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:34:13 + --> $DIR/checked_conversions.rs:32:13 | LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:35:13 + --> $DIR/checked_conversions.rs:33:13 | LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:39:13 + --> $DIR/checked_conversions.rs:37:13 | LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:40:13 + --> $DIR/checked_conversions.rs:38:13 | LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:46:13 + --> $DIR/checked_conversions.rs:44:13 | LL | let _ = value <= i32::max_value() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:47:13 + --> $DIR/checked_conversions.rs:45:13 | LL | let _ = value <= i32::MAX as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:51:13 + --> $DIR/checked_conversions.rs:49:13 | LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:52:13 + --> $DIR/checked_conversions.rs:50:13 | LL | let _ = value <= isize::MAX as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:56:13 + --> $DIR/checked_conversions.rs:54:13 | LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:57:13 + --> $DIR/checked_conversions.rs:55:13 | LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs index ed8e7a708a5..5ff2af7cd82 100644 --- a/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -12,7 +12,6 @@ extern crate proc_macro; use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; -use std::iter::FromIterator; #[proc_macro] pub fn macro_test(input_stream: TokenStream) -> TokenStream { diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 12db43b5343..403c3b3e443 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -4,7 +4,6 @@ #![allow(unused_imports)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; -use std::iter::FromIterator; struct Foo(Vec); diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index f5ec190e0cd..fefc7b01a65 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -4,7 +4,6 @@ #![allow(unused_imports)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; -use std::iter::FromIterator; struct Foo(Vec); diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 8f08ac8c3ff..8aa3c3c01f8 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,5 +1,5 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:19:9 + --> $DIR/from_iter_instead_of_collect.rs:18:9 | LL | >::from_iter(iter.into_iter().copied()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::()` @@ -7,85 +7,85 @@ LL | >::from_iter(iter.into_iter().copied()) = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:25:13 + --> $DIR/from_iter_instead_of_collect.rs:24:13 | LL | let _ = Vec::from_iter(iter_expr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:27:13 + --> $DIR/from_iter_instead_of_collect.rs:26:13 | LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:32:19 + --> $DIR/from_iter_instead_of_collect.rs:31:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:33:19 + --> $DIR/from_iter_instead_of_collect.rs:32:19 | LL | assert_eq!(a, Vec::::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:35:17 + --> $DIR/from_iter_instead_of_collect.rs:34:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:38:17 + --> $DIR/from_iter_instead_of_collect.rs:37:17 | LL | let mut b = VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:43:21 + --> $DIR/from_iter_instead_of_collect.rs:42:21 | LL | let mut b = collections::VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:48:14 + --> $DIR/from_iter_instead_of_collect.rs:47:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:49:19 + --> $DIR/from_iter_instead_of_collect.rs:48:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:52:19 + --> $DIR/from_iter_instead_of_collect.rs:51:19 | LL | let mut bts = BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:56:17 + --> $DIR/from_iter_instead_of_collect.rs:55:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:57:17 + --> $DIR/from_iter_instead_of_collect.rs:56:17 | LL | let _ = collections::BTreeSet::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:60:15 + --> $DIR/from_iter_instead_of_collect.rs:59:15 | LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:61:15 + --> $DIR/from_iter_instead_of_collect.rs:60:15 | LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index c3a36dcabd1..8f165d67589 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -7,7 +7,6 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::VecDeque; -use std::iter::FromIterator; struct GetFalsePositive { arr: [u32; 3], diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index d77a202aa39..786749daa74 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -7,7 +7,6 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::VecDeque; -use std::iter::FromIterator; struct GetFalsePositive { arr: [u32; 3], diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index cb5f44fbd59..ea8fec52735 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -1,5 +1,5 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:36:17 + --> $DIR/get_unwrap.rs:35:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` @@ -11,7 +11,7 @@ LL | #![deny(clippy::get_unwrap)] | ^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:36:17 + --> $DIR/get_unwrap.rs:35:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,13 +20,13 @@ LL | let _ = boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:37:17 + --> $DIR/get_unwrap.rs:36:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:37:17 + --> $DIR/get_unwrap.rs:36:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,13 +34,13 @@ LL | let _ = some_slice.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:38:17 + --> $DIR/get_unwrap.rs:37:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:38:17 + --> $DIR/get_unwrap.rs:37:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,13 +48,13 @@ LL | let _ = some_vec.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:39:17 + --> $DIR/get_unwrap.rs:38:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:39:17 + --> $DIR/get_unwrap.rs:38:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,13 +62,13 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:40:17 + --> $DIR/get_unwrap.rs:39:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:40:17 + --> $DIR/get_unwrap.rs:39:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,13 +76,13 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:41:17 + --> $DIR/get_unwrap.rs:40:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:41:17 + --> $DIR/get_unwrap.rs:40:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,13 +90,13 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:45:21 + --> $DIR/get_unwrap.rs:44:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:45:22 + --> $DIR/get_unwrap.rs:44:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,13 +104,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:50:9 + --> $DIR/get_unwrap.rs:49:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:50:10 + --> $DIR/get_unwrap.rs:49:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,13 +118,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:51:9 + --> $DIR/get_unwrap.rs:50:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:51:10 + --> $DIR/get_unwrap.rs:50:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,13 +132,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:52:9 + --> $DIR/get_unwrap.rs:51:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:52:10 + --> $DIR/get_unwrap.rs:51:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,13 +146,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:53:9 + --> $DIR/get_unwrap.rs:52:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:53:10 + --> $DIR/get_unwrap.rs:52:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,13 +160,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:65:17 + --> $DIR/get_unwrap.rs:64:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:65:17 + --> $DIR/get_unwrap.rs:64:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,13 +174,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:66:17 + --> $DIR/get_unwrap.rs:65:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on `an Option` value - --> $DIR/get_unwrap.rs:66:17 + --> $DIR/get_unwrap.rs:65:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index 1fe68897765..a1e5fad0c62 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -51,7 +51,6 @@ fn main() { mod finite_collect { use std::collections::HashSet; - use std::iter::FromIterator; struct C; impl FromIterator for C { diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index 5f5e7ac9f25..ba277e36339 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -98,7 +98,7 @@ LL | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:64:31 + --> $DIR/infinite_iter.rs:63:31 | LL | let _: HashSet = (0..).collect(); // Infinite iter | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_str_repeat.fixed b/tests/ui/manual_str_repeat.fixed index dc140257f32..0704ba2f933 100644 --- a/tests/ui/manual_str_repeat.fixed +++ b/tests/ui/manual_str_repeat.fixed @@ -4,7 +4,7 @@ #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; -use std::iter::{repeat, FromIterator}; +use std::iter::repeat; fn main() { let _: String = "test".repeat(10); diff --git a/tests/ui/manual_str_repeat.rs b/tests/ui/manual_str_repeat.rs index 0d69c989b2e..f522be439aa 100644 --- a/tests/ui/manual_str_repeat.rs +++ b/tests/ui/manual_str_repeat.rs @@ -4,7 +4,7 @@ #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; -use std::iter::{repeat, FromIterator}; +use std::iter::repeat; fn main() { let _: String = std::iter::repeat("test").take(10).collect(); diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index 00e037843f8..bb35ab1a14e 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -1,6 +1,5 @@ #![warn(clippy::map_err_ignore)] #![allow(clippy::unnecessary_wraps)] -use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 37e87e64de2..c035840521e 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,5 +1,5 @@ error: `map_err(|_|...` wildcard pattern discards the original error - --> $DIR/map_err.rs:23:32 + --> $DIR/map_err.rs:22:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 977ce54327b..9805097084d 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -26,7 +26,6 @@ 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}; diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index b63672dd6fd..6be38b24fbd 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:104:5 + --> $DIR/methods.rs:103:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:125:13 + --> $DIR/methods.rs:124:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index 3787ea99144..39f54c27bee 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -1,7 +1,5 @@ #![deny(clippy::useless_conversion)] -use std::convert::{TryFrom, TryInto}; - fn test_generic(val: T) -> T { let _ = T::try_from(val).unwrap(); val.try_into().unwrap() diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index 2e0d9129bfb..b691c13f7db 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion_try.rs:6:13 + --> $DIR/useless_conversion_try.rs:4:13 | LL | let _ = T::try_from(val).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::useless_conversion)] = help: consider removing `T::try_from()` error: useless conversion to the same type: `T` - --> $DIR/useless_conversion_try.rs:7:5 + --> $DIR/useless_conversion_try.rs:5:5 | LL | val.try_into().unwrap() | ^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | val.try_into().unwrap() = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:29:21 + --> $DIR/useless_conversion_try.rs:27:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:30:21 + --> $DIR/useless_conversion_try.rs:28:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); = help: consider removing `TryFrom::try_from()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:31:13 + --> $DIR/useless_conversion_try.rs:29:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:32:13 + --> $DIR/useless_conversion_try.rs:30:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:33:21 + --> $DIR/useless_conversion_try.rs:31:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:34:21 + --> $DIR/useless_conversion_try.rs:32:21 | LL | let _: String = "".to_owned().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _: String = "".to_owned().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:35:27 + --> $DIR/useless_conversion_try.rs:33:27 | LL | let _: String = match String::from("_").try_into() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 4e5f69cc869f734d39f74a5b0d9250eb5fc101ce Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Fri, 13 May 2022 14:20:25 +0900 Subject: Tweak some words improved representation This PR has implemented improved representation. - Use "lib" instead of "lifb" - Use "triggered" instead of "triggere" - Use "blacklisted_name" instead of "blackisted_name" - Use "stabilization" instead of "stabilisation" - Use "behavior" instead of "behaviour" - Use "target" instead of "tartet" - Use "checked_add" instead of "chcked_add" - Use "anti-pattern" instead of "antipattern" - Use "suggestion" instead of "suggesttion" - Use "example" instead of "exampel" - Use "Cheat Sheet" instead of "Cheatsheet" --- clippy_dev/src/main.rs | 2 +- clippy_dev/src/new_lint.rs | 4 ++-- clippy_lints/src/assign_ops.rs | 2 +- clippy_lints/src/casts/cast_slice_different_sizes.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/default_union_representation.rs | 4 ++-- clippy_lints/src/derive.rs | 4 ++-- clippy_lints/src/main_recursion.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/needless_bitwise_bool.rs | 4 ++-- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/transmute/mod.rs | 4 ++-- doc/adding_lints.md | 4 ++-- tests/ui/blacklisted_name.rs | 4 ++-- 16 files changed, 23 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index dcfaabbc204..d5cd7ca96c0 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -124,7 +124,7 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { * the lint count in README.md is correct\n \ * the changelog contains markdown link references at the bottom\n \ * all lint groups include the correct lints\n \ - * lint modules in `clippy_lints/*` are visible in `src/lifb.rs` via `pub mod`\n \ + * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \ * all lints are registered in the lint store", ) .arg(Arg::with_name("print-only").long("print-only").help( diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 10f67d301f8..07d19638788 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -133,7 +133,7 @@ fn to_camel_case(name: &str) -> String { .collect() } -fn get_stabilisation_version() -> String { +fn get_stabilization_version() -> String { fn parse_manifest(contents: &str) -> Option { let version = contents .lines() @@ -199,7 +199,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }, }; - let version = get_stabilisation_version(); + let version = get_stabilization_version(); let lint_name = lint.name; let category = lint.category; let name_camel = to_camel_case(lint.name); diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 12c1bddf79d..4c2d3366483 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { /// ### Known problems /// Clippy cannot know for sure if `a op= a op b` should have /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. - /// If `a op= a op b` is really the correct behaviour it should be + /// If `a op= a op b` is really the correct behavior it should be /// written as `a = a op a op b` as it's less confusing. /// /// ### Example diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index bb09a6708a0..027c660ce3b 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -121,7 +121,7 @@ fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio let to_slice_ty = get_raw_slice_ty_mut(cast_to)?; // If the expression that makes up the source of this cast is itself a cast, recursively - // call `expr_cast_chain_tys` and update the end type with the final tartet type. + // call `expr_cast_chain_tys` and update the end type with the final target type. // Otherwise, this cast is not immediately nested, just construct the info for this cast if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) { Some(CastChainInfo { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 108e119c104..daf3b7b4ce4 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -306,7 +306,7 @@ declare_clippy_lint! { /// Checks for casts of `&T` to `&mut T` anywhere in the code. /// /// ### Why is this bad? - /// It’s basically guaranteed to be undefined behaviour. + /// It’s basically guaranteed to be undefined behavior. /// `UnsafeCell` is the only way to obtain aliasable data that is considered /// mutable. /// diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index 9b5da0bd8a6..d559ad423df 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// /// fn main() { /// let _x: u32 = unsafe { - /// Foo { a: 0_i32 }.b // Undefined behaviour: `b` is allowed to be padding + /// Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding /// }; /// } /// ``` @@ -39,7 +39,7 @@ declare_clippy_lint! { /// /// fn main() { /// let _x: u32 = unsafe { - /// Foo { a: 0_i32 }.b // Now defined behaviour, this is just an i32 -> u32 transmute + /// Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute /// }; /// } /// ``` diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a4757ebd8c7..fbbc5bf78a5 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -102,8 +102,8 @@ declare_clippy_lint! { /// types. /// /// ### Why is this bad? - /// To avoid surprising behaviour, these traits should - /// agree and the behaviour of `Copy` cannot be overridden. In almost all + /// To avoid surprising behavior, these traits should + /// agree and the behavior of `Copy` cannot be overridden. In almost all /// situations a `Copy` type should have a `Clone` implementation that does /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]` /// gets you. diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index fad8fa467d4..20333c150e3 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Apart from special setups (which we could detect following attributes like #![no_std]), - /// recursing into main() seems like an unintuitive antipattern we should be able to detect. + /// recursing into main() seems like an unintuitive anti-pattern we should be able to detect. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3e07961fcb3..35fc452ed7c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1563,7 +1563,7 @@ declare_clippy_lint! { #[clippy::version = "1.39.0"] pub MANUAL_SATURATING_ARITHMETIC, style, - "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`" + "`.checked_add/sub(x).unwrap_or(MAX/MIN)`" } declare_clippy_lint! { diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 4ba68c8eacd..8dba60f3a58 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// ### Why is this bad? /// In release builds `debug_assert!` macros are optimized out by the /// compiler. - /// Therefore mutating something in a `debug_assert!` macro results in different behaviour + /// Therefore mutating something in a `debug_assert!` macro results in different behavior /// between a release and debug build. /// /// ### Example diff --git a/clippy_lints/src/needless_bitwise_bool.rs b/clippy_lints/src/needless_bitwise_bool.rs index 95395e2e136..623d22bc9bd 100644 --- a/clippy_lints/src/needless_bitwise_bool.rs +++ b/clippy_lints/src/needless_bitwise_bool.rs @@ -53,7 +53,7 @@ fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { false } -fn suggesstion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn suggestion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let ExprKind::Binary(ref op, left, right) = expr.kind { if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) { let op_snippet = match op.node { @@ -75,7 +75,7 @@ impl LateLintPass<'_> for NeedlessBitwiseBool { expr.span, "use of bitwise operator instead of lazy operator between booleans", |diag| { - if let Some(sugg) = suggesstion_snippet(cx, expr) { + if let Some(sugg) = suggestion_snippet(cx, expr) { diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable); } }, diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index c5b8b8103a1..e3ded716341 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -52,7 +52,7 @@ declare_clippy_lint! { /// to a function that needs the memory address. For further details, refer to /// [this issue](https://github.com/rust-lang/rust-clippy/issues/5953) /// that explains a real case in which this false positive - /// led to an **undefined behaviour** introduced with unsafe code. + /// led to an **undefined behavior** introduced with unsafe code. /// /// ### Example /// diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 9904617353f..b19f9aff611 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -632,7 +632,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { } /// Collect possible borrowed for every `&mut` local. -/// For exampel, `_1 = &mut _2` generate _1: {_2,...} +/// For example, `_1 = &mut _2` generate _1: {_2,...} /// Known Problems: not sure all borrowed are tracked struct PossibleOriginVisitor<'a, 'tcx> { possible_origin: TransitiveRelation, diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 342f23f030c..d2a040beb0c 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// architecture. /// /// ### Why is this bad? - /// It's basically guaranteed to be undefined behaviour. + /// It's basically guaranteed to be undefined behavior. /// /// ### Known problems /// When accessing C, users might want to store pointer @@ -40,7 +40,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub WRONG_TRANSMUTE, correctness, - "transmutes that are confusing at best, undefined behaviour at worst and always useless" + "transmutes that are confusing at best, undefined behavior at worst and always useless" } // FIXME: Move this to `complexity` again, after #5343 is fixed diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 4dc94d9f5a5..e8f0c338fd5 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -28,7 +28,7 @@ because that's clearly a non-descriptive name. - [Debugging](#debugging) - [PR Checklist](#pr-checklist) - [Adding configuration to a lint](#adding-configuration-to-a-lint) - - [Cheatsheet](#cheatsheet) + - [Cheat Sheet](#cheat-sheet) ## Setup @@ -649,7 +649,7 @@ in the following steps: with the configuration value and a rust file that should be linted by Clippy. The test can otherwise be written as usual. -## Cheatsheet +## Cheat Sheet Here are some pointers to things you are likely going to need for every lint: diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/blacklisted_name.rs index 57d7139fef5..27df732a088 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/blacklisted_name.rs @@ -46,10 +46,10 @@ fn issue_1647_ref_mut() { mod tests { fn issue_7305() { - // `blackisted_name` lint should not be triggered inside of the test code. + // `blacklisted_name` lint should not be triggered inside of the test code. let foo = 0; - // Check that even in nested functions warning is still not triggere. + // Check that even in nested functions warning is still not triggered. fn nested() { let foo = 0; } -- cgit 1.4.1-3-g733a5 From 855849034c15330f146376ae7073c38cbacb00b2 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 20 May 2022 20:33:31 +0000 Subject: get_last_with_len: lint VecDeque and any deref to slice previously only vecs were supported --- clippy_lints/src/get_last_with_len.rs | 107 -------------------------- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/get_last_with_len.rs | 55 +++++++++++++ clippy_lints/src/methods/mod.rs | 35 +++++++++ tests/ui/get_last_with_len.fixed | 28 +++++-- tests/ui/get_last_with_len.rs | 28 +++++-- tests/ui/get_last_with_len.stderr | 36 ++++++++- 10 files changed, 172 insertions(+), 125 deletions(-) delete mode 100644 clippy_lints/src/get_last_with_len.rs create mode 100644 clippy_lints/src/methods/get_last_with_len.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs deleted file mode 100644 index df29d9308e7..00000000000 --- a/clippy_lints/src/get_last_with_len.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! lint on using `x.get(x.len() - 1)` instead of `x.last()` - -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::SpanlessEq; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for using `x.get(x.len() - 1)` instead of - /// `x.last()`. - /// - /// ### Why is this bad? - /// Using `x.last()` is easier to read and has the same - /// result. - /// - /// Note that using `x[x.len() - 1]` is semantically different from - /// `x.last()`. Indexing into the array will panic on out-of-bounds - /// accesses, while `x.get()` and `x.last()` will return `None`. - /// - /// There is another lint (get_unwrap) that covers the case of using - /// `x.get(index).unwrap()` instead of `x[index]`. - /// - /// ### Example - /// ```rust - /// // Bad - /// let x = vec![2, 3, 5]; - /// let last_element = x.get(x.len() - 1); - /// - /// // Good - /// let x = vec![2, 3, 5]; - /// let last_element = x.last(); - /// ``` - #[clippy::version = "1.37.0"] - pub GET_LAST_WITH_LEN, - complexity, - "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler" -} - -declare_lint_pass!(GetLastWithLen => [GET_LAST_WITH_LEN]); - -impl<'tcx> LateLintPass<'tcx> for GetLastWithLen { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - // Is a method call - if let ExprKind::MethodCall(path, args, _) = expr.kind; - - // Method name is "get" - if path.ident.name == sym!(get); - - // Argument 0 (the struct we're calling the method on) is a vector - if let Some(struct_calling_on) = args.get(0); - let struct_ty = cx.typeck_results().expr_ty(struct_calling_on); - if is_type_diagnostic_item(cx, struct_ty, sym::Vec); - - // Argument to "get" is a subtraction - if let Some(get_index_arg) = args.get(1); - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Sub, - .. - }, - lhs, - rhs, - ) = &get_index_arg.kind; - - // LHS of subtraction is "x.len()" - if let ExprKind::MethodCall(arg_lhs_path, lhs_args, _) = &lhs.kind; - if arg_lhs_path.ident.name == sym::len; - if let Some(arg_lhs_struct) = lhs_args.get(0); - - // The two vectors referenced (x in x.get(...) and in x.len()) - if SpanlessEq::new(cx).eq_expr(struct_calling_on, arg_lhs_struct); - - // RHS of subtraction is 1 - if let ExprKind::Lit(rhs_lit) = &rhs.kind; - if let LitKind::Int(1, ..) = rhs_lit.node; - - then { - let mut applicability = Applicability::MachineApplicable; - let vec_name = snippet_with_applicability( - cx, - struct_calling_on.span, "vec", - &mut applicability, - ); - - span_lint_and_sugg( - cx, - GET_LAST_WITH_LEN, - expr.span, - &format!("accessing last element with `{0}.get({0}.len() - 1)`", vec_name), - "try", - format!("{}.last()", vec_name), - applicability, - ); - } - } - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index be5c478900f..87279de05c0 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -91,7 +91,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_last_with_len::GET_LAST_WITH_LEN), LintId::of(identity_op::IDENTITY_OP), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), @@ -166,6 +165,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::IS_DIGIT_ASCII_RADIX), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index b15c979d0c7..d5dfcd10a66 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -15,7 +15,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(explicit_write::EXPLICIT_WRITE), LintId::of(format::USELESS_FORMAT), LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_last_with_len::GET_LAST_WITH_LEN), LintId::of(identity_op::IDENTITY_OP), LintId::of(int_plus_one::INT_PLUS_ONE), LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), @@ -37,6 +36,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::ITER_COUNT), LintId::of(methods::MANUAL_FILTER_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 5552ea8aa80..527ff3485f2 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -183,7 +183,6 @@ store.register_lints(&[ functions::TOO_MANY_ARGUMENTS, functions::TOO_MANY_LINES, future_not_send::FUTURE_NOT_SEND, - get_last_with_len::GET_LAST_WITH_LEN, identity_op::IDENTITY_OP, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, @@ -302,6 +301,7 @@ store.register_lints(&[ methods::FLAT_MAP_IDENTITY, methods::FLAT_MAP_OPTION, methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_LAST_WITH_LEN, methods::GET_UNWRAP, methods::IMPLICIT_CLONE, methods::INEFFICIENT_TO_STRING, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4ac834f7240..2f8533723ef 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -242,7 +242,6 @@ mod from_over_into; mod from_str_radix_10; mod functions; mod future_not_send; -mod get_last_with_len; mod identity_op; mod if_let_mutex; mod if_not_else; @@ -652,7 +651,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::StringLitAsBytes)); store.register_late_pass(|| Box::new(derive::Derive)); store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls)); - store.register_late_pass(|| Box::new(get_last_with_len::GetLastWithLen)); store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons)); diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs new file mode 100644 index 00000000000..23368238ef5 --- /dev/null +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -0,0 +1,55 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::SpanlessEq; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::source_map::Spanned; +use rustc_span::sym; + +use super::GET_LAST_WITH_LEN; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { + // Argument to "get" is a subtraction + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, .. + }, + lhs, + rhs, + ) = arg.kind + + // LHS of subtraction is "x.len()" + && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind + && lhs_path.ident.name == sym::len + + // RHS of subtraction is 1 + && let ExprKind::Lit(rhs_lit) = &rhs.kind + && let LitKind::Int(1, ..) = rhs_lit.node + + // check that recv == lhs_recv `recv.get(lhs_recv.len() - 1)` + && SpanlessEq::new(cx).eq_expr(recv, lhs_recv) + && !recv.can_have_side_effects() + { + let method = match cx.typeck_results().expr_ty_adjusted(recv).peel_refs().kind() { + ty::Adt(def, _) if cx.tcx.is_diagnostic_item(sym::VecDeque, def.did()) => "back", + ty::Slice(_) => "last", + _ => return, + }; + + let mut applicability = Applicability::MachineApplicable; + let recv_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability); + + span_lint_and_sugg( + cx, + GET_LAST_WITH_LEN, + expr.span, + &format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"), + "try", + format!("{recv_snippet}.{method}()"), + applicability, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 35fc452ed7c..8e89f43e207 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -21,6 +21,7 @@ mod filter_next; mod flat_map_identity; mod flat_map_option; mod from_iter_instead_of_collect; +mod get_last_with_len; mod get_unwrap; mod implicit_clone; mod inefficient_to_string; @@ -1209,6 +1210,38 @@ declare_clippy_lint! { "replace `.drain(..)` with `.into_iter()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for using `x.get(x.len() - 1)` instead of + /// `x.last()`. + /// + /// ### Why is this bad? + /// Using `x.last()` is easier to read and has the same + /// result. + /// + /// Note that using `x[x.len() - 1]` is semantically different from + /// `x.last()`. Indexing into the array will panic on out-of-bounds + /// accesses, while `x.get()` and `x.last()` will return `None`. + /// + /// There is another lint (get_unwrap) that covers the case of using + /// `x.get(index).unwrap()` instead of `x[index]`. + /// + /// ### Example + /// ```rust + /// // Bad + /// let x = vec![2, 3, 5]; + /// let last_element = x.get(x.len() - 1); + /// + /// // Good + /// let x = vec![2, 3, 5]; + /// let last_element = x.last(); + /// ``` + #[clippy::version = "1.37.0"] + pub GET_LAST_WITH_LEN, + complexity, + "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler" +} + declare_clippy_lint! { /// ### What it does /// Checks for use of `.get().unwrap()` (or @@ -2264,6 +2297,7 @@ impl_lint_pass!(Methods => [ BYTES_NTH, ITER_SKIP_NEXT, GET_UNWRAP, + GET_LAST_WITH_LEN, STRING_EXTEND_CHARS, ITER_CLONED_COLLECT, ITER_WITH_DRAIN, @@ -2590,6 +2624,7 @@ impl Methods { inspect_for_each::check(cx, expr, span2); } }, + ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg), ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), diff --git a/tests/ui/get_last_with_len.fixed b/tests/ui/get_last_with_len.fixed index c8b363f9c38..1e90b37687a 100644 --- a/tests/ui/get_last_with_len.fixed +++ b/tests/ui/get_last_with_len.fixed @@ -1,10 +1,13 @@ // run-rustfix #![warn(clippy::get_last_with_len)] +#![allow(unused)] + +use std::collections::VecDeque; fn dont_use_last() { let x = vec![2, 3, 5]; - let _ = x.last(); // ~ERROR Use x.last() + let _ = x.last(); } fn indexing_two_from_end() { @@ -23,9 +26,24 @@ fn use_last_with_different_vec_length() { let _ = x.get(y.len() - 1); } +struct S { + field: Vec, +} + +fn in_field(s: &S) { + let _ = s.field.last(); +} + fn main() { - dont_use_last(); - indexing_two_from_end(); - index_into_last(); - use_last_with_different_vec_length(); + let slice = &[1, 2, 3]; + let _ = slice.last(); + + let array = [4, 5, 6]; + let _ = array.last(); + + let deq = VecDeque::from([7, 8, 9]); + let _ = deq.back(); + + let nested = [[1]]; + let _ = nested[0].last(); } diff --git a/tests/ui/get_last_with_len.rs b/tests/ui/get_last_with_len.rs index bf9cb2d7e0c..d63a731bd52 100644 --- a/tests/ui/get_last_with_len.rs +++ b/tests/ui/get_last_with_len.rs @@ -1,10 +1,13 @@ // run-rustfix #![warn(clippy::get_last_with_len)] +#![allow(unused)] + +use std::collections::VecDeque; fn dont_use_last() { let x = vec![2, 3, 5]; - let _ = x.get(x.len() - 1); // ~ERROR Use x.last() + let _ = x.get(x.len() - 1); } fn indexing_two_from_end() { @@ -23,9 +26,24 @@ fn use_last_with_different_vec_length() { let _ = x.get(y.len() - 1); } +struct S { + field: Vec, +} + +fn in_field(s: &S) { + let _ = s.field.get(s.field.len() - 1); +} + fn main() { - dont_use_last(); - indexing_two_from_end(); - index_into_last(); - use_last_with_different_vec_length(); + let slice = &[1, 2, 3]; + let _ = slice.get(slice.len() - 1); + + let array = [4, 5, 6]; + let _ = array.get(array.len() - 1); + + let deq = VecDeque::from([7, 8, 9]); + let _ = deq.get(deq.len() - 1); + + let nested = [[1]]; + let _ = nested[0].get(nested[0].len() - 1); } diff --git a/tests/ui/get_last_with_len.stderr b/tests/ui/get_last_with_len.stderr index 55baf87384a..ac8dd6c2e41 100644 --- a/tests/ui/get_last_with_len.stderr +++ b/tests/ui/get_last_with_len.stderr @@ -1,10 +1,40 @@ error: accessing last element with `x.get(x.len() - 1)` - --> $DIR/get_last_with_len.rs:7:13 + --> $DIR/get_last_with_len.rs:10:13 | -LL | let _ = x.get(x.len() - 1); // ~ERROR Use x.last() +LL | let _ = x.get(x.len() - 1); | ^^^^^^^^^^^^^^^^^^ help: try: `x.last()` | = note: `-D clippy::get-last-with-len` implied by `-D warnings` -error: aborting due to previous error +error: accessing last element with `s.field.get(s.field.len() - 1)` + --> $DIR/get_last_with_len.rs:34:13 + | +LL | let _ = s.field.get(s.field.len() - 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.field.last()` + +error: accessing last element with `slice.get(slice.len() - 1)` + --> $DIR/get_last_with_len.rs:39:13 + | +LL | let _ = slice.get(slice.len() - 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `slice.last()` + +error: accessing last element with `array.get(array.len() - 1)` + --> $DIR/get_last_with_len.rs:42:13 + | +LL | let _ = array.get(array.len() - 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array.last()` + +error: accessing last element with `deq.get(deq.len() - 1)` + --> $DIR/get_last_with_len.rs:45:13 + | +LL | let _ = deq.get(deq.len() - 1); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `deq.back()` + +error: accessing last element with `nested[0].get(nested[0].len() - 1)` + --> $DIR/get_last_with_len.rs:48:13 + | +LL | let _ = nested[0].get(nested[0].len() - 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `nested[0].last()` + +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From ea62347a5a4b952b416dddc8053a495c9238e7d7 Mon Sep 17 00:00:00 2001 From: Federico Guerinoni Date: Mon, 25 Apr 2022 16:12:48 +0200 Subject: New lint `no_effect_replace` Closes #1595 changelog: Add no_effect_replace lint. --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 + clippy_lints/src/methods/mod.rs | 23 ++++++++++++ clippy_lints/src/methods/no_effect_replace.rs | 47 ++++++++++++++++++++++++ tests/ui/no_effect_replace.rs | 51 ++++++++++++++++++++++++++ tests/ui/no_effect_replace.stderr | 52 +++++++++++++++++++++++++++ 8 files changed, 177 insertions(+) create mode 100644 clippy_lints/src/methods/no_effect_replace.rs create mode 100644 tests/ui/no_effect_replace.rs create mode 100644 tests/ui/no_effect_replace.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 47aaae9c198..4b62ccbf8bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3594,6 +3594,7 @@ Released 2018-09-13 [`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect +[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index fca5e109509..2d0dca87b10 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -190,6 +190,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 7489f53fd3c..5d6360838ec 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -331,6 +331,7 @@ store.register_lints(&[ methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, + methods::NO_EFFECT_REPLACE, methods::OK_EXPECT, methods::OPTION_AS_REF_DEREF, methods::OPTION_FILTER_MAP, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 940bf7ace5e..7e1ba5336c6 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -23,6 +23,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(octal_escapes::OCTAL_ESCAPES), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cfeee4d0c70..5102fa17a67 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -44,6 +44,7 @@ mod map_identity; mod map_unwrap_or; mod needless_option_as_deref; mod needless_option_take; +mod no_effect_replace; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -2197,6 +2198,24 @@ declare_clippy_lint! { "using `.as_ref().take()` on a temporary value" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `replace` statements which have no effect. + /// + /// ### Why is this bad? + /// It's either a mistake or confusing. + /// + /// ### Example + /// ```rust + /// "1234".replace("12", "12"); + /// "1234".replacen("12", "12", 1); + /// ``` + #[clippy::version = "1.62.0"] + pub NO_EFFECT_REPLACE, + suspicious, + "replace with no effect" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2296,6 +2315,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_AS_DEREF, IS_DIGIT_ASCII_RADIX, NEEDLESS_OPTION_TAKE, + NO_EFFECT_REPLACE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2707,6 +2727,9 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); }, }, + ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { + no_effect_replace::check(cx, expr, arg1, arg2); + }, _ => {}, } } diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs new file mode 100644 index 00000000000..a76341855b6 --- /dev/null +++ b/clippy_lints/src/methods/no_effect_replace.rs @@ -0,0 +1,47 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::SpanlessEq; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_hir::ExprKind; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::NO_EFFECT_REPLACE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx rustc_hir::Expr<'_>, + arg1: &'tcx rustc_hir::Expr<'_>, + arg2: &'tcx rustc_hir::Expr<'_>, +) { + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + if !(ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)) { + return; + } + + if_chain! { + if let ExprKind::Lit(spanned) = &arg1.kind; + if let Some(param1) = lit_string_value(&spanned.node); + + if let ExprKind::Lit(spanned) = &arg2.kind; + if let LitKind::Str(param2, _) = &spanned.node; + if param1 == param2.as_str(); + + then { + span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself"); + } + } + + if SpanlessEq::new(cx).eq_expr(arg1, arg2) { + span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself"); + } +} + +fn lit_string_value(node: &LitKind) -> Option { + match node { + LitKind::Char(value) => Some(value.to_string()), + LitKind::Str(value, _) => Some(value.as_str().to_owned()), + _ => None, + } +} diff --git a/tests/ui/no_effect_replace.rs b/tests/ui/no_effect_replace.rs new file mode 100644 index 00000000000..ad17d53f789 --- /dev/null +++ b/tests/ui/no_effect_replace.rs @@ -0,0 +1,51 @@ +#![warn(clippy::no_effect_replace)] + +fn main() { + let _ = "12345".replace('1', "1"); + let _ = "12345".replace("12", "12"); + let _ = String::new().replace("12", "12"); + + let _ = "12345".replacen('1', "1", 1); + let _ = "12345".replacen("12", "12", 1); + let _ = String::new().replacen("12", "12", 1); + + let _ = "12345".replace("12", "22"); + let _ = "12345".replacen("12", "22", 1); + + let mut x = X::default(); + let _ = "hello".replace(&x.f(), &x.f()); + let _ = "hello".replace(&x.f(), &x.ff()); + + let _ = "hello".replace(&y(), &y()); + let _ = "hello".replace(&y(), &z()); + + let _ = Replaceme.replace("a", "a"); +} + +#[derive(Default)] +struct X {} + +impl X { + fn f(&mut self) -> String { + "he".to_string() + } + + fn ff(&mut self) -> String { + "hh".to_string() + } +} + +fn y() -> String { + "he".to_string() +} + +fn z() -> String { + "hh".to_string() +} + +struct Replaceme; +impl Replaceme { + pub fn replace(&mut self, a: &str, b: &str) -> Self { + Self + } +} diff --git a/tests/ui/no_effect_replace.stderr b/tests/ui/no_effect_replace.stderr new file mode 100644 index 00000000000..53a28aa73b7 --- /dev/null +++ b/tests/ui/no_effect_replace.stderr @@ -0,0 +1,52 @@ +error: replacing text with itself + --> $DIR/no_effect_replace.rs:4:13 + | +LL | let _ = "12345".replace('1', "1"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::no-effect-replace` implied by `-D warnings` + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:5:13 + | +LL | let _ = "12345".replace("12", "12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:6:13 + | +LL | let _ = String::new().replace("12", "12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:8:13 + | +LL | let _ = "12345".replacen('1', "1", 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:9:13 + | +LL | let _ = "12345".replacen("12", "12", 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:10:13 + | +LL | let _ = String::new().replacen("12", "12", 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:16:13 + | +LL | let _ = "hello".replace(&x.f(), &x.f()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: replacing text with itself + --> $DIR/no_effect_replace.rs:19:13 + | +LL | let _ = "hello".replace(&y(), &y()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From b531eb1a7aca3357d2d5fce97f3f07d2a6956bfe Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Tue, 24 May 2022 18:55:39 +0900 Subject: suggest first() instead of get(0) --- clippy_lints/src/methods/iter_next_slice.rs | 9 +++++++-- tests/ui/iter_next_slice.fixed | 8 ++++---- tests/ui/iter_next_slice.rs | 4 ++-- tests/ui/iter_next_slice.stderr | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index d053ff56756..b8d1dabe007 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -34,13 +34,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal if let ast::LitKind::Int(start_idx, _) = start_lit.node; then { let mut applicability = Applicability::MachineApplicable; + let suggest = if start_idx == 0 { + format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) + } else { + format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx) + }; span_lint_and_sugg( cx, ITER_NEXT_SLICE, expr.span, "using `.iter().next()` on a Slice without end index", "try calling", - format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), + suggest, applicability, ); } @@ -55,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal "using `.iter().next()` on an array", "try calling", format!( - "{}.get(0)", + "{}.first()", snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability) ), applicability, diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed index 11ffc8edb14..f612d26aaab 100644 --- a/tests/ui/iter_next_slice.fixed +++ b/tests/ui/iter_next_slice.fixed @@ -6,8 +6,8 @@ fn main() { let s = [1, 2, 3]; let v = vec![1, 2, 3]; - let _ = s.get(0); - // Should be replaced by s.get(0) + let _ = s.first(); + // Should be replaced by s.first() let _ = s.get(2); // Should be replaced by s.get(2) @@ -15,8 +15,8 @@ fn main() { let _ = v.get(5); // Should be replaced by v.get(5) - let _ = v.get(0); - // Should be replaced by v.get(0) + let _ = v.first(); + // Should be replaced by v.first() let o = Some(5); o.iter().next(); diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs index e0d3aabd54a..5195f1c8667 100644 --- a/tests/ui/iter_next_slice.rs +++ b/tests/ui/iter_next_slice.rs @@ -7,7 +7,7 @@ fn main() { let v = vec![1, 2, 3]; let _ = s.iter().next(); - // Should be replaced by s.get(0) + // Should be replaced by s.first() let _ = s[2..].iter().next(); // Should be replaced by s.get(2) @@ -16,7 +16,7 @@ fn main() { // Should be replaced by v.get(5) let _ = v.iter().next(); - // Should be replaced by v.get(0) + // Should be replaced by v.first() let o = Some(5); o.iter().next(); diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr index a78d2c2d5e8..d8b89061ff8 100644 --- a/tests/ui/iter_next_slice.stderr +++ b/tests/ui/iter_next_slice.stderr @@ -2,7 +2,7 @@ error: using `.iter().next()` on an array --> $DIR/iter_next_slice.rs:9:13 | LL | let _ = s.iter().next(); - | ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)` + | ^^^^^^^^^^^^^^^ help: try calling: `s.first()` | = note: `-D clippy::iter-next-slice` implied by `-D warnings` @@ -22,7 +22,7 @@ error: using `.iter().next()` on an array --> $DIR/iter_next_slice.rs:18:13 | LL | let _ = v.iter().next(); - | ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)` + | ^^^^^^^^^^^^^^^ help: try calling: `v.first()` error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From cfd0f5592b681957a6bcdc33d90cc82a9a76ceff Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sat, 28 May 2022 09:22:59 -0400 Subject: Make docs more consistent --- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/assign_ops.rs | 10 +++++++-- clippy_lints/src/attrs.rs | 32 ++++++++++++++------------- clippy_lints/src/blocks_in_if_conditions.rs | 2 +- clippy_lints/src/booleans.rs | 19 ++++++++++++---- clippy_lints/src/bytecount.rs | 8 ++++++- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/double_comparison.rs | 2 +- clippy_lints/src/duration_subsec.rs | 18 ++++++++------- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_enum.rs | 3 +-- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/equatable_if_let.rs | 2 +- clippy_lints/src/escape.rs | 6 +++-- clippy_lints/src/excessive_bools.rs | 3 +-- clippy_lints/src/explicit_write.rs | 10 ++++++++- clippy_lints/src/fallible_impl_from.rs | 3 +-- clippy_lints/src/float_literal.rs | 5 +++-- clippy_lints/src/floating_point_arithmetic.rs | 3 +-- clippy_lints/src/format.rs | 7 +++--- clippy_lints/src/formatting.rs | 16 +++++++++----- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 ++--- 29 files changed, 109 insertions(+), 68 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index da1b646f477..159f3b0cd01 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// let x = 3.14; /// let y = 1_f64 / x; /// ``` - /// Use predefined constants instead: + /// Use instead: /// ```rust /// let x = std::f32::consts::PI; /// let y = std::f64::consts::FRAC_1_PI; diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 88b91d58907..5fa8934c71b 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// f(a as u16); /// ``` /// - /// Usually better represents the semantics you expect: + /// Use instead: /// ```rust,ignore /// f(a.try_into()?); /// ``` diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 4c2d3366483..f81da2d4223 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -27,10 +27,16 @@ declare_clippy_lint! { /// let mut a = 5; /// let b = 0; /// // ... - /// // Bad + /// /// a = a + b; + /// ``` + /// + /// Use instead: + /// ```rust + /// let mut a = 5; + /// let b = 0; + /// // ... /// - /// // Good /// a += b; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 7105ce4b292..79a5b670fc8 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -89,13 +89,14 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// // Bad /// #[deny(dead_code)] /// extern crate foo; /// #[forbid(dead_code)] /// use foo::bar; + /// ``` /// - /// // Ok + /// Use instead: + /// ```rust,ignore /// #[allow(unused_imports)] /// use foo::baz; /// #[allow(unused_imports)] @@ -146,15 +147,19 @@ declare_clippy_lint! { /// /// ### Example /// ```rust + /// #[allow(dead_code)] + /// + /// fn not_quite_good_code() { } + /// ``` + /// + /// Use instead: + /// ```rust /// // Good (as inner attribute) /// #![allow(dead_code)] /// /// fn this_is_fine() { } /// - /// // Bad - /// #[allow(dead_code)] - /// - /// fn not_quite_good_code() { } + /// // or /// /// // Good (as outer attribute) /// #[allow(dead_code)] @@ -175,12 +180,11 @@ declare_clippy_lint! { /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. /// /// ### Example - /// Bad: /// ```rust /// #![deny(clippy::restriction)] /// ``` /// - /// Good: + /// Use instead: /// ```rust /// #![deny(clippy::as_conversions)] /// ``` @@ -205,13 +209,12 @@ declare_clippy_lint! { /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) /// /// ### Example - /// Bad: /// ```rust /// #[cfg_attr(rustfmt, rustfmt_skip)] /// fn main() { } /// ``` /// - /// Good: + /// Use instead: /// ```rust /// #[rustfmt::skip] /// fn main() { } @@ -231,19 +234,19 @@ declare_clippy_lint! { /// by the conditional compilation engine. /// /// ### Example - /// Bad: /// ```rust /// #[cfg(linux)] /// fn conditional() { } /// ``` /// - /// Good: + /// Use instead: /// ```rust /// #[cfg(target_os = "linux")] /// fn conditional() { } /// ``` /// - /// Or: + /// or + /// /// ```rust /// #[cfg(unix)] /// fn conditional() { } @@ -266,14 +269,13 @@ declare_clippy_lint! { /// ensure that others understand the reasoning /// /// ### Example - /// Bad: /// ```rust /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint)] /// ``` /// - /// Good: + /// Use instead: /// ```rust /// #![feature(lint_reasons)] /// diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 4c4dd85d518..86e28ea7f7a 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// if true { /* ... */ } /// ``` /// - /// // or + /// or /// /// ```rust /// # fn somefunc() -> bool { true }; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 0adb6327164..e4e122ba6eb 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -27,8 +27,14 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// if a && true // should be: if a - /// if !(a == b) // should be: if a != b + /// if a && true {} + /// if !(a == b) {} + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// if a {} + /// if a != b {} /// ``` #[clippy::version = "pre 1.29.0"] pub NONMINIMAL_BOOL, @@ -48,10 +54,15 @@ declare_clippy_lint! { /// Ignores short circuiting behavior. /// /// ### Example - /// ```ignore + /// ```rust,ignore + /// // The `b` is unnecessary, the expression is equivalent to `if a`. /// if a && b || a { ... } /// ``` - /// The `b` is unnecessary, the expression is equivalent to `if a`. + /// + /// Use instead: + /// ```rust,ignore + /// if a {} + /// ``` #[clippy::version = "pre 1.29.0"] pub LOGIC_BUG, correctness, diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 02d97bf43df..bfdbaf2413a 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -28,7 +28,13 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let vec = vec![1_u8]; - /// &vec.iter().filter(|x| **x == 0u8).count(); // use bytecount::count instead + /// let count = vec.iter().filter(|x| **x == 0u8).count(); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// # let vec = vec![1_u8]; + /// let count = bytecount::count(&vec, 0u8); /// ``` #[clippy::version = "pre 1.29.0"] pub NAIVE_BYTECOUNT, diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 317c4bfb322..33c44f8b2db 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// complexity. /// /// ### Example - /// No. You'll see it when you get the warning. + /// You'll see it when you get the warning. #[clippy::version = "1.35.0"] pub COGNITIVE_COMPLEXITY, nursery, diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 3227e6e86af..3eceb848822 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// /// ``` /// - /// Should be written: + /// Use instead: /// /// ```rust,ignore /// if x && y { diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 399d11472b0..913e081af3b 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -34,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// Could be written: + /// Use instead: /// /// ```rust,ignore /// use std::cmp::Ordering; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index e6a0162fd02..1e9a1153011 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -141,7 +141,7 @@ declare_clippy_lint! { /// }; /// ``` /// - /// Could be written as: + /// Use instead: /// ```ignore /// println!("Hello World"); /// let foo = if … { diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 34a5f8444de..e98691fd5bb 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// bar: bool /// } /// - /// impl std::default::Default for Foo { + /// impl Default for Foo { /// fn default() -> Self { /// Self { /// bar: false diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index be95375789d..ee0440e52ff 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// if x == y || x < y {} /// ``` /// - /// Could be written as: + /// Use instead: /// /// ```rust /// # let x = 1; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 09318f74527..d85ace3a279 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -22,15 +22,17 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # use std::time::Duration; - /// let dur = Duration::new(5, 0); - /// - /// // Bad - /// let _micros = dur.subsec_nanos() / 1_000; - /// let _millis = dur.subsec_nanos() / 1_000_000; + /// # let duration = Duration::new(5, 0); + /// let micros = duration.subsec_nanos() / 1_000; + /// let millis = duration.subsec_nanos() / 1_000_000; + /// ``` /// - /// // Good - /// let _micros = dur.subsec_micros(); - /// let _millis = dur.subsec_millis(); + /// Use instead: + /// ```rust + /// # use std::time::Duration; + /// # let duration = Duration::new(5, 0); + /// let micros = duration.subsec_micros(); + /// let millis = duration.subsec_millis(); /// ``` #[clippy::version = "pre 1.29.0"] pub DURATION_SUBSEC, diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 0b9f54231c5..bf4488570ea 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// Could be written: + /// Use instead: /// /// ```rust /// # fn a() {} diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index b5d6b3c7524..bbebc024414 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -23,12 +23,11 @@ declare_clippy_lint! { /// /// /// ### Example - /// Bad: /// ```rust /// enum Test {} /// ``` /// - /// Good: + /// Use instead: /// ```rust /// #![feature(never_type)] /// diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index c5a987842c3..27743a0ebec 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { /// map.insert(k, v); /// } /// ``` - /// can both be rewritten as: + /// Use instead: /// ```rust /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index e029b8e8537..263a5b573c9 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// BattenbergCake, /// } /// ``` - /// Could be written as: + /// Use instead: /// ```rust /// enum Cake { /// BlackForest, diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index cf47e581ccb..ef1216358dd 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// do_thing(); /// } /// ``` - /// Should be written + /// Use instead: /// ```rust,ignore /// if x == Some(2) { /// do_thing(); diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index af591dd71aa..b0854ed9bbb 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -31,12 +31,14 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # fn foo(bar: usize) {} - /// // Bad /// let x = Box::new(1); /// foo(*x); /// println!("{}", *x); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # fn foo(bar: usize) {} /// let x = 1; /// foo(x); /// println!("{}", x); diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 7a81fb37e84..a2af10e2ba5 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -18,7 +18,6 @@ declare_clippy_lint! { /// readability and API. /// /// ### Example - /// Bad: /// ```rust /// struct S { /// is_pending: bool, @@ -27,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// Good: + /// Use instead: /// ```rust /// enum S { /// Pending, diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 3e2217c28da..6b9805efbcf 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -21,8 +21,16 @@ declare_clippy_lint! { /// ```rust /// # use std::io::Write; /// # let bar = "furchtbar"; - /// // this would be clearer as `eprintln!("foo: {:?}", bar);` /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); + /// writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap(); + /// ``` + /// + /// Use instead: + /// ```rust + /// # use std::io::Write; + /// # let bar = "furchtbar"; + /// eprintln!("foo: {:?}", bar); + /// println!("foo: {:?}", bar); /// ``` #[clippy::version = "pre 1.29.0"] pub EXPLICIT_WRITE, diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 9f868df3ad0..b88e53aeca6 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -20,7 +20,6 @@ declare_clippy_lint! { /// ```rust /// struct Foo(i32); /// - /// // Bad /// impl From for Foo { /// fn from(s: String) -> Self { /// Foo(s.parse().unwrap()) @@ -28,8 +27,8 @@ declare_clippy_lint! { /// } /// ``` /// + /// Use instead: /// ```rust - /// // Good /// struct Foo(i32); /// /// impl TryFrom for Foo { diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 7a4397a7b74..f850ea31f4d 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -19,11 +19,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let v: f32 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789 + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let v: f64 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789_9 /// ``` diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 42503c26de1..df9b41d2c98 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -35,8 +35,7 @@ declare_clippy_lint! { /// let _ = a.exp() - 1.0; /// ``` /// - /// is better expressed as - /// + /// Use instead: /// ```rust /// let a = 3f32; /// let _ = a.cbrt(); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 64c41b56587..3084c70589f 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -25,12 +25,13 @@ declare_clippy_lint! { /// /// ### Examples /// ```rust - /// - /// // Bad /// let foo = "foo"; /// format!("{}", foo); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// let foo = "foo"; /// foo.to_owned(); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 57964b8d48e..db0166da57f 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -36,12 +36,18 @@ declare_clippy_lint! { /// This is either a typo in the binary operator or confusing. /// /// ### Example - /// ```rust,ignore - /// if foo <- 30 { // this should be `foo < -30` but looks like a different operator - /// } + /// ```rust + /// # let foo = true; + /// # let bar = false; + /// // &&! looks like a different operator + /// if foo &&! bar {} + /// ``` /// - /// if foo &&! bar { // this should be `foo && !bar` but looks like a different operator - /// } + /// Use instead: + /// ```rust + /// # let foo = true; + /// # let bar = false; + /// if foo && !bar {} /// ``` #[clippy::version = "1.40.0"] pub SUSPICIOUS_UNARY_OP_FORMATTING, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 75d771f992a..417248e31ae 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -192,7 +192,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// // or + /// or /// /// ```rust /// # let res: Result = Ok(1); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b820b740930..eb1bce8c7d2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -203,7 +203,7 @@ declare_clippy_lint! { /// opt.expect("more helpful message"); /// ``` /// - /// // or + /// or /// /// ```rust /// # let res: Result = Ok(1); @@ -245,7 +245,7 @@ declare_clippy_lint! { /// opt?; /// ``` /// - /// // or + /// or /// /// ```rust /// # let res: Result = Ok(1); @@ -440,7 +440,7 @@ declare_clippy_lint! { /// x.map_or(0, |a| a + 1); /// ``` /// - /// // or + /// or /// /// ```rust /// # let x: Result = Ok(1); -- cgit 1.4.1-3-g733a5 From c5410150eb5563ed1f0529bf16e0524846a8979d Mon Sep 17 00:00:00 2001 From: lyj Date: Sun, 29 May 2022 09:57:15 +0800 Subject: needless_deref --- CHANGELOG.md | 1 + clippy_lints/src/borrow_deref_ref.rs | 118 +++++++++++++++++++++ clippy_lints/src/checked_conversions.rs | 4 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/loops/never_loop.rs | 2 +- clippy_lints/src/matches/match_bool.rs | 4 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/mixed_read_write_in_expression.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/redundant_clone.rs | 6 +- clippy_lints/src/redundant_static_lifetimes.rs | 9 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 8 +- .../src/utils/internal_lints/metadata_collector.rs | 3 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/hir_utils.rs | 6 +- clippy_utils/src/lib.rs | 4 +- tests/ui-internal/unnecessary_symbol_str.fixed | 1 + tests/ui-internal/unnecessary_symbol_str.rs | 1 + tests/ui-internal/unnecessary_symbol_str.stderr | 10 +- tests/ui/borrow_deref_ref.rs | 58 ++++++++++ tests/ui/borrow_deref_ref.stderr | 37 +++++++ tests/ui/collapsible_match2.rs | 2 +- tests/ui/collapsible_match2.stderr | 4 +- tests/ui/deref_by_slicing.fixed | 1 + tests/ui/deref_by_slicing.rs | 1 + tests/ui/deref_by_slicing.stderr | 18 ++-- tests/ui/explicit_deref_methods.fixed | 7 +- tests/ui/explicit_deref_methods.rs | 7 +- tests/ui/explicit_deref_methods.stderr | 24 ++--- tests/ui/forget_ref.rs | 1 + tests/ui/forget_ref.stderr | 36 +++---- tests/ui/recursive_format_impl.rs | 3 +- tests/ui/recursive_format_impl.stderr | 20 ++-- 41 files changed, 325 insertions(+), 94 deletions(-) create mode 100644 clippy_lints/src/borrow_deref_ref.rs create mode 100644 tests/ui/borrow_deref_ref.rs create mode 100644 tests/ui/borrow_deref_ref.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aaa79a1719..ece80343622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3296,6 +3296,7 @@ Released 2018-09-13 [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison [`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr +[`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box [`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs new file mode 100644 index 00000000000..ec2f31cf673 --- /dev/null +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -0,0 +1,118 @@ +use crate::reference::DEREF_ADDROF; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_parent_expr, is_lint_allowed}; +use rustc_errors::Applicability; +use rustc_hir::{ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::mir::Mutability; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `&*(&T)`. + /// + /// ### Why is this bad? + /// Dereferencing and then borrowing a reference value has no effect in most cases. + /// + /// ### Known problems + /// false negative on such code: + /// ``` + /// let x = &12; + /// let addr_x = &x as *const _ as usize; + /// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggerd. + /// // But if we fix it, assert will fail. + /// assert_ne!(addr_x, addr_y); + /// ``` + /// + /// ### Example + /// ```rust + /// let s = &String::new(); + /// + /// // Bad + /// let a: &String = &* s; + /// foo(&*s); + /// + /// // Good + /// let a: &String = s; + /// foo(&**s); + /// + /// fn foo(_: &str){ } + /// ``` + #[clippy::version = "1.59.0"] + pub BORROW_DEREF_REF, + complexity, + "deref on an immutable reference returns the same type as itself" +} + +declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); + +impl LateLintPass<'_> for BorrowDerefRef { + fn check_expr(&mut self, cx: &LateContext<'_>, e: &rustc_hir::Expr<'_>) { + if_chain! { + if !e.span.from_expansion(); + if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind; + if !addrof_target.span.from_expansion(); + if let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind; + if !deref_target.span.from_expansion(); + if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ); + let ref_ty = cx.typeck_results().expr_ty(deref_target); + if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind(); + then{ + + if let Some(parent_expr) = get_parent_expr(cx, e){ + if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) && + !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) { + return; + } + + // modification to `&mut &*x` is different from `&mut x` + if matches!(deref_target.kind, ExprKind::Path(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Unary(UnOp::Deref, ..)) + && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) { + return; + } + } + + span_lint_and_then( + cx, + BORROW_DEREF_REF, + e.span, + "deref on an immutable reference", + |diag| { + diag.span_suggestion( + e.span, + "if you would like to reborrow, try removing `&*`", + snippet_opt(cx, deref_target.span).unwrap(), + Applicability::MachineApplicable + ); + + // has deref trait -> give 2 help + // doesn't have deref trait -> give 1 help + if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){ + if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { + return; + } + } + + diag.span_suggestion( + e.span, + "if you would like to deref, try using `&**`", + format!( + "&**{}", + &snippet_opt(cx, deref_target.span).unwrap(), + ), + Applicability::MaybeIncorrect + ); + + } + ); + + } + } + } +} diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 7eeaaa01921..1010340c712 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -318,7 +318,7 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: if let QPath::TypeRelative(ty, path) = &path; if path.ident.name.as_str() == function; if let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind; - if let [int] = &*tp.segments; + if let [int] = tp.segments; then { let name = int.ident.name.as_str(); candidates.iter().find(|c| &name == *c).copied() @@ -332,7 +332,7 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { if_chain! { if let QPath::Resolved(_, path) = *path; - if let [ty] = &*path.segments; + if let [ty] = path.segments; then { let name = ty.ident.name.as_str(); INTS.iter().find(|c| &name == *c).copied() diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index db09d00d730..56bbbbbc819 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind; if !is_local_used(cx, *cond, canonical_id); if let hir::ExprKind::Block(then, _) = then.kind; - if let Some(value) = check_assign(cx, canonical_id, &*then); + if let Some(value) = check_assign(cx, canonical_id, then); if !is_local_used(cx, value, canonical_id); then { let span = stmt.span.to(if_.span); diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index a028b41db77..de43d4be1b3 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -24,6 +24,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(booleans::LOGIC_BUG), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(borrow_deref_ref::BORROW_DEREF_REF), LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ENUM_CONSTRUCTOR), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index d5dfcd10a66..67ddae45bc0 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -5,6 +5,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ LintId::of(attrs::DEPRECATED_CFG_ATTR), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(borrow_deref_ref::BORROW_DEREF_REF), LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::UNNECESSARY_CAST), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 1f2132cf620..42a17eb12ce 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -64,6 +64,7 @@ store.register_lints(&[ booleans::LOGIC_BUG, booleans::NONMINIMAL_BOOL, borrow_as_ptr::BORROW_AS_PTR, + borrow_deref_ref::BORROW_DEREF_REF, bytecount::NAIVE_BYTECOUNT, bytes_count_to_len::BYTES_COUNT_TO_LEN, cargo::CARGO_COMMON_METADATA, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d611600cf71..ca5e62ff431 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -183,6 +183,7 @@ mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; mod borrow_as_ptr; +mod borrow_deref_ref; mod bytecount; mod bytes_count_to_len; mod cargo; @@ -638,6 +639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(mutex_atomic::Mutex)); store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate)); store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); + store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef)); store.register_late_pass(|| Box::new(no_effect::NoEffect)); store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment)); store.register_late_pass(|| Box::new(transmute::Transmute)); diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 70a118d6b35..c025f5972d5 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -146,7 +146,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { if arms.is_empty() { e } else { - let arms = never_loop_expr_branch(&mut arms.iter().map(|a| &*a.body), main_loop_id); + let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), main_loop_id); combine_seq(e, arms) } }, diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index 90c50b994d2..1c216e13570 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -24,8 +24,8 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { if let ExprKind::Lit(ref lit) = arm_bool.kind { match lit.node { - LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), - LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)), + LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), + LitKind::Bool(false) => Some((arms[1].body, arms[0].body)), _ => None, } } else { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 97c4feb3122..b4c6bfb31ed 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -415,7 +415,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - is_clone_like(cx, &*method_name.as_str(), method_def_id) + is_clone_like(cx, method_name.as_str(), method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) || is_to_string(cx, method_name, method_def_id) } diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 405fc23e8de..024bd076071 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { self.visit_expr(if_expr); } // make sure top level arm expressions aren't linted - self.maybe_walk_expr(&*arm.body); + self.maybe_walk_expr(arm.body); } }, _ => walk_expr(self, e), diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index cba54e14212..7e2531c7ca5 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { if let hir::PatKind::Wild = local.pat.kind { return; } - check_ty(cx, local.span, cx.typeck_results().pat_ty(&*local.pat)); + check_ty(cx, local.span, cx.typeck_results().pat_ty(local.pat)); } } diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index b7a56970b33..21acf003d92 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -61,7 +61,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir expr_visitor_no_bodies(|expr| { let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true }; if matches!( - &*cx.tcx.item_name(macro_call.def_id).as_str(), + cx.tcx.item_name(macro_call.def_id).as_str(), "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne" ) { panics.push(macro_call.span); diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index e3ded716341..5a93431f25a 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -233,7 +233,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind { - self.check_poly_fn(cx, item.def_id, &*method_sig.decl, None); + self.check_poly_fn(cx, item.def_id, method_sig.decl, None); } } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 0004b8afdd3..f7a6fbac166 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -288,8 +288,8 @@ fn is_call_with_ref_arg<'tcx>( if let mir::TerminatorKind::Call { func, args, destination, .. } = kind; if args.len() == 1; if let mir::Operand::Move(mir::Place { local, .. }) = &args[0]; - if let ty::FnDef(def_id, _) = *func.ty(&*mir, cx.tcx).kind(); - if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx)); + if let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind(); + if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx)); if !is_copy(cx, inner_ty); then { Some((def_id, *local, inner_ty, destination.as_ref().map(|(dest, _)| dest)?.as_local()?)) @@ -318,7 +318,7 @@ fn find_stmt_assigns_to<'tcx>( None })?; - match (by_ref, &*rvalue) { + match (by_ref, rvalue) { (true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => { Some(base_local_and_movability(cx, mir, *place)) }, diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 2d26c49252f..0825f00f421 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -51,12 +51,12 @@ impl RedundantStaticLifetimes { fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) { match ty.kind { // Be careful of nested structures (arrays and tuples) - TyKind::Array(ref ty, _) => { - self.visit_type(&*ty, cx, reason); + TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => { + self.visit_type(ty, cx, reason); }, TyKind::Tup(ref tup) => { for tup_ty in tup { - self.visit_type(&*tup_ty, cx, reason); + self.visit_type(tup_ty, cx, reason); } }, // This is what we are looking for ! @@ -89,9 +89,6 @@ impl RedundantStaticLifetimes { } self.visit_type(&*borrow_type.ty, cx, reason); }, - TyKind::Slice(ref ty) => { - self.visit_type(ty, cx, reason); - }, _ => {}, } } diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 3d7dc49b406..bfb9f0d01e1 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -110,7 +110,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind; let method_ident = method_path.ident.as_str(); - if METHODS.iter().any(|m| *m == &*method_ident); + if METHODS.iter().any(|m| *m == method_ident); // Get the pointee type if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 0e8f40e9210..60f98876994 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -422,7 +422,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { } } else if let Some(macro_call) = root_macro_call_first_node(cx, item) { if !matches!( - &*cx.tcx.item_name(macro_call.def_id).as_str(), + cx.tcx.item_name(macro_call.def_id).as_str(), "impl_lint_pass" | "declare_lint_pass" ) { return; @@ -504,7 +504,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' return; } - if RustcVersion::parse(&*value.as_str()).is_err() { + if RustcVersion::parse(value.as_str()).is_err() { span_lint_and_help( cx, INVALID_CLIPPY_VERSION_ATTRIBUTE, @@ -595,7 +595,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; let fn_name = path.ident; - if let Some(sugg) = self.map.get(&*fn_name.as_str()); + if let Some(sugg) = self.map.get(fn_name.as_str()); let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); @@ -679,7 +679,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { then { let and_then_snippets = get_and_then_snippets(cx, and_then_args); let mut sle = SpanlessEq::new(cx).deny_side_effects(); - match &*ps.ident.as_str() { + match ps.ident.as_str() { "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => { suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args)); }, diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 8c1910b3b2a..53579ccb4c2 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -527,12 +527,11 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option, item: &Item<'_>) -> Option { let attrs = cx.tcx.hir().attrs(item.hir_id()); let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str); - let mut docs = String::from(&*lines.next()?.as_str()); + let mut docs = String::from(lines.next()?.as_str()); let mut in_code_block = false; let mut is_code_block_rust = false; for line in lines { let line = line.as_str(); - let line = &*line; // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :) if is_code_block_rust && line.trim_start().starts_with("# ") { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 9f162a117b2..d487868cafe 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -478,7 +478,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option { if let Some(Constant::Bool(b)) = self.expr(cond) { if b { - self.expr(&*then) + self.expr(then) } else { otherwise.as_ref().and_then(|expr| self.expr(expr)) } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 1e0fc789af2..4604ae5c2c7 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -35,7 +35,7 @@ impl<'tcx> ForLoop<'tcx> { if let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind; if let hir::ExprKind::Call(_, [arg]) = iterexpr.kind; if let hir::ExprKind::Loop(block, ..) = arm.body.kind; - if let [stmt] = &*block.stmts; + if let [stmt] = block.stmts; if let hir::StmtKind::Expr(e) = stmt.kind; if let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind; if let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c440793b90e..cbd0a257cfb 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -411,10 +411,10 @@ impl HirEqInterExpr<'_, '_, '_> { (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_array_length(ll, rl), (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => { - l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty) + l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty) }, (&TyKind::Rptr(_, ref l_rmut), &TyKind::Rptr(_, ref r_rmut)) => { - l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty) + l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty) }, (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r), (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)), @@ -608,7 +608,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(i.ident.name); } if let Some(j) = *j { - self.hash_expr(&*j); + self.hash_expr(j); } }, ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b8a80d4adc3..1ca7cf5c177 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1443,7 +1443,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, PatKind::Tuple(pats, _) => are_refutable(cx, pats), PatKind::Struct(ref qpath, fields, _) => { - is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat)) + is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat)) }, PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats), PatKind::Slice(head, middle, tail) => { @@ -1658,7 +1658,7 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, let mut blocks: Vec<&Block<'_>> = Vec::new(); while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) { - conds.push(&*cond); + conds.push(cond); if let ExprKind::Block(block, _) = then.kind { blocks.push(block); } else { diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index 4f5336663a8..6033d06e4f6 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -2,6 +2,7 @@ #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( + clippy::borrow_deref_ref, clippy::unnecessary_operation, unused_must_use, clippy::missing_clippy_version_attribute diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs index 894aa1d3bc6..1bb5d55f0b6 100644 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ b/tests/ui-internal/unnecessary_symbol_str.rs @@ -2,6 +2,7 @@ #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( + clippy::borrow_deref_ref, clippy::unnecessary_operation, unused_must_use, clippy::missing_clippy_version_attribute diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr index 75367bf4bc5..a1f507f331d 100644 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ b/tests/ui-internal/unnecessary_symbol_str.stderr @@ -1,5 +1,5 @@ error: unnecessary `Symbol` to string conversion - --> $DIR/unnecessary_symbol_str.rs:15:5 + --> $DIR/unnecessary_symbol_str.rs:16:5 | LL | Symbol::intern("foo").as_str() == "clippy"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy` @@ -12,25 +12,25 @@ LL | #![deny(clippy::internal)] = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]` error: unnecessary `Symbol` to string conversion - --> $DIR/unnecessary_symbol_str.rs:16:5 + --> $DIR/unnecessary_symbol_str.rs:17:5 | LL | Symbol::intern("foo").to_string() == "self"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower` error: unnecessary `Symbol` to string conversion - --> $DIR/unnecessary_symbol_str.rs:17:5 + --> $DIR/unnecessary_symbol_str.rs:18:5 | LL | Symbol::intern("foo").to_ident_string() != "Self"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper` error: unnecessary `Symbol` to string conversion - --> $DIR/unnecessary_symbol_str.rs:18:5 + --> $DIR/unnecessary_symbol_str.rs:19:5 | LL | &*Ident::empty().as_str() == "clippy"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy` error: unnecessary `Symbol` to string conversion - --> $DIR/unnecessary_symbol_str.rs:19:5 + --> $DIR/unnecessary_symbol_str.rs:20:5 | LL | "clippy" == Ident::empty().to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs new file mode 100644 index 00000000000..c8a2c397ff6 --- /dev/null +++ b/tests/ui/borrow_deref_ref.rs @@ -0,0 +1,58 @@ +fn main() {} + +mod should_lint { + fn foo() { + let a = &12; + let b = &*a; + + let s = &String::new(); + let x: &str = &*s; + + let b = &mut &*bar(&12); + } + + fn bar(x: &u32) -> &u32 { + x + } +} + +// this mod explains why we should not lint `&mut &* (&T)` +mod should_not_lint1 { + fn foo(x: &mut &u32) { + *x = &1; + } + + fn main() { + let mut x = &0; + foo(&mut &*x); // should not lint + assert_eq!(*x, 0); + + foo(&mut x); + assert_eq!(*x, 1); + } +} + +// similar to should_not_lint1 +mod should_not_lint2 { + struct S<'a> { + a: &'a u32, + b: u32, + } + + fn main() { + let s = S { a: &1, b: 1 }; + let x = &mut &*s.a; + *x = &2; + } +} + +// this mod explains why we should not lint `& &* (&T)` +mod false_negative { + fn foo() { + let x = &12; + let addr_x = &x as *const _ as usize; + let addr_y = &&*x as *const _ as usize; // assert ok + // let addr_y = &x as *const _ as usize; // assert fail + assert_ne!(addr_x, addr_y); + } +} diff --git a/tests/ui/borrow_deref_ref.stderr b/tests/ui/borrow_deref_ref.stderr new file mode 100644 index 00000000000..b550b928519 --- /dev/null +++ b/tests/ui/borrow_deref_ref.stderr @@ -0,0 +1,37 @@ +error: deref on an immutable reference + --> $DIR/borrow_deref_ref.rs:6:17 + | +LL | let b = &*a; + | ^^^ help: if you would like to reborrow, try removing `&*`: `a` + | + = note: `-D clippy::borrow-deref-ref` implied by `-D warnings` + +error: deref on an immutable reference + --> $DIR/borrow_deref_ref.rs:9:23 + | +LL | let x: &str = &*s; + | ^^^ + | +help: if you would like to reborrow, try removing `&*` + | +LL | let x: &str = s; + | ~ +help: if you would like to deref, try using `&**` + | +LL | let x: &str = &**s; + | ~~~~ + +error: deref on an immutable reference + --> $DIR/borrow_deref_ref.rs:11:22 + | +LL | let b = &mut &*bar(&12); + | ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)` + +error: deref on an immutable reference + --> $DIR/borrow_deref_ref.rs:54:23 + | +LL | let addr_y = &&*x as *const _ as usize; // assert ok + | ^^^ help: if you would like to reborrow, try removing `&*`: `x` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/collapsible_match2.rs b/tests/ui/collapsible_match2.rs index 542e6948427..c8fb0a39e95 100644 --- a/tests/ui/collapsible_match2.rs +++ b/tests/ui/collapsible_match2.rs @@ -57,7 +57,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // ref pattern and deref match Some(&[1]) { - Some(ref s) => match &*s { + Some(ref s) => match s { [n] => foo(n), _ => (), }, diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr index 46b645aea13..fe64e469379 100644 --- a/tests/ui/collapsible_match2.stderr +++ b/tests/ui/collapsible_match2.stderr @@ -78,7 +78,7 @@ LL | [n] => foo(n), error: this `match` can be collapsed into the outer `match` --> $DIR/collapsible_match2.rs:60:24 | -LL | Some(ref s) => match &*s { +LL | Some(ref s) => match s { | ________________________^ LL | | [n] => foo(n), LL | | _ => (), @@ -88,7 +88,7 @@ LL | | }, help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:60:14 | -LL | Some(ref s) => match &*s { +LL | Some(ref s) => match s { | ^^^^^ replace this binding LL | [n] => foo(n), | ^^^ with this pattern diff --git a/tests/ui/deref_by_slicing.fixed b/tests/ui/deref_by_slicing.fixed index b26276218b7..257393e56ff 100644 --- a/tests/ui/deref_by_slicing.fixed +++ b/tests/ui/deref_by_slicing.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::deref_by_slicing)] +#![allow(clippy::borrow_deref_ref)] use std::io::Read; diff --git a/tests/ui/deref_by_slicing.rs b/tests/ui/deref_by_slicing.rs index 6aa1408ba17..e288046f927 100644 --- a/tests/ui/deref_by_slicing.rs +++ b/tests/ui/deref_by_slicing.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::deref_by_slicing)] +#![allow(clippy::borrow_deref_ref)] use std::io::Read; diff --git a/tests/ui/deref_by_slicing.stderr b/tests/ui/deref_by_slicing.stderr index ffd76de378d..8f042ef47eb 100644 --- a/tests/ui/deref_by_slicing.stderr +++ b/tests/ui/deref_by_slicing.stderr @@ -1,5 +1,5 @@ error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:9:13 + --> $DIR/deref_by_slicing.rs:10:13 | LL | let _ = &vec[..]; | ^^^^^^^^ help: dereference the original value instead: `&*vec` @@ -7,49 +7,49 @@ LL | let _ = &vec[..]; = note: `-D clippy::deref-by-slicing` implied by `-D warnings` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:10:13 + --> $DIR/deref_by_slicing.rs:11:13 | LL | let _ = &mut vec[..]; | ^^^^^^^^^^^^ help: dereference the original value instead: `&mut *vec` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:13:13 + --> $DIR/deref_by_slicing.rs:14:13 | LL | let _ = &ref_vec[..]; | ^^^^^^^^^^^^ help: dereference the original value instead: `&**ref_vec` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:14:21 + --> $DIR/deref_by_slicing.rs:15:21 | LL | let mut_slice = &mut ref_vec[..]; | ^^^^^^^^^^^^^^^^ help: dereference the original value instead: `&mut **ref_vec` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:15:13 + --> $DIR/deref_by_slicing.rs:16:13 | LL | let _ = &mut mut_slice[..]; // Err, re-borrows slice | ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:18:13 + --> $DIR/deref_by_slicing.rs:19:13 | LL | let _ = &s[..]; | ^^^^^^ help: dereference the original value instead: `&*s` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:21:18 + --> $DIR/deref_by_slicing.rs:22:18 | LL | let _ = &mut &S[..]; // Err, re-borrows slice | ^^^^^^ help: reborrow the original value instead: `&*S` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:25:13 + --> $DIR/deref_by_slicing.rs:26:13 | LL | let _ = &slice_ref[..]; // Err, derefs slice | ^^^^^^^^^^^^^^ help: dereference the original value instead: `*slice_ref` error: slicing when dereferencing would work - --> $DIR/deref_by_slicing.rs:28:13 + --> $DIR/deref_by_slicing.rs:29:13 | LL | let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice | ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)` diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 3de2a51ffa5..92f27e68549 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -1,6 +1,11 @@ // run-rustfix -#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)] +#![allow( + unused_variables, + clippy::clone_double_ref, + clippy::needless_borrow, + clippy::borrow_deref_ref +)] #![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index a08d7596422..d118607f992 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -1,6 +1,11 @@ // run-rustfix -#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)] +#![allow( + unused_variables, + clippy::clone_double_ref, + clippy::needless_borrow, + clippy::borrow_deref_ref +)] #![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/explicit_deref_methods.stderr b/tests/ui/explicit_deref_methods.stderr index 8035d77d18d..8e8b358972b 100644 --- a/tests/ui/explicit_deref_methods.stderr +++ b/tests/ui/explicit_deref_methods.stderr @@ -1,5 +1,5 @@ error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:30:19 + --> $DIR/explicit_deref_methods.rs:35:19 | LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try this: `&*a` @@ -7,67 +7,67 @@ LL | let b: &str = a.deref(); = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` error: explicit `deref_mut` method call - --> $DIR/explicit_deref_methods.rs:32:23 + --> $DIR/explicit_deref_methods.rs:37:23 | LL | let b: &mut str = a.deref_mut(); | ^^^^^^^^^^^^^ help: try this: `&mut **a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:35:39 + --> $DIR/explicit_deref_methods.rs:40:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:35:50 + --> $DIR/explicit_deref_methods.rs:40:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:37:20 + --> $DIR/explicit_deref_methods.rs:42:20 | LL | println!("{}", a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:40:11 + --> $DIR/explicit_deref_methods.rs:45:11 | LL | match a.deref() { | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:44:28 + --> $DIR/explicit_deref_methods.rs:49:28 | LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:46:13 + --> $DIR/explicit_deref_methods.rs:51:13 | LL | let b = just_return(a).deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:48:28 + --> $DIR/explicit_deref_methods.rs:53:28 | LL | let b: String = concat(just_return(a).deref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:50:19 + --> $DIR/explicit_deref_methods.rs:55:19 | LL | let b: &str = a.deref().deref(); | ^^^^^^^^^^^^^^^^^ help: try this: `&**a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:53:13 + --> $DIR/explicit_deref_methods.rs:58:13 | LL | let b = opt_a.unwrap().deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:79:31 + --> $DIR/explicit_deref_methods.rs:84:31 | LL | let b: &str = expr_deref!(a.deref()); | ^^^^^^^^^ help: try this: `&*a` diff --git a/tests/ui/forget_ref.rs b/tests/ui/forget_ref.rs index 6c8c4c9c0ed..031b415f56f 100644 --- a/tests/ui/forget_ref.rs +++ b/tests/ui/forget_ref.rs @@ -1,6 +1,7 @@ #![warn(clippy::forget_ref)] #![allow(clippy::toplevel_ref_arg)] #![allow(clippy::unnecessary_wraps, clippy::forget_non_drop)] +#![allow(clippy::borrow_deref_ref)] use std::mem::forget; diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr index 73409388ed1..df5cd8cacdb 100644 --- a/tests/ui/forget_ref.stderr +++ b/tests/ui/forget_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:10:5 + --> $DIR/forget_ref.rs:11:5 | LL | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:10:12 + --> $DIR/forget_ref.rs:11:12 | LL | forget(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:13:5 + --> $DIR/forget_ref.rs:14:5 | LL | forget(&owned); | ^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:13:12 + --> $DIR/forget_ref.rs:14:12 | LL | forget(&owned); | ^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:14:5 + --> $DIR/forget_ref.rs:15:5 | LL | forget(&&owned); | ^^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/forget_ref.rs:14:12 + --> $DIR/forget_ref.rs:15:12 | LL | forget(&&owned); | ^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:15:5 + --> $DIR/forget_ref.rs:16:5 | LL | forget(&mut owned); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:15:12 + --> $DIR/forget_ref.rs:16:12 | LL | forget(&mut owned); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:19:5 + --> $DIR/forget_ref.rs:20:5 | LL | forget(&*reference1); | ^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:19:12 + --> $DIR/forget_ref.rs:20:12 | LL | forget(&*reference1); | ^^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:22:5 + --> $DIR/forget_ref.rs:23:5 | LL | forget(reference2); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:22:12 + --> $DIR/forget_ref.rs:23:12 | LL | forget(reference2); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:25:5 + --> $DIR/forget_ref.rs:26:5 | LL | forget(reference3); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:25:12 + --> $DIR/forget_ref.rs:26:12 | LL | forget(reference3); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:30:5 + --> $DIR/forget_ref.rs:31:5 | LL | forget(&val); | ^^^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/forget_ref.rs:30:12 + --> $DIR/forget_ref.rs:31:12 | LL | forget(&val); | ^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:38:5 + --> $DIR/forget_ref.rs:39:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:38:22 + --> $DIR/forget_ref.rs:39:22 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/recursive_format_impl.rs b/tests/ui/recursive_format_impl.rs index f72fc77ab99..cb6ba36b14c 100644 --- a/tests/ui/recursive_format_impl.rs +++ b/tests/ui/recursive_format_impl.rs @@ -2,7 +2,8 @@ #![allow( clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args, - clippy::deref_addrof + clippy::deref_addrof, + clippy::borrow_deref_ref )] use std::fmt; diff --git a/tests/ui/recursive_format_impl.stderr b/tests/ui/recursive_format_impl.stderr index 1a717ac92d8..84ce69df566 100644 --- a/tests/ui/recursive_format_impl.stderr +++ b/tests/ui/recursive_format_impl.stderr @@ -1,5 +1,5 @@ error: using `self.to_string` in `fmt::Display` implementation will cause infinite recursion - --> $DIR/recursive_format_impl.rs:29:25 + --> $DIR/recursive_format_impl.rs:30:25 | LL | write!(f, "{}", self.to_string()) | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | write!(f, "{}", self.to_string()) = note: `-D clippy::recursive-format-impl` implied by `-D warnings` error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:73:9 + --> $DIR/recursive_format_impl.rs:74:9 | LL | write!(f, "{}", self) | ^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | write!(f, "{}", self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:82:9 + --> $DIR/recursive_format_impl.rs:83:9 | LL | write!(f, "{}", &self) | ^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | write!(f, "{}", &self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Debug` in `impl Debug` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:88:9 + --> $DIR/recursive_format_impl.rs:89:9 | LL | write!(f, "{:?}", &self) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | write!(f, "{:?}", &self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:97:9 + --> $DIR/recursive_format_impl.rs:98:9 | LL | write!(f, "{}", &&&self) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | write!(f, "{}", &&&self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:171:9 + --> $DIR/recursive_format_impl.rs:172:9 | LL | write!(f, "{}", &*self) | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | write!(f, "{}", &*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Debug` in `impl Debug` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:177:9 + --> $DIR/recursive_format_impl.rs:178:9 | LL | write!(f, "{:?}", &*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | write!(f, "{:?}", &*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:193:9 + --> $DIR/recursive_format_impl.rs:194:9 | LL | write!(f, "{}", *self) | ^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | write!(f, "{}", *self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:209:9 + --> $DIR/recursive_format_impl.rs:210:9 | LL | write!(f, "{}", **&&*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | write!(f, "{}", **&&*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> $DIR/recursive_format_impl.rs:225:9 + --> $DIR/recursive_format_impl.rs:226:9 | LL | write!(f, "{}", &&**&&*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From b20f95c1a1780934367a019a6adba4ec74895716 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Wed, 1 Jun 2022 18:36:02 -0400 Subject: Combine doc examples --- clippy_lints/src/as_conversions.rs | 7 +- clippy_lints/src/attrs.rs | 6 +- clippy_lints/src/blocks_in_if_conditions.rs | 12 ++-- clippy_lints/src/double_parens.rs | 14 ++-- clippy_lints/src/eq_op.rs | 6 +- clippy_lints/src/loops/mod.rs | 15 ++--- clippy_lints/src/methods/mod.rs | 99 ++++++++++++----------------- clippy_lints/src/minmax.rs | 8 +-- clippy_lints/src/misc.rs | 14 ++-- clippy_lints/src/mutable_debug_assertion.rs | 7 +- clippy_lints/src/trait_bounds.rs | 10 +-- 11 files changed, 88 insertions(+), 110 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 5fa8934c71b..6e5c8f44581 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -32,12 +32,11 @@ declare_clippy_lint! { /// Use instead: /// ```rust,ignore /// f(a.try_into()?); - /// ``` - /// or - /// ```rust,ignore + /// + /// // or + /// /// f(a.try_into().expect("Unexpected u16 overflow in f")); /// ``` - /// #[clippy::version = "1.41.0"] pub AS_CONVERSIONS, restriction, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 79a5b670fc8..770cb6a3d7b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -241,13 +241,13 @@ declare_clippy_lint! { /// /// Use instead: /// ```rust + /// # mod hidden { /// #[cfg(target_os = "linux")] /// fn conditional() { } - /// ``` + /// # } /// - /// or + /// // or /// - /// ```rust /// #[cfg(unix)] /// fn conditional() { } /// ``` diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 86e28ea7f7a..5bd7a342389 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -22,21 +22,17 @@ declare_clippy_lint! { /// /// ### Examples /// ```rust - /// // Bad + /// # fn somefunc() -> bool { true }; /// if { true } { /* ... */ } /// - /// // Good - /// if true { /* ... */ } + /// if { let x = somefunc(); x } { /* ... */ } /// ``` /// - /// or - /// + /// Use instead: /// ```rust /// # fn somefunc() -> bool { true }; - /// // Bad - /// if { let x = somefunc(); x } { /* ... */ } + /// if true { /* ... */ } /// - /// // Good /// let res = { let x = somefunc(); x }; /// if res { /* ... */ } /// ``` diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index e10f740d24a..a33ef5ce6e3 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -13,23 +13,21 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// fn simple_double_parens() -> i32 { /// ((0)) /// } /// - /// // Good + /// # fn foo(bar: usize) {} + /// foo((0)); + /// ``` + /// + /// Use instead: + /// ```rust /// fn simple_no_parens() -> i32 { /// 0 /// } /// - /// // or - /// /// # fn foo(bar: usize) {} - /// // Bad - /// foo((0)); - /// - /// // Good /// foo(0); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index afb5d32f953..c3176d987c6 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -30,9 +30,9 @@ declare_clippy_lint! { /// ```rust /// # let x = 1; /// if x + 1 == x + 1 {} - /// ``` - /// or - /// ```rust + /// + /// // or + /// /// # let a = 3; /// # let b = 4; /// assert_eq!(a, a); diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 417248e31ae..d61be78895f 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -180,29 +180,24 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let opt = Some(1); - /// - /// // Bad + /// # let res: Result = Ok(1); /// for x in opt { /// // .. /// } /// - /// // Good - /// if let Some(x) = opt { + /// for x in &res { /// // .. /// } /// ``` /// - /// or - /// + /// Use instead: /// ```rust + /// # let opt = Some(1); /// # let res: Result = Ok(1); - /// - /// // Bad - /// for x in &res { + /// if let Some(x) = opt { /// // .. /// } /// - /// // Good /// if let Ok(x) = res { /// // .. /// } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index eb1bce8c7d2..08c89ceb796 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -194,25 +194,18 @@ declare_clippy_lint! { /// /// ### Examples /// ```rust - /// # let opt = Some(1); - /// - /// // Bad - /// opt.unwrap(); - /// - /// // Good - /// opt.expect("more helpful message"); + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.unwrap(); + /// result.unwrap(); /// ``` /// - /// or - /// + /// Use instead: /// ```rust - /// # let res: Result = Ok(1); - /// - /// // Bad - /// res.unwrap(); - /// - /// // Good - /// res.expect("more helpful message"); + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.expect("more helpful message"); + /// result.expect("more helpful message"); /// ``` #[clippy::version = "1.45.0"] pub UNWRAP_USED, @@ -235,27 +228,21 @@ declare_clippy_lint! { /// /// ### Examples /// ```rust,ignore - /// # let opt = Some(1); - /// - /// // Bad - /// opt.expect("one"); - /// - /// // Good - /// let opt = Some(1); - /// opt?; + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.expect("one"); + /// result.expect("one"); /// ``` /// - /// or - /// - /// ```rust - /// # let res: Result = Ok(1); + /// Use instead: + /// ```rust,ignore + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option?; /// - /// // Bad - /// res.expect("one"); + /// // or /// - /// // Good - /// res?; - /// # Ok::<(), ()>(()) + /// result?; /// ``` #[clippy::version = "1.45.0"] pub EXPECT_USED, @@ -431,26 +418,20 @@ declare_clippy_lint! { /// /// ### Examples /// ```rust - /// # let x = Some(1); - /// - /// // Bad - /// x.map(|a| a + 1).unwrap_or(0); - /// - /// // Good - /// x.map_or(0, |a| a + 1); + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// # fn some_function(foo: ()) -> usize { 1 } + /// option.map(|a| a + 1).unwrap_or(0); + /// result.map(|a| a + 1).unwrap_or_else(some_function); /// ``` /// - /// or - /// + /// Use instead: /// ```rust - /// # let x: Result = Ok(1); + /// # let option = Some(1); + /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } - /// - /// // Bad - /// x.map(|a| a + 1).unwrap_or_else(some_function); - /// - /// // Good - /// x.map_or_else(some_function, |a| a + 1); + /// option.map_or(0, |a| a + 1); + /// result.map_or_else(some_function, |a| a + 1); /// ``` #[clippy::version = "1.45.0"] pub MAP_UNWRAP_OR, @@ -793,13 +774,14 @@ declare_clippy_lint! { /// # let foo = Some(String::new()); /// foo.unwrap_or(String::new()); /// ``` - /// this can instead be written: + /// + /// Use instead: /// ```rust /// # let foo = Some(String::new()); /// foo.unwrap_or_else(String::new); - /// ``` - /// or - /// ```rust + /// + /// // or + /// /// # let foo = Some(String::new()); /// foo.unwrap_or_default(); /// ``` @@ -863,15 +845,14 @@ declare_clippy_lint! { /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; /// foo.expect(&format!("Err {}: {}", err_code, err_msg)); - /// ``` - /// or - /// ```rust + /// + /// // or + /// /// # let foo = Some(String::new()); - /// # let err_code = "418"; - /// # let err_msg = "I'm a teapot"; /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str()); /// ``` - /// this can instead be written: + /// + /// Use instead: /// ```rust /// # let foo = Some(String::new()); /// # let err_code = "418"; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 65d1f440b76..a081cde8572 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -18,11 +18,11 @@ declare_clippy_lint! { /// the least it hurts readability of the code. /// /// ### Example - /// ```ignore + /// ```rust,ignore /// min(0, max(100, x)) - /// ``` - /// or - /// ```ignore + /// + /// // or + /// /// x.max(100).min(0) /// ``` /// It will always be equal to `0`. Probably the author meant to clamp the value diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 7fdc28c5a06..55665699453 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -103,11 +103,14 @@ declare_clippy_lint! { /// let x = 1.2331f64; /// let y = 1.2332f64; /// - /// // Bad /// if y == 1.23f64 { } /// if y != x {} // where both are floats + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let x = 1.2331f64; + /// # let y = 1.2332f64; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. /// // let error_margin = std::f64::EPSILON; @@ -258,10 +261,13 @@ declare_clippy_lint! { /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; /// - /// // Bad /// if x == ONE { } // where both are floats + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let x: f64 = 1.0; + /// # const ONE: f64 = 1.00; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. /// // let error_margin = std::f64::EPSILON; diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 8dba60f3a58..321db08dfe8 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -22,9 +22,12 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// debug_assert_eq!(vec![3].pop(), Some(3)); + /// /// // or - /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() } - /// debug_assert!(take_a_mut_parameter(&mut 5)); + /// + /// # let mut x = 5; + /// # fn takes_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() } + /// debug_assert!(takes_a_mut_parameter(&mut x)); /// ``` #[clippy::version = "1.40.0"] pub DEBUG_ASSERT_WITH_MUT_CALL, diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 6c60fb4b8e0..b91be0eb4be 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -54,14 +54,14 @@ declare_clippy_lint! { /// fn func(arg: T) where T: Clone + Default {} /// ``` /// - /// Could be written as: - /// + /// Use instead: /// ```rust + /// # mod hidden { /// fn func(arg: T) {} - /// ``` - /// or + /// # } + /// + /// // or /// - /// ```rust /// fn func(arg: T) where T: Clone + Default {} /// ``` #[clippy::version = "1.47.0"] -- cgit 1.4.1-3-g733a5 From 007fae10ed8c8fa51b396bcc02071fe792f2c288 Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Thu, 2 Jun 2022 00:57:08 +0900 Subject: fix(manual_find_map and manual_filter_map): check clone method --- clippy_lints/src/methods/filter_map.rs | 10 +++++++++- tests/ui/manual_filter_map.fixed | 22 ++++++++++++++++++++++ tests/ui/manual_filter_map.rs | 23 +++++++++++++++++++++++ tests/ui/manual_filter_map.stderr | 16 +++++++++++++++- tests/ui/manual_find_map.fixed | 20 ++++++++++++++++++++ tests/ui/manual_find_map.rs | 20 ++++++++++++++++++++ tests/ui/manual_find_map.stderr | 14 +++++++++++++- 7 files changed, 122 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 558cb6bd64e..04ca295dc69 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -155,7 +155,15 @@ pub(super) fn check<'tcx>( } false }; - if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg); + + if match map_arg.kind { + ExprKind::MethodCall(clone, [original_arg], _) => { + clone.ident.name == sym::clone + && SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, original_arg) + }, + _ => SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg) + }; + then { let span = filter_span.with_hi(expr.span.hi()); let (filter_name, lint) = if is_find { diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index fc8f58f8ea5..c88a4f43de2 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -35,3 +35,25 @@ fn to_opt(_: T) -> Option { fn to_res(_: T) -> Result { unimplemented!() } + +struct OptionFoo { + field: Option, +} + +struct ResultFoo { + field: Result, +} + +fn issue_8920() { + let vec = vec![OptionFoo { + field: Some(String::from("str")), + }]; + let _ = vec + .iter() + .filter_map(|f| f.field.clone()); + + let vec = vec![ResultFoo { + field: Ok(String::from("str")), + }]; + let _ = vec.iter().filter_map(|f| f.field.clone().ok()); +} diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 3af4bbee3bf..bb859ebe315 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -35,3 +35,26 @@ fn to_opt(_: T) -> Option { fn to_res(_: T) -> Result { unimplemented!() } + +struct OptionFoo { + field: Option, +} + +struct ResultFoo { + field: Result, +} + +fn issue_8920() { + let vec = vec![OptionFoo { + field: Some(String::from("str")), + }]; + let _ = vec + .iter() + .filter(|f| f.field.is_some()) + .map(|f| f.field.clone().unwrap()); + + let vec = vec![ResultFoo { + field: Ok(String::from("str")), + }]; + let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); +} diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index 4d4e2d5c12f..a78343e882f 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -18,5 +18,19 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)` LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` -error: aborting due to 3 previous errors +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:53:10 + | +LL | .filter(|f| f.field.is_some()) + | __________^ +LL | | .map(|f| f.field.clone().unwrap()); + | |__________________________________________^ help: try: `filter_map(|f| f.field.clone())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:59:24 + | +LL | let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|f| f.field.clone().ok())` + +error: aborting due to 5 previous errors diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index 95e97c4fd1f..d78d72d8e8f 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -35,3 +35,23 @@ fn to_opt(_: T) -> Option { fn to_res(_: T) -> Result { unimplemented!() } + +struct OptionFoo { + field: Option, +} + +struct ResultFoo { + field: Result, +} + +fn issue_8920() { + let vec = vec![OptionFoo { + field: Some(String::from("str")), + }]; + let _ = vec.iter().find_map(|f| f.field.clone()); + + let vec = vec![ResultFoo { + field: Ok(String::from("str")), + }]; + let _ = vec.iter().find_map(|f| f.field.clone().ok()); +} diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index cd3c82e3b25..74e8e52ed16 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -35,3 +35,23 @@ fn to_opt(_: T) -> Option { fn to_res(_: T) -> Result { unimplemented!() } + +struct OptionFoo { + field: Option, +} + +struct ResultFoo { + field: Result, +} + +fn issue_8920() { + let vec = vec![OptionFoo { + field: Some(String::from("str")), + }]; + let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap()); + + let vec = vec![ResultFoo { + field: Ok(String::from("str")), + }]; + let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); +} diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index 9e7f798df45..0b1465a8422 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -18,5 +18,17 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` -error: aborting due to 3 previous errors +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:51:24 + | +LL | let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:56:24 + | +LL | let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone().ok())` + +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From 678dcdd2be649e83eb1ce766f3ba141030f69e49 Mon Sep 17 00:00:00 2001 From: dswij Date: Thu, 2 Jun 2022 20:17:00 +0800 Subject: Apply `needless_return` suggestions --- clippy_lints/src/methods/option_map_or_none.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 76bc9466ed8..8989db54f6c 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( let func_snippet = snippet(cx, map_arg.span, ".."); let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ `and_then(..)` instead"; - return span_lint_and_sugg( + span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, expr.span, @@ -110,7 +110,7 @@ pub(super) fn check<'tcx>( let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ `ok()` instead"; let self_snippet = snippet(cx, recv.span, ".."); - return span_lint_and_sugg( + span_lint_and_sugg( cx, RESULT_MAP_OR_INTO_OPTION, expr.span, -- cgit 1.4.1-3-g733a5 From 990f8bf5a6354d98a7e0b628f9f1b810644c3ad8 Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Sat, 4 Jun 2022 16:55:33 +0900 Subject: refactor: Add some methods --- clippy_lints/src/methods/filter_map.rs | 19 ++++++++++++--- tests/ui/manual_filter_map.fixed | 22 +++++++++++++++++- tests/ui/manual_filter_map.rs | 27 +++++++++++++++++++++- tests/ui/manual_filter_map.stderr | 42 +++++++++++++++++++++++++++++++++- tests/ui/manual_find_map.fixed | 20 +++++++++++++++- tests/ui/manual_find_map.rs | 24 ++++++++++++++++++- tests/ui/manual_find_map.stderr | 40 +++++++++++++++++++++++++++++++- 7 files changed, 185 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 04ca295dc69..6cabe74fdef 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, PatKind, QPath, UnOp}; +use rustc_hir::{Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol}; @@ -157,8 +157,8 @@ pub(super) fn check<'tcx>( }; if match map_arg.kind { - ExprKind::MethodCall(clone, [original_arg], _) => { - clone.ident.name == sym::clone + ExprKind::MethodCall(method, [original_arg], _) => { + acceptable_methods(method) && SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, original_arg) }, _ => SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg) @@ -179,3 +179,16 @@ pub(super) fn check<'tcx>( } } } + +fn acceptable_methods(method: &PathSegment<'_>) -> bool { + let methods: [Symbol; 6] = [ + sym::clone, + sym::as_ref, + sym!(as_deref), + sym!(as_mut), + sym!(as_deref_mut), + sym!(to_owned), + ]; + + methods.contains(&method.ident.name) +} diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index c88a4f43de2..9de7040000a 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -52,8 +52,28 @@ fn issue_8920() { .iter() .filter_map(|f| f.field.clone()); - let vec = vec![ResultFoo { + let mut vec = vec![ResultFoo { field: Ok(String::from("str")), }]; let _ = vec.iter().filter_map(|f| f.field.clone().ok()); + + let _ = vec + .iter() + .filter_map(|f| f.field.as_ref().ok()); + + let _ = vec + .iter() + .filter_map(|f| f.field.as_deref().ok()); + + let _ = vec + .iter_mut() + .filter_map(|f| f.field.as_mut().ok()); + + let _ = vec + .iter_mut() + .filter_map(|f| f.field.as_deref_mut().ok()); + + let _ = vec + .iter() + .filter_map(|f| f.field.to_owned().ok()); } diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index bb859ebe315..6766078d694 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -53,8 +53,33 @@ fn issue_8920() { .filter(|f| f.field.is_some()) .map(|f| f.field.clone().unwrap()); - let vec = vec![ResultFoo { + let mut vec = vec![ResultFoo { field: Ok(String::from("str")), }]; let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); + + let _ = vec + .iter() + .filter(|f| f.field.is_ok()) + .map(|f| f.field.as_ref().unwrap()); + + let _ = vec + .iter() + .filter(|f| f.field.is_ok()) + .map(|f| f.field.as_deref().unwrap()); + + let _ = vec + .iter_mut() + .filter(|f| f.field.is_ok()) + .map(|f| f.field.as_mut().unwrap()); + + let _ = vec + .iter_mut() + .filter(|f| f.field.is_ok()) + .map(|f| f.field.as_deref_mut().unwrap()); + + let _ = vec + .iter() + .filter(|f| f.field.is_ok()) + .map(|f| f.field.to_owned().unwrap()); } diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index a78343e882f..5e67ca348fa 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -32,5 +32,45 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)` LL | let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|f| f.field.clone().ok())` -error: aborting due to 5 previous errors +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:63:10 + | +LL | .filter(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_ref().unwrap()); + | |___________________________________________^ help: try: `filter_map(|f| f.field.as_ref().ok())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:68:10 + | +LL | .filter(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_deref().unwrap()); + | |_____________________________________________^ help: try: `filter_map(|f| f.field.as_deref().ok())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:73:10 + | +LL | .filter(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_mut().unwrap()); + | |___________________________________________^ help: try: `filter_map(|f| f.field.as_mut().ok())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:78:10 + | +LL | .filter(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_deref_mut().unwrap()); + | |_________________________________________________^ help: try: `filter_map(|f| f.field.as_deref_mut().ok())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:83:10 + | +LL | .filter(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.to_owned().unwrap()); + | |_____________________________________________^ help: try: `filter_map(|f| f.field.to_owned().ok())` + +error: aborting due to 10 previous errors diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index d78d72d8e8f..e7b5081ea59 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -50,8 +50,26 @@ fn issue_8920() { }]; let _ = vec.iter().find_map(|f| f.field.clone()); - let vec = vec![ResultFoo { + let mut vec = vec![ResultFoo { field: Ok(String::from("str")), }]; let _ = vec.iter().find_map(|f| f.field.clone().ok()); + + let _ = vec.iter().find_map(|f| f.field.as_ref().ok()); + + let _ = vec + .iter() + .find_map(|f| f.field.as_deref().ok()); + + let _ = vec + .iter_mut() + .find_map(|f| f.field.as_mut().ok()); + + let _ = vec + .iter_mut() + .find_map(|f| f.field.as_deref_mut().ok()); + + let _ = vec + .iter() + .find_map(|f| f.field.to_owned().ok()); } diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index 74e8e52ed16..46badbb9a18 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -50,8 +50,30 @@ fn issue_8920() { }]; let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap()); - let vec = vec![ResultFoo { + let mut vec = vec![ResultFoo { field: Ok(String::from("str")), }]; let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); + + let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.as_ref().unwrap()); + + let _ = vec + .iter() + .find(|f| f.field.is_ok()) + .map(|f| f.field.as_deref().unwrap()); + + let _ = vec + .iter_mut() + .find(|f| f.field.is_ok()) + .map(|f| f.field.as_mut().unwrap()); + + let _ = vec + .iter_mut() + .find(|f| f.field.is_ok()) + .map(|f| f.field.as_deref_mut().unwrap()); + + let _ = vec + .iter() + .find(|f| f.field.is_ok()) + .map(|f| f.field.to_owned().unwrap()); } diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index 0b1465a8422..2b6955a17df 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -30,5 +30,43 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` LL | let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone().ok())` -error: aborting due to 5 previous errors +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:58:24 + | +LL | let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.as_ref().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.as_ref().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:62:10 + | +LL | .find(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_deref().unwrap()); + | |_____________________________________________^ help: try: `find_map(|f| f.field.as_deref().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:67:10 + | +LL | .find(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_mut().unwrap()); + | |___________________________________________^ help: try: `find_map(|f| f.field.as_mut().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:72:10 + | +LL | .find(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.as_deref_mut().unwrap()); + | |_________________________________________________^ help: try: `find_map(|f| f.field.as_deref_mut().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:77:10 + | +LL | .find(|f| f.field.is_ok()) + | __________^ +LL | | .map(|f| f.field.to_owned().unwrap()); + | |_____________________________________________^ help: try: `find_map(|f| f.field.to_owned().ok())` + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 42cf98553a72f4b6cdac2c4c6378121d30f3bf5f Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Sat, 4 Jun 2022 21:20:41 +0900 Subject: refactor: check copied and cloned --- clippy_lints/src/methods/filter_map.rs | 4 +- tests/ui/manual_filter_map.fixed | 44 +++++++++++--------- tests/ui/manual_filter_map.rs | 59 ++++++++++++++++----------- tests/ui/manual_filter_map.stderr | 74 +++++++++++++++++++++------------- tests/ui/manual_find_map.fixed | 48 +++++++++++++--------- tests/ui/manual_find_map.rs | 61 ++++++++++++++++++---------- tests/ui/manual_find_map.stderr | 74 ++++++++++++++++++++++------------ 7 files changed, 227 insertions(+), 137 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 6cabe74fdef..7127d8242d8 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -181,9 +181,11 @@ pub(super) fn check<'tcx>( } fn acceptable_methods(method: &PathSegment<'_>) -> bool { - let methods: [Symbol; 6] = [ + let methods: [Symbol; 8] = [ sym::clone, sym::as_ref, + sym!(copied), + sym!(cloned), sym!(as_deref), sym!(as_mut), sym!(as_deref_mut), diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index 9de7040000a..de0d8614889 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -36,44 +36,52 @@ fn to_res(_: T) -> Result { unimplemented!() } -struct OptionFoo { - field: Option, -} - -struct ResultFoo { - field: Result, +struct Issue8920<'a> { + option_field: Option, + result_field: Result, + ref_field: Option<&'a usize>, } fn issue_8920() { - let vec = vec![OptionFoo { - field: Some(String::from("str")), + let mut vec = vec![Issue8920 { + option_field: Some(String::from("str")), + result_field: Ok(String::from("str")), + ref_field: Some(&1), }]; + let _ = vec .iter() - .filter_map(|f| f.field.clone()); + .filter_map(|f| f.option_field.clone()); - let mut vec = vec![ResultFoo { - field: Ok(String::from("str")), - }]; - let _ = vec.iter().filter_map(|f| f.field.clone().ok()); + let _ = vec + .iter() + .filter_map(|f| f.ref_field.cloned()); + + let _ = vec + .iter() + .filter_map(|f| f.ref_field.copied()); + + let _ = vec + .iter() + .filter_map(|f| f.result_field.clone().ok()); let _ = vec .iter() - .filter_map(|f| f.field.as_ref().ok()); + .filter_map(|f| f.result_field.as_ref().ok()); let _ = vec .iter() - .filter_map(|f| f.field.as_deref().ok()); + .filter_map(|f| f.result_field.as_deref().ok()); let _ = vec .iter_mut() - .filter_map(|f| f.field.as_mut().ok()); + .filter_map(|f| f.result_field.as_mut().ok()); let _ = vec .iter_mut() - .filter_map(|f| f.field.as_deref_mut().ok()); + .filter_map(|f| f.result_field.as_deref_mut().ok()); let _ = vec .iter() - .filter_map(|f| f.field.to_owned().ok()); + .filter_map(|f| f.result_field.to_owned().ok()); } diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 6766078d694..bd6516f038b 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -36,50 +36,61 @@ fn to_res(_: T) -> Result { unimplemented!() } -struct OptionFoo { - field: Option, -} - -struct ResultFoo { - field: Result, +struct Issue8920<'a> { + option_field: Option, + result_field: Result, + ref_field: Option<&'a usize>, } fn issue_8920() { - let vec = vec![OptionFoo { - field: Some(String::from("str")), + let mut vec = vec![Issue8920 { + option_field: Some(String::from("str")), + result_field: Ok(String::from("str")), + ref_field: Some(&1), }]; + let _ = vec .iter() - .filter(|f| f.field.is_some()) - .map(|f| f.field.clone().unwrap()); + .filter(|f| f.option_field.is_some()) + .map(|f| f.option_field.clone().unwrap()); - let mut vec = vec![ResultFoo { - field: Ok(String::from("str")), - }]; - let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); + let _ = vec + .iter() + .filter(|f| f.ref_field.is_some()) + .map(|f| f.ref_field.cloned().unwrap()); + + let _ = vec + .iter() + .filter(|f| f.ref_field.is_some()) + .map(|f| f.ref_field.copied().unwrap()); + + let _ = vec + .iter() + .filter(|f| f.result_field.is_ok()) + .map(|f| f.result_field.clone().unwrap()); let _ = vec .iter() - .filter(|f| f.field.is_ok()) - .map(|f| f.field.as_ref().unwrap()); + .filter(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_ref().unwrap()); let _ = vec .iter() - .filter(|f| f.field.is_ok()) - .map(|f| f.field.as_deref().unwrap()); + .filter(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_deref().unwrap()); let _ = vec .iter_mut() - .filter(|f| f.field.is_ok()) - .map(|f| f.field.as_mut().unwrap()); + .filter(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_mut().unwrap()); let _ = vec .iter_mut() - .filter(|f| f.field.is_ok()) - .map(|f| f.field.as_deref_mut().unwrap()); + .filter(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_deref_mut().unwrap()); let _ = vec .iter() - .filter(|f| f.field.is_ok()) - .map(|f| f.field.to_owned().unwrap()); + .filter(|f| f.result_field.is_ok()) + .map(|f| f.result_field.to_owned().unwrap()); } diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index 5e67ca348fa..465f1b19110 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -19,58 +19,76 @@ LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_o | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:53:10 + --> $DIR/manual_filter_map.rs:54:10 | -LL | .filter(|f| f.field.is_some()) +LL | .filter(|f| f.option_field.is_some()) | __________^ -LL | | .map(|f| f.field.clone().unwrap()); - | |__________________________________________^ help: try: `filter_map(|f| f.field.clone())` +LL | | .map(|f| f.option_field.clone().unwrap()); + | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:59:24 + --> $DIR/manual_filter_map.rs:59:10 | -LL | let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|f| f.field.clone().ok())` +LL | .filter(|f| f.ref_field.is_some()) + | __________^ +LL | | .map(|f| f.ref_field.cloned().unwrap()); + | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:64:10 + | +LL | .filter(|f| f.ref_field.is_some()) + | __________^ +LL | | .map(|f| f.ref_field.copied().unwrap()); + | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:69:10 + | +LL | .filter(|f| f.result_field.is_ok()) + | __________^ +LL | | .map(|f| f.result_field.clone().unwrap()); + | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:63:10 + --> $DIR/manual_filter_map.rs:74:10 | -LL | .filter(|f| f.field.is_ok()) +LL | .filter(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_ref().unwrap()); - | |___________________________________________^ help: try: `filter_map(|f| f.field.as_ref().ok())` +LL | | .map(|f| f.result_field.as_ref().unwrap()); + | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:68:10 + --> $DIR/manual_filter_map.rs:79:10 | -LL | .filter(|f| f.field.is_ok()) +LL | .filter(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_deref().unwrap()); - | |_____________________________________________^ help: try: `filter_map(|f| f.field.as_deref().ok())` +LL | | .map(|f| f.result_field.as_deref().unwrap()); + | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:73:10 + --> $DIR/manual_filter_map.rs:84:10 | -LL | .filter(|f| f.field.is_ok()) +LL | .filter(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_mut().unwrap()); - | |___________________________________________^ help: try: `filter_map(|f| f.field.as_mut().ok())` +LL | | .map(|f| f.result_field.as_mut().unwrap()); + | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:78:10 + --> $DIR/manual_filter_map.rs:89:10 | -LL | .filter(|f| f.field.is_ok()) +LL | .filter(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_deref_mut().unwrap()); - | |_________________________________________________^ help: try: `filter_map(|f| f.field.as_deref_mut().ok())` +LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); + | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:83:10 + --> $DIR/manual_filter_map.rs:94:10 | -LL | .filter(|f| f.field.is_ok()) +LL | .filter(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.to_owned().unwrap()); - | |_____________________________________________^ help: try: `filter_map(|f| f.field.to_owned().ok())` +LL | | .map(|f| f.result_field.to_owned().unwrap()); + | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())` -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index e7b5081ea59..d69b6c1dcf3 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -36,40 +36,52 @@ fn to_res(_: T) -> Result { unimplemented!() } -struct OptionFoo { - field: Option, -} - -struct ResultFoo { - field: Result, +struct Issue8920<'a> { + option_field: Option, + result_field: Result, + ref_field: Option<&'a usize>, } fn issue_8920() { - let vec = vec![OptionFoo { - field: Some(String::from("str")), + let mut vec = vec![Issue8920 { + option_field: Some(String::from("str")), + result_field: Ok(String::from("str")), + ref_field: Some(&1), }]; - let _ = vec.iter().find_map(|f| f.field.clone()); - let mut vec = vec![ResultFoo { - field: Ok(String::from("str")), - }]; - let _ = vec.iter().find_map(|f| f.field.clone().ok()); + let _ = vec + .iter() + .find_map(|f| f.option_field.clone()); + + let _ = vec + .iter() + .find_map(|f| f.ref_field.cloned()); - let _ = vec.iter().find_map(|f| f.field.as_ref().ok()); + let _ = vec + .iter() + .find_map(|f| f.ref_field.copied()); + + let _ = vec + .iter() + .find_map(|f| f.result_field.clone().ok()); + + let _ = vec + .iter() + .find_map(|f| f.result_field.as_ref().ok()); let _ = vec .iter() - .find_map(|f| f.field.as_deref().ok()); + .find_map(|f| f.result_field.as_deref().ok()); let _ = vec .iter_mut() - .find_map(|f| f.field.as_mut().ok()); + .find_map(|f| f.result_field.as_mut().ok()); let _ = vec .iter_mut() - .find_map(|f| f.field.as_deref_mut().ok()); + .find_map(|f| f.result_field.as_deref_mut().ok()); let _ = vec .iter() - .find_map(|f| f.field.to_owned().ok()); + .find_map(|f| f.result_field.to_owned().ok()); } diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index 46badbb9a18..1c4e18e31c8 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -36,44 +36,61 @@ fn to_res(_: T) -> Result { unimplemented!() } -struct OptionFoo { - field: Option, -} - -struct ResultFoo { - field: Result, +struct Issue8920<'a> { + option_field: Option, + result_field: Result, + ref_field: Option<&'a usize>, } fn issue_8920() { - let vec = vec![OptionFoo { - field: Some(String::from("str")), + let mut vec = vec![Issue8920 { + option_field: Some(String::from("str")), + result_field: Ok(String::from("str")), + ref_field: Some(&1), }]; - let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap()); - let mut vec = vec![ResultFoo { - field: Ok(String::from("str")), - }]; - let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); + let _ = vec + .iter() + .find(|f| f.option_field.is_some()) + .map(|f| f.option_field.clone().unwrap()); + + let _ = vec + .iter() + .find(|f| f.ref_field.is_some()) + .map(|f| f.ref_field.cloned().unwrap()); - let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.as_ref().unwrap()); + let _ = vec + .iter() + .find(|f| f.ref_field.is_some()) + .map(|f| f.ref_field.copied().unwrap()); + + let _ = vec + .iter() + .find(|f| f.result_field.is_ok()) + .map(|f| f.result_field.clone().unwrap()); + + let _ = vec + .iter() + .find(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_ref().unwrap()); let _ = vec .iter() - .find(|f| f.field.is_ok()) - .map(|f| f.field.as_deref().unwrap()); + .find(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_deref().unwrap()); let _ = vec .iter_mut() - .find(|f| f.field.is_ok()) - .map(|f| f.field.as_mut().unwrap()); + .find(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_mut().unwrap()); let _ = vec .iter_mut() - .find(|f| f.field.is_ok()) - .map(|f| f.field.as_deref_mut().unwrap()); + .find(|f| f.result_field.is_ok()) + .map(|f| f.result_field.as_deref_mut().unwrap()); let _ = vec .iter() - .find(|f| f.field.is_ok()) - .map(|f| f.field.to_owned().unwrap()); + .find(|f| f.result_field.is_ok()) + .map(|f| f.result_field.to_owned().unwrap()); } diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index 2b6955a17df..9dea42b7686 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -19,54 +19,76 @@ LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:51:24 + --> $DIR/manual_find_map.rs:54:10 | -LL | let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone())` +LL | .find(|f| f.option_field.is_some()) + | __________^ +LL | | .map(|f| f.option_field.clone().unwrap()); + | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:59:10 + | +LL | .find(|f| f.ref_field.is_some()) + | __________^ +LL | | .map(|f| f.ref_field.cloned().unwrap()); + | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:56:24 + --> $DIR/manual_find_map.rs:64:10 | -LL | let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone().ok())` +LL | .find(|f| f.ref_field.is_some()) + | __________^ +LL | | .map(|f| f.ref_field.copied().unwrap()); + | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:58:24 + --> $DIR/manual_find_map.rs:69:10 | -LL | let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.as_ref().unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.as_ref().ok())` +LL | .find(|f| f.result_field.is_ok()) + | __________^ +LL | | .map(|f| f.result_field.clone().unwrap()); + | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:74:10 + | +LL | .find(|f| f.result_field.is_ok()) + | __________^ +LL | | .map(|f| f.result_field.as_ref().unwrap()); + | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:62:10 + --> $DIR/manual_find_map.rs:79:10 | -LL | .find(|f| f.field.is_ok()) +LL | .find(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_deref().unwrap()); - | |_____________________________________________^ help: try: `find_map(|f| f.field.as_deref().ok())` +LL | | .map(|f| f.result_field.as_deref().unwrap()); + | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:67:10 + --> $DIR/manual_find_map.rs:84:10 | -LL | .find(|f| f.field.is_ok()) +LL | .find(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_mut().unwrap()); - | |___________________________________________^ help: try: `find_map(|f| f.field.as_mut().ok())` +LL | | .map(|f| f.result_field.as_mut().unwrap()); + | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:72:10 + --> $DIR/manual_find_map.rs:89:10 | -LL | .find(|f| f.field.is_ok()) +LL | .find(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.as_deref_mut().unwrap()); - | |_________________________________________________^ help: try: `find_map(|f| f.field.as_deref_mut().ok())` +LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); + | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:77:10 + --> $DIR/manual_find_map.rs:94:10 | -LL | .find(|f| f.field.is_ok()) +LL | .find(|f| f.result_field.is_ok()) | __________^ -LL | | .map(|f| f.field.to_owned().unwrap()); - | |_____________________________________________^ help: try: `find_map(|f| f.field.to_owned().ok())` +LL | | .map(|f| f.result_field.to_owned().unwrap()); + | |____________________________________________________^ help: try: `find_map(|f| f.result_field.to_owned().ok())` -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors -- cgit 1.4.1-3-g733a5 From 9aeed6b9bfea42e4a580ad6e7289b4fc72b4365c Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sun, 5 Jun 2022 15:24:41 -0400 Subject: Improve lint doc consistency --- clippy_lints/src/assertions_on_constants.rs | 3 - clippy_lints/src/async_yields_async.rs | 1 + clippy_lints/src/await_holding_invalid.rs | 2 - clippy_lints/src/bool_assert_comparison.rs | 5 +- clippy_lints/src/borrow_deref_ref.rs | 13 +- clippy_lints/src/casts/mod.rs | 46 +++-- clippy_lints/src/comparison_chain.rs | 1 - clippy_lints/src/dbg_macro.rs | 5 +- clippy_lints/src/default.rs | 11 +- clippy_lints/src/dereference.rs | 16 +- clippy_lints/src/derivable_impls.rs | 4 +- clippy_lints/src/enum_variants.rs | 3 +- clippy_lints/src/eq_op.rs | 10 +- clippy_lints/src/eta_reduction.rs | 8 +- clippy_lints/src/excessive_bools.rs | 3 +- clippy_lints/src/float_literal.rs | 5 +- clippy_lints/src/functions/mod.rs | 5 +- clippy_lints/src/get_first.rs | 3 +- clippy_lints/src/implicit_saturating_sub.rs | 14 +- clippy_lints/src/indexing_slicing.rs | 45 ++--- clippy_lints/src/infinite_iter.rs | 1 + clippy_lints/src/inherent_to_string.rs | 12 +- clippy_lints/src/int_plus_one.rs | 3 +- clippy_lints/src/integer_division.rs | 5 +- clippy_lints/src/items_after_statements.rs | 3 +- clippy_lints/src/large_const_arrays.rs | 5 +- clippy_lints/src/large_enum_variant.rs | 4 +- clippy_lints/src/let_underscore.rs | 24 +-- clippy_lints/src/lib.rs | 5 +- clippy_lints/src/lifetimes.rs | 12 +- clippy_lints/src/literal_representation.rs | 28 ++- clippy_lints/src/loops/mod.rs | 20 +- clippy_lints/src/matches/mod.rs | 68 ++++--- clippy_lints/src/methods/mod.rs | 207 +++++++++++++-------- clippy_lints/src/misc.rs | 30 +-- clippy_lints/src/misc_early/mod.rs | 71 ++++--- clippy_lints/src/mixed_read_write_in_expression.rs | 6 +- clippy_lints/src/mut_reference.rs | 15 +- clippy_lints/src/mutex_atomic.rs | 11 +- clippy_lints/src/needless_bool.rs | 12 +- clippy_lints/src/needless_borrowed_ref.rs | 9 +- clippy_lints/src/needless_update.rs | 7 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 14 +- clippy_lints/src/neg_multiply.rs | 9 +- clippy_lints/src/non_copy_const.rs | 14 +- clippy_lints/src/octal_escapes.rs | 5 +- clippy_lints/src/pass_by_ref_or_value.rs | 12 +- clippy_lints/src/ptr.rs | 22 ++- clippy_lints/src/ranges.rs | 43 +++-- clippy_lints/src/redundant_closure_call.rs | 11 +- clippy_lints/src/reference.rs | 5 +- clippy_lints/src/return_self_not_must_use.rs | 14 +- clippy_lints/src/shadow.rs | 15 +- clippy_lints/src/slow_vector_initialization.rs | 7 +- clippy_lints/src/strings.rs | 18 +- clippy_lints/src/trait_bounds.rs | 3 +- clippy_lints/src/unicode.rs | 3 +- clippy_lints/src/unused_async.rs | 5 +- clippy_lints/src/useless_conversion.rs | 5 +- clippy_lints/src/utils/internal_lints.rs | 22 +-- clippy_lints/src/vec.rs | 8 +- clippy_lints/src/wildcard_imports.rs | 14 +- clippy_lints/src/write.rs | 33 +++- clippy_lints/src/zero_div_zero.rs | 5 +- 64 files changed, 621 insertions(+), 427 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index c82837746bd..2705ffffdcb 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -14,9 +14,6 @@ declare_clippy_lint! { /// Will be optimized out by the compiler or should probably be replaced by a /// `panic!()` or `unreachable!()` /// - /// ### Known problems - /// None - /// /// ### Example /// ```rust,ignore /// assert!(false) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 0619490e73c..aef21bfc36c 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -24,6 +24,7 @@ declare_clippy_lint! { /// }; /// } /// ``` + /// /// Use instead: /// ```rust /// async fn foo() {} diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 5b7c4591504..eee5f90d178 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -140,8 +140,6 @@ declare_clippy_lint! { /// from a memory access perspective but will cause bugs at runtime if they /// are held in such a way. /// - /// ### Known problems - /// /// ### Example /// /// ```toml diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index c50e214be28..95abe8aa59f 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -17,11 +17,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// assert_eq!("a".is_empty(), false); /// assert_ne!("a".is_empty(), true); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// assert!(!"a".is_empty()); /// ``` #[clippy::version = "1.53.0"] diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index ec2f31cf673..1582ec9ee5c 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Dereferencing and then borrowing a reference value has no effect in most cases. /// /// ### Known problems - /// false negative on such code: + /// False negative on such code: /// ``` /// let x = &12; /// let addr_x = &x as *const _ as usize; @@ -29,17 +29,20 @@ declare_clippy_lint! { /// /// ### Example /// ```rust + /// fn foo(_x: &str) {} + /// /// let s = &String::new(); /// - /// // Bad /// let a: &String = &* s; /// foo(&*s); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # fn foo(_x: &str) {} + /// # let s = &String::new(); /// let a: &String = s; /// foo(&**s); - /// - /// fn foo(_: &str){ } /// ``` #[clippy::version = "1.59.0"] pub BORROW_DEREF_REF, diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index daf3b7b4ce4..fe8e372b6f5 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -219,13 +219,16 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// fn fun() -> i32 { 1 } - /// let a = fun as i64; + /// # let _ = + /// fun as i64; + /// ``` /// - /// // Good - /// fn fun2() -> i32 { 1 } - /// let a = fun2 as usize; + /// Use instead: + /// ```rust + /// # fn fun() -> i32 { 1 } + /// # let _ = + /// fun as usize; /// ``` #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, @@ -245,17 +248,20 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// fn fn1() -> i16 { /// 1 /// }; - /// let _ = fn1 as i32; + /// # let _ = + /// fn1 as i32; + /// ``` /// - /// // Better: Cast to usize first, then comment with the reason for the truncation - /// fn fn2() -> i16 { + /// Use instead: + /// ```rust + /// // Cast to usize first, then comment with the reason for the truncation + /// fn fn1() -> i16 { /// 1 /// }; - /// let fn_ptr = fn2 as usize; + /// let fn_ptr = fn1 as usize; /// let fn_ptr_truncated = fn_ptr as i32; /// ``` #[clippy::version = "pre 1.29.0"] @@ -277,23 +283,31 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad: fn1 is cast as `usize` + /// // fn1 is cast as `usize` /// fn fn1() -> u16 { /// 1 /// }; - /// let _ = fn1 as usize; + /// # let _ = + /// fn1 as usize; + /// ``` /// - /// // Good: maybe you intended to call the function? + /// Use instead: + /// ```rust + /// // maybe you intended to call the function? /// fn fn2() -> u16 { /// 1 /// }; - /// let _ = fn2() as usize; + /// # let _ = + /// fn2() as usize; + /// + /// // or /// - /// // Good: maybe you intended to cast it to a function type? + /// // maybe you intended to cast it to a function type? /// fn fn3() -> u16 { /// 1 /// } - /// let _ = fn3 as fn() -> u16; + /// # let _ = + /// fn3 as fn() -> u16; /// ``` #[clippy::version = "1.58.0"] pub FN_TO_NUMERIC_CAST_ANY, diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 913e081af3b..a05b41eb3ab 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -35,7 +35,6 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// /// ```rust,ignore /// use std::cmp::Ordering; /// # fn a() {} diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 17deccf8c39..fe9f4f9ae3c 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -18,10 +18,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// dbg!(true) + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// true /// ``` #[clippy::version = "1.34.0"] diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 243dfd3a461..d99a1aa2969 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -18,15 +18,16 @@ declare_clippy_lint! { /// Checks for literal calls to `Default::default()`. /// /// ### Why is this bad? - /// It's more clear to the reader to use the name of the type whose default is - /// being gotten than the generic `Default`. + /// It's easier for the reader if the name of the type is used, rather than the + /// generic `Default`. /// /// ### Example /// ```rust - /// // Bad /// let s: String = Default::default(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let s = String::default(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -47,13 +48,13 @@ declare_clippy_lint! { /// Assignments to patterns that are of tuple type are not linted. /// /// ### Example - /// Bad: /// ``` /// # #[derive(Default)] /// # struct A { i: i32 } /// let mut a: A = Default::default(); /// a.i = 42; /// ``` + /// /// Use instead: /// ``` /// # #[derive(Default)] diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 8288f7a8b9b..dee83e60d7e 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -30,13 +30,14 @@ declare_clippy_lint! { /// let a: &mut String = &mut String::from("foo"); /// let b: &str = a.deref(); /// ``` - /// Could be written as: + /// + /// Use instead: /// ```rust /// let a: &mut String = &mut String::from("foo"); /// let b = &*a; /// ``` /// - /// This lint excludes + /// This lint excludes: /// ```rust,ignore /// let _ = d.unwrap().deref(); /// ``` @@ -59,11 +60,13 @@ declare_clippy_lint! { /// ```rust /// fn fun(_a: &i32) {} /// - /// // Bad /// let x: &i32 = &&&&&&5; /// fun(&x); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # fn fun(_a: &i32) {} /// let x: &i32 = &5; /// fun(x); /// ``` @@ -82,13 +85,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let x = Some(""); /// if let Some(ref x) = x { /// // use `x` here /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let x = Some(""); /// if let Some(x) = x { /// // use `&x` here diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index e98691fd5bb..4d7f4076d7b 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -30,8 +30,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// Could be written as: - /// + /// Use instead: /// ```rust /// #[derive(Default)] /// struct Foo { @@ -45,7 +44,6 @@ declare_clippy_lint! { /// specialized than what derive will produce. This lint can't detect the manual `impl` /// has exactly equal bounds, and therefore this lint is disabled for types with /// generic parameters. - /// #[clippy::version = "1.57.0"] pub DERIVABLE_IMPLS, complexity, diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 263a5b573c9..23b75104570 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -60,7 +60,8 @@ declare_clippy_lint! { /// struct BlackForestCake; /// } /// ``` - /// Could be written as: + /// + /// Use instead: /// ```rust /// mod cake { /// struct BlackForest; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index c3176d987c6..2f4c90d07cf 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -52,15 +52,13 @@ declare_clippy_lint! { /// ### Why is this bad? /// It is more idiomatic to dereference the other argument. /// - /// ### Known problems - /// None - /// /// ### Example - /// ```ignore - /// // Bad + /// ```rust,ignore /// &x == y + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// x == *y /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 530d6d4de35..aa537aa90ec 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -34,14 +34,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// xs.map(|x| foo(x)) + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore + /// // where `foo(_)` is a plain function that takes the exact argument type of `x`. /// xs.map(foo) /// ``` - /// where `foo(_)` is a plain function that takes the exact argument type of - /// `x`. #[clippy::version = "pre 1.29.0"] pub REDUNDANT_CLOSURE, style, diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index a2af10e2ba5..f7a92bc0795 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -54,12 +54,11 @@ declare_clippy_lint! { /// API easier to use. /// /// ### Example - /// Bad: /// ```rust,ignore /// fn f(is_round: bool, is_hot: bool) { ... } /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// enum Shape { /// Round, diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index f850ea31f4d..f2e07980963 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -45,10 +45,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let _: f32 = 16_777_217.0; // 16_777_216.0 + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let _: f32 = 16_777_216.0; /// let _: f64 = 16_777_217.0; /// ``` diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index ad031cbc09d..73261fb8a44 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -76,12 +76,13 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// pub fn foo(x: *const u8) { /// println!("{}", unsafe { *x }); /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// pub unsafe fn foo(x: *const u8) { /// println!("{}", unsafe { *x }); /// } diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs index 0748ab45252..529f7babaa5 100644 --- a/clippy_lints/src/get_first.rs +++ b/clippy_lints/src/get_first.rs @@ -20,13 +20,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let x = vec![2, 3, 5]; /// let first_element = x.get(0); /// ``` + /// /// Use instead: /// ```rust - /// // Good /// let x = vec![2, 3, 5]; /// let first_element = x.first(); /// ``` diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index ae4158662d4..9d858e0c212 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -16,17 +16,15 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// let end: u32 = 10; - /// let start: u32 = 5; - /// - /// let mut i: u32 = end - start; - /// - /// // Bad + /// # let mut i: u32 = 0; /// if i != 0 { /// i -= 1; /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let mut i: u32 = 0; /// i = i.saturating_sub(1); /// ``` #[clippy::version = "1.44.0"] @@ -48,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Check if the conditional expression is a binary operation if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind; - // Ensure that the binary operator is >, != and < + // Ensure that the binary operator is >, !=, or < if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node; // Check if assign operation is done diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 4ba7477add8..301686612a1 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -17,19 +17,20 @@ declare_clippy_lint! { /// ### Why is this bad? /// This will always panic at runtime. /// - /// ### Known problems - /// Hopefully none. - /// /// ### Example - /// ```no_run + /// ```rust,no_run /// # #![allow(const_err)] /// let x = [1, 2, 3, 4]; /// - /// // Bad /// x[9]; /// &x[2..9]; + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = [1, 2, 3, 4]; + /// // Index within bounds /// - /// // Good /// x[0]; /// x[3]; /// ``` @@ -49,42 +50,34 @@ declare_clippy_lint! { /// Indexing and slicing can panic at runtime and there are /// safe alternatives. /// - /// ### Known problems - /// Hopefully none. - /// /// ### Example /// ```rust,no_run /// // Vector /// let x = vec![0; 5]; /// - /// // Bad /// x[2]; /// &x[2..100]; - /// &x[2..]; - /// &x[..100]; - /// - /// // Good - /// x.get(2); - /// x.get(2..100); - /// x.get(2..); - /// x.get(..100); /// /// // Array /// let y = [0, 1, 2, 3]; /// - /// // Bad /// &y[10..100]; /// &y[10..]; - /// &y[..100]; + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = vec![0; 5]; + /// # let y = [0, 1, 2, 3]; + /// # let _ = + /// x.get(2); + /// # let _ = + /// x.get(2..100); /// - /// // Good - /// &y[2..]; - /// &y[..2]; - /// &y[0..3]; + /// # let _ = /// y.get(10); + /// # let _ = /// y.get(10..100); - /// y.get(10..); - /// y.get(..100); /// ``` #[clippy::version = "pre 1.29.0"] pub INDEXING_SLICING, diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index b2b9889f5dc..fc8e473dd9e 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// ### Example /// ```rust /// let infinite_iter = 0..; + /// # let _ = /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 55c04a1186f..39f68a8a1b4 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -14,12 +14,8 @@ declare_clippy_lint! { /// ### Why is this bad? /// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. /// - /// ### Known problems - /// None - /// /// ### Example /// ```rust - /// // Bad /// pub struct A; /// /// impl A { @@ -29,8 +25,8 @@ declare_clippy_lint! { /// } /// ``` /// + /// Use instead: /// ```rust - /// // Good /// use std::fmt; /// /// pub struct A; @@ -54,12 +50,8 @@ declare_clippy_lint! { /// ### Why is this bad? /// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. /// - /// ### Known problems - /// None - /// /// ### Example /// ```rust - /// // Bad /// use std::fmt; /// /// pub struct A; @@ -77,8 +69,8 @@ declare_clippy_lint! { /// } /// ``` /// + /// Use instead: /// ```rust - /// // Good /// use std::fmt; /// /// pub struct A; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 8db7b307ddb..9a944def3eb 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -21,8 +21,7 @@ declare_clippy_lint! { /// if x >= y + 1 {} /// ``` /// - /// Could be written as: - /// + /// Use instead: /// ```rust /// # let x = 1; /// # let y = 1; diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index fa786205678..3effba56826 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -15,11 +15,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let x = 3 / 2; /// println!("{}", x); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let x = 3f32 / 2f32; /// println!("{}", x); /// ``` diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index cdefe627efd..46d439b4497 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -17,7 +17,6 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// fn foo() { /// println!("cake"); /// } @@ -31,8 +30,8 @@ declare_clippy_lint! { /// } /// ``` /// + /// Use instead: /// ```rust - /// // Good /// fn foo() { /// println!("cake"); /// } diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 27db6388136..0b972bc3916 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -21,10 +21,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// pub const a = [0u32; 1_000_000]; + /// ``` /// - /// // Good + /// Use instead: + /// ```rust.ignore /// pub static a = [0u32; 1_000_000]; /// ``` #[clippy::version = "1.44.0"] diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 63ac092dfaf..9be057bcf90 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -38,12 +38,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// enum Test { /// A(i32), /// B([i32; 8000]), /// } + /// ``` /// + /// Use instead: + /// ```rust /// // Possibly better /// enum Test2 { /// A(i32), diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index cb1ef01f5ba..26c540e2223 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -45,13 +45,11 @@ declare_clippy_lint! { /// `std::mem::drop` conveys your intention better and is less error-prone. /// /// ### Example - /// - /// Bad: /// ```rust,ignore /// let _ = mutex.lock(); /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// let _lock = mutex.lock(); /// ``` @@ -75,24 +73,20 @@ declare_clippy_lint! { /// better and is less error-prone. /// /// ### Example - /// - /// Bad: - /// ```rust,ignore - /// struct Droppable; - /// impl Drop for Droppable { - /// fn drop(&mut self) {} - /// } + /// ```rust + /// # struct DroppableItem; /// { - /// let _ = Droppable; - /// // ^ dropped here + /// let _ = DroppableItem; + /// // ^ dropped here /// /* more code */ /// } /// ``` /// - /// Good: - /// ```rust,ignore + /// Use instead: + /// ```rust + /// # struct DroppableItem; /// { - /// let _droppable = Droppable; + /// let _droppable = DroppableItem; /// /* more code */ /// // dropped at end of scope /// } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ee0416fc0ff..85f7ff149d1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -88,10 +88,11 @@ use rustc_session::Session; /// /// /// /// ### Example /// /// ```rust -/// /// // Bad /// /// Insert a short example of code that triggers the lint +/// /// ``` /// /// -/// /// // Good +/// /// Use instead: +/// /// ```rust /// /// Insert a short example of improved code that doesn't trigger the lint /// /// ``` /// pub LINT_NAME, diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 070c7e59142..93f5663312f 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -36,12 +36,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad: unnecessary lifetime annotations + /// // Unnecessary lifetime annotations /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { /// x /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// fn elided(x: &u8, y: u8) -> &u8 { /// x /// } @@ -65,12 +67,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad: unnecessary lifetimes + /// // unnecessary lifetimes /// fn unused_lifetime<'a>(x: u8) { /// // .. /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// fn no_lifetime(x: u8) { /// // ... /// } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 9998712b852..cbd084c4168 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -22,11 +22,16 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let x: u64 = 61864918973511; + /// # let _: u64 = + /// 61864918973511 + /// # ; + /// ``` /// - /// // Good - /// let x: u64 = 61_864_918_973_511; + /// Use instead: + /// ```rust + /// # let _: u64 = + /// 61_864_918_973_511 + /// # ; /// ``` #[clippy::version = "pre 1.29.0"] pub UNREADABLE_LITERAL, @@ -66,11 +71,16 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let x: u64 = 618_64_9189_73_511; + /// # let _: u64 = + /// 618_64_9189_73_511 + /// # ; + /// ``` /// - /// // Good - /// let x: u64 = 61_864_918_973_511; + /// Use instead: + /// ```rust + /// # let _: u64 = + /// 61_864_918_973_511 + /// # ; /// ``` #[clippy::version = "pre 1.29.0"] pub INCONSISTENT_DIGIT_GROUPING, @@ -125,9 +135,11 @@ declare_clippy_lint! { /// readable than a decimal representation. /// /// ### Example + /// ```text /// `255` => `0xFF` /// `65_535` => `0xFFFF` /// `4_042_322_160` => `0xF0F0_F0F0` + /// ``` #[clippy::version = "pre 1.29.0"] pub DECIMAL_LITERAL_REPRESENTATION, restriction, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index e32b228e104..acf974c586a 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -42,7 +42,8 @@ declare_clippy_lint! { /// dst[i + 64] = src[i]; /// } /// ``` - /// Could be written as: + /// + /// Use instead: /// ```rust /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; @@ -70,7 +71,8 @@ declare_clippy_lint! { /// println!("{}", vec[i]); /// } /// ``` - /// Could be written as: + /// + /// Use instead: /// ```rust /// let vec = vec!['a', 'b', 'c']; /// for i in vec { @@ -103,7 +105,8 @@ declare_clippy_lint! { /// // .. /// } /// ``` - /// can be rewritten to + /// + /// Use instead: /// ```rust /// # let y = vec![1]; /// for x in &y { @@ -286,7 +289,8 @@ declare_clippy_lint! { /// i += 1; /// } /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} @@ -473,7 +477,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// This kind of operation can be expressed more succinctly with - /// `vec![item;SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also + /// `vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also /// have better performance. /// /// ### Example @@ -488,7 +492,8 @@ declare_clippy_lint! { /// vec.push(item2); /// } /// ``` - /// could be written as + /// + /// Use instead: /// ```rust /// let item1 = 2; /// let item2 = 3; @@ -516,7 +521,8 @@ declare_clippy_lint! { /// println!("{}", item); /// } /// ``` - /// could be written as + /// + /// Use instead: /// ```rust /// let item1 = 2; /// let item = &item1; diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index d1e42f39e47..3e765173fb9 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -43,13 +43,16 @@ declare_clippy_lint! { /// ```rust /// # fn bar(stool: &str) {} /// # let x = Some("abc"); - /// // Bad /// match x { /// Some(ref foo) => bar(foo), /// _ => (), /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # fn bar(stool: &str) {} + /// # let x = Some("abc"); /// if let Some(ref foo) = x { /// bar(foo); /// } @@ -114,14 +117,15 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// match x { /// &A(ref y) => foo(y), /// &B => bar(), /// _ => frob(&x), /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// match *x { /// A(ref y) => foo(y), /// B => bar(), @@ -227,13 +231,16 @@ declare_clippy_lint! { /// ```rust /// let x: Option<()> = None; /// - /// // Bad /// let r: Option<&()> = match x { /// None => None, /// Some(ref v) => Some(v), /// }; + /// ``` + /// + /// Use instead: + /// ```rust + /// let x: Option<()> = None; /// - /// // Good /// let r: Option<&()> = x.as_ref(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -257,13 +264,16 @@ declare_clippy_lint! { /// ```rust /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); - /// // Bad /// match x { /// Foo::A(_) => {}, /// _ => {}, /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # enum Foo { A(usize), B(usize) } + /// # let x = Foo::B(1); /// match x { /// Foo::A(_) => {}, /// Foo::B(_) => {}, @@ -290,14 +300,17 @@ declare_clippy_lint! { /// ```rust /// # enum Foo { A, B, C } /// # let x = Foo::B; - /// // Bad /// match x { /// Foo::A => {}, /// Foo::B => {}, /// _ => {}, /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # enum Foo { A, B, C } + /// # let x = Foo::B; /// match x { /// Foo::A => {}, /// Foo::B => {}, @@ -320,14 +333,17 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// match "foo" { + /// # let s = "foo"; + /// match s { /// "a" => {}, /// "bar" | _ => {}, /// } + /// ``` /// - /// // Good - /// match "foo" { + /// Use instead: + /// ```rust + /// # let s = "foo"; + /// match s { /// "a" => {}, /// _ => {}, /// } @@ -389,15 +405,17 @@ declare_clippy_lint! { /// ```rust /// # let a = 1; /// # let b = 2; - /// - /// // Bad /// match (a, b) { /// (c, d) => { /// // useless match /// } /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let a = 1; + /// # let b = 2; /// let (c, d) = (a, b); /// ``` #[clippy::version = "1.43.0"] @@ -419,13 +437,16 @@ declare_clippy_lint! { /// # struct A { a: i32 } /// let a = A { a: 5 }; /// - /// // Bad /// match a { /// A { a: 5, .. } => {}, /// _ => {}, /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # struct A { a: i32 } + /// # let a = A { a: 5 }; /// match a { /// A { a: 5 } => {}, /// _ => {}, @@ -509,7 +530,6 @@ declare_clippy_lint! { /// ```rust /// let x = Some(5); /// - /// // Bad /// let a = match x { /// Some(0) => true, /// _ => false, @@ -520,8 +540,11 @@ declare_clippy_lint! { /// } else { /// false /// }; + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// let x = Some(5); /// let a = matches!(x, Some(0)); /// ``` #[clippy::version = "1.47.0"] @@ -695,19 +718,18 @@ declare_clippy_lint! { /// let arr = vec![0, 1, 2, 3]; /// let idx = 1; /// - /// // Bad /// match arr[idx] { /// 0 => println!("{}", 0), /// 1 => println!("{}", 3), /// _ => {}, /// } /// ``` + /// /// Use instead: /// ```rust, no_run /// let arr = vec![0, 1, 2, 3]; /// let idx = 1; /// - /// // Good /// match arr.get(idx) { /// Some(0) => println!("{}", 0), /// Some(1) => println!("{}", 3), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7308e74c323..9d78f0a9fc1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -124,27 +124,27 @@ declare_clippy_lint! { /// It's often inefficient to clone all elements of an iterator, when eventually, only some /// of them will be consumed. /// + /// ### Known Problems + /// This `lint` removes the side of effect of cloning items in the iterator. + /// A code that relies on that side-effect could fail. + /// /// ### Examples /// ```rust /// # let vec = vec!["string".to_string()]; - /// - /// // Bad + /// # let _ = /// vec.iter().cloned().take(10); - /// - /// // Good - /// vec.iter().take(10).cloned(); - /// - /// // Bad + /// # let _ = /// vec.iter().cloned().last(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let vec = vec!["string".to_string()]; + /// # let _ = + /// vec.iter().take(10).cloned(); + /// # let _ = /// vec.iter().last().cloned(); - /// /// ``` - /// ### Known Problems - /// This `lint` removes the side of effect of cloning items in the iterator. - /// A code that relies on that side-effect could fail. - /// #[clippy::version = "1.59.0"] pub ITER_OVEREAGER_CLONED, perf, @@ -342,11 +342,12 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let x = Ok::<_, ()>(()); - /// - /// // Bad /// x.ok().expect("why did I do this again?"); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let x = Ok::<_, ()>(()); /// x.expect("why did I do this again?"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -390,12 +391,13 @@ declare_clippy_lint! { /// ### Examples /// ```rust /// # let x = Some(1); - /// - /// // Bad /// x.unwrap_or_else(Default::default); /// x.unwrap_or_else(u32::default); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let x = Some(1); /// x.unwrap_or_default(); /// ``` #[clippy::version = "1.56.0"] @@ -453,11 +455,12 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let opt = Some(1); - /// - /// // Bad /// opt.map_or(None, |a| Some(a + 1)); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let opt = Some(1); /// opt.and_then(|a| Some(a + 1)); /// ``` #[clippy::version = "pre 1.29.0"] @@ -475,13 +478,12 @@ declare_clippy_lint! { /// `_.ok()`. /// /// ### Example - /// Bad: /// ```rust /// # let r: Result = Ok(1); /// assert_eq!(Some(1), r.map_or(None, Some)); /// ``` /// - /// Good: + /// Use instead: /// ```rust /// # let r: Result = Ok(1); /// assert_eq!(Some(1), r.ok()); @@ -538,7 +540,8 @@ declare_clippy_lint! { /// # let vec = vec![1]; /// vec.iter().filter(|x| **x == 0).next(); /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// # let vec = vec![1]; /// vec.iter().find(|x| **x == 0); @@ -562,7 +565,8 @@ declare_clippy_lint! { /// # let vec = vec![1]; /// vec.iter().skip_while(|x| **x == 0).next(); /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// # let vec = vec![1]; /// vec.iter().find(|x| **x != 0); @@ -586,11 +590,16 @@ declare_clippy_lint! { /// let vec = vec![vec![1]]; /// let opt = Some(5); /// - /// // Bad + /// # let _ = /// vec.iter().map(|x| x.iter()).flatten(); /// opt.map(|x| Some(x * 2)).flatten(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let vec = vec![vec![1]]; + /// # let opt = Some(5); + /// # let _ = /// vec.iter().flat_map(|x| x.iter()); /// opt.and_then(|x| Some(x * 2)); /// ``` @@ -610,15 +619,16 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// Bad: /// ```rust + /// # let _ = /// (0_i32..10) /// .filter(|n| n.checked_add(1).is_some()) /// .map(|n| n.checked_add(1).unwrap()); /// ``` /// - /// Good: + /// Use instead: /// ```rust + /// # let _ = /// (0_i32..10).filter_map(|n| n.checked_add(1)); /// ``` #[clippy::version = "1.51.0"] @@ -637,14 +647,13 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// Bad: /// ```rust /// (0_i32..10) /// .find(|n| n.checked_add(1).is_some()) /// .map(|n| n.checked_add(1).unwrap()); /// ``` /// - /// Good: + /// Use instead: /// ```rust /// (0_i32..10).find_map(|n| n.checked_add(1)); /// ``` @@ -713,16 +722,20 @@ declare_clippy_lint! { /// ### Example /// ```rust /// let vec = vec![1]; + /// # let _ = /// vec.iter().find(|x| **x == 0).is_some(); /// - /// let _ = "hello world".find("world").is_none(); + /// # let _ = + /// "hello world".find("world").is_none(); /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); /// - /// let _ = !"hello world".contains("world"); + /// # let _ = + /// !"hello world".contains("world"); /// ``` #[clippy::version = "pre 1.29.0"] pub SEARCH_IS_SOME, @@ -744,7 +757,8 @@ declare_clippy_lint! { /// let name = "foo"; /// if name.chars().next() == Some('_') {}; /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// let name = "foo"; /// if name.starts_with('_') {}; @@ -899,10 +913,13 @@ declare_clippy_lint! { /// # use std::rc::Rc; /// let x = Rc::new(1); /// - /// // Bad /// x.clone(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # use std::rc::Rc; + /// # let x = Rc::new(1); /// Rc::clone(&x); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1034,11 +1051,13 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// _.split("x"); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// _.split('x'); + /// ``` #[clippy::version = "pre 1.29.0"] pub SINGLE_CHAR_PATTERN, perf, @@ -1099,12 +1118,14 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # use std::collections::HashSet; - /// // Bad /// # let mut s = HashSet::new(); /// # s.insert(1); /// let x = s.iter().nth(0); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); /// let x = s.iter().next(); @@ -1210,11 +1231,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let x = vec![2, 3, 5]; /// let last_element = x.get(x.len() - 1); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let x = vec![2, 3, 5]; /// let last_element = x.last(); /// ``` @@ -1273,10 +1295,14 @@ declare_clippy_lint! { /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// - /// // Bad /// a.extend(b.drain(..)); + /// ``` + /// + /// Use instead: + /// ```rust + /// let mut a = vec![1, 2, 3]; + /// let mut b = vec![4, 5, 6]; /// - /// // Good /// a.append(&mut b); /// ``` #[clippy::version = "1.55.0"] @@ -1351,11 +1377,12 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let name = "_"; - /// - /// // Bad /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let name = "_"; /// name.ends_with('_') || name.ends_with('-'); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1401,11 +1428,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// let _ = (0..3).fold(false, |acc, x| acc || x > 2); + /// # let _ = + /// (0..3).fold(false, |acc, x| acc || x > 2); /// ``` - /// This could be written as: + /// + /// Use instead: /// ```rust - /// let _ = (0..3).any(|x| x > 2); + /// # let _ = + /// (0..3).any(|x| x > 2); /// ``` #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_FOLD, @@ -1485,11 +1515,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let _ = (&vec![3, 4, 5]).into_iter(); + /// # let _ = + /// (&vec![3, 4, 5]).into_iter(); + /// ``` /// - /// // Good - /// let _ = (&vec![3, 4, 5]).iter(); + /// Use instead: + /// ```rust + /// # let _ = + /// (&vec![3, 4, 5]).iter(); /// ``` #[clippy::version = "1.32.0"] pub INTO_ITER_ON_REF, @@ -1704,13 +1737,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// let mut string = String::new(); + /// # let mut string = String::new(); /// string.insert_str(0, "R"); /// string.push_str("R"); /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust - /// let mut string = String::new(); + /// # let mut string = String::new(); /// string.insert(0, 'R'); /// string.push('R'); /// ``` @@ -1897,11 +1931,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let _ = "Hello".bytes().nth(3); + /// # let _ = + /// "Hello".bytes().nth(3); + /// ``` /// - /// // Good - /// let _ = "Hello".as_bytes().get(3); + /// Use instead: + /// ```rust + /// # let _ = + /// "Hello".as_bytes().get(3); /// ``` #[clippy::version = "1.52.0"] pub BYTES_NTH, @@ -1945,15 +1982,20 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let some_vec = vec![0, 1, 2, 3]; - /// let _ = some_vec.iter().count(); - /// let _ = &some_vec[..].iter().count(); + /// # let _ = + /// some_vec.iter().count(); + /// # let _ = + /// &some_vec[..].iter().count(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let some_vec = vec![0, 1, 2, 3]; - /// let _ = some_vec.len(); - /// let _ = &some_vec[..].len(); + /// # let _ = + /// some_vec.len(); + /// # let _ = + /// &some_vec[..].len(); /// ``` #[clippy::version = "1.52.0"] pub ITER_COUNT, @@ -1973,16 +2015,17 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let s = ""; + /// # let s = ""; /// for x in s.splitn(1, ":") { - /// // use x + /// // .. /// } + /// ``` /// - /// // Good - /// let s = ""; + /// Use instead: + /// ```rust + /// # let s = ""; /// for x in s.splitn(2, ":") { - /// // use x + /// // .. /// } /// ``` #[clippy::version = "1.54.0"] @@ -2000,10 +2043,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let x: String = std::iter::repeat('x').take(10).collect(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let x: String = "x".repeat(10); /// ``` #[clippy::version = "1.54.0"] @@ -2021,7 +2065,6 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// let s = "key=value=add"; /// let (key, value) = s.splitn(2, '=').next_tuple()?; /// let value = s.splitn(2, '=').nth(1)?; @@ -2030,9 +2073,9 @@ declare_clippy_lint! { /// let key = parts.next()?; /// let value = parts.next()?; /// ``` + /// /// Use instead: /// ```rust,ignore - /// // Good /// let s = "key=value=add"; /// let (key, value) = s.split_once('=')?; /// let value = s.split_once('=')?.1; @@ -2057,13 +2100,12 @@ declare_clippy_lint! { /// that both functions return a lazy iterator. /// ### Example /// ```rust - /// // Bad /// let str = "key=value=add"; /// let _ = str.splitn(3, '=').next().unwrap(); /// ``` + /// /// Use instead: /// ```rust - /// // Good /// let str = "key=value=add"; /// let _ = str.split('=').next().unwrap(); /// ``` @@ -2149,7 +2191,8 @@ declare_clippy_lint! { /// let a = Some(&1); /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> /// ``` - /// Could be written as: + /// + /// Use instead: /// ```rust /// let a = Some(&1); /// let b = a; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 55665699453..01bf871198a 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -45,16 +45,13 @@ declare_clippy_lint! { /// dereferences, e.g., changing `*x` to `x` within the function. /// /// ### Example - /// ```rust,ignore - /// // Bad - /// fn foo(ref x: u8) -> bool { - /// true - /// } + /// ```rust + /// fn foo(ref _x: u8) {} + /// ``` /// - /// // Good - /// fn foo(x: &u8) -> bool { - /// true - /// } + /// Use instead: + /// ```rust + /// fn foo(_x: &u8) {} /// ``` #[clippy::version = "pre 1.29.0"] pub TOPLEVEL_REF_ARG, @@ -73,11 +70,12 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let x = 1.0; - /// - /// // Bad /// if x == f32::NAN { } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let x = 1.0f32; /// if x.is_nan() { } /// ``` #[clippy::version = "pre 1.29.0"] @@ -139,7 +137,8 @@ declare_clippy_lint! { /// # let y = String::from("foo"); /// if x.to_owned() == y {} /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// # let x = "foo"; /// # let y = String::from("foo"); @@ -232,10 +231,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let a = 0 as *const u32; + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let a = std::ptr::null::(); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 6860b60acbd..704918c0b97 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -34,13 +34,21 @@ declare_clippy_lint! { /// # } /// let f = Foo { a: 0, b: 0, c: 0 }; /// - /// // Bad /// match f { /// Foo { a: _, b: 0, .. } => {}, /// Foo { a: _, b: _, c: _ } => {}, /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// # struct Foo { + /// # a: i32, + /// # b: i32, + /// # c: i32, + /// # } + /// let f = Foo { a: 0, b: 0, c: 0 }; /// - /// // Good /// match f { /// Foo { b: 0, .. } => {}, /// Foo { .. } => {}, @@ -62,10 +70,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// fn foo(a: i32, _a: i32) {} + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// fn bar(a: i32, _b: i32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -103,11 +112,16 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let y = 0x1a9BAcD; + /// # let _ = + /// 0x1a9BAcD + /// # ; + /// ``` /// - /// // Good - /// let y = 0x1A9BACD; + /// Use instead: + /// ```rust + /// # let _ = + /// 0x1A9BACD + /// # ; /// ``` #[clippy::version = "pre 1.29.0"] pub MIXED_CASE_HEX_LITERALS, @@ -127,11 +141,16 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let y = 123832i32; + /// # let _ = + /// 123832i32 + /// # ; + /// ``` /// - /// // Good - /// let y = 123832_i32; + /// Use instead: + /// ```rust + /// # let _ = + /// 123832_i32 + /// # ; /// ``` #[clippy::version = "pre 1.29.0"] pub UNSEPARATED_LITERAL_SUFFIX, @@ -150,11 +169,16 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let y = 123832_i32; + /// # let _ = + /// 123832_i32 + /// # ; + /// ``` /// - /// // Good - /// let y = 123832i32; + /// Use instead: + /// ```rust + /// # let _ = + /// 123832i32 + /// # ; /// ``` #[clippy::version = "1.58.0"] pub SEPARATED_LITERAL_SUFFIX, @@ -234,14 +258,15 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let v = Some("abc"); - /// - /// // Bad /// match v { /// Some(x) => (), /// y @ _ => (), /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let v = Some("abc"); /// match v { /// Some(x) => (), /// y => (), @@ -262,6 +287,7 @@ declare_clippy_lint! { /// means there are 0 or more elements left. This can make a difference /// when refactoring, but shouldn't result in errors in the refactored code, /// since the wildcard pattern isn't used anyway. + /// /// ### Why is this bad? /// The wildcard pattern is unneeded as the rest pattern /// can match that element as well. @@ -270,13 +296,16 @@ declare_clippy_lint! { /// ```rust /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); - /// // Bad /// match t { /// TupleStruct(0, .., _) => (), /// _ => (), /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # struct TupleStruct(u32, u32, u32); + /// # let t = TupleStruct(1, 2, 3); /// match t { /// TupleStruct(0, ..) => (), /// _ => (), diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 024bd076071..1ad07125b54 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -25,14 +25,16 @@ declare_clippy_lint! { /// ```rust /// let mut x = 0; /// - /// // Bad /// let a = { /// x = 1; /// 1 /// } + x; /// // Unclear whether a is 1 or 2. + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let mut x = 0; /// let tmp = { /// x = 1; /// 1 diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 9d8f8999ce4..f434a655f8a 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -16,12 +16,17 @@ declare_clippy_lint! { /// the value. Also the code misleads about the intent of the call site. /// /// ### Example - /// ```ignore - /// // Bad - /// my_vec.push(&mut value) + /// ```rust + /// # let mut vec = Vec::new(); + /// # let mut value = 5; + /// vec.push(&mut value); + /// ``` /// - /// // Good - /// my_vec.push(&value) + /// Use instead: + /// ```rust + /// # let mut vec = Vec::new(); + /// # let value = 5; + /// vec.push(&value); /// ``` #[clippy::version = "pre 1.29.0"] pub UNNECESSARY_MUT_PASSED, diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 73823779e49..a98577093ed 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -27,12 +27,13 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let y = true; - /// - /// // Bad /// # use std::sync::Mutex; /// let x = Mutex::new(&y); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let y = true; /// # use std::sync::atomic::AtomicBool; /// let x = AtomicBool::new(y); /// ``` @@ -60,8 +61,10 @@ declare_clippy_lint! { /// ```rust /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// # use std::sync::atomic::AtomicUsize; /// let x = AtomicUsize::new(0usize); /// ``` diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 778d49cb4b6..33638fe3734 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -30,16 +30,22 @@ declare_clippy_lint! { /// shorter code. /// /// ### Example - /// ```rust,ignore + /// ```rust + /// # let x = true; /// if x { /// false + /// # ; /// } else { /// true + /// # ; /// } /// ``` - /// Could be written as - /// ```rust,ignore + /// + /// Use instead: + /// ```rust + /// # let x = true; /// !x + /// # ; /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BOOL, diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 0fcc419e722..55da6e0f0a3 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -27,16 +27,17 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// Bad: /// ```rust /// let mut v = Vec::::new(); - /// let _ = v.iter_mut().filter(|&ref a| a.is_empty()); + /// # let _ = + /// v.iter_mut().filter(|&ref a| a.is_empty()); /// ``` /// - /// Good: + /// Use instead: /// ```rust /// let mut v = Vec::::new(); - /// let _ = v.iter_mut().filter(|a| a.is_empty()); + /// # let _ = + /// v.iter_mut().filter(|a| a.is_empty()); /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BORROWED_REFERENCE, diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index c87c174ef73..0bd29d1776b 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -24,16 +24,17 @@ declare_clippy_lint! { /// # z: i32, /// # } /// # let zero_point = Point { x: 0, y: 0, z: 0 }; - /// - /// // Bad /// Point { /// x: 1, /// y: 1, /// z: 1, /// ..zero_point /// }; + /// ``` /// - /// // Ok + /// Use instead: + /// ```rust,ignore + /// // Missing field `z` /// Point { /// x: 1, /// y: 1, diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index efe31a15441..a7e0e35787c 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -19,17 +19,17 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// use std::cmp::Ordering; - /// - /// // Bad /// let a = 1.0; /// let b = f64::NAN; /// - /// let _not_less_or_equal = !(a <= b); + /// let not_less_or_equal = !(a <= b); + /// ``` /// - /// // Good - /// let a = 1.0; - /// let b = f64::NAN; + /// Use instead: + /// ```rust + /// use std::cmp::Ordering; + /// # let a = 1.0; + /// # let b = f64::NAN; /// /// let _not_less_or_equal = match a.partial_cmp(&b) { /// None | Some(Ordering::Greater) => true, diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 707f3b2181a..ce6bb38b7c0 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -19,12 +19,13 @@ declare_clippy_lint! { /// This only catches integers (for now). /// /// ### Example - /// ```ignore - /// // Bad + /// ```rust,ignore /// let a = x * -1; + /// ``` /// - /// // Good - /// let b = -x; + /// Use instead: + /// ```rust,ignore + /// let a = -x; /// ``` #[clippy::version = "pre 1.29.0"] pub NEG_MULTIPLY, diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 8db41ba6ee2..b727105f670 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -58,12 +58,14 @@ declare_clippy_lint! { /// ```rust /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// - /// // Bad. /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct + /// ``` /// - /// // Good. + /// Use instead: + /// ```rust + /// # use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); /// STATIC_ATOM.store(9, SeqCst); /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance @@ -104,11 +106,15 @@ declare_clippy_lint! { /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// - /// // Bad. /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct + /// ``` + /// + /// Use instead: + /// ```rust + /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// - /// // Good. /// static STATIC_ATOM: AtomicUsize = CONST_ATOM; /// STATIC_ATOM.store(9, SeqCst); /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index e8532db4f71..c8854539677 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -33,11 +33,12 @@ declare_clippy_lint! { /// /// # Example /// ```rust - /// // Bad /// let one = "\033[1m Bold? \033[0m"; // \033 intended as escape /// let two = "\033\0"; // \033 intended as null-3-3 + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let one = "\x1b[1mWill this be bold?\x1b[0m"; /// let two = "\x0033\x00"; /// ``` diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 5a93431f25a..05ab62786f4 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -57,12 +57,11 @@ declare_clippy_lint! { /// ### Example /// /// ```rust - /// // Bad /// fn foo(v: &u32) {} /// ``` /// + /// Use instead: /// ```rust - /// // Better /// fn foo(v: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -89,14 +88,13 @@ declare_clippy_lint! { /// #[derive(Clone, Copy)] /// struct TooLarge([u8; 2048]); /// - /// // Bad /// fn foo(v: TooLarge) {} /// ``` - /// ```rust - /// #[derive(Clone, Copy)] - /// struct TooLarge([u8; 2048]); /// - /// // Good + /// Use instead: + /// ```rust + /// # #[derive(Clone, Copy)] + /// # struct TooLarge([u8; 2048]); /// fn foo(v: &TooLarge) {} /// ``` #[clippy::version = "1.49.0"] diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 0b96f6ff683..b06eba13d2f 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -48,10 +48,11 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// // Bad /// fn foo(&Vec) { .. } + /// ``` /// - /// // Good + /// Use instead: + /// ```ignore /// fn foo(&[u32]) { .. } /// ``` #[clippy::version = "pre 1.29.0"] @@ -70,15 +71,18 @@ declare_clippy_lint! { /// method instead /// /// ### Example - /// ```ignore - /// // Bad + /// ```rust,ignore + /// use std::ptr; + /// /// if x == ptr::null { - /// .. + /// // .. /// } + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// if x.is_null() { - /// .. + /// // .. /// } /// ``` #[clippy::version = "pre 1.29.0"] @@ -129,12 +133,12 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// // Bad. Undefined behavior + /// // Undefined behavior /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); } /// ``` /// + /// Use instead: /// ```ignore - /// // Good /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } /// ``` #[clippy::version = "1.53.0"] diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 584b561dcf0..be7eae02687 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -27,11 +27,14 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let x = vec![1]; + /// # let _ = /// x.iter().zip(0..x.len()); /// ``` - /// Could be written as + /// + /// Use instead: /// ```rust /// # let x = vec![1]; + /// # let _ = /// x.iter().enumerate(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -65,12 +68,21 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust,ignore - /// for x..(y+1) { .. } + /// ```rust + /// # let x = 0; + /// # let y = 1; + /// for i in x..(y+1) { + /// // .. + /// } /// ``` - /// Could be written as - /// ```rust,ignore - /// for x..=y { .. } + /// + /// Use instead: + /// ```rust + /// # let x = 0; + /// # let y = 1; + /// for i in x..=y { + /// // .. + /// } /// ``` #[clippy::version = "pre 1.29.0"] pub RANGE_PLUS_ONE, @@ -94,12 +106,21 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust,ignore - /// for x..=(y-1) { .. } + /// ```rust + /// # let x = 0; + /// # let y = 1; + /// for i in x..=(y-1) { + /// // .. + /// } /// ``` - /// Could be written as - /// ```rust,ignore - /// for x..y { .. } + /// + /// Use instead: + /// ```rust + /// # let x = 0; + /// # let y = 1; + /// for i in x..y { + /// // .. + /// } /// ``` #[clippy::version = "pre 1.29.0"] pub RANGE_MINUS_ONE, diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 5a25008e95e..3aa18557d91 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -23,12 +23,13 @@ declare_clippy_lint! { /// complexity. /// /// ### Example - /// ```rust,ignore - /// // Bad - /// let a = (|| 42)() + /// ```rust + /// let a = (|| 42)(); + /// ``` /// - /// // Good - /// let a = 42 + /// Use instead: + /// ```rust + /// let a = 42; /// ``` #[clippy::version = "pre 1.29.0"] pub REDUNDANT_CLOSURE_CALL, diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index f789cec6d6a..a642e2da3ba 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -21,11 +21,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// let a = f(*&mut b); /// let c = *&d; + /// ``` /// - /// // Good + /// Use instead: + /// ```rust,ignore /// let a = f(b); /// let c = d; /// ``` diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 91e5e1e8b28..60be6bd335f 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -26,19 +26,20 @@ declare_clippy_lint! { /// if it was added on constructors for example. /// /// ### Example - /// Missing attribute /// ```rust /// pub struct Bar; /// impl Bar { - /// // Bad + /// // Missing attribute /// pub fn bar(&self) -> Self { /// Self /// } /// } /// ``` /// - /// It's better to have the `#[must_use]` attribute on the method like this: + /// Use instead: /// ```rust + /// # { + /// // It's better to have the `#[must_use]` attribute on the method like this: /// pub struct Bar; /// impl Bar { /// #[must_use] @@ -46,10 +47,10 @@ declare_clippy_lint! { /// Self /// } /// } - /// ``` + /// # } /// - /// Or on the type definition like this: - /// ```rust + /// # { + /// // Or on the type definition like this: /// #[must_use] /// pub struct Bar; /// impl Bar { @@ -57,6 +58,7 @@ declare_clippy_lint! { /// Self /// } /// } + /// # } /// ``` #[clippy::version = "1.59.0"] pub RETURN_SELF_NOT_MUST_USE, diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 4f74c1e44c2..bf318c055da 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -23,10 +23,12 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let x = 1; - /// // Bad /// let x = &x; + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let x = 1; /// let y = &x; // use different variable name /// ``` #[clippy::version = "pre 1.29.0"] @@ -79,11 +81,14 @@ declare_clippy_lint! { /// # let y = 1; /// # let z = 2; /// let x = y; - /// - /// // Bad /// let x = z; // shadows the earlier binding + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let y = 1; + /// # let z = 2; + /// let x = y; /// let w = z; // use different variable name /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index b4ad5dcbe3e..975a0a06e38 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -23,15 +23,16 @@ declare_clippy_lint! { /// ```rust /// # use core::iter::repeat; /// # let len = 4; - /// - /// // Bad /// let mut vec1 = Vec::with_capacity(len); /// vec1.resize(len, 0); /// /// let mut vec2 = Vec::with_capacity(len); /// vec2.extend(repeat(0).take(len)); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # let len = 4; /// let mut vec1 = vec![0; len]; /// let mut vec2 = vec![0; len]; /// ``` diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 7c196ccaa8c..9ea2de001e2 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -99,11 +99,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad - /// let bs = "a byte string".as_bytes(); + /// let bstr = "a byte string".as_bytes(); + /// ``` /// - /// // Good - /// let bs = b"a byte string"; + /// Use instead: + /// ```rust + /// let bstr = b"a byte string"; /// ``` #[clippy::version = "pre 1.29.0"] pub STRING_LIT_AS_BYTES, @@ -223,11 +224,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); + /// # let _ = + /// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); /// ``` - /// could be written as + /// + /// Use instead: /// ```rust - /// let _ = &"Hello World!"[6..11]; + /// # let _ = + /// &"Hello World!"[6..11]; /// ``` #[clippy::version = "1.50.0"] pub STRING_FROM_UTF8_AS_BYTES, diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index b91be0eb4be..71957572f2e 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -29,8 +29,7 @@ declare_clippy_lint! { /// pub fn foo(t: T) where T: Copy, T: Clone {} /// ``` /// - /// Could be written as: - /// + /// Use instead: /// ```rust /// pub fn foo(t: T) where T: Copy + Clone {} /// ``` diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index afd7be89a4e..cc64d17be05 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -41,7 +41,8 @@ declare_clippy_lint! { /// ```rust /// let x = String::from("€"); /// ``` - /// Could be written as: + /// + /// Use instead: /// ```rust /// let x = String::from("\u{20ac}"); /// ``` diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 41333bb2add..c8ec4442ab1 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -17,13 +17,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// async fn get_random_number() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } /// let number_future = get_random_number(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// fn get_random_number_improved() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 4a3b5383c89..fe29bf29d0c 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -21,11 +21,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// // format!() returns a `String` /// let s: String = format!("hello").into(); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let s: String = format!("hello"); /// ``` #[clippy::version = "1.45.0"] diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 60f98876994..17323e4d0ef 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -89,12 +89,11 @@ declare_clippy_lint! { /// warning/error messages. /// /// ### Example - /// Bad: /// ```rust,ignore /// cx.span_lint(LINT_NAME, "message"); /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// utils::span_lint(cx, LINT_NAME, "message"); /// ``` @@ -112,12 +111,11 @@ declare_clippy_lint! { /// `cx.outer_expn_data()` is faster and more concise. /// /// ### Example - /// Bad: /// ```rust,ignore /// expr.span.ctxt().outer().expn_data() /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// expr.span.ctxt().outer_expn_data() /// ``` @@ -135,7 +133,6 @@ declare_clippy_lint! { /// ICE in large quantities can damage your teeth /// /// ### Example - /// Bad: /// ```rust,ignore /// 🍦🍦🍦🍦🍦 /// ``` @@ -153,12 +150,11 @@ declare_clippy_lint! { /// Indicates that the lint is not finished. /// /// ### Example - /// Bad: /// ```rust,ignore /// declare_lint! { pub COOL_LINT, nursery, "default lint description" } /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" } /// ``` @@ -183,7 +179,6 @@ declare_clippy_lint! { /// convenient, readable and less error prone. /// /// ### Example - /// Bad: /// ```rust,ignore /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| { /// diag.span_suggestion( @@ -207,7 +202,7 @@ declare_clippy_lint! { /// }); /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// span_lint_and_sugg( /// cx, @@ -237,12 +232,11 @@ declare_clippy_lint! { /// `utils::is_type_diagnostic_item()` does not require hardcoded paths. /// /// ### Example - /// Bad: /// ```rust,ignore /// utils::match_type(cx, ty, &paths::VEC) /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) /// ``` @@ -273,12 +267,11 @@ declare_clippy_lint! { /// It's faster and easier to use the symbol constant. /// /// ### Example - /// Bad: /// ```rust,ignore /// let _ = sym!(f32); /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// let _ = sym::f32; /// ``` @@ -295,12 +288,11 @@ declare_clippy_lint! { /// It's faster use symbols directly instead of strings. /// /// ### Example - /// Bad: /// ```rust,ignore /// symbol.as_str() == "clippy"; /// ``` /// - /// Good: + /// Use instead: /// ```rust,ignore /// symbol == sym::clippy; /// ``` diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index ba1ff65479d..297a80e5767 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -28,12 +28,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # fn foo(my_vec: &[u8]) {} + /// fn foo(_x: &[u8]) {} /// - /// // Bad /// foo(&vec![1, 2]); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # fn foo(_x: &[u8]) {} /// foo(&[1, 2]); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 2f74eaf3cf5..5418eca382d 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -26,13 +26,18 @@ declare_clippy_lint! { /// still around. /// /// ### Example - /// ```rust,ignore - /// // Bad + /// ```rust /// use std::cmp::Ordering::*; + /// + /// # fn foo(_: std::cmp::Ordering) {} /// foo(Less); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// use std::cmp::Ordering; + /// + /// # fn foo(_: Ordering) {} /// foo(Ordering::Less) /// ``` #[clippy::version = "pre 1.29.0"] @@ -76,14 +81,13 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// // Bad /// use crate1::*; /// /// foo(); /// ``` /// + /// Use instead: /// ```rust,ignore - /// // Good /// use crate1::foo; /// /// foo(); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index d2493c055a5..bb74f2a7f0f 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -25,10 +25,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// println!(""); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// println!(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -177,10 +178,15 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); - /// // Bad + /// # let _ = /// writeln!(buf, ""); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # use std::fmt::Write; + /// # let mut buf = String::new(); + /// # let _ = /// writeln!(buf); /// ``` #[clippy::version = "pre 1.29.0"] @@ -204,10 +210,16 @@ declare_clippy_lint! { /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; - /// // Bad + /// # let _ = /// write!(buf, "Hello {}!\n", name); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # use std::fmt::Write; + /// # let mut buf = String::new(); + /// # let name = "World"; + /// # let _ = /// writeln!(buf, "Hello {}!", name); /// ``` #[clippy::version = "pre 1.29.0"] @@ -233,10 +245,15 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); - /// // Bad + /// # let _ = /// writeln!(buf, "{}", "foo"); + /// ``` /// - /// // Good + /// Use instead: + /// ```rust + /// # use std::fmt::Write; + /// # let mut buf = String::new(); + /// # let _ = /// writeln!(buf, "foo"); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 641681185a2..50d3c079fe6 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -14,10 +14,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // Bad /// let nan = 0.0f32 / 0.0; + /// ``` /// - /// // Good + /// Use instead: + /// ```rust /// let nan = f32::NAN; /// ``` #[clippy::version = "pre 1.29.0"] -- cgit 1.4.1-3-g733a5 From cab5362d3258c14dc4f1763a494827b61e997ebb Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:28:16 -0400 Subject: Suppress `unused` in doc examples --- clippy_lints/src/casts/mod.rs | 18 +++++---------- clippy_lints/src/checked_conversions.rs | 12 ++++------ clippy_lints/src/indexing_slicing.rs | 6 ++--- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/methods/mod.rs | 37 ++++++++++++------------------- clippy_lints/src/needless_borrowed_ref.rs | 4 ++-- clippy_lints/src/ranges.rs | 6 ++--- clippy_lints/src/strings.rs | 2 -- clippy_lints/src/write.rs | 6 ----- 9 files changed, 31 insertions(+), 62 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index fe8e372b6f5..74ea70d1af1 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -220,15 +220,13 @@ declare_clippy_lint! { /// ### Example /// ```rust /// fn fun() -> i32 { 1 } - /// # let _ = - /// fun as i64; + /// let _ = fun as i64; /// ``` /// /// Use instead: /// ```rust /// # fn fun() -> i32 { 1 } - /// # let _ = - /// fun as usize; + /// let _ = fun as usize; /// ``` #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, @@ -251,8 +249,7 @@ declare_clippy_lint! { /// fn fn1() -> i16 { /// 1 /// }; - /// # let _ = - /// fn1 as i32; + /// let _ = fn1 as i32; /// ``` /// /// Use instead: @@ -287,8 +284,7 @@ declare_clippy_lint! { /// fn fn1() -> u16 { /// 1 /// }; - /// # let _ = - /// fn1 as usize; + /// let _ = fn1 as usize; /// ``` /// /// Use instead: @@ -297,8 +293,7 @@ declare_clippy_lint! { /// fn fn2() -> u16 { /// 1 /// }; - /// # let _ = - /// fn2() as usize; + /// let _ = fn2() as usize; /// /// // or /// @@ -306,8 +301,7 @@ declare_clippy_lint! { /// fn fn3() -> u16 { /// 1 /// } - /// # let _ = - /// fn3 as fn() -> u16; + /// let _ = fn3 as fn() -> u16; /// ``` #[clippy::version = "1.58.0"] pub FN_TO_NUMERIC_CAST_ANY, diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1010340c712..4b99d1d614e 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -22,18 +22,14 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let foo: u32 = 5; - /// # let _ = - /// foo <= i32::MAX as u32 - /// # ; + /// foo <= i32::MAX as u32; /// ``` /// - /// Could be written: - /// + /// Use instead: /// ```rust /// # let foo = 1; - /// # let _ = - /// i32::try_from(foo).is_ok() - /// # ; + /// # #[allow(unused)] + /// i32::try_from(foo).is_ok(); /// ``` #[clippy::version = "1.37.0"] pub CHECKED_CONVERSIONS, diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 301686612a1..4a375752e1d 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -67,16 +67,14 @@ declare_clippy_lint! { /// /// Use instead: /// ```rust + /// # #![allow(unused)] + /// /// # let x = vec![0; 5]; /// # let y = [0, 1, 2, 3]; - /// # let _ = /// x.get(2); - /// # let _ = /// x.get(2..100); /// - /// # let _ = /// y.get(10); - /// # let _ = /// y.get(10..100); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index fc8e473dd9e..27fa9042269 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ### Example /// ```rust /// let infinite_iter = 0..; - /// # let _ = + /// # #[allow(unused)] /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9d78f0a9fc1..e1ea8426e58 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -131,18 +131,14 @@ declare_clippy_lint! { /// ### Examples /// ```rust /// # let vec = vec!["string".to_string()]; - /// # let _ = /// vec.iter().cloned().take(10); - /// # let _ = /// vec.iter().cloned().last(); /// ``` /// /// Use instead: /// ```rust /// # let vec = vec!["string".to_string()]; - /// # let _ = /// vec.iter().take(10).cloned(); - /// # let _ = /// vec.iter().last().cloned(); /// ``` #[clippy::version = "1.59.0"] @@ -590,7 +586,6 @@ declare_clippy_lint! { /// let vec = vec![vec![1]]; /// let opt = Some(5); /// - /// # let _ = /// vec.iter().map(|x| x.iter()).flatten(); /// opt.map(|x| Some(x * 2)).flatten(); /// ``` @@ -599,7 +594,6 @@ declare_clippy_lint! { /// ```rust /// # let vec = vec![vec![1]]; /// # let opt = Some(5); - /// # let _ = /// vec.iter().flat_map(|x| x.iter()); /// opt.and_then(|x| Some(x * 2)); /// ``` @@ -620,7 +614,7 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # let _ = + /// # #![allow(unused)] /// (0_i32..10) /// .filter(|n| n.checked_add(1).is_some()) /// .map(|n| n.checked_add(1).unwrap()); @@ -628,7 +622,7 @@ declare_clippy_lint! { /// /// Use instead: /// ```rust - /// # let _ = + /// # #[allow(unused)] /// (0_i32..10).filter_map(|n| n.checked_add(1)); /// ``` #[clippy::version = "1.51.0"] @@ -721,11 +715,10 @@ declare_clippy_lint! { /// /// ### Example /// ```rust + /// # #![allow(unused)] /// let vec = vec![1]; - /// # let _ = /// vec.iter().find(|x| **x == 0).is_some(); /// - /// # let _ = /// "hello world".find("world").is_none(); /// ``` /// @@ -734,7 +727,7 @@ declare_clippy_lint! { /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); /// - /// # let _ = + /// # #[allow(unused)] /// !"hello world".contains("world"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1428,13 +1421,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # let _ = + /// # #[allow(unused)] /// (0..3).fold(false, |acc, x| acc || x > 2); /// ``` /// /// Use instead: /// ```rust - /// # let _ = /// (0..3).any(|x| x > 2); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1515,14 +1507,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # let _ = - /// (&vec![3, 4, 5]).into_iter(); + /// # let vec = vec![3, 4, 5]; + /// (&vec).into_iter(); /// ``` /// /// Use instead: /// ```rust - /// # let _ = - /// (&vec![3, 4, 5]).iter(); + /// # let vec = vec![3, 4, 5]; + /// (&vec).iter(); /// ``` #[clippy::version = "1.32.0"] pub INTO_ITER_ON_REF, @@ -1931,13 +1923,13 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # let _ = + /// # #[allow(unused)] /// "Hello".bytes().nth(3); /// ``` /// /// Use instead: /// ```rust - /// # let _ = + /// # #[allow(unused)] /// "Hello".as_bytes().get(3); /// ``` #[clippy::version = "1.52.0"] @@ -1982,19 +1974,18 @@ declare_clippy_lint! { /// /// ### Example /// ```rust + /// # #![allow(unused)] /// let some_vec = vec![0, 1, 2, 3]; - /// # let _ = + /// /// some_vec.iter().count(); - /// # let _ = /// &some_vec[..].iter().count(); /// ``` /// /// Use instead: /// ```rust /// let some_vec = vec![0, 1, 2, 3]; - /// # let _ = + /// /// some_vec.len(); - /// # let _ = /// &some_vec[..].len(); /// ``` #[clippy::version = "1.52.0"] diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 55da6e0f0a3..05c012b92e8 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// ### Example /// ```rust /// let mut v = Vec::::new(); - /// # let _ = + /// # #[allow(unused)] /// v.iter_mut().filter(|&ref a| a.is_empty()); /// ``` /// /// Use instead: /// ```rust /// let mut v = Vec::::new(); - /// # let _ = + /// # #[allow(unused)] /// v.iter_mut().filter(|a| a.is_empty()); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index be7eae02687..056637c2048 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -27,15 +27,13 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let x = vec![1]; - /// # let _ = - /// x.iter().zip(0..x.len()); + /// let _ = x.iter().zip(0..x.len()); /// ``` /// /// Use instead: /// ```rust /// # let x = vec![1]; - /// # let _ = - /// x.iter().enumerate(); + /// let _ = x.iter().enumerate(); /// ``` #[clippy::version = "pre 1.29.0"] pub RANGE_ZIP_WITH_LEN, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 9ea2de001e2..71f3e6b6a6e 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -224,13 +224,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # let _ = /// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); /// ``` /// /// Use instead: /// ```rust - /// # let _ = /// &"Hello World!"[6..11]; /// ``` #[clippy::version = "1.50.0"] diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index bb74f2a7f0f..67b2bc8c3f3 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -178,7 +178,6 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); - /// # let _ = /// writeln!(buf, ""); /// ``` /// @@ -186,7 +185,6 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); - /// # let _ = /// writeln!(buf); /// ``` #[clippy::version = "pre 1.29.0"] @@ -210,7 +208,6 @@ declare_clippy_lint! { /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; - /// # let _ = /// write!(buf, "Hello {}!\n", name); /// ``` /// @@ -219,7 +216,6 @@ declare_clippy_lint! { /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; - /// # let _ = /// writeln!(buf, "Hello {}!", name); /// ``` #[clippy::version = "pre 1.29.0"] @@ -245,7 +241,6 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); - /// # let _ = /// writeln!(buf, "{}", "foo"); /// ``` /// @@ -253,7 +248,6 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); - /// # let _ = /// writeln!(buf, "foo"); /// ``` #[clippy::version = "pre 1.29.0"] -- cgit 1.4.1-3-g733a5 From bf3ab592f04fafd854190f6960510bf0c23ef8ae Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 7 Jun 2022 00:40:32 -0400 Subject: Changes to `iter_overeager_cloned` * Don't lint on `.cloned().flatten()` when `T::Item` doesn't implement `IntoIterator` * Reduce verbosity of lint message * Narrow down the scope of the replacement range --- clippy_lints/src/methods/iter_overeager_cloned.rs | 97 ++++++++++------------- clippy_lints/src/methods/mod.rs | 24 +++--- clippy_utils/src/ty.rs | 4 +- tests/ui/iter_overeager_cloned.fixed | 6 +- tests/ui/iter_overeager_cloned.rs | 3 + tests/ui/iter_overeager_cloned.stderr | 42 ++++++---- 6 files changed, 92 insertions(+), 84 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index 54c9ca435a4..06a39c5997e 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -1,70 +1,59 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy}; -use itertools::Itertools; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::{get_associated_type, implements_trait, is_copy}; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::sym; -use std::ops::Not; use super::ITER_OVEREAGER_CLONED; use crate::redundant_clone::REDUNDANT_CLONE; -/// lint overeager use of `cloned()` for `Iterator`s pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - recv: &'tcx hir::Expr<'_>, - name: &str, - map_arg: &[hir::Expr<'_>], + expr: &'tcx Expr<'_>, + cloned_call: &'tcx Expr<'_>, + cloned_recv: &'tcx Expr<'_>, + is_count: bool, + needs_into_iter: bool, ) { - // Check if it's iterator and get type associated with `Item`. - let inner_ty = if_chain! { - if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - let recv_ty = cx.typeck_results().expr_ty(recv); - if implements_trait(cx, recv_ty, iterator_trait_id, &[]); - if let Some(inner_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)); - then { - inner_ty - } else { + let typeck = cx.typeck_results(); + if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let Some(method_id) = typeck.type_dependent_def_id(expr.hir_id) + && cx.tcx.trait_of_item(method_id) == Some(iter_id) + && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id) + && cx.tcx.trait_of_item(method_id) == Some(iter_id) + && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv) + && let Some(iter_assoc_ty) = get_associated_type(cx, cloned_recv_ty, iter_id, "Item") + && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty)) + { + if needs_into_iter + && let Some(into_iter_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && !implements_trait(cx, iter_assoc_ty, into_iter_id, &[]) + { return; } - }; - - match inner_ty.kind() { - ty::Ref(_, ty, _) if !is_copy(cx, *ty) => {}, - _ => return, - }; - let (lint, preserve_cloned) = match name { - "count" => (REDUNDANT_CLONE, false), - _ => (ITER_OVEREAGER_CLONED, true), - }; - let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default(); - let msg = format!( - "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead", - name, - wildcard_params, - name, - wildcard_params, - preserve_cloned.then(|| ".cloned()").unwrap_or_default(), - ); + let (lint, msg, trailing_clone) = if is_count { + (REDUNDANT_CLONE, "unneeded cloning of iterator items", "") + } else { + (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()") + }; - span_lint_and_sugg( - cx, - lint, - expr.span, - &msg, - "try this", - format!( - "{}.{}({}){}", - snippet(cx, recv.span, ".."), - name, - map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "), - preserve_cloned.then(|| ".cloned()").unwrap_or_default(), - ), - Applicability::MachineApplicable, - ); + span_lint_and_then( + cx, + lint, + expr.span, + msg, + |diag| { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(mut snip) = snippet_opt(cx, method_span) { + snip.push_str(trailing_clone); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try this", snip, Applicability::MachineApplicable); + } + } + ); + } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7308e74c323..2ebfcb7a5fe 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2583,8 +2583,8 @@ impl Methods { }, _ => {}, }, - (name @ "count", args @ []) => match method_call(recv) { - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + ("count", []) => 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], _)) => { iter_count::check(cx, expr, recv2, name2); }, @@ -2614,9 +2614,9 @@ impl Methods { flat_map_identity::check(cx, expr, arg, span); flat_map_option::check(cx, expr, arg, span); }, - (name @ "flatten", args @ []) => match method_call(recv) { + ("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, recv2, name, args), + Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), _ => {}, }, ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), @@ -2636,10 +2636,10 @@ impl Methods { unnecessary_join::check(cx, expr, recv, join_arg, span); } }, - ("last", args @ []) | ("skip", args @ [_]) => { + ("last", []) | ("skip", [_]) => { if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { - iter_overeager_cloned::check(cx, expr, recv2, name, args); + iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } } }, @@ -2660,10 +2660,10 @@ impl Methods { map_identity::check(cx, expr, recv, m_arg, name, span); }, ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), - (name @ "next", args @ []) => { + ("next", []) => { if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args), + ("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), ("iter", []) => iter_next_slice::check(cx, expr, recv2), @@ -2673,9 +2673,9 @@ impl Methods { } } }, - ("nth", args @ [n_arg]) => match method_call(recv) { + ("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, recv2, name, args), + 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), @@ -2698,10 +2698,10 @@ impl Methods { } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("take", args @ [_arg]) => { + ("take", [_arg]) => { if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { - iter_overeager_cloned::check(cx, expr, recv2, name, args); + iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } } }, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index a10515d2fec..227e97d37ec 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -78,9 +78,9 @@ pub fn get_associated_type<'tcx>( cx.tcx .associated_items(trait_id) .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) - .map(|assoc| { + .and_then(|assoc| { let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[])); - cx.tcx.normalize_erasing_regions(cx.param_env, proj) + cx.tcx.try_normalize_erasing_regions(cx.param_env, proj).ok() }) } diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index 7c2b05d837b..c100705d017 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -18,7 +18,8 @@ fn main() { let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned(); let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] - .iter().flatten().cloned(); + .iter() + .flatten().cloned(); // Not implemented yet let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); @@ -43,6 +44,9 @@ fn main() { // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); + + // `&Range<_>` doesn't implement `IntoIterator` + let _ = [0..1, 2..5].iter().cloned().flatten(); } // #8527 diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index f2d0b155d2c..2caa8802066 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -45,6 +45,9 @@ fn main() { // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); + + // `&Range<_>` doesn't implement `IntoIterator` + let _ = [0..1, 2..5].iter().cloned().flatten(); } // #8527 diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index 0582700fd16..dcae7cecd33 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -1,44 +1,56 @@ -error: called `cloned().last()` on an `Iterator`. It may be more efficient to call `last().cloned()` instead +error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:8:29 | LL | let _: Option = vec.iter().cloned().last(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().last().cloned()` + | ^^^^^^^^^^---------------- + | | + | help: try this: `.last().cloned()` | = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings` -error: called `cloned().next()` on an `Iterator`. It may be more efficient to call `next().cloned()` instead +error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:10:29 | LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().chain(vec.iter()).next().cloned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- + | | + | help: try this: `.next().cloned()` -error: called `cloned().count()` on an `Iterator`. It may be more efficient to call `count()` instead +error: unneeded cloning of iterator items --> $DIR/iter_overeager_cloned.rs:12:20 | LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------- + | | + | help: try this: `.count()` | = note: `-D clippy::redundant-clone` implied by `-D warnings` -error: called `cloned().take(...)` on an `Iterator`. It may be more efficient to call `take(...).cloned()` instead +error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:14:21 | LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().take(2).cloned()` + | ^^^^^^^^^^----------------- + | | + | help: try this: `.take(2).cloned()` -error: called `cloned().skip(...)` on an `Iterator`. It may be more efficient to call `skip(...).cloned()` instead +error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:16:21 | LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().skip(2).cloned()` + | ^^^^^^^^^^----------------- + | | + | help: try this: `.skip(2).cloned()` -error: called `cloned().nth(...)` on an `Iterator`. It may be more efficient to call `nth(...).cloned()` instead +error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:18:13 | LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").nth(2).cloned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- + | | + | help: try this: `.nth(2).cloned()` -error: called `cloned().flatten()` on an `Iterator`. It may be more efficient to call `flatten().cloned()` instead +error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:20:13 | LL | let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] @@ -50,8 +62,8 @@ LL | | .flatten(); | help: try this | -LL ~ let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] -LL ~ .iter().flatten().cloned(); +LL ~ .iter() +LL ~ .flatten().cloned(); | error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 2b655d46309aa688fcb7dff6aa692278a722ee68 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 9 Jun 2022 13:43:26 +0000 Subject: Correct some `#[clippy::version]`s --- clippy_lints/src/casts/mod.rs | 4 ++-- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/single_char_lifetime_names.rs | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 74ea70d1af1..02c2f30a4dd 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -414,7 +414,7 @@ declare_clippy_lint! { /// enum E { X = 256 }; /// let _ = E::X as u8; /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.61.0"] pub CAST_ENUM_TRUNCATION, suspicious, "casts from an enum type to an integral type which will truncate the value" @@ -459,7 +459,7 @@ declare_clippy_lint! { /// println!("{:?}", &*new_ptr); /// } /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.61.0"] pub CAST_SLICE_DIFFERENT_SIZES, correctness, "casting using `as` between raw pointers to slices of types with different sizes" diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index aaec88f50c7..bb0d39866a4 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -163,7 +163,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.52.0"] + #[clippy::version = "1.51.0"] pub MISSING_PANICS_DOC, pedantic, "`pub fn` may panic without `# Panics` in doc comment" diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 9ce5b8e17a9..d0c6495e35a 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// println!("{}", first); /// } /// ``` - #[clippy::version = "1.58.0"] + #[clippy::version = "1.59.0"] pub INDEX_REFUTABLE_SLICE, nursery, "avoid indexing on slices which could be destructed" diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index acf974c586a..391de922e1e 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -596,7 +596,7 @@ declare_clippy_lint! { /// std::hint::spin_loop() /// } /// ``` - #[clippy::version = "1.59.0"] + #[clippy::version = "1.61.0"] pub MISSING_SPIN_LOOP, perf, "An empty busy waiting loop" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ec19c317c88..9bb7bb7a7ab 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -141,7 +141,7 @@ declare_clippy_lint! { /// vec.iter().take(10).cloned(); /// vec.iter().last().cloned(); /// ``` - #[clippy::version = "1.59.0"] + #[clippy::version = "1.60.0"] pub ITER_OVEREAGER_CLONED, perf, "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies" @@ -1907,7 +1907,7 @@ declare_clippy_lint! { /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); /// ``` - #[clippy::version = "1.52.0"] + #[clippy::version = "1.47.0"] pub MAP_IDENTITY, complexity, "using iterator.map(|x| x)" @@ -2100,7 +2100,7 @@ declare_clippy_lint! { /// let str = "key=value=add"; /// let _ = str.split('=').next().unwrap(); /// ``` - #[clippy::version = "1.58.0"] + #[clippy::version = "1.59.0"] pub NEEDLESS_SPLITN, complexity, "usages of `str::splitn` that can be replaced with `str::split`" @@ -2131,7 +2131,7 @@ declare_clippy_lint! { /// foo(&path.to_string_lossy()); /// fn foo(s: &str) {} /// ``` - #[clippy::version = "1.58.0"] + #[clippy::version = "1.59.0"] pub UNNECESSARY_TO_OWNED, perf, "unnecessary calls to `to_owned`-like functions" diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 4154c71b428..e8a0da7e478 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -56,7 +56,7 @@ declare_clippy_lint! { /// -1 /// }; /// ``` - #[clippy::version = "1.58.0"] + #[clippy::version = "1.59.0"] pub NEEDLESS_LATE_INIT, style, "late initializations that can be replaced by a `let` statement with an initializer" diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index c8854539677..3ab4b6c4f6f 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -42,7 +42,7 @@ declare_clippy_lint! { /// let one = "\x1b[1mWill this be bold?\x1b[0m"; /// let two = "\x0033\x00"; /// ``` - #[clippy::version = "1.58.0"] + #[clippy::version = "1.59.0"] pub OCTAL_ESCAPES, suspicious, "string escape sequences looking like octal characters" diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index d66698f8adc..30b11618801 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -87,7 +87,7 @@ declare_clippy_lint! { /// # print!("{}", f(1)); /// # } /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.61.0"] pub ONLY_USED_IN_RECURSION, nursery, "arguments that is only used in recursion can be removed" diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 25a9072ef6e..db6c97f3739 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -60,7 +60,7 @@ declare_clippy_lint! { /// let vec = vec![1, 2, 3]; /// let slice = &*vec; /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.61.0"] pub DEREF_BY_SLICING, restriction, "slicing instead of dereferencing" diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index aa306a630c4..3dc995e2fa5 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// source: &'src str, /// } /// ``` - #[clippy::version = "1.59.0"] + #[clippy::version = "1.60.0"] pub SINGLE_CHAR_LIFETIME_NAMES, restriction, "warns against single-character lifetime names" -- cgit 1.4.1-3-g733a5 From a2b8a67777500139ba36d07d21f7e543e9c0f65c Mon Sep 17 00:00:00 2001 From: Muhammad Hamza Date: Fri, 1 Jul 2022 00:14:38 +0500 Subject: Fix broken hyperlink --- clippy_lints/src/methods/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9bb7bb7a7ab..cc1530f0ed0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2196,12 +2196,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Finds usages of [`char::is_digit`] - /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that - /// can be replaced with [`is_ascii_digit`] - /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or - /// [`is_ascii_hexdigit`] - /// (https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit). + /// Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that + /// can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or + /// [`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit). /// /// ### Why is this bad? /// `is_digit(..)` is slower and requires specifying the radix. -- cgit 1.4.1-3-g733a5 From 2dd5fc14da4065fa0ac7710582e7393822d40d37 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 3 Jul 2022 17:02:48 +0200 Subject: Correct `[clippy::version]` for 1.62 lints and add note to docs --- book/src/development/infrastructure/changelog_update.md | 3 +++ clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 4 ++-- clippy_lints/src/empty_drop.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++--- 7 files changed, 12 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index e560f4c6a3e..80a47affe30 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -95,6 +95,9 @@ As section headers, we use: Please also be sure to update the Beta/Unreleased sections at the top with the relevant commit ranges. +If you have the time, it would be appreciated if you double-check, that the +`#[clippy::version]` attributes for the added lints contains the correct version. + [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index eee5f90d178..1761360fb28 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -161,7 +161,7 @@ declare_clippy_lint! { /// baz().await; // Lint violation /// } /// ``` - #[clippy::version = "1.49.0"] + #[clippy::version = "1.62.0"] pub AWAIT_HOLDING_INVALID_TYPE, suspicious, "holding a type across an await point which is not allowed to be held as per the configuration" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 02c2f30a4dd..af3798a0cc8 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -500,7 +500,7 @@ declare_clippy_lint! { /// let x: i32 = -42; /// let y: u32 = x.unsigned_abs(); /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub CAST_ABS_TO_UNSIGNED, suspicious, "casting the result of `abs()` to an unsigned integer can panic" diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 9b8a481b6ea..f6ec8fe7edc 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// #[allow(clippy::crate_in_macro_def)] /// macro_rules! ok { ... crate::foo ... } /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub CRATE_IN_MACRO_DEF, suspicious, "using `crate` in a macro definition" diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 25014bfa1a5..b35f0b8ca52 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -116,7 +116,7 @@ declare_clippy_lint! { /// let x = Foo; /// std::mem::drop(x); /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub DROP_NON_DROP, suspicious, "call to `std::mem::drop` with a value which does not implement `Drop`" @@ -136,7 +136,7 @@ declare_clippy_lint! { /// let x = Foo; /// std::mem::forget(x); /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub FORGET_NON_DROP, suspicious, "call to `std::mem::forget` with a value which does not implement `Drop`" diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 325ae2356c1..ec063c0f777 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ```rust /// struct S; /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub EMPTY_DROP, restriction, "empty `Drop` implementations" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cc1530f0ed0..e8a239ecc7a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -369,7 +369,7 @@ declare_clippy_lint! { /// let x: Result = Ok(10); /// x.expect_err("Testing expect_err"); /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub ERR_EXPECT, style, r#"using `.err().expect("")` when `.expect_err("")` can be used"# @@ -2215,7 +2215,7 @@ declare_clippy_lint! { /// c.is_ascii_digit(); /// c.is_ascii_hexdigit(); /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub IS_DIGIT_ASCII_RADIX, style, "use of `char::is_digit(..)` with literal radix of 10 or 16" @@ -2235,7 +2235,7 @@ declare_clippy_lint! { /// let x = Some(3); /// x.as_ref(); /// ``` - #[clippy::version = "1.61.0"] + #[clippy::version = "1.62.0"] pub NEEDLESS_OPTION_TAKE, complexity, "using `.as_ref().take()` on a temporary value" -- cgit 1.4.1-3-g733a5 From 528308b5aa544454e6c90f6d051c3adeb1a46e1b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 2 Jul 2022 15:00:24 -0700 Subject: Extend unnecessary_lazy_eval to cover `bool::then` -> `bool::then_some` --- clippy_lints/src/methods/mod.rs | 1 + clippy_lints/src/methods/unnecessary_lazy_eval.rs | 7 ++- tests/ui/unnecessary_lazy_eval.fixed | 2 + tests/ui/unnecessary_lazy_eval.rs | 2 + tests/ui/unnecessary_lazy_eval.stderr | 76 +++++++++++++---------- 5 files changed, 52 insertions(+), 36 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cc1530f0ed0..36389d798ed 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2737,6 +2737,7 @@ impl Methods { } }, ("take", []) => needless_option_take::check(cx, expr, recv), + ("then", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 865f6d0318e..a9c641b4606 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -20,8 +20,9 @@ pub(super) fn check<'tcx>( ) { let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); + let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); - if is_option || is_result { + if is_option || is_result || is_bool { if let hir::ExprKind::Closure { body, .. } = arg.kind { let body = cx.tcx.hir().body(body); let body_expr = &body.value; @@ -33,8 +34,10 @@ pub(super) fn check<'tcx>( if eager_or_lazy::switch_to_eager_eval(cx, body_expr) { let msg = if is_option { "unnecessary closure used to substitute value for `Option::None`" - } else { + } else if is_result { "unnecessary closure used to substitute value for `Result::Err`" + } else { + "unnecessary closure used with `bool::then`" }; let applicability = if body .params diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 65fcdc43061..eed81796883 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -30,6 +30,7 @@ fn main() { let ext_opt = Some(42); let nested_opt = Some(Some(42)); let nested_tuple_opt = Some(Some((42, 43))); + let cond = true; // Should lint - Option let _ = opt.unwrap_or(2); @@ -42,6 +43,7 @@ fn main() { let _ = opt.get_or_insert(2); let _ = opt.ok_or(2); let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); + let _ = cond.then_some(astronomers_pi); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or(2); diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 206080ed69a..1588db79b38 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -30,6 +30,7 @@ fn main() { let ext_opt = Some(42); let nested_opt = Some(Some(42)); let nested_tuple_opt = Some(Some((42, 43))); + let cond = true; // Should lint - Option let _ = opt.unwrap_or_else(|| 2); @@ -42,6 +43,7 @@ fn main() { let _ = opt.get_or_insert_with(|| 2); let _ = opt.ok_or_else(|| 2); let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + let _ = cond.then(|| astronomers_pi); // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or_else(|| 2); diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 7e4dd7730e7..83dc7fd832c 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:35:13 + --> $DIR/unnecessary_lazy_eval.rs:36:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -9,7 +9,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:36:13 + --> $DIR/unnecessary_lazy_eval.rs:37:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -17,7 +17,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:37:13 + --> $DIR/unnecessary_lazy_eval.rs:38:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -25,7 +25,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:39:13 + --> $DIR/unnecessary_lazy_eval.rs:40:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -33,7 +33,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:40:13 + --> $DIR/unnecessary_lazy_eval.rs:41:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -41,7 +41,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:41:13 + --> $DIR/unnecessary_lazy_eval.rs:42:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -49,7 +49,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:42:13 + --> $DIR/unnecessary_lazy_eval.rs:43:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -57,7 +57,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:43:13 + --> $DIR/unnecessary_lazy_eval.rs:44:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -65,15 +65,23 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:44:13 + --> $DIR/unnecessary_lazy_eval.rs:45:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- | | | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:46:13 + | +LL | let _ = cond.then(|| astronomers_pi); + | ^^^^^----------------------- + | | + | help: use `then_some(..)` instead: `then_some(astronomers_pi)` + error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:47:13 + --> $DIR/unnecessary_lazy_eval.rs:49:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -81,7 +89,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:13 + --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -89,7 +97,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:28 + --> $DIR/unnecessary_lazy_eval.rs:51:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -97,7 +105,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:13 + --> $DIR/unnecessary_lazy_eval.rs:52:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -105,7 +113,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:35 + --> $DIR/unnecessary_lazy_eval.rs:53:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -113,7 +121,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:52:28 + --> $DIR/unnecessary_lazy_eval.rs:54:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -121,7 +129,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:55:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -129,7 +137,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:56:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -137,7 +145,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:59:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -145,7 +153,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:60:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -153,7 +161,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:59:13 + --> $DIR/unnecessary_lazy_eval.rs:61:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -161,7 +169,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:79:28 + --> $DIR/unnecessary_lazy_eval.rs:81:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -169,7 +177,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:80:13 + --> $DIR/unnecessary_lazy_eval.rs:82:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -177,7 +185,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:81:13 + --> $DIR/unnecessary_lazy_eval.rs:83:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -185,7 +193,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:87:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -193,7 +201,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:88:13 + --> $DIR/unnecessary_lazy_eval.rs:90:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -201,7 +209,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:89:13 + --> $DIR/unnecessary_lazy_eval.rs:91:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -209,7 +217,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:111:35 + --> $DIR/unnecessary_lazy_eval.rs:113:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -217,7 +225,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:112:35 + --> $DIR/unnecessary_lazy_eval.rs:114:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -225,7 +233,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:113:35 + --> $DIR/unnecessary_lazy_eval.rs:115:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -233,7 +241,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:115:35 + --> $DIR/unnecessary_lazy_eval.rs:117:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -241,7 +249,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:116:35 + --> $DIR/unnecessary_lazy_eval.rs:118:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -249,7 +257,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:117:35 + --> $DIR/unnecessary_lazy_eval.rs:119:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -257,7 +265,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:118:35 + --> $DIR/unnecessary_lazy_eval.rs:120:35 | LL | let _: Result = res. | ___________________________________^ @@ -271,5 +279,5 @@ LL | | or_else(|_| Ok(ext_str.some_field)); | | | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 33 previous errors +error: aborting due to 34 previous errors -- cgit 1.4.1-3-g733a5 From ebff7206bcc4c740be9016dc7d2e10cf421463f9 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 6 Jul 2022 00:51:40 -0700 Subject: Add MSRV check for `bool::then_some` --- clippy_lints/src/methods/mod.rs | 7 ++++++- clippy_utils/src/msrvs.rs | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 36389d798ed..15d98098f33 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2737,7 +2737,12 @@ impl Methods { } }, ("take", []) => needless_option_take::check(cx, expr, recv), - ("then", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"), + ("then", [arg]) => { + if !meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { + return; + } + unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); + }, ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index b09c929f76e..9e238c6f1ac 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -12,6 +12,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,62,0 { BOOL_THEN_SOME } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } -- cgit 1.4.1-3-g733a5 From b7230d4f44e974c6639980a2e44e8d7523b6c90c Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 6 Jul 2022 00:52:53 -0700 Subject: Dogfood fixes to use `bool::then_some` --- clippy_dev/src/update_lints.rs | 2 +- clippy_lints/src/dereference.rs | 4 +++- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/matches/manual_map.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 4 ++-- clippy_lints/src/matches/mod.rs | 4 ++-- clippy_lints/src/methods/manual_str_repeat.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- clippy_lints/src/write.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/source.rs | 2 +- 16 files changed, 20 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 2e0659f42d7..c089f4d8ce4 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -553,7 +553,7 @@ fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option usize { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 59dcc1ebf19..6a35044d459 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -730,7 +730,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::DerefStable(precedence) }) }, - ExprKind::Call(func, _) if func.hir_id == child_id => (child_id == e.hir_id).then(|| Position::Callee), + ExprKind::Call(func, _) if func.hir_id == child_id => { + (child_id == e.hir_id).then_some(Position::Callee) + }, ExprKind::Call(func, args) => args .iter() .position(|arg| arg.hir_id == child_id) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 27743a0ebec..4e3ae4c9614 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -650,7 +650,7 @@ fn find_insert_calls<'tcx>( let allow_insert_closure = s.allow_insert_closure; let is_single_insert = s.is_single_insert; let edits = s.edits; - s.can_use_entry.then(|| InsertSearchResults { + s.can_use_entry.then_some(InsertSearchResults { edits, allow_insert_closure, is_single_insert, diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 6a031a627df..c5abcc46254 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -127,7 +127,7 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option { (!span.from_expansion() && impl_item.generics.params.is_empty() && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id)) - .then(|| span) + .then_some(span) } else { None } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 4278e98dc91..2b04475c7a9 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { (matches!(v.data, hir::VariantData::Unit(_)) && v.ident.as_str().starts_with('_') && is_doc_hidden(cx.tcx.hir().attrs(v.id))) - .then(|| (id, v.span)) + .then_some((id, v.span)) }); if let Some((id, span)) = iter.next() && iter.next().is_none() diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index 542905a2d76..8f98b43b9e5 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -105,7 +105,7 @@ fn check<'tcx>( // Determine which binding mode to use. let explicit_ref = some_pat.contains_explicit_ref_binding(); - let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability)); + let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then_some(ty_mutability)); let as_ref_str = match binding_ref { Some(Mutability::Mut) => ".as_mut()", diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 15513de7d86..61d28b15066 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { normalized_pats[i + 1..] .iter() .enumerate() - .find_map(|(j, other)| pat.has_overlapping_values(other).then(|| i + 1 + j)) + .find_map(|(j, other)| pat.has_overlapping_values(other).then_some(i + 1 + j)) .unwrap_or(normalized_pats.len()) }) .collect(); @@ -55,7 +55,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { .zip(forwards_blocking_idxs[..i].iter().copied().rev()) .skip_while(|&(_, forward_block)| forward_block > i) .find_map(|((j, other), forward_block)| { - (forward_block == i || pat.has_overlapping_values(other)).then(|| j) + (forward_block == i || pat.has_overlapping_values(other)).then_some(j) }) .unwrap_or(0) }) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index b2a873ef582..5c996bc33f3 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1061,7 +1061,7 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar let start = scrutinee_span.hi(); let mut arm_spans = arms.iter().map(|arm| { let data = arm.span.data(); - (data.ctxt == SyntaxContext::root()).then(|| (data.lo, data.hi)) + (data.ctxt == SyntaxContext::root()).then_some((data.lo, data.hi)) }); let end = e.span.hi(); @@ -1095,7 +1095,7 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar parent: None, } .span(); - (!span_contains_cfg(cx, span)).then(|| next_start).ok_or(()) + (!span_contains_cfg(cx, span)).then_some(next_start).ok_or(()) }); match found { Ok(start) => { diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 68a75667914..46d2fc493f8 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -43,7 +43,7 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { Some(RepeatKind::String) } else { let ty = ty.peel_refs(); - (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)).then(|| RepeatKind::String) + (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)).then_some(RepeatKind::String) } } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index ea5a8f0858b..44f153cffac 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -146,7 +146,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> }); if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind { match some_captures.get(local_id) - .or_else(|| (method_sugg == "map_or_else").then(|| ()).and_then(|_| none_captures.get(local_id))) + .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|_| none_captures.get(local_id))) { Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 25b73918c0a..8bacc6f6b32 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -501,7 +501,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio .iter() .filter_map(get_rptr_lm) .filter(|&(lt, _, _)| lt.name == out.name) - .map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span)) + .map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span)) .collect(); if let Some(args) = args && !args.is_empty() diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 75d3b040c96..3cbbda80f3a 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -73,7 +73,7 @@ fn is_ptr_to_ref(cx: &LateContext<'_>, e: &Expr<'_>, ctxt: SyntaxContext) -> (bo && let ExprKind::Unary(UnOp::Deref, derefed_expr) = borrowed_expr.kind && cx.typeck_results().expr_ty(derefed_expr).is_unsafe_ptr() { - (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then(|| derefed_expr.span)) + (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span)) } else { (false, None) } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 6518e0a6ea0..3010fc0223c 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -843,7 +843,7 @@ fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option { fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> { DEFAULT_LINT_LEVELS .iter() - .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level)) + .find_map(|(group_name, group_level)| (*group_name == lint_group).then_some(*group_level)) } pub(super) fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 67b2bc8c3f3..08b88947520 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -515,7 +515,7 @@ impl Write { args.push(arg, span); } - parser.errors.is_empty().then(move || args) + parser.errors.is_empty().then_some(args) } /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9fa28e137f9..0e739303683 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1016,7 +1016,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' captures: HirIdMap::default(), }; v.visit_expr(expr); - v.allow_closure.then(|| v.captures) + v.allow_closure.then_some(v.captures) } /// Returns the method names and argument list of nested method call expressions that make up diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index f88a92fb11c..1197fe914de 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -353,7 +353,7 @@ pub fn snippet_with_context<'a>( /// span containing `m!(0)`. pub fn walk_span_to_context(span: Span, outer: SyntaxContext) -> Option { let outer_span = hygiene::walk_chain(span, outer); - (outer_span.ctxt() == outer).then(|| outer_span) + (outer_span.ctxt() == outer).then_some(outer_span) } /// Removes block comments from the given `Vec` of lines. -- cgit 1.4.1-3-g733a5 From 307b8cd82537b5ac46da2f04cced4e4362835757 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 6 Jun 2022 15:09:37 +0000 Subject: Lint simple expressions in manual_filter_map, manual_find_map --- clippy_lints/src/methods/filter_map.rs | 107 +++++++++++++------------- tests/ui/manual_filter_map.fixed | 34 +++++++++ tests/ui/manual_filter_map.rs | 38 +++++++++ tests/ui/manual_filter_map.stderr | 120 ++++++++++++++++++++++++++--- tests/ui/manual_find_map.fixed | 37 +++++++++ tests/ui/manual_find_map.rs | 41 ++++++++++ tests/ui/manual_find_map.stderr | 136 ++++++++++++++++++++++++++++++--- 7 files changed, 440 insertions(+), 73 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 58c3e52e138..b694a5a7948 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -8,6 +8,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::Adjust; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol}; use std::borrow::Cow; @@ -49,35 +50,18 @@ fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_> is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } -/// lint use of `filter().map()` for `Iterators` -fn lint_filter_some_map_unwrap( +/// is `filter(|x| x.is_some()).map(|x| x.unwrap())` +fn is_filter_some_map_unwrap( cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_recv: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, - target_span: Span, - methods_span: Span, -) { +) -> bool { let iterator = is_trait_method(cx, expr, sym::Iterator); let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::Option); - if (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) { - let msg = "`filter` for `Some` followed by `unwrap`"; - let help = "consider using `flatten` instead"; - let sugg = format!( - "{}", - reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, target_span),) - ); - span_lint_and_sugg( - cx, - OPTION_FILTER_MAP, - methods_span, - msg, - help, - sugg, - Applicability::MachineApplicable, - ); - } + + (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) } /// lint use of `filter().map()` or `find().map()` for `Iterators` @@ -93,15 +77,20 @@ pub(super) fn check<'tcx>( map_span: Span, is_find: bool, ) { - lint_filter_some_map_unwrap( - cx, - expr, - filter_recv, - filter_arg, - map_arg, - map_span, - filter_span.with_hi(expr.span.hi()), - ); + if is_filter_some_map_unwrap(cx, expr, filter_recv, filter_arg, map_arg) { + span_lint_and_sugg( + cx, + OPTION_FILTER_MAP, + filter_span.with_hi(expr.span.hi()), + "`filter` for `Some` followed by `unwrap`", + "consider using `flatten` instead", + reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(), + Applicability::MachineApplicable, + ); + + return; + } + if_chain! { if is_trait_method(cx, map_recv, sym::Iterator); @@ -118,7 +107,7 @@ pub(super) fn check<'tcx>( // closure ends with is_some() or is_ok() if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { Some(false) } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { @@ -137,6 +126,19 @@ pub(super) fn check<'tcx>( if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind; if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + // .filter(..).map(|y| f(y).copied().unwrap()) + // ~~~~ + let map_arg_peeled = match map_arg.kind { + ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => { + original_arg + }, + _ => map_arg, + }; + + // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) + let simple_equal = path_to_local_id(filter_arg, filter_param_id) + && path_to_local_id(map_arg_peeled, map_param_id); + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { // in `filter(|x| ..)`, replace `*x` with `x` let a_path = if_chain! { @@ -145,25 +147,12 @@ pub(super) fn check<'tcx>( then { expr_path } else { a } }; // let the filter closure arg and the map closure arg be equal - if_chain! { - if path_to_local_id(a_path, filter_param_id); - if path_to_local_id(b, map_param_id); - if cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b); - then { - return true; - } - } - false - }; - - if match map_arg.kind { - ExprKind::MethodCall(method, [original_arg], _) => { - acceptable_methods(method) - && SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, original_arg) - }, - _ => SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg) + path_to_local_id(a_path, filter_param_id) + && path_to_local_id(b, map_param_id) + && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) }; + if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); then { let span = filter_span.with_hi(expr.span.hi()); let (filter_name, lint) = if is_find { @@ -171,10 +160,22 @@ pub(super) fn check<'tcx>( } else { ("filter", MANUAL_FILTER_MAP) }; - let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name); - let to_opt = if is_result { ".ok()" } else { "" }; - let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident, - snippet(cx, map_arg.span, ".."), to_opt); + let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); + let (to_opt, deref) = if is_result { + (".ok()", String::new()) + } else { + let derefs = cx.typeck_results() + .expr_adjustments(map_arg) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); + + ("", "*".repeat(derefs)) + }; + let sugg = format!( + "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", + snippet(cx, map_arg.span, ".."), + ); span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); } } diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index de0d8614889..4936dc9b2e0 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -12,6 +12,32 @@ fn main() { // is_ok(), unwrap_or() let _ = (0..).filter_map(|a| to_res(a).ok()); + + let _ = (1..5) + .filter_map(|y| *to_ref(to_opt(y))); + let _ = (1..5) + .filter_map(|y| *to_ref(to_opt(y))); + + let _ = (1..5) + .filter_map(|y| to_ref(to_res(y)).ok()); + let _ = (1..5) + .filter_map(|y| to_ref(to_res(y)).ok()); +} + +#[rustfmt::skip] +fn simple_equal() { + iter::>().find_map(|x| x.cloned()); + iter::<&Option<&u8>>().find_map(|x| x.cloned()); + iter::<&Option>().find_map(|x| x.as_deref()); + iter::>().find_map(|y| to_ref(y).cloned()); + + iter::>().find_map(|x| x.ok()); + iter::<&Result>().find_map(|x| x.ok()); + iter::<&&Result>().find_map(|x| x.ok()); + iter::>().find_map(|x| x.cloned().ok()); + iter::<&Result<&u8, ()>>().find_map(|x| x.cloned().ok()); + iter::<&Result>().find_map(|x| x.as_deref().ok()); + iter::>().find_map(|y| to_ref(y).cloned().ok()); } fn no_lint() { @@ -28,6 +54,10 @@ fn no_lint() { .map(|a| to_opt(a).unwrap()); } +fn iter() -> impl Iterator { + std::iter::empty() +} + fn to_opt(_: T) -> Option { unimplemented!() } @@ -36,6 +66,10 @@ fn to_res(_: T) -> Result { unimplemented!() } +fn to_ref<'a, T>(_: T) -> &'a T { + unimplemented!() +} + struct Issue8920<'a> { option_field: Option, result_field: Result, diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index bd6516f038b..8c67e827b4c 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -12,6 +12,36 @@ fn main() { // is_ok(), unwrap_or() let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + + let _ = (1..5) + .filter(|&x| to_ref(to_opt(x)).is_some()) + .map(|y| to_ref(to_opt(y)).unwrap()); + let _ = (1..5) + .filter(|x| to_ref(to_opt(*x)).is_some()) + .map(|y| to_ref(to_opt(y)).unwrap()); + + let _ = (1..5) + .filter(|&x| to_ref(to_res(x)).is_ok()) + .map(|y| to_ref(to_res(y)).unwrap()); + let _ = (1..5) + .filter(|x| to_ref(to_res(*x)).is_ok()) + .map(|y| to_ref(to_res(y)).unwrap()); +} + +#[rustfmt::skip] +fn simple_equal() { + iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); + iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + + iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); + iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); + iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); } fn no_lint() { @@ -28,6 +58,10 @@ fn no_lint() { .map(|a| to_opt(a).unwrap()); } +fn iter() -> impl Iterator { + std::iter::empty() +} + fn to_opt(_: T) -> Option { unimplemented!() } @@ -36,6 +70,10 @@ fn to_res(_: T) -> Result { unimplemented!() } +fn to_ref<'a, T>(_: T) -> &'a T { + unimplemented!() +} + struct Issue8920<'a> { option_field: Option, result_field: Result, diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index 465f1b19110..6e5bbe8f2aa 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -19,7 +19,107 @@ LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_o | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:54:10 + --> $DIR/manual_filter_map.rs:17:10 + | +LL | .filter(|&x| to_ref(to_opt(x)).is_some()) + | __________^ +LL | | .map(|y| to_ref(to_opt(y)).unwrap()); + | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:20:10 + | +LL | .filter(|x| to_ref(to_opt(*x)).is_some()) + | __________^ +LL | | .map(|y| to_ref(to_opt(y)).unwrap()); + | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:24:10 + | +LL | .filter(|&x| to_ref(to_res(x)).is_ok()) + | __________^ +LL | | .map(|y| to_ref(to_res(y)).unwrap()); + | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:27:10 + | +LL | .filter(|x| to_ref(to_res(*x)).is_ok()) + | __________^ +LL | | .map(|y| to_ref(to_res(y)).unwrap()); + | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:33:27 + | +LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` + | + = note: `-D clippy::manual-find-map` implied by `-D warnings` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:34:28 + | +LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:35:31 + | +LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:36:31 + | +LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:38:30 + | +LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:39:31 + | +LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:40:32 + | +LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:41:31 + | +LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:42:32 + | +LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:43:35 + | +LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_filter_map.rs:44:35 + | +LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:92:10 | LL | .filter(|f| f.option_field.is_some()) | __________^ @@ -27,7 +127,7 @@ LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:59:10 + --> $DIR/manual_filter_map.rs:97:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ @@ -35,7 +135,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:64:10 + --> $DIR/manual_filter_map.rs:102:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ @@ -43,7 +143,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:69:10 + --> $DIR/manual_filter_map.rs:107:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -51,7 +151,7 @@ LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:74:10 + --> $DIR/manual_filter_map.rs:112:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -59,7 +159,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:79:10 + --> $DIR/manual_filter_map.rs:117:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -67,7 +167,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:84:10 + --> $DIR/manual_filter_map.rs:122:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -75,7 +175,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:89:10 + --> $DIR/manual_filter_map.rs:127:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -83,12 +183,12 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:94:10 + --> $DIR/manual_filter_map.rs:132:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ LL | | .map(|f| f.result_field.to_owned().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())` -error: aborting due to 12 previous errors +error: aborting due to 27 previous errors diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index d69b6c1dcf3..54302beceff 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -12,6 +12,35 @@ fn main() { // is_ok(), unwrap_or() let _ = (0..).find_map(|a| to_res(a).ok()); + + let _ = (1..5) + .find_map(|y| *to_ref(to_opt(y))); + let _ = (1..5) + .find_map(|y| *to_ref(to_opt(y))); + + let _ = (1..5) + .find_map(|y| to_ref(to_res(y)).ok()); + let _ = (1..5) + .find_map(|y| to_ref(to_res(y)).ok()); +} + +#[rustfmt::skip] +fn simple_equal() { + iter::>().find_map(|x| x); + iter::<&Option>().find_map(|x| *x); + iter::<&&Option>().find_map(|x| **x); + iter::>().find_map(|x| x.cloned()); + iter::<&Option<&u8>>().find_map(|x| x.cloned()); + iter::<&Option>().find_map(|x| x.as_deref()); + iter::>().find_map(|y| to_ref(y).cloned()); + + iter::>().find_map(|x| x.ok()); + iter::<&Result>().find_map(|x| x.ok()); + iter::<&&Result>().find_map(|x| x.ok()); + iter::>().find_map(|x| x.cloned().ok()); + iter::<&Result<&u8, ()>>().find_map(|x| x.cloned().ok()); + iter::<&Result>().find_map(|x| x.as_deref().ok()); + iter::>().find_map(|y| to_ref(y).cloned().ok()); } fn no_lint() { @@ -28,6 +57,10 @@ fn no_lint() { .map(|a| to_opt(a).unwrap()); } +fn iter() -> impl Iterator { + std::iter::empty() +} + fn to_opt(_: T) -> Option { unimplemented!() } @@ -36,6 +69,10 @@ fn to_res(_: T) -> Result { unimplemented!() } +fn to_ref<'a, T>(_: T) -> &'a T { + unimplemented!() +} + struct Issue8920<'a> { option_field: Option, result_field: Result, diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index 1c4e18e31c8..afcc1825a9a 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -12,6 +12,39 @@ fn main() { // is_ok(), unwrap_or() let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + + let _ = (1..5) + .find(|&x| to_ref(to_opt(x)).is_some()) + .map(|y| to_ref(to_opt(y)).unwrap()); + let _ = (1..5) + .find(|x| to_ref(to_opt(*x)).is_some()) + .map(|y| to_ref(to_opt(y)).unwrap()); + + let _ = (1..5) + .find(|&x| to_ref(to_res(x)).is_ok()) + .map(|y| to_ref(to_res(y)).unwrap()); + let _ = (1..5) + .find(|x| to_ref(to_res(*x)).is_ok()) + .map(|y| to_ref(to_res(y)).unwrap()); +} + +#[rustfmt::skip] +fn simple_equal() { + iter::>().find(|x| x.is_some()).map(|x| x.unwrap()); + iter::<&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); + iter::<&&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); + iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); + iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + + iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); + iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); + iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); } fn no_lint() { @@ -28,6 +61,10 @@ fn no_lint() { .map(|a| to_opt(a).unwrap()); } +fn iter() -> impl Iterator { + std::iter::empty() +} + fn to_opt(_: T) -> Option { unimplemented!() } @@ -36,6 +73,10 @@ fn to_res(_: T) -> Result { unimplemented!() } +fn to_ref<'a, T>(_: T) -> &'a T { + unimplemented!() +} + struct Issue8920<'a> { option_field: Option, result_field: Result, diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index 9dea42b7686..c1ac499f7c6 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -19,7 +19,123 @@ LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or( | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:54:10 + --> $DIR/manual_find_map.rs:17:10 + | +LL | .find(|&x| to_ref(to_opt(x)).is_some()) + | __________^ +LL | | .map(|y| to_ref(to_opt(y)).unwrap()); + | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:20:10 + | +LL | .find(|x| to_ref(to_opt(*x)).is_some()) + | __________^ +LL | | .map(|y| to_ref(to_opt(y)).unwrap()); + | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:24:10 + | +LL | .find(|&x| to_ref(to_res(x)).is_ok()) + | __________^ +LL | | .map(|y| to_ref(to_res(y)).unwrap()); + | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:27:10 + | +LL | .find(|x| to_ref(to_res(*x)).is_ok()) + | __________^ +LL | | .map(|y| to_ref(to_res(y)).unwrap()); + | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:33:26 + | +LL | iter::>().find(|x| x.is_some()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:34:27 + | +LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:35:28 + | +LL | iter::<&&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:36:27 + | +LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:37:28 + | +LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:38:31 + | +LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:39:31 + | +LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:41:30 + | +LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:42:31 + | +LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:43:32 + | +LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:44:31 + | +LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:45:32 + | +LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:46:35 + | +LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:47:35 + | +LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` + +error: `find(..).map(..)` can be simplified as `find_map(..)` + --> $DIR/manual_find_map.rs:95:10 | LL | .find(|f| f.option_field.is_some()) | __________^ @@ -27,7 +143,7 @@ LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:59:10 + --> $DIR/manual_find_map.rs:100:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ @@ -35,7 +151,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:64:10 + --> $DIR/manual_find_map.rs:105:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ @@ -43,7 +159,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:69:10 + --> $DIR/manual_find_map.rs:110:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -51,7 +167,7 @@ LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:74:10 + --> $DIR/manual_find_map.rs:115:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -59,7 +175,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:79:10 + --> $DIR/manual_find_map.rs:120:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -67,7 +183,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:84:10 + --> $DIR/manual_find_map.rs:125:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -75,7 +191,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:89:10 + --> $DIR/manual_find_map.rs:130:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -83,12 +199,12 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:94:10 + --> $DIR/manual_find_map.rs:135:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ LL | | .map(|f| f.result_field.to_owned().unwrap()); | |____________________________________________________^ help: try: `find_map(|f| f.result_field.to_owned().ok())` -error: aborting due to 12 previous errors +error: aborting due to 30 previous errors -- cgit 1.4.1-3-g733a5 From 97cd46fa33a36bc1edcbc8eba2c142be5da34055 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Sun, 10 Jul 2022 13:11:19 +0300 Subject: Fix span for or_fun_call --- clippy_lints/src/methods/or_fun_call.rs | 23 +++---- tests/ui/or_fun_call.fixed | 12 ++-- tests/ui/or_fun_call.stderr | 106 +++++++------------------------- 3 files changed, 37 insertions(+), 104 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 3d1208824fa..16e160e6a17 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; -use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::{implements_trait, match_type}; use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths}; use if_chain::if_chain; @@ -28,10 +28,10 @@ pub(super) fn check<'tcx>( cx: &LateContext<'_>, name: &str, fun: &hir::Expr<'_>, - self_expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, or_has_args: bool, span: Span, + method_span: Span, ) -> bool { let is_default_default = || is_trait_item(cx, fun, sym::Default); @@ -52,24 +52,15 @@ pub(super) fn check<'tcx>( || (matches!(path, sym::new) && implements_default(arg, default_trait_id)); then { - let mut applicability = Applicability::MachineApplicable; - let hint = "unwrap_or_default()"; - let sugg_span = span; - - let sugg: String = format!( - "{}.{}", - snippet_with_applicability(cx, self_expr.span, "..", &mut applicability), - hint - ); - + let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( cx, OR_FUN_CALL, - sugg_span, + span_replace_word, &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - sugg, - applicability, + format!("unwrap_or_default()"), + Applicability::MachineApplicable, ); true @@ -171,7 +162,7 @@ pub(super) fn check<'tcx>( match inner_arg.kind { hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) { + if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span); } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 123aed40251..fdb08d953ff 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -185,7 +185,8 @@ mod issue8239 { .reduce(|mut acc, f| { acc.push_str(&f); acc - }).unwrap_or_default(); + }) + .unwrap_or_default(); } fn more_to_max_suggestion_highest_lines_1() { @@ -197,7 +198,8 @@ mod issue8239 { let _ = ""; acc.push_str(&f); acc - }).unwrap_or_default(); + }) + .unwrap_or_default(); } fn equal_to_max_suggestion_highest_lines() { @@ -208,7 +210,8 @@ mod issue8239 { let _ = ""; acc.push_str(&f); acc - }).unwrap_or_default(); + }) + .unwrap_or_default(); } fn less_than_max_suggestion_highest_lines() { @@ -218,7 +221,8 @@ mod issue8239 { map.reduce(|mut acc, f| { acc.push_str(&f); acc - }).unwrap_or_default(); + }) + .unwrap_or_default(); } } diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index dfe15654bc3..4c5938ab88b 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -7,10 +7,10 @@ LL | with_constructor.unwrap_or(make()); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:52:5 + --> $DIR/or_fun_call.rs:52:14 | LL | with_new.unwrap_or(Vec::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:55:21 @@ -31,16 +31,16 @@ LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:64:5 + --> $DIR/or_fun_call.rs:64:24 | LL | with_default_trait.unwrap_or(Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:67:5 + --> $DIR/or_fun_call.rs:67:23 | LL | with_default_type.unwrap_or(u64::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:70:18 @@ -49,16 +49,16 @@ LL | self_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(::default)` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:73:5 + --> $DIR/or_fun_call.rs:73:18 | LL | real_default.unwrap_or(::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `real_default.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:76:5 + --> $DIR/or_fun_call.rs:76:14 | LL | with_vec.unwrap_or(vec![]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:79:21 @@ -109,90 +109,28 @@ LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:182:9 - | -LL | / frames -LL | | .iter() -LL | | .map(|f: &String| f.to_lowercase()) -LL | | .reduce(|mut acc, f| { -... | -LL | | }) -LL | | .unwrap_or(String::new()); - | |_____________________________________^ - | -help: try this - | -LL ~ frames -LL + .iter() -LL + .map(|f: &String| f.to_lowercase()) -LL + .reduce(|mut acc, f| { -LL + acc.push_str(&f); -LL + acc -LL ~ }).unwrap_or_default(); + --> $DIR/or_fun_call.rs:189:14 | +LL | .unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:195:9 - | -LL | / iter.map(|f: &String| f.to_lowercase()) -LL | | .reduce(|mut acc, f| { -LL | | let _ = ""; -LL | | let _ = ""; -... | -LL | | }) -LL | | .unwrap_or(String::new()); - | |_____________________________________^ - | -help: try this - | -LL ~ iter.map(|f: &String| f.to_lowercase()) -LL + .reduce(|mut acc, f| { -LL + let _ = ""; -LL + let _ = ""; -LL + acc.push_str(&f); -LL + acc -LL ~ }).unwrap_or_default(); + --> $DIR/or_fun_call.rs:202:14 | +LL | .unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:208:9 - | -LL | / iter.map(|f: &String| f.to_lowercase()) -LL | | .reduce(|mut acc, f| { -LL | | let _ = ""; -LL | | acc.push_str(&f); -LL | | acc -LL | | }) -LL | | .unwrap_or(String::new()); - | |_____________________________________^ - | -help: try this - | -LL ~ iter.map(|f: &String| f.to_lowercase()) -LL + .reduce(|mut acc, f| { -LL + let _ = ""; -LL + acc.push_str(&f); -LL + acc -LL ~ }).unwrap_or_default(); + --> $DIR/or_fun_call.rs:214:14 | +LL | .unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:221:9 - | -LL | / map.reduce(|mut acc, f| { -LL | | acc.push_str(&f); -LL | | acc -LL | | }) -LL | | .unwrap_or(String::new()); - | |_________________________________^ - | -help: try this - | -LL ~ map.reduce(|mut acc, f| { -LL + acc.push_str(&f); -LL + acc -LL ~ }).unwrap_or_default(); + --> $DIR/or_fun_call.rs:225:10 | +LL | .unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: aborting due to 22 previous errors -- cgit 1.4.1-3-g733a5 From 783992e69389bff1890adaca4cac5967c6724b40 Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Sun, 10 Jul 2022 13:34:58 +0300 Subject: Fix dogfood issue for or_fun_call --- clippy_lints/src/methods/or_fun_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 16e160e6a17..5a356108434 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -59,7 +59,7 @@ pub(super) fn check<'tcx>( span_replace_word, &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - format!("unwrap_or_default()"), + "unwrap_or_default()".to_string(), Applicability::MachineApplicable, ); -- cgit 1.4.1-3-g733a5 From c3c4cda50b1b1b212eb02e5d822b3fd1479dc24c Mon Sep 17 00:00:00 2001 From: alex-semenyuk Date: Mon, 11 Jul 2022 10:34:01 +0300 Subject: Address review --- clippy_lints/src/methods/or_fun_call.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 5a356108434..6af134019a4 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -52,11 +52,10 @@ pub(super) fn check<'tcx>( || (matches!(path, sym::new) && implements_default(arg, default_trait_id)); then { - let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( cx, OR_FUN_CALL, - span_replace_word, + method_span.with_hi(span.hi()), &format!("use of `{}` followed by a call to `{}`", name, path), "try this", "unwrap_or_default()".to_string(), -- cgit 1.4.1-3-g733a5 From e7804355de8bfc93b3604beec7a7c32665a305ee Mon Sep 17 00:00:00 2001 From: alexey semenyuk Date: Sun, 19 Jun 2022 14:15:14 +0000 Subject: NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements NEEDLESS_OPTION_TAKE doc improvements --- clippy_lints/src/methods/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9bb7bb7a7ab..4bdb5785cff 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2225,8 +2225,12 @@ declare_clippy_lint! { } declare_clippy_lint! { + /// ### What it does + /// Checks for calling `take` function after `as_ref`. /// /// ### Why is this bad? + /// Redundant code. `take` writes `None` to its argument. + /// In this case the modification is useless as it's a temporary that cannot be read from afterwards. /// /// ### Example /// ```rust -- cgit 1.4.1-3-g733a5 From 9ff7c911008fc74c8d6c76afe12d7e30e67f8d25 Mon Sep 17 00:00:00 2001 From: Ariel Uy Date: Sun, 10 Jul 2022 14:37:38 -0700 Subject: Add new lint `obfuscated_if_else` New lint suggests using `if .. else ..` instead of `.then_some(..).unwrap_or(..)`. --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/methods/mod.rs | 34 +++++++++++++++++++++ clippy_lints/src/methods/obfuscated_if_else.rs | 42 ++++++++++++++++++++++++++ tests/ui/obfuscated_if_else.fixed | 7 +++++ tests/ui/obfuscated_if_else.rs | 7 +++++ tests/ui/obfuscated_if_else.stderr | 10 ++++++ 9 files changed, 104 insertions(+) create mode 100644 clippy_lints/src/methods/obfuscated_if_else.rs create mode 100644 tests/ui/obfuscated_if_else.fixed create mode 100644 tests/ui/obfuscated_if_else.rs create mode 100644 tests/ui/obfuscated_if_else.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b792736a6a..00fce79ec06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3792,6 +3792,7 @@ Released 2018-09-13 [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref +[`obfuscated_if_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#obfuscated_if_else [`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index da26a3f0130..69387d560c9 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -188,6 +188,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::NO_EFFECT_REPLACE), + LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index ceb8470657f..24b921faf03 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -330,6 +330,7 @@ store.register_lints(&[ methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, methods::NO_EFFECT_REPLACE, + methods::OBFUSCATED_IF_ELSE, methods::OK_EXPECT, methods::OPTION_AS_REF_DEREF, methods::OPTION_FILTER_MAP, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 15a1bc569af..e95bab1d045 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -70,6 +70,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 29ec6e04286..c252272e254 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -46,6 +46,7 @@ mod map_unwrap_or; mod needless_option_as_deref; mod needless_option_take; mod no_effect_replace; +mod obfuscated_if_else; mod ok_expect; mod option_as_ref_deref; mod option_map_or_none; @@ -2259,6 +2260,35 @@ declare_clippy_lint! { "replace with no effect" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of `.then_some(..).unwrap_or(..)` + /// + /// ### Why is this bad? + /// This can be written more clearly with `if .. else ..` + /// + /// ### Limitations + /// This lint currently only looks for usages of + /// `.then_some(..).unwrap_or(..)`, but will be expanded + /// to account for similar patterns. + /// + /// ### Example + /// ```rust + /// let x = true; + /// x.then_some("a").unwrap_or("b"); + /// ``` + /// Use instead: + /// ```rust + /// let x = true; + /// if x { "a" } else { "b" }; + /// ``` + #[clippy::version = "1.64.0"] + pub OBFUSCATED_IF_ELSE, + style, + "use of `.then_some(..).unwrap_or(..)` can be written \ + more clearly with `if .. else ..`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2360,6 +2390,7 @@ impl_lint_pass!(Methods => [ IS_DIGIT_ASCII_RADIX, NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, + OBFUSCATED_IF_ELSE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2768,6 +2799,9 @@ impl Methods { 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], _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); + }, _ => {}, }, ("unwrap_or_else", [u_arg]) => match method_call(recv) { diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs new file mode 100644 index 00000000000..4d7427b2662 --- /dev/null +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -0,0 +1,42 @@ +// run-rustfix + +use super::OBFUSCATED_IF_ELSE; +use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + then_recv: &'tcx hir::Expr<'_>, + then_arg: &'tcx hir::Expr<'_>, + unwrap_arg: &'tcx hir::Expr<'_>, +) { + // something.then_some(blah).unwrap_or(blah) + // ^^^^^^^^^-then_recv ^^^^-then_arg ^^^^- unwrap_arg + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr + + let recv_ty = cx.typeck_results().expr_ty(then_recv); + + if recv_ty.is_bool() { + let mut applicability = Applicability::MachineApplicable; + let sugg = format!( + "if {} {{ {} }} else {{ {} }}", + snippet_with_applicability(cx, then_recv.span, "..", &mut applicability), + snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability) + ); + + span_lint_and_sugg( + cx, + OBFUSCATED_IF_ELSE, + expr.span, + "use of `.then_some(..).unwrap_or(..)` can be written \ + more clearly with `if .. else ..`", + "try", + sugg, + applicability, + ); + } +} diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed new file mode 100644 index 00000000000..62d932c2c6b --- /dev/null +++ b/tests/ui/obfuscated_if_else.fixed @@ -0,0 +1,7 @@ +// run-rustfix + +#![warn(clippy::obfuscated_if_else)] + +fn main() { + if true { "a" } else { "b" }; +} diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs new file mode 100644 index 00000000000..273be9092a7 --- /dev/null +++ b/tests/ui/obfuscated_if_else.rs @@ -0,0 +1,7 @@ +// run-rustfix + +#![warn(clippy::obfuscated_if_else)] + +fn main() { + true.then_some("a").unwrap_or("b"); +} diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr new file mode 100644 index 00000000000..e4180c28869 --- /dev/null +++ b/tests/ui/obfuscated_if_else.stderr @@ -0,0 +1,10 @@ +error: use of `.then_some(..).unwrap_or(..)` can be written more clearly with `if .. else ..` + --> $DIR/obfuscated_if_else.rs:6:5 + | +LL | true.then_some("a").unwrap_or("b"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` + | + = note: `-D clippy::obfuscated-if-else` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 6ee03e2b014fc98e1bbfdbf5c39872b8308cd15d Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Thu, 21 Jul 2022 22:45:12 +0200 Subject: unwrap_used: Stop recommending using `expect` when the `expect_used` lint is not allowed --- clippy_lints/src/methods/unwrap_used.rs | 21 +++++++++++-------- tests/ui/unwrap_expect_used.rs | 10 +++++++++ tests/ui/unwrap_expect_used.stderr | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tests/ui/unwrap_expect_used.rs create mode 100644 tests/ui/unwrap_expect_used.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 5c761014927..eae6ba693a2 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_test_function; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_test_function, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; -use super::UNWRAP_USED; +use super::{EXPECT_USED, UNWRAP_USED}; /// lint use of `unwrap()` for `Option`s and `Result`s pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { @@ -24,17 +24,22 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr } if let Some((lint, kind, none_value)) = mess { + let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { + format!( + "if you don't want to handle the `{none_value}` case gracefully, consider \ + using `expect()` to provide a better panic message" + ) + } else { + format!("if this value is an `{none_value}`, it will panic") + }; + span_lint_and_help( cx, lint, expr.span, - &format!("used `unwrap()` on `{}` value", kind,), + &format!("used `unwrap()` on `{kind}` value"), None, - &format!( - "if you don't want to handle the `{}` case gracefully, consider \ - using `expect()` to provide a better panic message", - none_value, - ), + &help, ); } } diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs new file mode 100644 index 00000000000..0d4a0504a6e --- /dev/null +++ b/tests/ui/unwrap_expect_used.rs @@ -0,0 +1,10 @@ +#![warn(clippy::unwrap_used, clippy::expect_used)] + +fn main() { + Some(3).unwrap(); + Some(3).expect("Hello world!"); + + let a: Result = Ok(3); + a.unwrap(); + a.expect("Hello world!"); +} diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr new file mode 100644 index 00000000000..a44aed4cb38 --- /dev/null +++ b/tests/ui/unwrap_expect_used.stderr @@ -0,0 +1,36 @@ +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:4:5 + | +LL | Some(3).unwrap(); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: if this value is an `None`, it will panic + +error: used `expect()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:5:5 + | +LL | Some(3).expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::expect-used` implied by `-D warnings` + = help: if this value is an `None`, it will panic + +error: used `unwrap()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:8:5 + | +LL | a.unwrap(); + | ^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: used `expect()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:9:5 + | +LL | a.expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 3e5203147176bf4e7895c917d694a14d33e13419 Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Fri, 22 Jul 2022 19:14:31 +0200 Subject: unwrap_used: Fix help, "an `None`" -> "`None`" --- clippy_lints/src/methods/expect_used.rs | 10 +++++----- clippy_lints/src/methods/unwrap_used.rs | 8 ++++---- tests/ui-toml/expect_used/expect_used.stderr | 2 +- tests/ui/expect.stderr | 2 +- tests/ui/unwrap_expect_used.stderr | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index fbc3348f185..5ef08ca6290 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((EXPECT_USED, "an Option", "None")) + Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err")) + Some((EXPECT_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { span_lint_and_help( cx, lint, expr.span, - &format!("used `expect()` on `{}` value", kind,), + &format!("used `expect()` on `{kind}` value"), None, - &format!("if this value is an `{}`, it will panic", none_value,), + &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); } } diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index eae6ba693a2..ce1a52e5480 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((UNWRAP_USED, "an Option", "None")) + Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err")) + Some((UNWRAP_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { format!( "if you don't want to handle the `{none_value}` case gracefully, consider \ using `expect()` to provide a better panic message" ) } else { - format!("if this value is an `{none_value}`, it will panic") + format!("if this value is {none_prefix}`{none_value}`, it will panic") }; span_lint_and_help( diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index 9cb2199ed21..c5d95cb8a14 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect_used.rs:11:13 diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index 9d3fc7df15c..ab28aac4556 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect.rs:10:13 diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index a44aed4cb38..f54bfd617c4 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -5,7 +5,7 @@ LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unwrap-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `an Option` value --> $DIR/unwrap_expect_used.rs:5:5 @@ -14,7 +14,7 @@ LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `unwrap()` on `a Result` value --> $DIR/unwrap_expect_used.rs:8:5 -- cgit 1.4.1-3-g733a5 From 307b800f27aaab6363ad5ca09009a71852f6d7cc Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Thu, 28 Jul 2022 22:08:48 +0200 Subject: unwrap_used: Fix doc to not recommend expect when expect_used is not allowed --- clippy_lints/src/methods/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 202fbc1f7f6..05f20e6cb9c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -197,13 +197,22 @@ declare_clippy_lint! { /// result.unwrap(); /// ``` /// - /// Use instead: + /// If [expect_used](#expect_used) is allowed, instead: /// ```rust /// # let option = Some(1); /// # let result: Result = Ok(1); /// option.expect("more helpful message"); /// result.expect("more helpful message"); /// ``` + /// + /// Otherwise try using + /// ```rust + /// option?; + /// + /// // or + /// + /// result?; + /// ``` #[clippy::version = "1.45.0"] pub UNWRAP_USED, restriction, -- cgit 1.4.1-3-g733a5 From 1fd9f2d2716689022a0473f8bce5d2f40275bd64 Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Thu, 28 Jul 2022 22:27:50 +0200 Subject: Fix tests --- clippy_lints/src/methods/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 05f20e6cb9c..06e7af57ee1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -206,7 +206,9 @@ declare_clippy_lint! { /// ``` /// /// Otherwise try using - /// ```rust + /// ```rust,ignore + /// # let option = Some(1); + /// # let result: Result = Ok(1); /// option?; /// /// // or -- cgit 1.4.1-3-g733a5 From 23b4fe6da55291a5937535d09af2bdfed8a9a50d Mon Sep 17 00:00:00 2001 From: Sosthene <51865119+sgued@users.noreply.github.com> Date: Sat, 30 Jul 2022 13:17:51 +0200 Subject: Apply suggestions from code review The expect_used lint is allow-by-default, so it would be better to show the case where this is enabled. Co-authored-by: Takayuki Nakata --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 06e7af57ee1..5ac6b09f0aa 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -197,7 +197,7 @@ declare_clippy_lint! { /// result.unwrap(); /// ``` /// - /// If [expect_used](#expect_used) is allowed, instead: + /// Use instead: /// ```rust /// # let option = Some(1); /// # let result: Result = Ok(1); @@ -205,7 +205,7 @@ declare_clippy_lint! { /// result.expect("more helpful message"); /// ``` /// - /// Otherwise try using + /// If [expect_used](#expect_used) is enabled, instead: /// ```rust,ignore /// # let option = Some(1); /// # let result: Result = Ok(1); -- cgit 1.4.1-3-g733a5 From 145ebb1cd723e34dc5a940ec3e498de814e6293d Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Tue, 2 Aug 2022 10:39:35 -0500 Subject: add paren before '?' when suggesting deref --- clippy_lints/src/methods/clone_on_copy.rs | 6 +++++- tests/ui/clone_on_copy.fixed | 6 +++++- tests/ui/clone_on_copy.rs | 6 +++++- tests/ui/clone_on_copy.stderr | 8 +++++++- 4 files changed, 22 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 0b38a07204e..a813d39441b 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; @@ -86,6 +86,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, { return; }, + ExprKind::Call(hir_callee, _) => match hir_callee.kind { + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) => true, + _ => false, + }, ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index dc062762604..43849121b04 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42; vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,8 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42); + + let opt: &Option = &None; + let value = (*opt)?; + None } diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 8c39d0d55dd..1f10599da22 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42.clone(); vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,8 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42.clone()); + + let opt: &Option = &None; + let value = opt.clone()?; + None } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 861543d0aa9..483ea35af2a 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: aborting due to 8 previous errors +error: using `clone` on type `std::option::Option` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:76:17 + | +LL | let value = opt.clone()?; + | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` + +error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From 503c03c5584bb697071f3585953ed6e5b16d2e10 Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Tue, 2 Aug 2022 12:06:22 -0500 Subject: clean up --- clippy_lints/src/methods/clone_on_copy.rs | 9 +++++---- tests/ui/clone_on_copy.fixed | 3 ++- tests/ui/clone_on_copy.rs | 3 ++- tests/ui/clone_on_copy.stderr | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index a813d39441b..60e1355f9b9 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -86,10 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, { return; }, - ExprKind::Call(hir_callee, _) => match hir_callee.kind { - ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) => true, - _ => false, - }, + // ? is a Call, makes sure not to rec *x?, but rather (*x)? + ExprKind::Call(hir_callee, _) => matches!( + hir_callee.kind, + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) + ), ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index 43849121b04..72b12227098 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -72,7 +72,8 @@ fn clone_on_copy() -> Option<(i32)> { let mut vec = Vec::new(); vec.push(42); + // Issue #9277 let opt: &Option = &None; - let value = (*opt)?; + let value = (*opt)?; // operator precedence needed (*opt)? None } diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 1f10599da22..03e210ebad9 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -72,7 +72,8 @@ fn clone_on_copy() -> Option<(i32)> { let mut vec = Vec::new(); vec.push(42.clone()); + // Issue #9277 let opt: &Option = &None; - let value = opt.clone()?; + let value = opt.clone()?; // operator precedence needed (*opt)? None } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 483ea35af2a..42ae227777c 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -49,9 +49,9 @@ LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` error: using `clone` on type `std::option::Option` which implements the `Copy` trait - --> $DIR/clone_on_copy.rs:76:17 + --> $DIR/clone_on_copy.rs:77:17 | -LL | let value = opt.clone()?; +LL | let value = opt.clone()?; // operator precedence needed (*opt)? | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From f3f86d8fd96dfa5986ffe10d0837169e473b9b83 Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Sat, 16 Jul 2022 23:07:06 +0200 Subject: Move iter_once and iter_empty to methods as a late pass This enables more thorough checking of types to avoid triggering on custom Some and None enum variants --- clippy_lints/src/iter_once_empty.rs | 164 ---------------------------- clippy_lints/src/lib.register_lints.rs | 4 +- clippy_lints/src/lib.register_pedantic.rs | 2 - clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/iter_once_empty.rs | 70 ++++++++++++ clippy_lints/src/methods/mod.rs | 81 ++++++++++++++ tests/ui/iter_empty.fixed | 23 ++++ tests/ui/iter_empty.rs | 23 ++++ tests/ui/iter_once.fixed | 23 ++++ tests/ui/iter_once.rs | 23 ++++ 10 files changed, 245 insertions(+), 170 deletions(-) delete mode 100644 clippy_lints/src/iter_once_empty.rs create mode 100644 clippy_lints/src/methods/iter_once_empty.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/iter_once_empty.rs b/clippy_lints/src/iter_once_empty.rs deleted file mode 100644 index 09896001112..00000000000 --- a/clippy_lints/src/iter_once_empty.rs +++ /dev/null @@ -1,164 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use rustc_ast::ast::{Expr, ExprKind}; -use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// - /// Checks for usage of: - /// - /// - `[foo].iter()` - /// - `[foo].iter_mut()` - /// - `[foo].into_iter()` - /// - `Some(foo).iter()` - /// - `Some(foo).iter_mut()` - /// - `Some(foo).into_iter()` - /// - /// ### Why is this bad? - /// - /// It is simpler to use the once function from the standard library: - /// - /// ### Example - /// - /// ```rust - /// let a = [123].iter(); - /// let b = Some(123).into_iter(); - /// ``` - /// Use instead: - /// ```rust - /// use std::iter; - /// let a = iter::once(&123); - /// let b = iter::once(123); - /// ``` - /// - /// ### Known problems - /// - /// The type of the resulting iterator might become incompatible with its usage - #[clippy::version = "1.64.0"] - pub ITER_ONCE, - nursery, - "Iterator for array of length 1" -} - -declare_clippy_lint! { - /// ### What it does - /// - /// Checks for usage of: - /// - /// - `[].iter()` - /// - `[].iter_mut()` - /// - `[].into_iter()` - /// - `None.iter()` - /// - `None.iter_mut()` - /// - `None.into_iter()` - /// - /// ### Why is this bad? - /// - /// It is simpler to use the empty function from the standard library: - /// - /// ### Example - /// - /// ```rust - /// use std::{slice, option}; - /// let a: slice::Iter = [].iter(); - /// let f: option::IntoIter = None.into_iter(); - /// ``` - /// Use instead: - /// ```rust - /// use std::iter; - /// let a: iter::Empty = iter::empty(); - /// let b: iter::Empty = iter::empty(); - /// ``` - /// - /// ### Known problems - /// - /// The type of the resulting iterator might become incompatible with its usage - #[clippy::version = "1.64.0"] - pub ITER_EMPTY, - nursery, - "Iterator for empty array" -} - -declare_lint_pass!(IterOnceEmpty => [ITER_ONCE, ITER_EMPTY]); - -impl EarlyLintPass for IterOnceEmpty { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - // Don't lint match expressions present in - // macro_rules! block - return; - } - - let (method_name, args) = if let ExprKind::MethodCall(seg, args, _) = &expr.kind { - (seg.ident.as_str(), args) - } else { - return; - }; - let arg = if args.len() == 1 { - &args[0] - } else { - return; - }; - - let item = match &arg.kind { - ExprKind::Array(v) if v.len() <= 1 => v.first(), - ExprKind::Path(None, p) => { - if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::None { - None - } else { - return; - } - }, - ExprKind::Call(f, some_args) if some_args.len() == 1 => { - if let ExprKind::Path(None, p) = &f.kind { - if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::Some { - Some(&some_args[0]) - } else { - return; - } - } else { - return; - } - }, - _ => return, - }; - - if let Some(i) = item { - let (sugg, msg) = match method_name { - "iter" => ( - format!("std::iter::once(&{})", snippet(cx, i.span, "...")), - "this `iter` call can be replaced with std::iter::once", - ), - "iter_mut" => ( - format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), - "this `iter_mut` call can be replaced with std::iter::once", - ), - "into_iter" => ( - format!("std::iter::once({})", snippet(cx, i.span, "...")), - "this `into_iter` call can be replaced with std::iter::once", - ), - _ => return, - }; - span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); - } else { - let msg = match method_name { - "iter" => "this `iter call` can be replaced with std::iter::empty", - "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", - "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", - _ => return, - }; - span_lint_and_sugg( - cx, - ITER_EMPTY, - expr.span, - msg, - "try", - "std::iter::empty()".to_string(), - Applicability::Unspecified, - ); - } - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 49fc3a89527..e49321d83fa 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -200,8 +200,6 @@ store.register_lints(&[ invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, - iter_once_empty::ITER_EMPTY, - iter_once_empty::ITER_ONCE, large_const_arrays::LARGE_CONST_ARRAYS, large_enum_variant::LARGE_ENUM_VARIANT, large_include_file::LARGE_INCLUDE_FILE, @@ -314,9 +312,11 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, + methods::ITER_EMPTY, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, + methods::ITER_ONCE, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6063fb00a7b..4250ee055e6 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -41,8 +41,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), - LintId::of(iter_once_empty::ITER_EMPTY), - LintId::of(iter_once_empty::ITER_ONCE), LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(let_underscore::LET_UNDERSCORE_DROP), LintId::of(literal_representation::LARGE_DIGIT_GROUPS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 78279db9ad5..88c1a727f8d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -258,7 +258,6 @@ mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; mod iter_not_returning_iterator; -mod iter_once_empty; mod large_const_arrays; mod large_enum_variant; mod large_include_file; @@ -932,7 +931,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); - store.register_early_pass(|| Box::new(iter_once_empty::IterOnceEmpty)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs new file mode 100644 index 00000000000..d45dfc67880 --- /dev/null +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -0,0 +1,70 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; +use clippy_utils::source::snippet; + +use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::{ITER_EMPTY, ITER_ONCE}; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { + let item = match &recv.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(p) => { + if is_lang_ctor(cx, p, OptionNone) { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(p) = &f.kind { + if is_lang_ctor(cx, p, OptionSome) { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + + if let Some(i) = item { + let (sugg, msg) = match method_name { + "iter" => ( + format!("std::iter::once(&{})", snippet(cx, i.span, "...")), + "this `iter` call can be replaced with std::iter::once", + ), + "iter_mut" => ( + format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), + "this `iter_mut` call can be replaced with std::iter::once", + ), + "into_iter" => ( + format!("std::iter::once({})", snippet(cx, i.span, "...")), + "this `into_iter` call can be replaced with std::iter::once", + ), + _ => return, + }; + span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + } else { + let msg = match method_name { + "iter" => "this `iter call` can be replaced with std::iter::empty", + "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", + "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", + _ => return, + }; + span_lint_and_sugg( + cx, + ITER_EMPTY, + expr.span, + msg, + "try", + "std::iter::empty()".to_string(), + Applicability::Unspecified, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ac6b09f0aa..e449ae0e424 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,6 +33,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; +mod iter_once_empty; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; @@ -2304,6 +2305,83 @@ declare_clippy_lint! { more clearly with `if .. else ..`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[foo].iter()` + /// - `[foo].iter_mut()` + /// - `[foo].into_iter()` + /// - `Some(foo).iter()` + /// - `Some(foo).iter_mut()` + /// - `Some(foo).into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the once function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// let a = [123].iter(); + /// let b = Some(123).into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a = iter::once(&123); + /// let b = iter::once(123); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ONCE, + nursery, + "Iterator for array of length 1" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[].iter()` + /// - `[].iter_mut()` + /// - `[].into_iter()` + /// - `None.iter()` + /// - `None.iter_mut()` + /// - `None.into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the empty function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// use std::{slice, option}; + /// let a: slice::Iter = [].iter(); + /// let f: option::IntoIter = None.into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a: iter::Empty = iter::empty(); + /// let b: iter::Empty = iter::empty(); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_EMPTY, + nursery, + "Iterator for empty array" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2406,6 +2484,8 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, + ITER_ONCE, + ITER_EMPTY ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2708,6 +2788,7 @@ impl Methods { ("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_once_empty::check(cx, expr, name, recv), ("join", [join_arg]) => { if let Some(("collect", _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed index fb7118f0d4a..690da5a8761 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_empty.fixed @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs index bb192fe16d1..f8b56898f2d 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_empty.rs @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed index 7247e34d7e8..0c82ab20be1 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_once.fixed @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs index 3a2b9c95cc5..d561bf27c1d 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_once.rs @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } -- cgit 1.4.1-3-g733a5 From f30d7c2495b3188bfa0cf8bd6dbbf76494c9845e Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Tue, 19 Jul 2022 22:08:03 +0200 Subject: Improve suggestions --- clippy_lints/src/methods/iter_once_empty.rs | 70 ++++++++++++++++++----------- clippy_lints/src/methods/mod.rs | 18 +------- tests/ui/iter_empty.stderr | 12 ++--- tests/ui/iter_once.stderr | 12 ++--- 4 files changed, 59 insertions(+), 53 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs index d45dfc67880..82fafb8a45e 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_lang_ctor; +use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet; use rustc_errors::Applicability; @@ -9,6 +10,22 @@ use rustc_lint::LateContext; use super::{ITER_EMPTY, ITER_ONCE}; +enum IterType { + Iter, + IterMut, + IntoIter, +} + +impl IterType { + fn ref_prefix(&self) -> &'static str { + match self { + Self::Iter => "&", + Self::IterMut => "&mut ", + Self::IntoIter => "", + } + } +} + pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { let item = match &recv.kind { ExprKind::Array(v) if v.len() <= 1 => v.first(), @@ -32,39 +49,42 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: }, _ => return, }; + let iter_type = match method_name { + "iter" => IterType::Iter, + "iter_mut" => IterType::IterMut, + "into_iter" => IterType::IntoIter, + _ => return, + }; if let Some(i) = item { - let (sugg, msg) = match method_name { - "iter" => ( - format!("std::iter::once(&{})", snippet(cx, i.span, "...")), - "this `iter` call can be replaced with std::iter::once", - ), - "iter_mut" => ( - format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), - "this `iter_mut` call can be replaced with std::iter::once", - ), - "into_iter" => ( - format!("std::iter::once({})", snippet(cx, i.span, "...")), - "this `into_iter` call can be replaced with std::iter::once", - ), - _ => return, - }; - span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + let sugg = format!( + "{}::iter::once({}{})", + if is_no_std_crate(cx) { "core" } else { "std" }, + iter_type.ref_prefix(), + snippet(cx, i.span, "...") + ); + span_lint_and_sugg( + cx, + ITER_ONCE, + expr.span, + &format!("`{method_name}` call on a collection with only one item"), + "try", + sugg, + Applicability::MaybeIncorrect, + ); } else { - let msg = match method_name { - "iter" => "this `iter call` can be replaced with std::iter::empty", - "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", - "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", - _ => return, - }; span_lint_and_sugg( cx, ITER_EMPTY, expr.span, - msg, + &format!("`{method_name}` call on an empty collection"), "try", - "std::iter::empty()".to_string(), - Applicability::Unspecified, + if is_no_std_crate(cx) { + "core::iter::empty()".to_string() + } else { + "std::iter::empty()".to_string() + }, + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e449ae0e424..015cd094a9e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2308,14 +2308,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks for usage of: - /// - /// - `[foo].iter()` - /// - `[foo].iter_mut()` - /// - `[foo].into_iter()` - /// - `Some(foo).iter()` - /// - `Some(foo).iter_mut()` - /// - `Some(foo).into_iter()` + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item /// /// ### Why is this bad? /// @@ -2346,14 +2339,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks for usage of: - /// - /// - `[].iter()` - /// - `[].iter_mut()` - /// - `[].into_iter()` - /// - `None.iter()` - /// - `None.iter_mut()` - /// - `None.into_iter()` + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections /// /// ### Why is this bad? /// diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_empty.stderr index f4f06e93b23..40c08e6f82b 100644 --- a/tests/ui/iter_empty.stderr +++ b/tests/ui/iter_empty.stderr @@ -1,4 +1,4 @@ -error: this `into_iter` call can be replaced with std::iter::empty +error: `into_iter` call on an empty collection --> $DIR/iter_empty.rs:6:16 | LL | assert_eq!([].into_iter().next(), Option::::None); @@ -6,31 +6,31 @@ LL | assert_eq!([].into_iter().next(), Option::::None); | = note: `-D clippy::iter-empty` implied by `-D warnings` -error: this `iter_mut` call can be replaced with std::iter::empty +error: `iter_mut` call on an empty collection --> $DIR/iter_empty.rs:7:16 | LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter call` can be replaced with std::iter::empty +error: `iter` call on an empty collection --> $DIR/iter_empty.rs:8:16 | LL | assert_eq!([].iter().next(), Option::<&i32>::None); | ^^^^^^^^^ help: try: `std::iter::empty()` -error: this `into_iter` call can be replaced with std::iter::empty +error: `into_iter` call on an empty collection --> $DIR/iter_empty.rs:9:16 | LL | assert_eq!(None.into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter_mut` call can be replaced with std::iter::empty +error: `iter_mut` call on an empty collection --> $DIR/iter_empty.rs:10:16 | LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter call` can be replaced with std::iter::empty +error: `iter` call on an empty collection --> $DIR/iter_empty.rs:11:16 | LL | assert_eq!(None.iter().next(), Option::<&i32>::None); diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_once.stderr index d9e8f96f763..b22c8a99f10 100644 --- a/tests/ui/iter_once.stderr +++ b/tests/ui/iter_once.stderr @@ -1,4 +1,4 @@ -error: this `into_iter` call can be replaced with std::iter::once +error: `into_iter` call on a collection with only one item --> $DIR/iter_once.rs:6:16 | LL | assert_eq!([123].into_iter().next(), Some(123)); @@ -6,31 +6,31 @@ LL | assert_eq!([123].into_iter().next(), Some(123)); | = note: `-D clippy::iter-once` implied by `-D warnings` -error: this `iter_mut` call can be replaced with std::iter::once +error: `iter_mut` call on a collection with only one item --> $DIR/iter_once.rs:7:16 | LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` -error: this `iter` call can be replaced with std::iter::once +error: `iter` call on a collection with only one item --> $DIR/iter_once.rs:8:16 | LL | assert_eq!([123].iter().next(), Some(&123)); | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` -error: this `into_iter` call can be replaced with std::iter::once +error: `into_iter` call on a collection with only one item --> $DIR/iter_once.rs:9:16 | LL | assert_eq!(Some(123).into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` -error: this `iter_mut` call can be replaced with std::iter::once +error: `iter_mut` call on a collection with only one item --> $DIR/iter_once.rs:10:16 | LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` -error: this `iter` call can be replaced with std::iter::once +error: `iter` call on a collection with only one item --> $DIR/iter_once.rs:11:16 | LL | assert_eq!(Some(123).iter().next(), Some(&123)); -- cgit 1.4.1-3-g733a5 From b247594a39cb8e2c3d8d193860eac0eb1c63e1ae Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Thu, 28 Jul 2022 22:54:23 +0200 Subject: Prevent some false positives --- clippy_lints/src/methods/iter_once_empty.rs | 23 ++++++++++++++++++++--- clippy_lints/src/types/mod.rs | 1 - clippy_utils/src/lib.rs | 1 - tests/ui/iter_empty.fixed | 8 ++++++++ tests/ui/iter_empty.rs | 8 ++++++++ tests/ui/iter_once.fixed | 8 ++++++++ tests/ui/iter_once.rs | 8 ++++++++ 7 files changed, 52 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs index 82fafb8a45e..96b1484528c 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; -use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet; +use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; use super::{ITER_EMPTY, ITER_ONCE}; @@ -56,6 +55,24 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: _ => return, }; + let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { + Some((Node::Expr(parent), child_id)) => match parent.kind { + ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::If(_, _, _) + | ExprKind::Match(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Ret(_) + | ExprKind::Break(_, _) => true, + _ => false, + }, + Some((Node::Stmt(_) | Node::Local(_), _)) => false, + _ => true, + }; + + if is_unified { + return; + } + if let Some(i) = item { let sugg = format!( "{}::iter::once({}{})", diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index f3ba096237f..353a6f6b899 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -490,7 +490,6 @@ impl Types { } } } - #[allow(clippy::iter_empty)] match *qpath { QPath::Resolved(Some(ty), p) => { context.is_nested_call = true; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9c58978a070..dcfc03475b4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -484,7 +484,6 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { } fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let single = |ty| tcx.incoherent_impls(ty).iter().copied(); - #[allow(clippy::iter_empty)] let empty = || [].iter().copied(); match name { "bool" => single(BoolSimplifiedType), diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed index 690da5a8761..ad1e106d2b1 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_empty.fixed @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = None.clone(); let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs index f8b56898f2d..625149b5da5 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_empty.rs @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = None.clone(); let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed index 0c82ab20be1..0495bc47e4b 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_once.fixed @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs index d561bf27c1d..96641109bb9 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_once.rs @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { -- cgit 1.4.1-3-g733a5 From af4885c0cde76bf1faace76dc8fb53d3d4791422 Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Sat, 30 Jul 2022 13:39:55 +0200 Subject: Rename new lints to iter_on_empty_collections and iter_on_single_items --- CHANGELOG.md | 4 +- clippy_lints/src/lib.register_lints.rs | 4 +- clippy_lints/src/lib.register_nursery.rs | 4 +- .../methods/iter_on_single_or_empty_collections.rs | 107 +++++++++++++++++++++ clippy_lints/src/methods/iter_once_empty.rs | 107 --------------------- clippy_lints/src/methods/mod.rs | 14 +-- tests/ui/iter_empty.fixed | 63 ------------ tests/ui/iter_empty.rs | 63 ------------ tests/ui/iter_empty.stderr | 40 -------- tests/ui/iter_on_empty_collections.fixed | 63 ++++++++++++ tests/ui/iter_on_empty_collections.rs | 63 ++++++++++++ tests/ui/iter_on_empty_collections.stderr | 40 ++++++++ tests/ui/iter_on_single_items.fixed | 63 ++++++++++++ tests/ui/iter_on_single_items.rs | 63 ++++++++++++ tests/ui/iter_on_single_items.stderr | 40 ++++++++ tests/ui/iter_once.fixed | 63 ------------ tests/ui/iter_once.rs | 63 ------------ tests/ui/iter_once.stderr | 40 -------- 18 files changed, 453 insertions(+), 451 deletions(-) create mode 100644 clippy_lints/src/methods/iter_on_single_or_empty_collections.rs delete mode 100644 clippy_lints/src/methods/iter_once_empty.rs delete mode 100644 tests/ui/iter_empty.fixed delete mode 100644 tests/ui/iter_empty.rs delete mode 100644 tests/ui/iter_empty.stderr create mode 100644 tests/ui/iter_on_empty_collections.fixed create mode 100644 tests/ui/iter_on_empty_collections.rs create mode 100644 tests/ui/iter_on_empty_collections.stderr create mode 100644 tests/ui/iter_on_single_items.fixed create mode 100644 tests/ui/iter_on_single_items.rs create mode 100644 tests/ui/iter_on_single_items.stderr delete mode 100644 tests/ui/iter_once.fixed delete mode 100644 tests/ui/iter_once.rs delete mode 100644 tests/ui/iter_once.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 94f71eba0a2..03a76ccf607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3651,13 +3651,13 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count -[`iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_empty [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero -[`iter_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_once +[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections +[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e49321d83fa..b697eb76290 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -312,11 +312,11 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, - methods::ITER_EMPTY, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, - methods::ITER_ONCE, + methods::ITER_ON_EMPTY_COLLECTIONS, + methods::ITER_ON_SINGLE_ITEMS, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 9953aca43ee..d6590192655 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -14,8 +14,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), - LintId::of(methods::ITER_EMPTY), - LintId::of(methods::ITER_ONCE), + LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS), + LintId::of(methods::ITER_ON_SINGLE_ITEMS), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs new file mode 100644 index 00000000000..cea7b0d82ff --- /dev/null +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -0,0 +1,107 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; + +use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::{Expr, ExprKind, Node}; +use rustc_lint::LateContext; + +use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; + +enum IterType { + Iter, + IterMut, + IntoIter, +} + +impl IterType { + fn ref_prefix(&self) -> &'static str { + match self { + Self::Iter => "&", + Self::IterMut => "&mut ", + Self::IntoIter => "", + } + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { + let item = match &recv.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(p) => { + if is_lang_ctor(cx, p, OptionNone) { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(p) = &f.kind { + if is_lang_ctor(cx, p, OptionSome) { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + let iter_type = match method_name { + "iter" => IterType::Iter, + "iter_mut" => IterType::IterMut, + "into_iter" => IterType::IntoIter, + _ => return, + }; + + let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { + Some((Node::Expr(parent), child_id)) => match parent.kind { + ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::If(_, _, _) + | ExprKind::Match(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Ret(_) + | ExprKind::Break(_, _) => true, + _ => false, + }, + Some((Node::Stmt(_) | Node::Local(_), _)) => false, + _ => true, + }; + + if is_unified { + return; + } + + if let Some(i) = item { + let sugg = format!( + "{}::iter::once({}{})", + if is_no_std_crate(cx) { "core" } else { "std" }, + iter_type.ref_prefix(), + snippet(cx, i.span, "...") + ); + span_lint_and_sugg( + cx, + ITER_ON_SINGLE_ITEMS, + expr.span, + &format!("`{method_name}` call on a collection with only one item"), + "try", + sugg, + Applicability::MaybeIncorrect, + ); + } else { + span_lint_and_sugg( + cx, + ITER_ON_EMPTY_COLLECTIONS, + expr.span, + &format!("`{method_name}` call on an empty collection"), + "try", + if is_no_std_crate(cx) { + "core::iter::empty()".to_string() + } else { + "std::iter::empty()".to_string() + }, + Applicability::MaybeIncorrect, + ); + } +} diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs deleted file mode 100644 index 96b1484528c..00000000000 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ /dev/null @@ -1,107 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; - -use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{Expr, ExprKind, Node}; -use rustc_lint::LateContext; - -use super::{ITER_EMPTY, ITER_ONCE}; - -enum IterType { - Iter, - IterMut, - IntoIter, -} - -impl IterType { - fn ref_prefix(&self) -> &'static str { - match self { - Self::Iter => "&", - Self::IterMut => "&mut ", - Self::IntoIter => "", - } - } -} - -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { - let item = match &recv.kind { - ExprKind::Array(v) if v.len() <= 1 => v.first(), - ExprKind::Path(p) => { - if is_lang_ctor(cx, p, OptionNone) { - None - } else { - return; - } - }, - ExprKind::Call(f, some_args) if some_args.len() == 1 => { - if let ExprKind::Path(p) = &f.kind { - if is_lang_ctor(cx, p, OptionSome) { - Some(&some_args[0]) - } else { - return; - } - } else { - return; - } - }, - _ => return, - }; - let iter_type = match method_name { - "iter" => IterType::Iter, - "iter_mut" => IterType::IterMut, - "into_iter" => IterType::IntoIter, - _ => return, - }; - - let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { - Some((Node::Expr(parent), child_id)) => match parent.kind { - ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, - ExprKind::If(_, _, _) - | ExprKind::Match(_, _, _) - | ExprKind::Closure(_) - | ExprKind::Ret(_) - | ExprKind::Break(_, _) => true, - _ => false, - }, - Some((Node::Stmt(_) | Node::Local(_), _)) => false, - _ => true, - }; - - if is_unified { - return; - } - - if let Some(i) = item { - let sugg = format!( - "{}::iter::once({}{})", - if is_no_std_crate(cx) { "core" } else { "std" }, - iter_type.ref_prefix(), - snippet(cx, i.span, "...") - ); - span_lint_and_sugg( - cx, - ITER_ONCE, - expr.span, - &format!("`{method_name}` call on a collection with only one item"), - "try", - sugg, - Applicability::MaybeIncorrect, - ); - } else { - span_lint_and_sugg( - cx, - ITER_EMPTY, - expr.span, - &format!("`{method_name}` call on an empty collection"), - "try", - if is_no_std_crate(cx) { - "core::iter::empty()".to_string() - } else { - "std::iter::empty()".to_string() - }, - Applicability::MaybeIncorrect, - ); - } -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 015cd094a9e..0936a3f48ca 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,7 +33,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; -mod iter_once_empty; +mod iter_on_single_or_empty_collections; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; @@ -2331,7 +2331,7 @@ declare_clippy_lint! { /// /// The type of the resulting iterator might become incompatible with its usage #[clippy::version = "1.64.0"] - pub ITER_ONCE, + pub ITER_ON_SINGLE_ITEMS, nursery, "Iterator for array of length 1" } @@ -2363,7 +2363,7 @@ declare_clippy_lint! { /// /// The type of the resulting iterator might become incompatible with its usage #[clippy::version = "1.64.0"] - pub ITER_EMPTY, + pub ITER_ON_EMPTY_COLLECTIONS, nursery, "Iterator for empty array" } @@ -2470,8 +2470,8 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, - ITER_ONCE, - ITER_EMPTY + ITER_ON_SINGLE_ITEMS, + ITER_ON_EMPTY_COLLECTIONS ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2774,7 +2774,9 @@ impl Methods { ("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_once_empty::check(cx, expr, name, recv), + ("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) { unnecessary_join::check(cx, expr, recv, join_arg, span); diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed deleted file mode 100644 index ad1e106d2b1..00000000000 --- a/tests/ui/iter_empty.fixed +++ /dev/null @@ -1,63 +0,0 @@ -// run-rustfix -#![warn(clippy::iter_empty)] -#![allow(clippy::iter_next_slice, clippy::redundant_clone)] - -fn array() { - assert_eq!(std::iter::empty().next(), Option::::None); - assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); - assert_eq!(std::iter::empty().next(), Option::<&i32>::None); - assert_eq!(std::iter::empty().next(), Option::::None); - assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); - assert_eq!(std::iter::empty().next(), Option::<&i32>::None); - - // Don't trigger on non-iter methods - let _: Option = None.clone(); - let _: [String; 0] = [].clone(); - - // Don't trigger on match or if branches - let _ = match 123 { - 123 => [].iter(), - _ => ["test"].iter(), - }; - - let _ = if false { ["test"].iter() } else { [].iter() }; -} - -macro_rules! in_macros { - () => { - assert_eq!([].into_iter().next(), Option::::None); - assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); - assert_eq!([].iter().next(), Option::<&i32>::None); - assert_eq!(None.into_iter().next(), Option::::None); - assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); - assert_eq!(None.iter().next(), Option::<&i32>::None); - }; -} - -// Don't trigger on a `None` that isn't std's option -mod custom_option { - #[allow(unused)] - enum CustomOption { - Some(i32), - None, - } - - impl CustomOption { - fn iter(&self) {} - fn iter_mut(&mut self) {} - fn into_iter(self) {} - } - use CustomOption::*; - - pub fn custom_option() { - None.iter(); - None.iter_mut(); - None.into_iter(); - } -} - -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs deleted file mode 100644 index 625149b5da5..00000000000 --- a/tests/ui/iter_empty.rs +++ /dev/null @@ -1,63 +0,0 @@ -// run-rustfix -#![warn(clippy::iter_empty)] -#![allow(clippy::iter_next_slice, clippy::redundant_clone)] - -fn array() { - assert_eq!([].into_iter().next(), Option::::None); - assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); - assert_eq!([].iter().next(), Option::<&i32>::None); - assert_eq!(None.into_iter().next(), Option::::None); - assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); - assert_eq!(None.iter().next(), Option::<&i32>::None); - - // Don't trigger on non-iter methods - let _: Option = None.clone(); - let _: [String; 0] = [].clone(); - - // Don't trigger on match or if branches - let _ = match 123 { - 123 => [].iter(), - _ => ["test"].iter(), - }; - - let _ = if false { ["test"].iter() } else { [].iter() }; -} - -macro_rules! in_macros { - () => { - assert_eq!([].into_iter().next(), Option::::None); - assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); - assert_eq!([].iter().next(), Option::<&i32>::None); - assert_eq!(None.into_iter().next(), Option::::None); - assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); - assert_eq!(None.iter().next(), Option::<&i32>::None); - }; -} - -// Don't trigger on a `None` that isn't std's option -mod custom_option { - #[allow(unused)] - enum CustomOption { - Some(i32), - None, - } - - impl CustomOption { - fn iter(&self) {} - fn iter_mut(&mut self) {} - fn into_iter(self) {} - } - use CustomOption::*; - - pub fn custom_option() { - None.iter(); - None.iter_mut(); - None.into_iter(); - } -} - -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_empty.stderr deleted file mode 100644 index 40c08e6f82b..00000000000 --- a/tests/ui/iter_empty.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: `into_iter` call on an empty collection - --> $DIR/iter_empty.rs:6:16 - | -LL | assert_eq!([].into_iter().next(), Option::::None); - | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` - | - = note: `-D clippy::iter-empty` implied by `-D warnings` - -error: `iter_mut` call on an empty collection - --> $DIR/iter_empty.rs:7:16 - | -LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); - | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` - -error: `iter` call on an empty collection - --> $DIR/iter_empty.rs:8:16 - | -LL | assert_eq!([].iter().next(), Option::<&i32>::None); - | ^^^^^^^^^ help: try: `std::iter::empty()` - -error: `into_iter` call on an empty collection - --> $DIR/iter_empty.rs:9:16 - | -LL | assert_eq!(None.into_iter().next(), Option::::None); - | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` - -error: `iter_mut` call on an empty collection - --> $DIR/iter_empty.rs:10:16 - | -LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); - | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` - -error: `iter` call on an empty collection - --> $DIR/iter_empty.rs:11:16 - | -LL | assert_eq!(None.iter().next(), Option::<&i32>::None); - | ^^^^^^^^^^^ help: try: `std::iter::empty()` - -error: aborting due to 6 previous errors - diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed new file mode 100644 index 00000000000..bd9b07aefbf --- /dev/null +++ b/tests/ui/iter_on_empty_collections.fixed @@ -0,0 +1,63 @@ +// run-rustfix +#![warn(clippy::iter_on_empty_collections)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!(std::iter::empty().next(), Option::::None); + assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + assert_eq!(std::iter::empty().next(), Option::::None); + assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + + // Don't trigger on non-iter methods + let _: Option = None.clone(); + let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; +} + +macro_rules! in_macros { + () => { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + }; +} + +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + +fn main() { + array(); + custom_option::custom_option(); + in_macros!(); +} diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs new file mode 100644 index 00000000000..e15ba94bd46 --- /dev/null +++ b/tests/ui/iter_on_empty_collections.rs @@ -0,0 +1,63 @@ +// run-rustfix +#![warn(clippy::iter_on_empty_collections)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + + // Don't trigger on non-iter methods + let _: Option = None.clone(); + let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; +} + +macro_rules! in_macros { + () => { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + }; +} + +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + +fn main() { + array(); + custom_option::custom_option(); + in_macros!(); +} diff --git a/tests/ui/iter_on_empty_collections.stderr b/tests/ui/iter_on_empty_collections.stderr new file mode 100644 index 00000000000..cbd61176956 --- /dev/null +++ b/tests/ui/iter_on_empty_collections.stderr @@ -0,0 +1,40 @@ +error: `into_iter` call on an empty collection + --> $DIR/iter_on_empty_collections.rs:6:16 + | +LL | assert_eq!([].into_iter().next(), Option::::None); + | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + | + = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings` + +error: `iter_mut` call on an empty collection + --> $DIR/iter_on_empty_collections.rs:7:16 + | +LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: `iter` call on an empty collection + --> $DIR/iter_on_empty_collections.rs:8:16 + | +LL | assert_eq!([].iter().next(), Option::<&i32>::None); + | ^^^^^^^^^ help: try: `std::iter::empty()` + +error: `into_iter` call on an empty collection + --> $DIR/iter_on_empty_collections.rs:9:16 + | +LL | assert_eq!(None.into_iter().next(), Option::::None); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: `iter_mut` call on an empty collection + --> $DIR/iter_on_empty_collections.rs:10:16 + | +LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: `iter` call on an empty collection + --> $DIR/iter_on_empty_collections.rs:11:16 + | +LL | assert_eq!(None.iter().next(), Option::<&i32>::None); + | ^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/iter_on_single_items.fixed b/tests/ui/iter_on_single_items.fixed new file mode 100644 index 00000000000..1fa4b03641b --- /dev/null +++ b/tests/ui/iter_on_single_items.fixed @@ -0,0 +1,63 @@ +// run-rustfix +#![warn(clippy::iter_on_single_items)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!(std::iter::once(123).next(), Some(123)); + assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + assert_eq!(std::iter::once(&123).next(), Some(&123)); + assert_eq!(std::iter::once(123).next(), Some(123)); + assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + assert_eq!(std::iter::once(&123).next(), Some(&123)); + + // Don't trigger on non-iter methods + let _: Option = Some("test".to_string()).clone(); + let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; +} + +macro_rules! in_macros { + () => { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + }; +} + +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + +fn main() { + array(); + custom_option::custom_option(); + in_macros!(); +} diff --git a/tests/ui/iter_on_single_items.rs b/tests/ui/iter_on_single_items.rs new file mode 100644 index 00000000000..ea96d8066c5 --- /dev/null +++ b/tests/ui/iter_on_single_items.rs @@ -0,0 +1,63 @@ +// run-rustfix +#![warn(clippy::iter_on_single_items)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + + // Don't trigger on non-iter methods + let _: Option = Some("test".to_string()).clone(); + let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; +} + +macro_rules! in_macros { + () => { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + }; +} + +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + +fn main() { + array(); + custom_option::custom_option(); + in_macros!(); +} diff --git a/tests/ui/iter_on_single_items.stderr b/tests/ui/iter_on_single_items.stderr new file mode 100644 index 00000000000..d6c54711636 --- /dev/null +++ b/tests/ui/iter_on_single_items.stderr @@ -0,0 +1,40 @@ +error: `into_iter` call on a collection with only one item + --> $DIR/iter_on_single_items.rs:6:16 + | +LL | assert_eq!([123].into_iter().next(), Some(123)); + | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` + | + = note: `-D clippy::iter-on-single-items` implied by `-D warnings` + +error: `iter_mut` call on a collection with only one item + --> $DIR/iter_on_single_items.rs:7:16 + | +LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` + +error: `iter` call on a collection with only one item + --> $DIR/iter_on_single_items.rs:8:16 + | +LL | assert_eq!([123].iter().next(), Some(&123)); + | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` + +error: `into_iter` call on a collection with only one item + --> $DIR/iter_on_single_items.rs:9:16 + | +LL | assert_eq!(Some(123).into_iter().next(), Some(123)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` + +error: `iter_mut` call on a collection with only one item + --> $DIR/iter_on_single_items.rs:10:16 + | +LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` + +error: `iter` call on a collection with only one item + --> $DIR/iter_on_single_items.rs:11:16 + | +LL | assert_eq!(Some(123).iter().next(), Some(&123)); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed deleted file mode 100644 index 0495bc47e4b..00000000000 --- a/tests/ui/iter_once.fixed +++ /dev/null @@ -1,63 +0,0 @@ -// run-rustfix -#![warn(clippy::iter_once)] -#![allow(clippy::iter_next_slice, clippy::redundant_clone)] - -fn array() { - assert_eq!(std::iter::once(123).next(), Some(123)); - assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); - assert_eq!(std::iter::once(&123).next(), Some(&123)); - assert_eq!(std::iter::once(123).next(), Some(123)); - assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); - assert_eq!(std::iter::once(&123).next(), Some(&123)); - - // Don't trigger on non-iter methods - let _: Option = Some("test".to_string()).clone(); - let _: [String; 1] = ["test".to_string()].clone(); - - // Don't trigger on match or if branches - let _ = match 123 { - 123 => [].iter(), - _ => ["test"].iter(), - }; - - let _ = if false { ["test"].iter() } else { [].iter() }; -} - -macro_rules! in_macros { - () => { - assert_eq!([123].into_iter().next(), Some(123)); - assert_eq!([123].iter_mut().next(), Some(&mut 123)); - assert_eq!([123].iter().next(), Some(&123)); - assert_eq!(Some(123).into_iter().next(), Some(123)); - assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); - assert_eq!(Some(123).iter().next(), Some(&123)); - }; -} - -// Don't trigger on a `Some` that isn't std's option -mod custom_option { - #[allow(unused)] - enum CustomOption { - Some(i32), - None, - } - - impl CustomOption { - fn iter(&self) {} - fn iter_mut(&mut self) {} - fn into_iter(self) {} - } - use CustomOption::*; - - pub fn custom_option() { - Some(3).iter(); - Some(3).iter_mut(); - Some(3).into_iter(); - } -} - -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs deleted file mode 100644 index 96641109bb9..00000000000 --- a/tests/ui/iter_once.rs +++ /dev/null @@ -1,63 +0,0 @@ -// run-rustfix -#![warn(clippy::iter_once)] -#![allow(clippy::iter_next_slice, clippy::redundant_clone)] - -fn array() { - assert_eq!([123].into_iter().next(), Some(123)); - assert_eq!([123].iter_mut().next(), Some(&mut 123)); - assert_eq!([123].iter().next(), Some(&123)); - assert_eq!(Some(123).into_iter().next(), Some(123)); - assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); - assert_eq!(Some(123).iter().next(), Some(&123)); - - // Don't trigger on non-iter methods - let _: Option = Some("test".to_string()).clone(); - let _: [String; 1] = ["test".to_string()].clone(); - - // Don't trigger on match or if branches - let _ = match 123 { - 123 => [].iter(), - _ => ["test"].iter(), - }; - - let _ = if false { ["test"].iter() } else { [].iter() }; -} - -macro_rules! in_macros { - () => { - assert_eq!([123].into_iter().next(), Some(123)); - assert_eq!([123].iter_mut().next(), Some(&mut 123)); - assert_eq!([123].iter().next(), Some(&123)); - assert_eq!(Some(123).into_iter().next(), Some(123)); - assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); - assert_eq!(Some(123).iter().next(), Some(&123)); - }; -} - -// Don't trigger on a `Some` that isn't std's option -mod custom_option { - #[allow(unused)] - enum CustomOption { - Some(i32), - None, - } - - impl CustomOption { - fn iter(&self) {} - fn iter_mut(&mut self) {} - fn into_iter(self) {} - } - use CustomOption::*; - - pub fn custom_option() { - Some(3).iter(); - Some(3).iter_mut(); - Some(3).into_iter(); - } -} - -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_once.stderr deleted file mode 100644 index b22c8a99f10..00000000000 --- a/tests/ui/iter_once.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: `into_iter` call on a collection with only one item - --> $DIR/iter_once.rs:6:16 - | -LL | assert_eq!([123].into_iter().next(), Some(123)); - | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` - | - = note: `-D clippy::iter-once` implied by `-D warnings` - -error: `iter_mut` call on a collection with only one item - --> $DIR/iter_once.rs:7:16 - | -LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); - | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` - -error: `iter` call on a collection with only one item - --> $DIR/iter_once.rs:8:16 - | -LL | assert_eq!([123].iter().next(), Some(&123)); - | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` - -error: `into_iter` call on a collection with only one item - --> $DIR/iter_once.rs:9:16 - | -LL | assert_eq!(Some(123).into_iter().next(), Some(123)); - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` - -error: `iter_mut` call on a collection with only one item - --> $DIR/iter_once.rs:10:16 - | -LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); - | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` - -error: `iter` call on a collection with only one item - --> $DIR/iter_once.rs:11:16 - | -LL | assert_eq!(Some(123).iter().next(), Some(&123)); - | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)` - -error: aborting due to 6 previous errors - -- cgit 1.4.1-3-g733a5 From f18cd274be3595c5b065fdba2b75ce9e8adc6c25 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 12 Aug 2022 23:19:53 +0200 Subject: Update lint versions for 1.63 release --- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/doc_link_with_quotes.rs | 2 +- clippy_lints/src/duplicate_mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/mismatching_type_param_order.rs | 2 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/unused_rounding.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 937765b6614..e65b67c655e 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -44,7 +44,7 @@ declare_clippy_lint! { /// let a: &String = s; /// foo(&**s); /// ``` - #[clippy::version = "1.59.0"] + #[clippy::version = "1.63.0"] pub BORROW_DEREF_REF, complexity, "deref on an immutable reference returns the same type as itself" diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs index cb07f57e870..0ff1d2755da 100644 --- a/clippy_lints/src/doc_link_with_quotes.rs +++ b/clippy_lints/src/doc_link_with_quotes.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// /// See also: [`foo`] /// fn bar() {} /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.63.0"] pub DOC_LINK_WITH_QUOTES, pedantic, "possible typo for an intra-doc link" diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs index e1eb3b6324c..7ff7068f0b0 100644 --- a/clippy_lints/src/duplicate_mod.rs +++ b/clippy_lints/src/duplicate_mod.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// // a.rs /// use crate::b; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub DUPLICATE_MOD, suspicious, "file loaded as module multiple times" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ac6b09f0aa..b8dba5ba165 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2269,7 +2269,7 @@ declare_clippy_lint! { /// "1234".replace("12", "12"); /// "1234".replacen("12", "12", 1); /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub NO_EFFECT_REPLACE, suspicious, "replace with no effect" diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index f763e0d24c9..020efeaebf0 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// } /// impl Foo {} /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub MISMATCHING_TYPE_PARAM_ORDER, pedantic, "type parameter positioned inconsistently between type def and impl block" diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 8db8c4e9b78..e82aa3a7b98 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// let data = std::rc::Rc::new("some data".to_string()); /// let v = vec![data; 100]; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub RC_CLONE_IN_VEC_INIT, suspicious, "initializing reference-counted pointer in `vec![elem; len]`" diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 306afe44148..72d8a4431fd 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```rust /// let x = 1f32; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub UNUSED_ROUNDING, nursery, "Uselessly rounding a whole number floating-point literal" -- cgit 1.4.1-3-g733a5 From 1bf88414790bacf5773bd7f19f0c58e183d0ca7c Mon Sep 17 00:00:00 2001 From: Guilherme-Vasconcelos <49197151+Guilherme-Vasconcelos@users.noreply.github.com> Date: Fri, 5 Aug 2022 20:59:50 -0300 Subject: Update all tests to comply with clippy::manual_empty_string_creations --- clippy_dev/src/new_lint.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- tests/ui/case_sensitive_file_extension_comparisons.rs | 10 +++++----- tests/ui/case_sensitive_file_extension_comparisons.stderr | 12 ++++++------ tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- tests/ui/identity_op.fixed | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/manual_empty_string_creations.fixed | 2 +- tests/ui/or_fun_call.fixed | 4 ++-- tests/ui/or_fun_call.rs | 4 ++-- tests/ui/or_fun_call.stderr | 6 +++--- tests/ui/string_add.rs | 4 ++-- tests/ui/string_add_assign.fixed | 4 ++-- tests/ui/string_add_assign.rs | 4 ++-- tests/ui/unnecessary_owned_empty_strings.fixed | 1 + tests/ui/unnecessary_owned_empty_strings.rs | 1 + tests/ui/unnecessary_owned_empty_strings.stderr | 2 +- tests/ui/useless_conversion_try.rs | 4 ++-- tests/ui/useless_conversion_try.stderr | 2 +- 23 files changed, 40 insertions(+), 38 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 10a8f31f457..be05e67d724 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -155,7 +155,7 @@ fn to_camel_case(name: &str) -> String { name.split('_') .map(|s| { if s.is_empty() { - String::from("") + String::new() } else { [&s[0..1].to_uppercase(), &s[1..]].concat() } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index a0ca7e6ff1e..2502c8f880d 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -192,7 +192,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, match output.kind { TyKind::Tup(tys) if tys.is_empty() => { let sugg = "remove the return type"; - Some((sugg, "".into())) + Some((sugg, String::new())) }, _ => { let sugg = "return the output of the future directly"; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 6c641af59f9..3c4002a3aef 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -78,7 +78,7 @@ pub(super) fn check<'tcx>( map_span, String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }), ), - (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")), + (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), ]; if !unwrap_snippet_none { diff --git a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index df044538fe1..7c4ae746e90 100644 --- a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -46,7 +46,7 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) { "these patterns are unneeded as the `..` pattern can match those elements" }, if only_one { "remove it" } else { "remove them" }, - "".to_string(), + String::new(), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index f4f5a4336a3..a5afbb8ff9d 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ( ret_expr.span, if inner_type.is_unit() { - "".to_string() + String::new() } else { snippet(cx, arg.span.source_callsite(), "..").to_string() } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 0d65071af15..6f0485b5279 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -14,31 +14,31 @@ fn is_rust_file(filename: &str) -> bool { fn main() { // std::string::String and &str should trigger the lint failure with .ext12 - let _ = String::from("").ends_with(".ext12"); + let _ = String::new().ends_with(".ext12"); let _ = "str".ends_with(".ext12"); // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); // std::string::String and &str should trigger the lint failure with .EXT12 - let _ = String::from("").ends_with(".EXT12"); + let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); // Should not trigger the lint failure with .eXT12 - let _ = String::from("").ends_with(".eXT12"); + let _ = String::new().ends_with(".eXT12"); let _ = "str".ends_with(".eXT12"); TestStruct {}.ends_with(".eXT12"); // Should not trigger the lint failure with .EXT123 (too long) - let _ = String::from("").ends_with(".EXT123"); + let _ = String::new().ends_with(".EXT123"); let _ = "str".ends_with(".EXT123"); TestStruct {}.ends_with(".EXT123"); // Shouldn't fail if it doesn't start with a dot - let _ = String::from("").ends_with("a.ext"); + let _ = String::new().ends_with("a.ext"); let _ = "str".ends_with("a.extA"); TestStruct {}.ends_with("a.ext"); } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index 05b98169f2d..5d9a043edb9 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -8,10 +8,10 @@ LL | filename.ends_with(".rs") = help: consider using a case-insensitive comparison instead error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:17:30 + --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27 | -LL | let _ = String::from("").ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ +LL | let _ = String::new().ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead @@ -24,10 +24,10 @@ LL | let _ = "str".ends_with(".ext12"); = help: consider using a case-insensitive comparison instead error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:24:30 + --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27 | -LL | let _ = String::from("").ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ +LL | let _ = String::new().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 6b754f3bd71..b56d6aec508 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -33,7 +33,7 @@ fn main() { format!("foo {}", "bar"); format!("{} bar", "foo"); - let arg: String = "".to_owned(); + let arg = String::new(); arg.to_string(); format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index ca9826b356e..4c1a3a840ed 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -35,7 +35,7 @@ fn main() { format!("foo {}", "bar"); format!("{} bar", "foo"); - let arg: String = "".to_owned(); + let arg = String::new(); format!("{}", arg); format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index 5f9cebe212a..fa564e23cd2 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -68,7 +68,7 @@ fn main() { &x; x; - let mut a = A("".into()); + let mut a = A(String::new()); let b = a << 0; // no error: non-integer 1 * Meter; // no error: non-integer diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index ca799c9cfac..3d06d2a73b6 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -68,7 +68,7 @@ fn main() { &x >> 0; x >> &0; - let mut a = A("".into()); + let mut a = A(String::new()); let b = a << 0; // no error: non-integer 1 * Meter; // no error: non-integer diff --git a/tests/ui/manual_empty_string_creations.fixed b/tests/ui/manual_empty_string_creations.fixed index 3516312ee0c..caf0c657c81 100644 --- a/tests/ui/manual_empty_string_creations.fixed +++ b/tests/ui/manual_empty_string_creations.fixed @@ -7,7 +7,7 @@ macro_rules! create_strings_from_macro { ($some_str:expr) => { let _: String = $some_str.into(); let _ = $some_str.to_string(); - } + }; } fn main() { diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index fdb08d953ff..18ea4e55029 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -90,8 +90,8 @@ fn or_fun_call() { let mut btree_vec = BTreeMap::>::new(); btree_vec.entry(42).or_insert(vec![]); - let stringy = Some(String::from("")); - let _ = stringy.unwrap_or_else(|| "".to_owned()); + let stringy = Some(String::new()); + let _ = stringy.unwrap_or_default(); let opt = Some(1); let hello = "Hello"; diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 57ab5f03ee2..c353b41e449 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -90,8 +90,8 @@ fn or_fun_call() { let mut btree_vec = BTreeMap::>::new(); btree_vec.entry(42).or_insert(vec![]); - let stringy = Some(String::from("")); - let _ = stringy.unwrap_or("".to_owned()); + let stringy = Some(String::new()); + let _ = stringy.unwrap_or(String::new()); let opt = Some(1); let hello = "Hello"; diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 4c5938ab88b..887f23ac976 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -66,11 +66,11 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` -error: use of `unwrap_or` followed by a function call +error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:94:21 | -LL | let _ = stringy.unwrap_or("".to_owned()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` +LL | let _ = stringy.unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:102:21 diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index 30fd17c59e5..16673c01e63 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -7,13 +7,13 @@ extern crate macro_rules; #[allow(clippy::string_add_assign, unused)] fn main() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = String::new(); for _ in 1..3 { x = x + "."; } - let y = "".to_owned(); + let y = String::new(); let z = y + "..."; assert_eq!(&x, &z); diff --git a/tests/ui/string_add_assign.fixed b/tests/ui/string_add_assign.fixed index db71bab1e52..b687f43b254 100644 --- a/tests/ui/string_add_assign.fixed +++ b/tests/ui/string_add_assign.fixed @@ -4,13 +4,13 @@ #[warn(clippy::string_add_assign)] fn main() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = String::new(); for _ in 1..3 { x += "."; } - let y = "".to_owned(); + let y = String::new(); let z = y + "..."; assert_eq!(&x, &z); diff --git a/tests/ui/string_add_assign.rs b/tests/ui/string_add_assign.rs index 644991945cb..e5dbde108fb 100644 --- a/tests/ui/string_add_assign.rs +++ b/tests/ui/string_add_assign.rs @@ -4,13 +4,13 @@ #[warn(clippy::string_add_assign)] fn main() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = String::new(); for _ in 1..3 { x = x + "."; } - let y = "".to_owned(); + let y = String::new(); let z = y + "..."; assert_eq!(&x, &z); diff --git a/tests/ui/unnecessary_owned_empty_strings.fixed b/tests/ui/unnecessary_owned_empty_strings.fixed index f95f91329a2..c390618ca98 100644 --- a/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/tests/ui/unnecessary_owned_empty_strings.fixed @@ -12,6 +12,7 @@ fn main() { ref_str_argument(""); // should be linted + #[allow(clippy::manual_empty_string_creations)] ref_str_argument(""); // should not be linted diff --git a/tests/ui/unnecessary_owned_empty_strings.rs b/tests/ui/unnecessary_owned_empty_strings.rs index 0cbdc151ed9..4a9d6125eb1 100644 --- a/tests/ui/unnecessary_owned_empty_strings.rs +++ b/tests/ui/unnecessary_owned_empty_strings.rs @@ -12,6 +12,7 @@ fn main() { ref_str_argument(&String::new()); // should be linted + #[allow(clippy::manual_empty_string_creations)] ref_str_argument(&String::from("")); // should not be linted diff --git a/tests/ui/unnecessary_owned_empty_strings.stderr b/tests/ui/unnecessary_owned_empty_strings.stderr index 46bc4597b33..1eb198a8675 100644 --- a/tests/ui/unnecessary_owned_empty_strings.stderr +++ b/tests/ui/unnecessary_owned_empty_strings.stderr @@ -7,7 +7,7 @@ LL | ref_str_argument(&String::new()); = note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings` error: usage of `&String::from("")` for a function expecting a `&str` argument - --> $DIR/unnecessary_owned_empty_strings.rs:15:22 + --> $DIR/unnecessary_owned_empty_strings.rs:16:22 | LL | ref_str_argument(&String::from("")); | ^^^^^^^^^^^^^^^^^ help: try: `""` diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index 39f54c27bee..4acf5b5fa2d 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -29,10 +29,10 @@ fn main() { let _ = String::try_from("foo".to_string()).unwrap(); let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); let _: String = format!("Hello {}", "world").try_into().unwrap(); - let _: String = "".to_owned().try_into().unwrap(); + let _: String = String::new().try_into().unwrap(); let _: String = match String::from("_").try_into() { Ok(a) => a, - Err(_) => "".into(), + Err(_) => String::new(), }; // FIXME this is a false negative #[allow(clippy::cmp_owned)] diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index b691c13f7db..12e74d61471 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -62,7 +62,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:32:21 | -LL | let _: String = "".to_owned().try_into().unwrap(); +LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider removing `.try_into()` -- cgit 1.4.1-3-g733a5 From 1a2aaf68de4989eaacf5b669da00b50dca8b41e0 Mon Sep 17 00:00:00 2001 From: xphoniex Date: Sun, 14 Aug 2022 16:29:26 +0000 Subject: Skip `unnecessary_to_owned` when `t != t.to_string()` Signed-off-by: xphoniex --- clippy_lints/src/methods/unnecessary_to_owned.rs | 17 ++++++++++++-- tests/ui/unnecessary_to_owned.fixed | 28 ++++++++++++++++++++++++ tests/ui/unnecessary_to_owned.rs | 28 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index b3276f1394e..99b56da7a50 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,8 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{ - contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs, + contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, + peel_mid_ty_refs, }; use clippy_utils::{meets_msrv, msrvs}; @@ -279,7 +280,19 @@ fn check_other_call_arg<'tcx>( &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], call_substs, ); - implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + // if `expr` is a `String` and generic target is [u8], skip + // (https://github.com/rust-lang/rust-clippy/issues/9317). + if let [subst] = composed_substs[..] + && let GenericArgKind::Type(arg_ty) = subst.unpack() + && arg_ty.is_slice() + && let inner_ty = arg_ty.builtin_index().unwrap() + && let ty::Uint(ty::UintTy::U8) = inner_ty.kind() + && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs() + && is_type_diagnostic_item(cx, self_ty, sym::String) { + false + } else { + implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + } } else { false }; diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index f4f76cd3dd4..9cd5bc73b1e 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -329,3 +329,31 @@ mod issue_8759_variant { rw.set_view(&rw.default_view().to_owned()); } } + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index fe09a489ab0..7f62ba3ab5d 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -329,3 +329,31 @@ mod issue_8759_variant { rw.set_view(&rw.default_view().to_owned()); } } + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} -- cgit 1.4.1-3-g733a5 From c1e04352bd220d2b912715aa07e1d04fe97d84f2 Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Mon, 15 Aug 2022 20:30:30 +0200 Subject: unwrap_used and expect_used: trigger on uses of their _err variants --- clippy_lints/src/methods/expect_used.rs | 18 +++++++++++++----- clippy_lints/src/methods/mod.rs | 10 ++++++---- clippy_lints/src/methods/unwrap_used.rs | 18 +++++++++++++----- tests/ui/unwrap_expect_used.rs | 25 +++++++++++++++++++++++++ tests/ui/unwrap_expect_used.stderr | 26 +++++++++++++++++++++----- 5 files changed, 78 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 5ef08ca6290..d59fefa1ddc 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -7,18 +7,26 @@ use rustc_span::sym; use super::EXPECT_USED; -/// lint use of `expect()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) { +/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + is_err: bool, + allow_expect_in_tests: bool, +) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err", "an ")) + Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; + let method = if is_err { "expect_err" } else { "expect" }; + if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; } @@ -28,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, lint, expr.span, - &format!("used `expect()` on `{kind}` value"), + &format!("used `{method}()` on `{kind}` value"), None, &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 99aae5800ff..b68a2651e1b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -174,7 +174,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.unwrap()` calls on `Option`s and on `Result`s. + /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. /// /// ### Why is this bad? /// It is better to handle the `None` or `Err` case, @@ -224,7 +224,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.expect()` calls on `Option`s and `Result`s. + /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. /// /// ### Why is this bad? /// Usually it is better to handle the `None` or `Err` case. @@ -2740,8 +2740,9 @@ 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), - _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests), + _ => 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), ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); @@ -2874,8 +2875,9 @@ impl Methods { }, _ => {}, } - unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests); + unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, + ("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], _)) => { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index ce1a52e5480..05915c14109 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -7,18 +7,26 @@ use rustc_span::sym; use super::{EXPECT_USED, UNWRAP_USED}; -/// lint use of `unwrap()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { +/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + is_err: bool, + allow_unwrap_in_tests: bool, +) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err", "an ")) + Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; + let method = if is_err { "unwrap_err" } else { "unwrap" }; + if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; } @@ -37,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, lint, expr.span, - &format!("used `unwrap()` on `{kind}` value"), + &format!("used `{method}()` on `{kind}` value"), None, &help, ); diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index 0d4a0504a6e..9f27fef8249 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -1,10 +1,35 @@ #![warn(clippy::unwrap_used, clippy::expect_used)] +trait OptionExt { + type Item; + + fn unwrap_err(self) -> Self::Item; + + fn expect_err(self, msg: &str) -> Self::Item; +} + +impl OptionExt for Option { + type Item = T; + fn unwrap_err(self) -> T { + panic!(); + } + + fn expect_err(self, msg: &str) -> T { + panic!(); + } +} + fn main() { Some(3).unwrap(); Some(3).expect("Hello world!"); + // Don't trigger on unwrap_err on an option + Some(3).unwrap_err(); + Some(3).expect_err("Hellow none!"); + let a: Result = Ok(3); a.unwrap(); a.expect("Hello world!"); + a.unwrap_err(); + a.expect_err("Hello error!"); } diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index f54bfd617c4..1a19459b2c1 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_expect_used.rs:4:5 + --> $DIR/unwrap_expect_used.rs:23:5 | LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | Some(3).unwrap(); = help: if this value is `None`, it will panic error: used `expect()` on `an Option` value - --> $DIR/unwrap_expect_used.rs:5:5 + --> $DIR/unwrap_expect_used.rs:24:5 | LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | Some(3).expect("Hello world!"); = help: if this value is `None`, it will panic error: used `unwrap()` on `a Result` value - --> $DIR/unwrap_expect_used.rs:8:5 + --> $DIR/unwrap_expect_used.rs:31:5 | LL | a.unwrap(); | ^^^^^^^^^^ @@ -25,12 +25,28 @@ LL | a.unwrap(); = help: if this value is an `Err`, it will panic error: used `expect()` on `a Result` value - --> $DIR/unwrap_expect_used.rs:9:5 + --> $DIR/unwrap_expect_used.rs:32:5 | LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if this value is an `Err`, it will panic -error: aborting due to 4 previous errors +error: used `unwrap_err()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:33:5 + | +LL | a.unwrap_err(); + | ^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: used `expect_err()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:34:5 + | +LL | a.expect_err("Hello error!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From a05cb74d3080f0359a97c7380913edd2a5ebe7ee Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Fri, 8 Jul 2022 05:29:10 -0400 Subject: Enhance `needless_borrow` to consider trait implementations --- clippy_lints/src/dereference.rs | 307 ++++++++++++++++++++--- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 19 +- clippy_utils/src/msrvs.rs | 2 +- tests/ui/needless_borrow.fixed | 117 ++++++++- tests/ui/needless_borrow.rs | 117 ++++++++- tests/ui/needless_borrow.stderr | 48 +++- 7 files changed, 559 insertions(+), 53 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index e0b94f7190a..e38704701ea 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,24 +1,31 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; -use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; +use clippy_utils::ty::{contains_ty, expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; +use clippy_utils::{fn_def_id, get_parent_expr, is_lint_allowed, meets_msrv, msrvs, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, - ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem, - TraitItemKind, TyKind, UnOp, + self as hir, def_id::DefId, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, + GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, + Path, QPath, TraitItem, TraitItemKind, TyKind, UnOp, }; +use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{ + self, subst::Subst, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, + ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, +}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use std::collections::VecDeque; declare_clippy_lint! { /// ### What it does @@ -151,6 +158,7 @@ pub struct Dereferencing { /// been finished. Note we can't lint at the end of every body as they can be nested within each /// other. current_body: Option, + /// The list of locals currently being checked by the lint. /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted. /// This is needed for or patterns where one of the branches can be linted, but another can not @@ -158,6 +166,19 @@ pub struct Dereferencing { /// /// e.g. `m!(x) | Foo::Bar(ref x)` ref_locals: FxIndexMap>, + + // `IntoIterator` for arrays requires Rust 1.53. + msrv: Option, +} + +impl Dereferencing { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { + msrv, + ..Dereferencing::default() + } + } } struct StateData { @@ -170,6 +191,7 @@ struct StateData { struct DerefedBorrow { count: usize, msg: &'static str, + snip_expr: Option, } enum State { @@ -250,7 +272,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { match (self.state.take(), kind) { (None, kind) => { let expr_ty = typeck.expr_ty(expr); - let (position, adjustments) = walk_parents(cx, expr); + let (position, adjustments) = walk_parents(cx, expr, self.msrv); match kind { RefOp::Deref => { @@ -331,20 +353,23 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { let deref_msg = "this expression creates a reference which is immediately dereferenced by the compiler"; let borrow_msg = "this expression borrows a value the compiler would automatically borrow"; + let impl_msg = "the borrowed expression implements the required traits"; - let (required_refs, msg) = if position.can_auto_borrow() { - (1, if deref_count == 1 { borrow_msg } else { deref_msg }) + let (required_refs, msg, snip_expr) = if position.can_auto_borrow() { + (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None) + } else if let Position::ImplArg(hir_id) = position { + (0, impl_msg, Some(hir_id)) } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) = next_adjust.map(|a| &a.kind) { if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable() { - (3, deref_msg) + (3, deref_msg, None) } else { - (2, deref_msg) + (2, deref_msg, None) } } else { - (2, deref_msg) + (2, deref_msg, None) }; if deref_count >= required_refs { @@ -354,6 +379,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { // can't be removed without breaking the code. See earlier comment. count: deref_count - required_refs, msg, + snip_expr, }), StateData { span: expr.span, hir_id: expr.hir_id, position }, )); @@ -510,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { spans: vec![pat.span], app, replacements: vec![(pat.span, snip.into())], - hir_id: pat.hir_id + hir_id: pat.hir_id, }), ); } @@ -542,6 +568,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { self.current_body = None; } } + + extract_msrv_attr!(LateContext); } fn try_parse_ref_op<'tcx>( @@ -594,6 +622,7 @@ enum Position { /// The method is defined on a reference type. e.g. `impl Foo for &T` MethodReceiverRefImpl, Callee, + ImplArg(HirId), FieldAccess(Symbol), Postfix, Deref, @@ -630,7 +659,7 @@ impl Position { | Self::Callee | Self::FieldAccess(_) | Self::Postfix => PREC_POSTFIX, - Self::Deref => PREC_PREFIX, + Self::ImplArg(_) | Self::Deref => PREC_PREFIX, Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, } } @@ -639,8 +668,12 @@ impl Position { /// Walks up the parent expressions attempting to determine both how stable the auto-deref result /// is, and which adjustments will be applied to it. Note this will not consider auto-borrow /// locations as those follow different rules. -#[allow(clippy::too_many_lines)] -fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) { +#[expect(clippy::too_many_lines)] +fn walk_parents<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + msrv: Option, +) -> (Position, &'tcx [Adjustment<'tcx>]) { let mut adjustments = [].as_slice(); let mut precedence = 0i8; let ctxt = e.span.ctxt(); @@ -732,13 +765,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .iter() .position(|arg| arg.hir_id == child_id) .zip(expr_sig(cx, func)) - .and_then(|(i, sig)| sig.input_with_hir(i)) - .map(|(hir_ty, ty)| match hir_ty { - // Type inference for closures can depend on how they're called. Only go by the explicit - // types here. - Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), - None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) - .position_for_arg(), + .and_then(|(i, sig)| { + sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty { + // Type inference for closures can depend on how they're called. Only go by the explicit + // types here. + Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), + None => { + if let ty::Param(param_ty) = ty.skip_binder().kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) + .position_for_arg() + } + }, + }) }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -779,12 +819,17 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() + } } }) }, @@ -946,6 +991,205 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { v.0 } +// Checks whether: +// * child is an expression of the form `&e` in an argument position requiring an `impl Trait` +// * `e`'s type implements `Trait` and is copyable +// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`. +// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to +// be moved, but it cannot be. +fn needless_borrow_impl_arg_position<'tcx>( + cx: &LateContext<'tcx>, + parent: &Expr<'tcx>, + arg_index: usize, + param_ty: ParamTy, + mut expr: &Expr<'tcx>, + precedence: i8, + msrv: Option, +) -> Position { + let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); + let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); + + let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) }; + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + let substs_with_expr_ty = cx + .typeck_results() + .node_substs(if let ExprKind::Call(callee, _) = parent.kind { + callee.hir_id + } else { + parent.hir_id + }); + + let predicates = cx.tcx.param_env(callee_def_id).caller_bounds(); + let projection_predicates = predicates + .iter() + .filter_map(|predicate| { + if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { + Some(projection_predicate) + } else { + None + } + }) + .collect::>(); + + let mut trait_with_ref_mut_self_method = false; + + // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return. + if predicates + .iter() + .filter_map(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx) + { + Some(trait_predicate.trait_ref.def_id) + } else { + None + } + }) + .inspect(|trait_def_id| { + trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id); + }) + .all(|trait_def_id| { + Some(trait_def_id) == destruct_trait_def_id + || Some(trait_def_id) == sized_trait_def_id + || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id) + }) + { + return Position::Other(precedence); + } + + // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same + // elements are modified each time `check_referent` is called. + let mut substs_with_referent_ty = substs_with_expr_ty.to_vec(); + + let mut check_referent = |referent| { + let referent_ty = cx.typeck_results().expr_ty(referent); + + if !is_copy(cx, referent_ty) { + return false; + } + + // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 + if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + return false; + } + + if !replace_types( + cx, + param_ty, + referent_ty, + fn_sig, + arg_index, + &projection_predicates, + &mut substs_with_referent_ty, + ) { + return false; + } + + predicates.iter().all(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) + && let ty::Param(param_ty) = trait_predicate.self_ty().kind() + && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() + && ty.is_array() + && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR) + { + return false; + } + + let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty); + let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); + cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + }) + }; + + let mut needless_borrow = false; + while let ExprKind::AddrOf(_, _, referent) = expr.kind { + if !check_referent(referent) { + break; + } + expr = referent; + needless_borrow = true; + } + + if needless_borrow { + Position::ImplArg(expr.hir_id) + } else { + Position::Other(precedence) + } +} + +fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { + cx.tcx + .associated_items(trait_def_id) + .in_definition_order() + .any(|assoc_item| { + if assoc_item.fn_has_self_parameter { + let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0]; + matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut)) + } else { + false + } + }) +} + +// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting +// projected type that is a type parameter. Returns `false` if replacing the types would have an +// effect on the function signature beyond substituting `new_ty` for `param_ty`. +// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757 +fn replace_types<'tcx>( + cx: &LateContext<'tcx>, + param_ty: ParamTy, + new_ty: Ty<'tcx>, + fn_sig: FnSig<'tcx>, + arg_index: usize, + projection_predicates: &[ProjectionPredicate<'tcx>], + substs: &mut [ty::GenericArg<'tcx>], +) -> bool { + let mut replaced = BitSet::new_empty(substs.len()); + + let mut deque = VecDeque::with_capacity(substs.len()); + deque.push_back((param_ty, new_ty)); + + while let Some((param_ty, new_ty)) = deque.pop_front() { + // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in. + if !fn_sig + .inputs_and_output + .iter() + .enumerate() + .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !contains_ty(ty, param_ty.to_ty(cx.tcx))) + { + return false; + } + + substs[param_ty.index as usize] = ty::GenericArg::from(new_ty); + + // The `replaced.insert(...)` check provides some protection against infinite loops. + if replaced.insert(param_ty.index) { + for projection_predicate in projection_predicates { + if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx) + && let ty::Term::Ty(term_ty) = projection_predicate.term + && let ty::Param(term_param_ty) = term_ty.kind() + { + let item_def_id = projection_predicate.projection_ty.item_def_id; + let assoc_item = cx.tcx.associated_item(item_def_id); + let projection = cx.tcx + .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[])); + + if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) + && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty) + { + deque.push_back((*term_param_ty, projected_ty)); + } + } + } + } + } + + true +} + struct TyPosition<'tcx> { position: Position, ty: Option>, @@ -1084,7 +1328,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }, State::DerefedBorrow(state) => { let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); + let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id)); + let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app); span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| { let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee); let sugg = if !snip_is_macro diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e6a405f8170..521739c28ff 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -821,7 +821,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads)); store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); - store.register_late_pass(|| Box::new(dereference::Dereferencing::default())); + store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 99b56da7a50..e4624167ad0 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -6,9 +6,8 @@ use clippy_utils::ty::{ contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, }; -use clippy_utils::{meets_msrv, msrvs}; - use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -373,25 +372,15 @@ fn get_input_traits_and_projections<'tcx>( ) -> (Vec>, Vec>) { let mut trait_predicates = Vec::new(); let mut projection_predicates = Vec::new(); - for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() { - // `substs` should have 1 + n elements. The first is the type on the left hand side of an - // `as`. The remaining n are trait parameters. - let is_input_substs = |substs: SubstsRef<'tcx>| { - if_chain! { - if let Some(arg) = substs.iter().next(); - if let GenericArgKind::Type(arg_ty) = arg.unpack(); - if arg_ty == input; - then { true } else { false } - } - }; + for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { match predicate.kind().skip_binder() { PredicateKind::Trait(trait_predicate) => { - if is_input_substs(trait_predicate.trait_ref.substs) { + if trait_predicate.trait_ref.self_ty() == input { trait_predicates.push(trait_predicate); } }, PredicateKind::Projection(projection_predicate) => { - if is_input_substs(projection_predicate.projection_ty.substs) { + if projection_predicate.projection_ty.self_ty() == input { projection_predicates.push(projection_predicate); } }, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 9e238c6f1ac..7fa0046a267 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -13,7 +13,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,62,0 { BOOL_THEN_SOME } - 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN } + 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } 1,50,0 { BOOL_THEN } diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index bfd2725ecaa..8cf93bd2481 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![feature(lint_reasons)] +#![feature(custom_inner_attributes, lint_reasons)] #[warn(clippy::all, clippy::needless_borrow)] #[allow(unused_variables, clippy::unnecessary_mut_passed)] @@ -127,6 +127,20 @@ fn main() { 0 } } + + let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap(); + let _ = std::path::Path::new(".").join("."); + deref_target_is_x(X); + multiple_constraints([[""]]); + multiple_constraints_normalizes_to_same(X, X); + let _ = Some("").unwrap_or(""); + + only_sized(&""); // Don't lint. `Sized` is only bound + let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound + let _ = Box::new(&""); // Don't lint. Type parameter appears in return type + ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter + refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't + multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments } #[allow(clippy::needless_borrowed_reference)] @@ -183,3 +197,104 @@ mod issue9160 { } } } + +#[derive(Clone, Copy)] +struct X; + +impl std::ops::Deref for X { + type Target = X; + fn deref(&self) -> &Self::Target { + self + } +} + +fn deref_target_is_x(_: T) +where + T: std::ops::Deref, +{ +} + +fn multiple_constraints(_: T) +where + T: IntoIterator + IntoIterator, + U: IntoIterator, + V: AsRef, + X: IntoIterator, + Y: AsRef, +{ +} + +fn multiple_constraints_normalizes_to_same(_: T, _: V) +where + T: std::ops::Deref, + U: std::ops::Deref, +{ +} + +fn only_sized(_: T) {} + +fn ref_as_ref_path(_: &'static T) +where + &'static T: AsRef, +{ +} + +trait RefsOnly { + type Referent; +} + +impl RefsOnly for &T { + type Referent = T; +} + +fn refs_only(_: T) +where + T: RefsOnly, +{ +} + +fn multiple_constraints_normalizes_to_different(_: T, _: U) +where + T: IntoIterator, + U: IntoIterator, + V: AsRef, +{ +} + +// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 +#[allow(dead_code)] +mod copyable_iterator { + #[derive(Clone, Copy)] + struct Iter; + impl Iterator for Iter { + type Item = (); + fn next(&mut self) -> Option { + None + } + } + fn takes_iter(_: impl Iterator) {} + fn dont_warn(mut x: Iter) { + takes_iter(&mut x); + } + fn warn(mut x: &mut Iter) { + takes_iter(&mut x) + } +} + +mod under_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.52.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + } +} + +mod meets_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.53.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap(); + } +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index c457d8c5471..fd9b2a11df9 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,6 +1,6 @@ // run-rustfix -#![feature(lint_reasons)] +#![feature(custom_inner_attributes, lint_reasons)] #[warn(clippy::all, clippy::needless_borrow)] #[allow(unused_variables, clippy::unnecessary_mut_passed)] @@ -127,6 +127,20 @@ fn main() { 0 } } + + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + let _ = std::path::Path::new(".").join(&&"."); + deref_target_is_x(&X); + multiple_constraints(&[[""]]); + multiple_constraints_normalizes_to_same(&X, X); + let _ = Some("").unwrap_or(&""); + + only_sized(&""); // Don't lint. `Sized` is only bound + let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound + let _ = Box::new(&""); // Don't lint. Type parameter appears in return type + ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter + refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't + multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments } #[allow(clippy::needless_borrowed_reference)] @@ -183,3 +197,104 @@ mod issue9160 { } } } + +#[derive(Clone, Copy)] +struct X; + +impl std::ops::Deref for X { + type Target = X; + fn deref(&self) -> &Self::Target { + self + } +} + +fn deref_target_is_x(_: T) +where + T: std::ops::Deref, +{ +} + +fn multiple_constraints(_: T) +where + T: IntoIterator + IntoIterator, + U: IntoIterator, + V: AsRef, + X: IntoIterator, + Y: AsRef, +{ +} + +fn multiple_constraints_normalizes_to_same(_: T, _: V) +where + T: std::ops::Deref, + U: std::ops::Deref, +{ +} + +fn only_sized(_: T) {} + +fn ref_as_ref_path(_: &'static T) +where + &'static T: AsRef, +{ +} + +trait RefsOnly { + type Referent; +} + +impl RefsOnly for &T { + type Referent = T; +} + +fn refs_only(_: T) +where + T: RefsOnly, +{ +} + +fn multiple_constraints_normalizes_to_different(_: T, _: U) +where + T: IntoIterator, + U: IntoIterator, + V: AsRef, +{ +} + +// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 +#[allow(dead_code)] +mod copyable_iterator { + #[derive(Clone, Copy)] + struct Iter; + impl Iterator for Iter { + type Item = (); + fn next(&mut self) -> Option { + None + } + } + fn takes_iter(_: impl Iterator) {} + fn dont_warn(mut x: Iter) { + takes_iter(&mut x); + } + fn warn(mut x: &mut Iter) { + takes_iter(&mut x) + } +} + +mod under_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.52.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + } +} + +mod meets_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.53.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + } +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 66588689d81..5af68706d4b 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -120,17 +120,59 @@ error: this expression creates a reference which is immediately dereferenced by LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:131:51 + | +LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:132:44 + | +LL | let _ = std::path::Path::new(".").join(&&"."); + | ^^^^^ help: change this to: `"."` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:133:23 + | +LL | deref_target_is_x(&X); + | ^^ help: change this to: `X` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:134:26 + | +LL | multiple_constraints(&[[""]]); + | ^^^^^^^ help: change this to: `[[""]]` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:135:45 + | +LL | multiple_constraints_normalizes_to_same(&X, X); + | ^^ help: change this to: `X` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:136:32 + | +LL | let _ = Some("").unwrap_or(&""); + | ^^^ help: change this to: `""` + error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:173:13 + --> $DIR/needless_borrow.rs:187:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:182:13 + --> $DIR/needless_borrow.rs:196:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` -error: aborting due to 22 previous errors +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:298:55 + | +LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` + +error: aborting due to 29 previous errors -- cgit 1.4.1-3-g733a5 From ab91d5a5408cdb888b49ed3d893c0e28afef5861 Mon Sep 17 00:00:00 2001 From: Sosthène Guédon Date: Wed, 17 Aug 2022 18:58:17 +0200 Subject: unwrap_used: Fix error message for unwrap_err when expect_used is allowed --- clippy_lints/src/methods/unwrap_used.rs | 6 +++--- tests/ui/expect.rs | 3 ++- tests/ui/expect.stderr | 10 +++++++++- tests/ui/unwrap.rs | 3 ++- tests/ui/unwrap.stderr | 10 +++++++++- 5 files changed, 25 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 05915c14109..ee17f2d7889 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -25,7 +25,7 @@ pub(super) fn check( None }; - let method = if is_err { "unwrap_err" } else { "unwrap" }; + let method_suffix = if is_err { "_err" } else { "" }; if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; @@ -35,7 +35,7 @@ pub(super) fn check( let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { format!( "if you don't want to handle the `{none_value}` case gracefully, consider \ - using `expect()` to provide a better panic message" + using `expect{method_suffix}()` to provide a better panic message" ) } else { format!("if this value is {none_prefix}`{none_value}`, it will panic") @@ -45,7 +45,7 @@ pub(super) fn check( cx, lint, expr.span, - &format!("used `{method}()` on `{kind}` value"), + &format!("used `unwrap{method_suffix}()` on `{kind}` value"), None, &help, ); diff --git a/tests/ui/expect.rs b/tests/ui/expect.rs index 1073acf6f0c..d742595e14d 100644 --- a/tests/ui/expect.rs +++ b/tests/ui/expect.rs @@ -6,8 +6,9 @@ fn expect_option() { } fn expect_result() { - let res: Result = Ok(0); + let res: Result = Ok(0); let _ = res.expect(""); + let _ = res.expect_err(""); } fn main() { diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index ab28aac4556..904c0904645 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -15,5 +15,13 @@ LL | let _ = res.expect(""); | = help: if this value is an `Err`, it will panic -error: aborting due to 2 previous errors +error: used `expect_err()` on `a Result` value + --> $DIR/expect.rs:11:13 + | +LL | let _ = res.expect_err(""); + | ^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: aborting due to 3 previous errors diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs index a4a3cd1d379..d9fd402e7cf 100644 --- a/tests/ui/unwrap.rs +++ b/tests/ui/unwrap.rs @@ -6,8 +6,9 @@ fn unwrap_option() { } fn unwrap_result() { - let res: Result = Ok(0); + let res: Result = Ok(0); let _ = res.unwrap(); + let _ = res.unwrap_err(); } fn main() { diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index 4f0858005f6..78422757819 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -15,5 +15,13 @@ LL | let _ = res.unwrap(); | = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message -error: aborting due to 2 previous errors +error: used `unwrap_err()` on `a Result` value + --> $DIR/unwrap.rs:11:13 + | +LL | let _ = res.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 25028986864fbb3231c54feb5e769c8778e037bf Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 11:39:36 -0400 Subject: Move `ByteCount` into `Methods` lint pass --- clippy_lints/src/bytecount.rs | 103 ------------------------------ clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/bytecount.rs | 70 ++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 42 +++++++++++- 6 files changed, 111 insertions(+), 110 deletions(-) delete mode 100644 clippy_lints/src/bytecount.rs create mode 100644 clippy_lints/src/methods/bytecount.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs deleted file mode 100644 index 326ce34082a..00000000000 --- a/clippy_lints/src/bytecount.rs +++ /dev/null @@ -1,103 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; -use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for naive byte counts - /// - /// ### Why is this bad? - /// The [`bytecount`](https://crates.io/crates/bytecount) - /// crate has methods to count your bytes faster, especially for large slices. - /// - /// ### Known problems - /// If you have predominantly small slices, the - /// `bytecount::count(..)` method may actually be slower. However, if you can - /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be - /// faster in those cases. - /// - /// ### Example - /// ```rust - /// # let vec = vec![1_u8]; - /// let count = vec.iter().filter(|x| **x == 0u8).count(); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// # let vec = vec![1_u8]; - /// let count = bytecount::count(&vec, 0u8); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub NAIVE_BYTECOUNT, - pedantic, - "use of naive `.filter(|&x| x == y).count()` to count byte values" -} - -declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]); - -impl<'tcx> LateLintPass<'tcx> for ByteCount { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(count, [count_recv], _) = expr.kind; - if count.ident.name == sym::count; - if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind; - if filter.ident.name == sym!(filter); - if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; - let body = cx.tcx.hir().body(body); - if let [param] = body.params; - if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; - if let ExprKind::Binary(ref op, l, r) = body.value.kind; - if op.node == BinOpKind::Eq; - if match_type(cx, - cx.typeck_results().expr_ty(filter_recv).peel_refs(), - &paths::SLICE_ITER); - let operand_is_arg = |expr| { - let expr = peel_ref_operators(cx, peel_blocks(expr)); - path_to_local_id(expr, arg_id) - }; - let needle = if operand_is_arg(l) { - r - } else if operand_is_arg(r) { - l - } else { - return; - }; - if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); - if !is_local_used(cx, needle, arg_id); - then { - let haystack = if let ExprKind::MethodCall(path, args, _) = - filter_recv.kind { - let p = path.ident.name; - if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { - &args[0] - } else { - filter_recv - } - } else { - filter_recv - }; - let mut applicability = Applicability::MaybeIncorrect; - span_lint_and_sugg( - cx, - NAIVE_BYTECOUNT, - expr.span, - "you appear to be counting bytes the naive way", - "consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet_with_applicability(cx, haystack.span, "..", &mut applicability), - snippet_with_applicability(cx, needle.span, "..", &mut applicability)), - applicability, - ); - } - }; - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 7883711e5a3..c3c24fb1668 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -59,7 +59,6 @@ store.register_lints(&[ booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_deref_ref::BORROW_DEREF_REF, - bytecount::NAIVE_BYTECOUNT, bytes_count_to_len::BYTES_COUNT_TO_LEN, cargo::CARGO_COMMON_METADATA, cargo::MULTIPLE_CRATE_VERSIONS, @@ -330,6 +329,7 @@ store.register_lints(&[ methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::NAIVE_BYTECOUNT, methods::NEEDLESS_OPTION_AS_DEREF, methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index ae9f046f023..241d70d2628 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(bytecount::NAIVE_BYTECOUNT), LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(casts::BORROW_AS_PTR), LintId::of(casts::CAST_LOSSLESS), @@ -64,6 +63,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(methods::NAIVE_BYTECOUNT), LintId::of(methods::UNNECESSARY_JOIN), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 63e0fcf6b0f..617f1622325 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -180,7 +180,6 @@ mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; mod borrow_deref_ref; -mod bytecount; mod bytes_count_to_len; mod cargo; mod case_sensitive_file_extension_comparisons; @@ -718,7 +717,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ); store.register_late_pass(move || Box::new(pass_by_ref_or_value)); store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef)); - store.register_late_pass(|| Box::new(bytecount::ByteCount)); store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter)); store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody)); store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs new file mode 100644 index 00000000000..6a7c63d76f7 --- /dev/null +++ b/clippy_lints/src/methods/bytecount.rs @@ -0,0 +1,70 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, UintTy}; +use rustc_span::sym; + +use super::NAIVE_BYTECOUNT; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + filter_recv: &'tcx Expr<'_>, + filter_arg: &'tcx Expr<'_>, +) { + if_chain! { + if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; + let body = cx.tcx.hir().body(body); + if let [param] = body.params; + if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; + if let ExprKind::Binary(ref op, l, r) = body.value.kind; + if op.node == BinOpKind::Eq; + if match_type(cx, + cx.typeck_results().expr_ty(filter_recv).peel_refs(), + &paths::SLICE_ITER); + let operand_is_arg = |expr| { + let expr = peel_ref_operators(cx, peel_blocks(expr)); + path_to_local_id(expr, arg_id) + }; + let needle = if operand_is_arg(l) { + r + } else if operand_is_arg(r) { + l + } else { + return; + }; + if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); + if !is_local_used(cx, needle, arg_id); + then { + let haystack = if let ExprKind::MethodCall(path, args, _) = + filter_recv.kind { + let p = path.ident.name; + if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { + &args[0] + } else { + filter_recv + } + } else { + filter_recv + }; + let mut applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + NAIVE_BYTECOUNT, + expr.span, + "you appear to be counting bytes the naive way", + "consider using the bytecount crate", + format!("bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + applicability, + ); + } + }; +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b68a2651e1b..f0d9dce5518 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod bytecount; mod bytes_nth; mod chars_cmp; mod chars_cmp_with_unwrap; @@ -82,7 +83,9 @@ 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, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; +use clippy_utils::{ + contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty, +}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -2368,6 +2371,37 @@ declare_clippy_lint! { "Iterator for empty array" } +declare_clippy_lint! { + /// ### What it does + /// Checks for naive byte counts + /// + /// ### Why is this bad? + /// The [`bytecount`](https://crates.io/crates/bytecount) + /// crate has methods to count your bytes faster, especially for large slices. + /// + /// ### Known problems + /// If you have predominantly small slices, the + /// `bytecount::count(..)` method may actually be slower. However, if you can + /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be + /// faster in those cases. + /// + /// ### Example + /// ```rust + /// # let vec = vec![1_u8]; + /// let count = vec.iter().filter(|x| **x == 0u8).count(); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// # let vec = vec![1_u8]; + /// let count = bytecount::count(&vec, 0u8); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub NAIVE_BYTECOUNT, + pedantic, + "use of naive `.filter(|&x| x == y).count()` to count byte values" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2471,7 +2505,8 @@ impl_lint_pass!(Methods => [ NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, ITER_ON_SINGLE_ITEMS, - ITER_ON_EMPTY_COLLECTIONS + ITER_ON_EMPTY_COLLECTIONS, + NAIVE_BYTECOUNT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2726,12 +2761,13 @@ impl Methods { }, _ => {}, }, - ("count", []) => match method_call(recv) { + ("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], _)) => { 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), _ => {}, }, ("drain", [arg]) => { -- cgit 1.4.1-3-g733a5 From ba6a4595285e38f35970e66db903475989e0be6f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:05:11 -0400 Subject: Move `BytesCountToLen` into `Methods` lint pass --- clippy_lints/src/bytes_count_to_len.rs | 70 -------------------------- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/bytes_count_to_len.rs | 37 ++++++++++++++ clippy_lints/src/methods/mod.rs | 28 +++++++++++ 7 files changed, 68 insertions(+), 75 deletions(-) delete mode 100644 clippy_lints/src/bytes_count_to_len.rs create mode 100644 clippy_lints/src/methods/bytes_count_to_len.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/bytes_count_to_len.rs b/clippy_lints/src/bytes_count_to_len.rs deleted file mode 100644 index d70dbf5b239..00000000000 --- a/clippy_lints/src/bytes_count_to_len.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// It checks for `str::bytes().count()` and suggests replacing it with - /// `str::len()`. - /// - /// ### Why is this bad? - /// `str::bytes().count()` is longer and may not be as performant as using - /// `str::len()`. - /// - /// ### Example - /// ```rust - /// "hello".bytes().count(); - /// String::from("hello").bytes().count(); - /// ``` - /// Use instead: - /// ```rust - /// "hello".len(); - /// String::from("hello").len(); - /// ``` - #[clippy::version = "1.62.0"] - pub BYTES_COUNT_TO_LEN, - complexity, - "Using `bytes().count()` when `len()` performs the same functionality" -} - -declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]); - -impl<'tcx> LateLintPass<'tcx> for BytesCountToLen { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind; - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, expr_def_id, &paths::ITER_COUNT); - - if let [bytes_expr] = &**expr_args; - if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind; - if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id); - if match_def_path(cx, bytes_def_id, &paths::STR_BYTES); - - if let [str_expr] = &**bytes_args; - let ty = cx.typeck_results().expr_ty(str_expr).peel_refs(); - - if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_COUNT_TO_LEN, - expr.span, - "using long and hard to read `.bytes().count()`", - "consider calling `.len()` instead", - format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)), - applicability - ); - } - }; - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index a0a4b07a77e..f48e542ee41 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -20,7 +20,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), - LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ENUM_CONSTRUCTOR), LintId::of(casts::CAST_ENUM_TRUNCATION), @@ -151,6 +150,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_COUNT_TO_LEN), LintId::of(methods::BYTES_NTH), LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 3784d3c68dc..324b380317f 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -6,7 +6,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(attrs::DEPRECATED_CFG_ATTR), LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), - LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::UNNECESSARY_CAST), LintId::of(dereference::EXPLICIT_AUTO_DEREF), @@ -33,6 +32,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(matches::NEEDLESS_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_COUNT_TO_LEN), LintId::of(methods::CLONE_ON_COPY), LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c3c24fb1668..bfd12b98944 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -59,7 +59,6 @@ store.register_lints(&[ booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_deref_ref::BORROW_DEREF_REF, - bytes_count_to_len::BYTES_COUNT_TO_LEN, cargo::CARGO_COMMON_METADATA, cargo::MULTIPLE_CRATE_VERSIONS, cargo::NEGATIVE_FEATURE_NAMES, @@ -284,6 +283,7 @@ store.register_lints(&[ mem_replace::MEM_REPLACE_WITH_DEFAULT, mem_replace::MEM_REPLACE_WITH_UNINIT, methods::BIND_INSTEAD_OF_MAP, + methods::BYTES_COUNT_TO_LEN, methods::BYTES_NTH, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 617f1622325..f4cb5e5bf16 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -180,7 +180,6 @@ mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; mod borrow_deref_ref; -mod bytes_count_to_len; mod cargo; mod case_sensitive_file_extension_comparisons; mod casts; @@ -907,7 +906,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|| Box::new(format_push_string::FormatPushString)); - store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen)); let max_include_file_size = conf.max_include_file_size; store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs new file mode 100644 index 00000000000..fcfc25b523d --- /dev/null +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::BYTES_COUNT_TO_LEN; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + count_recv: &'tcx hir::Expr<'_>, + bytes_recv: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); + if cx.tcx.type_of(impl_id).is_str(); + let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); + if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_COUNT_TO_LEN, + expr.span, + "using long and hard to read `.bytes().count()`", + "consider calling `.len()` instead", + format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)), + applicability + ); + } + }; +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f0d9dce5518..eab3ca1842b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,6 @@ mod bind_instead_of_map; mod bytecount; +mod bytes_count_to_len; mod bytes_nth; mod chars_cmp; mod chars_cmp_with_unwrap; @@ -2402,6 +2403,31 @@ declare_clippy_lint! { "use of naive `.filter(|&x| x == y).count()` to count byte values" } +declare_clippy_lint! { + /// ### What it does + /// It checks for `str::bytes().count()` and suggests replacing it with + /// `str::len()`. + /// + /// ### Why is this bad? + /// `str::bytes().count()` is longer and may not be as performant as using + /// `str::len()`. + /// + /// ### Example + /// ```rust + /// "hello".bytes().count(); + /// String::from("hello").bytes().count(); + /// ``` + /// Use instead: + /// ```rust + /// "hello".len(); + /// String::from("hello").len(); + /// ``` + #[clippy::version = "1.62.0"] + pub BYTES_COUNT_TO_LEN, + complexity, + "Using `bytes().count()` when `len()` performs the same functionality" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2507,6 +2533,7 @@ impl_lint_pass!(Methods => [ ITER_ON_SINGLE_ITEMS, ITER_ON_EMPTY_COLLECTIONS, NAIVE_BYTECOUNT, + BYTES_COUNT_TO_LEN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2768,6 +2795,7 @@ impl Methods { }, 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]) => { -- cgit 1.4.1-3-g733a5 From e3b77974d0025b6900fde9799ad4b2cd324050fb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:21:04 -0400 Subject: Move `CaseSensitiveFileExtensionComparisons` into `Methods` lint pass --- .../case_sensitive_file_extension_comparisons.rs | 85 ---------------------- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 4 - .../case_sensitive_file_extension_comparisons.rs | 41 +++++++++++ clippy_lints/src/methods/mod.rs | 34 +++++++++ 6 files changed, 77 insertions(+), 91 deletions(-) delete mode 100644 clippy_lints/src/case_sensitive_file_extension_comparisons.rs create mode 100644 clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs deleted file mode 100644 index bef196565a2..00000000000 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ /dev/null @@ -1,85 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{source_map::Spanned, symbol::sym, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `ends_with` with possible file extensions - /// and suggests to use a case-insensitive approach instead. - /// - /// ### Why is this bad? - /// `ends_with` is case-sensitive and may not detect files with a valid extension. - /// - /// ### Example - /// ```rust - /// fn is_rust_file(filename: &str) -> bool { - /// filename.ends_with(".rs") - /// } - /// ``` - /// Use instead: - /// ```rust - /// fn is_rust_file(filename: &str) -> bool { - /// let filename = std::path::Path::new(filename); - /// filename.extension() - /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) - /// } - /// ``` - #[clippy::version = "1.51.0"] - pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - pedantic, - "Checks for calls to ends_with with case-sensitive file extensions" -} - -declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]); - -fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if_chain! { - if let ExprKind::MethodCall(PathSegment { ident, .. }, [obj, extension, ..], span) = expr.kind; - if ident.as_str() == "ends_with"; - if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind; - if (2..=6).contains(&ext_literal.as_str().len()); - if ext_literal.as_str().starts_with('.'); - if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) - || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); - then { - let mut ty = ctx.typeck_results().expr_ty(obj); - ty = match ty.kind() { - ty::Ref(_, ty, ..) => *ty, - _ => ty - }; - - match ty.kind() { - ty::Str => { - return Some(span); - }, - ty::Adt(def, _) => { - if ctx.tcx.is_diagnostic_item(sym::String, def.did()) { - return Some(span); - } - }, - _ => { return None; } - } - } - } - None -} - -impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons { - fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) { - span_lint_and_help( - ctx, - CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - span, - "case-sensitive file extension comparison", - None, - "consider using a case-insensitive comparison instead", - ); - } - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index bfd12b98944..10ff1fa1f58 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -64,7 +64,6 @@ store.register_lints(&[ cargo::NEGATIVE_FEATURE_NAMES, cargo::REDUNDANT_FEATURE_NAMES, cargo::WILDCARD_DEPENDENCIES, - case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, casts::AS_UNDERSCORE, casts::BORROW_AS_PTR, casts::CAST_ABS_TO_UNSIGNED, @@ -285,6 +284,7 @@ store.register_lints(&[ methods::BIND_INSTEAD_OF_MAP, methods::BYTES_COUNT_TO_LEN, methods::BYTES_NTH, + methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, methods::CLONED_INSTEAD_OF_COPIED, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 241d70d2628..c9cf7dbd078 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(casts::BORROW_AS_PTR), LintId::of(casts::CAST_LOSSLESS), LintId::of(casts::CAST_POSSIBLE_TRUNCATION), @@ -56,6 +55,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(matches::MATCH_WILD_ERR_ARM), LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(methods::CLONED_INSTEAD_OF_COPIED), LintId::of(methods::FILTER_MAP_NEXT), LintId::of(methods::FLAT_MAP_OPTION), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f4cb5e5bf16..68f69dc64b8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -181,7 +181,6 @@ mod bool_assert_comparison; mod booleans; mod borrow_deref_ref; mod cargo; -mod case_sensitive_file_extension_comparisons; mod casts; mod checked_conversions; mod cognitive_complexity; @@ -852,9 +851,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::StringToString)); store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues)); store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default())); - store.register_late_pass(|| { - Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons) - }); store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs new file mode 100644 index 00000000000..b3c2c7c9a2d --- /dev/null +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::{source_map::Spanned, symbol::sym, Span}; + +use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + call_span: Span, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_str(); + if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind; + if (2..=6).contains(&ext_literal.as_str().len()); + let ext_str = ext_literal.as_str(); + if ext_str.starts_with('.'); + if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) + || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String); + then { + span_lint_and_help( + cx, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + call_span, + "case-sensitive file extension comparison", + None, + "consider using a case-insensitive comparison instead", + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index eab3ca1842b..0bb247c7e81 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2,6 +2,7 @@ mod bind_instead_of_map; mod bytecount; mod bytes_count_to_len; mod bytes_nth; +mod case_sensitive_file_extension_comparisons; mod chars_cmp; mod chars_cmp_with_unwrap; mod chars_last_cmp; @@ -2428,6 +2429,34 @@ declare_clippy_lint! { "Using `bytes().count()` when `len()` performs the same functionality" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `ends_with` with possible file extensions + /// and suggests to use a case-insensitive approach instead. + /// + /// ### Why is this bad? + /// `ends_with` is case-sensitive and may not detect files with a valid extension. + /// + /// ### Example + /// ```rust + /// fn is_rust_file(filename: &str) -> bool { + /// filename.ends_with(".rs") + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn is_rust_file(filename: &str) -> bool { + /// let filename = std::path::Path::new(filename); + /// filename.extension() + /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + /// } + /// ``` + #[clippy::version = "1.51.0"] + pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + pedantic, + "Checks for calls to ends_with with case-sensitive file extensions" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2534,6 +2563,7 @@ impl_lint_pass!(Methods => [ ITER_ON_EMPTY_COLLECTIONS, NAIVE_BYTECOUNT, BYTES_COUNT_TO_LEN, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2801,6 +2831,10 @@ impl Methods { ("drain", [arg]) => { iter_with_drain::check(cx, expr, recv, span, arg); }, + ("ends_with", [arg]) => { + if let ExprKind::MethodCall(_, _, span) = expr.kind { + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + }, ("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), -- cgit 1.4.1-3-g733a5 From a8d80d531f1d358c26295eb3d81624594544dd4b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:44:09 -0400 Subject: Move `GetFirst` into `Methods` lint pass --- clippy_lints/src/get_first.rs | 68 ---------------------------------- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/get_first.rs | 39 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 36 +++++++++++++++++- 7 files changed, 76 insertions(+), 75 deletions(-) delete mode 100644 clippy_lints/src/get_first.rs create mode 100644 clippy_lints/src/methods/get_first.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs deleted file mode 100644 index 529f7babaa5..00000000000 --- a/clippy_lints/src/get_first.rs +++ /dev/null @@ -1,68 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_slice_of_primitives, match_def_path, paths}; -use if_chain::if_chain; -use rustc_ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Checks for using `x.get(0)` instead of - /// `x.first()`. - /// - /// ### Why is this bad? - /// Using `x.first()` is easier to read and has the same - /// result. - /// - /// ### Example - /// ```rust - /// let x = vec![2, 3, 5]; - /// let first_element = x.get(0); - /// ``` - /// - /// Use instead: - /// ```rust - /// let x = vec![2, 3, 5]; - /// let first_element = x.first(); - /// ``` - #[clippy::version = "1.63.0"] - pub GET_FIRST, - style, - "Using `x.get(0)` when `x.first()` is simpler" -} -declare_lint_pass!(GetFirst => [GET_FIRST]); - -impl<'tcx> LateLintPass<'tcx> for GetFirst { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind; - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, expr_def_id, &paths::SLICE_GET); - - if let Some(_) = is_slice_of_primitives(cx, struct_calling_on); - if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind; - - then { - let mut applicability = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability( - cx, - struct_calling_on.span, "..", - &mut applicability, - ); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{0}.get(0)`", slice_name), - "try", - format!("{}.first()", slice_name), - applicability, - ); - } - } - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index f48e542ee41..8ce0a26915f 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -81,7 +81,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_first::GET_FIRST), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), @@ -162,6 +161,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::GET_FIRST), LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 10ff1fa1f58..a6224035ec8 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -174,7 +174,6 @@ store.register_lints(&[ functions::TOO_MANY_ARGUMENTS, functions::TOO_MANY_LINES, future_not_send::FUTURE_NOT_SEND, - get_first::GET_FIRST, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, @@ -302,6 +301,7 @@ store.register_lints(&[ methods::FLAT_MAP_IDENTITY, methods::FLAT_MAP_OPTION, methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_FIRST, methods::GET_LAST_WITH_LEN, methods::GET_UNWRAP, methods::IMPLICIT_CLONE, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 6972c75597a..5ddaba2396e 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -29,7 +29,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(get_first::GET_FIRST), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS), LintId::of(len_zero::COMPARISON_TO_EMPTY), @@ -62,6 +61,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::ERR_EXPECT), + LintId::of(methods::GET_FIRST), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::IS_DIGIT_ASCII_RADIX), LintId::of(methods::ITER_CLONED_COLLECT), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 68f69dc64b8..3fcdc84113d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -233,7 +233,6 @@ mod from_over_into; mod from_str_radix_10; mod functions; mod future_not_send; -mod get_first; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -907,7 +906,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); - store.register_late_pass(|| Box::new(get_first::GetFirst)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs new file mode 100644 index 00000000000..4de77de7404 --- /dev/null +++ b/clippy_lints/src/methods/get_first.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::GET_FIRST; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let Some(_) = is_slice_of_primitives(cx, recv); + if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; + then { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{0}.get(0)`", slice_name), + "try", + format!("{}.first()", slice_name), + app, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0bb247c7e81..c3438426985 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -24,6 +24,7 @@ mod filter_next; mod flat_map_identity; mod flat_map_option; mod from_iter_instead_of_collect; +mod get_first; mod get_last_with_len; mod get_unwrap; mod implicit_clone; @@ -2457,6 +2458,32 @@ declare_clippy_lint! { "Checks for calls to ends_with with case-sensitive file extensions" } +declare_clippy_lint! { + /// ### What it does + /// Checks for using `x.get(0)` instead of + /// `x.first()`. + /// + /// ### Why is this bad? + /// Using `x.first()` is easier to read and has the same + /// result. + /// + /// ### Example + /// ```rust + /// let x = vec![2, 3, 5]; + /// let first_element = x.get(0); + /// ``` + /// + /// Use instead: + /// ```rust + /// let x = vec![2, 3, 5]; + /// let first_element = x.first(); + /// ``` + #[clippy::version = "1.63.0"] + pub GET_FIRST, + style, + "Using `x.get(0)` when `x.first()` is simpler" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2564,6 +2591,7 @@ impl_lint_pass!(Methods => [ NAIVE_BYTECOUNT, BYTES_COUNT_TO_LEN, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + GET_FIRST, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2833,7 +2861,8 @@ impl Methods { }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(_, _, span) = expr.kind { - case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + } }, ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), @@ -2867,7 +2896,10 @@ impl Methods { inspect_for_each::check(cx, expr, span2); } }, - ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg), + ("get", [arg]) => { + get_first::check(cx, expr, recv, arg); + get_last_with_len::check(cx, expr, recv, arg); + }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), -- cgit 1.4.1-3-g733a5 From 5bc8813cdd4f33f42c4dc17572d148c284d3e81b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 15:20:47 -0400 Subject: Move `ManualOkOr` into `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/manual_ok_or.rs | 95 ------------------------------- clippy_lints/src/methods/manual_ok_or.rs | 64 +++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 33 ++++++++++- 6 files changed, 98 insertions(+), 100 deletions(-) delete mode 100644 clippy_lints/src/manual_ok_or.rs create mode 100644 clippy_lints/src/methods/manual_ok_or.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index a6224035ec8..ac30c8b6eac 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -243,7 +243,6 @@ store.register_lints(&[ manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS, manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, - manual_ok_or::MANUAL_OK_OR, manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, @@ -322,6 +321,7 @@ store.register_lints(&[ methods::ITER_WITH_DRAIN, methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, + methods::MANUAL_OK_OR, methods::MANUAL_SATURATING_ARITHMETIC, methods::MANUAL_SPLIT_ONCE, methods::MANUAL_STR_REPEAT, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index c9cf7dbd078..5c04a331d0a 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -48,7 +48,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(manual_assert::MANUAL_ASSERT), LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED), - LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_ON_VEC_ITEMS), LintId::of(matches::MATCH_SAME_ARMS), @@ -62,6 +61,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), + LintId::of(methods::MANUAL_OK_OR), LintId::of(methods::MAP_UNWRAP_OR), LintId::of(methods::NAIVE_BYTECOUNT), LintId::of(methods::UNNECESSARY_JOIN), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3fcdc84113d..774ae01cc4f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -270,7 +270,6 @@ mod manual_bits; mod manual_empty_string_creations; mod manual_instant_elapsed; mod manual_non_exhaustive; -mod manual_ok_or; mod manual_rem_euclid; mod manual_retain; mod manual_strip; @@ -838,7 +837,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); store.register_late_pass(|| Box::new(repeat_once::RepeatOnce)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); - store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); let disallowed_methods = conf.disallowed_methods.clone(); diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs deleted file mode 100644 index cf5004399b8..00000000000 --- a/clippy_lints/src/manual_ok_or.rs +++ /dev/null @@ -1,95 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_to_local_id}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Closure, Expr, ExprKind, PatKind}; -use rustc_lint::LintContext; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; - -declare_clippy_lint! { - /// ### What it does - /// - /// Finds patterns that reimplement `Option::ok_or`. - /// - /// ### Why is this bad? - /// - /// Concise code helps focusing on behavior instead of boilerplate. - /// - /// ### Examples - /// ```rust - /// let foo: Option = None; - /// foo.map_or(Err("error"), |v| Ok(v)); - /// ``` - /// - /// Use instead: - /// ```rust - /// let foo: Option = None; - /// foo.ok_or("error"); - /// ``` - #[clippy::version = "1.49.0"] - pub MANUAL_OK_OR, - pedantic, - "finds patterns that can be encoded more concisely with `Option::ok_or`" -} - -declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]); - -impl<'tcx> LateLintPass<'tcx> for ManualOkOr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) { - if in_external_macro(cx.sess(), scrutinee.span) { - return; - } - - if_chain! { - if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind; - if method_segment.ident.name == sym!(map_or); - let ty = cx.typeck_results().expr_ty(receiver); - if is_type_diagnostic_item(cx, ty, sym::Option); - if is_ok_wrapping(cx, map_expr); - if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; - if is_lang_ctor(cx, err_path, ResultErr); - if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span); - if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); - if let Some(indent) = indent_of(cx, scrutinee.span); - then { - let reindented_err_arg_snippet = - reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); - span_lint_and_sugg( - cx, - MANUAL_OK_OR, - scrutinee.span, - "this pattern reimplements `Option::ok_or`", - "replace with", - format!( - "{}.ok_or({})", - method_receiver_snippet, - reindented_err_arg_snippet - ), - Applicability::MachineApplicable, - ); - } - } - } -} - -fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { - if let ExprKind::Path(ref qpath) = map_expr.kind { - if is_lang_ctor(cx, qpath, ResultOk) { - return true; - } - } - if_chain! { - if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; - let body = cx.tcx.hir().body(body); - if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; - if is_lang_ctor(cx, ok_path, ResultOk); - then { path_to_local_id(ok_arg, param_id) } else { false } - } -} diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs new file mode 100644 index 00000000000..ffd2f4a38b8 --- /dev/null +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -0,0 +1,64 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_lang_ctor, path_to_local_id}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; +use rustc_hir::{Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::MANUAL_OK_OR; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'_>, + or_expr: &'tcx Expr<'_>, + map_expr: &'tcx Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option); + if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind; + if is_lang_ctor(cx, err_path, ResultErr); + if is_ok_wrapping(cx, map_expr); + if let Some(recv_snippet) = snippet_opt(cx, recv.span); + if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); + if let Some(indent) = indent_of(cx, expr.span); + then { + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + span_lint_and_sugg( + cx, + MANUAL_OK_OR, + expr.span, + "this pattern reimplements `Option::ok_or`", + "replace with", + format!( + "{}.ok_or({})", + recv_snippet, + reindented_err_arg_snippet + ), + Applicability::MachineApplicable, + ); + } + } +} + +fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { + if let ExprKind::Path(ref qpath) = map_expr.kind { + if is_lang_ctor(cx, qpath, ResultOk) { + return true; + } + } + if_chain! { + if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; + let body = cx.tcx.hir().body(body); + if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; + if is_lang_ctor(cx, ok_path, ResultOk); + then { path_to_local_id(ok_arg, param_id) } else { false } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c3438426985..132f6040a51 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -42,6 +42,7 @@ mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; mod map_collect_result_unit; @@ -2484,6 +2485,32 @@ declare_clippy_lint! { "Using `x.get(0)` when `x.first()` is simpler" } +declare_clippy_lint! { + /// ### What it does + /// + /// Finds patterns that reimplement `Option::ok_or`. + /// + /// ### Why is this bad? + /// + /// Concise code helps focusing on behavior instead of boilerplate. + /// + /// ### Examples + /// ```rust + /// let foo: Option = None; + /// foo.map_or(Err("error"), |v| Ok(v)); + /// ``` + /// + /// Use instead: + /// ```rust + /// let foo: Option = None; + /// foo.ok_or("error"); + /// ``` + #[clippy::version = "1.49.0"] + pub MANUAL_OK_OR, + pedantic, + "finds patterns that can be encoded more concisely with `Option::ok_or`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2592,6 +2619,7 @@ impl_lint_pass!(Methods => [ BYTES_COUNT_TO_LEN, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, GET_FIRST, + MANUAL_OK_OR, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2936,7 +2964,10 @@ impl Methods { } map_identity::check(cx, expr, recv, m_arg, name, span); }, - ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), + ("map_or", [def, map]) => { + option_map_or_none::check(cx, expr, recv, def, map); + manual_ok_or::check(cx, expr, recv, def, map); + }, ("next", []) => { if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { match (name2, args2) { -- cgit 1.4.1-3-g733a5 From 452395485b113b06c1a47313eeab75d374d97e9f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 15:45:04 -0400 Subject: Move `MapClone` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 3 - clippy_lints/src/map_clone.rs | 167 --------------------------------- clippy_lints/src/methods/map_clone.rs | 122 ++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 34 +++++++ 7 files changed, 159 insertions(+), 173 deletions(-) delete mode 100644 clippy_lints/src/map_clone.rs create mode 100644 clippy_lints/src/methods/map_clone.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 8ce0a26915f..c496fd289bb 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -127,7 +127,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID), LintId::of(manual_retain::MANUAL_RETAIN), LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(map_clone::MAP_CLONE), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(match_result_ok::MATCH_RESULT_OK), @@ -179,6 +178,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index ac30c8b6eac..c7ea7f703f2 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -246,7 +246,6 @@ store.register_lints(&[ manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, - map_clone::MAP_CLONE, map_err_ignore::MAP_ERR_IGNORE, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, @@ -325,6 +324,7 @@ store.register_lints(&[ methods::MANUAL_SATURATING_ARITHMETIC, methods::MANUAL_SPLIT_ONCE, methods::MANUAL_STR_REPEAT, + methods::MAP_CLONE, methods::MAP_COLLECT_RESULT_UNIT, methods::MAP_FLATTEN, methods::MAP_IDENTITY, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 5ddaba2396e..52bf019c82e 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -45,7 +45,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(manual_bits::MANUAL_BITS), LintId::of(manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS), LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(map_clone::MAP_CLONE), LintId::of(match_result_ok::MATCH_RESULT_OK), LintId::of(matches::COLLAPSIBLE_MATCH), LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), @@ -69,6 +68,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::ITER_NTH_ZERO), LintId::of(methods::ITER_SKIP_NEXT), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OBFUSCATED_IF_ELSE), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 774ae01cc4f..8f31e4b938c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,7 +273,6 @@ mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; mod manual_strip; -mod map_clone; mod map_err_ignore; mod map_unit_fn; mod match_result_ok; @@ -628,8 +627,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark)); store.register_late_pass(move || Box::new(casts::Casts::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); - store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv))); - store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs deleted file mode 100644 index 95c312f1fe2..00000000000 --- a/clippy_lints/src/map_clone.rs +++ /dev/null @@ -1,167 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; -use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::Mutability; -use rustc_middle::ty; -use rustc_middle::ty::adjustment::Adjust; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `map(|x| x.clone())` or - /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, - /// and suggests `cloned()` or `copied()` instead - /// - /// ### Why is this bad? - /// Readability, this can be written more concisely - /// - /// ### Example - /// ```rust - /// let x = vec![42, 43]; - /// let y = x.iter(); - /// let z = y.map(|i| *i); - /// ``` - /// - /// The correct use would be: - /// - /// ```rust - /// let x = vec![42, 43]; - /// let y = x.iter(); - /// let z = y.cloned(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MAP_CLONE, - style, - "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" -} - -pub struct MapClone { - msrv: Option, -} - -impl_lint_pass!(MapClone => [MAP_CLONE]); - -impl MapClone { - pub fn new(msrv: Option) -> Self { - Self { msrv } - } -} - -impl<'tcx> LateLintPass<'tcx> for MapClone { - fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) { - if e.span.from_expansion() { - return; - } - - if_chain! { - if let hir::ExprKind::MethodCall(method, args, _) = e.kind; - if args.len() == 2; - if method.ident.name == sym::map; - let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator); - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind; - then { - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); - match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, .., name, None - ) = inner.kind { - if ident_eq(name, closure_expr) { - self.lint_explicit_closure(cx, e.span, args[0].span, true); - } - }, - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { - match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { - if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { - self.lint_explicit_closure(cx, e.span, args[0].span, true); - } - } - }, - hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { - if ident_eq(name, obj) && method.ident.name == sym::clone; - if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); - if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); - if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); - // no autoderefs - if !cx.typeck_results().expr_adjustments(obj).iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); - then { - let obj_ty = cx.typeck_results().expr_ty(obj); - if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, *ty); - self.lint_explicit_closure(cx, e.span, args[0].span, copy); - } - } else { - lint_needless_cloning(cx, e.span, args[0].span); - } - } - }, - _ => {}, - } - }, - _ => {}, - } - } - } - } - - extract_msrv_attr!(LateContext); -} - -fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { - path.segments.len() == 1 && path.segments[0].ident == name - } else { - false - } -} - -fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { - span_lint_and_sugg( - cx, - MAP_CLONE, - root.trim_start(receiver).unwrap(), - "you are needlessly cloning iterator elements", - "remove the `map` call", - String::new(), - Applicability::MachineApplicable, - ); -} - -impl MapClone { - fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { - let mut applicability = Applicability::MachineApplicable; - - let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) { - ("you are using an explicit closure for copying elements", "copied") - } else { - ("you are using an explicit closure for cloning elements", "cloned") - }; - - span_lint_and_sugg( - cx, - MAP_CLONE, - replace, - message, - &format!("consider calling the dedicated `{}` method", sugg_method), - format!( - "{}.{}()", - snippet_with_applicability(cx, root, "..", &mut applicability), - sugg_method, - ), - applicability, - ); - } -} diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs new file mode 100644 index 00000000000..ffedda95ff8 --- /dev/null +++ b/clippy_lints/src/methods/map_clone.rs @@ -0,0 +1,122 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::mir::Mutability; +use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; +use rustc_semver::RustcVersion; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span}; + +use super::MAP_CLONE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'_>, + e: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, + msrv: Option, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); + if cx.tcx.impl_of_method(method_id) + .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option)) + || is_diag_trait_item(cx, method_id, sym::Iterator); + if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; + then { + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(&closure_body.value); + match closure_body.params[0].pat.kind { + hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( + hir::BindingAnnotation::Unannotated, .., name, None + ) = inner.kind { + if ident_eq(name, closure_expr) { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + }, + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { + match closure_expr.kind { + hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { + if ident_eq(name, inner) { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + } + }, + hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { + if ident_eq(name, obj) && method.ident.name == sym::clone; + if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); + if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); + if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); + // no autoderefs + if !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); + then { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, *ty); + lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + } + } else { + lint_needless_cloning(cx, e.span, recv.span); + } + } + }, + _ => {}, + } + }, + _ => {}, + } + } + } +} + +fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { + path.segments.len() == 1 && path.segments[0].ident == name + } else { + false + } +} + +fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { + span_lint_and_sugg( + cx, + MAP_CLONE, + root.trim_start(receiver).unwrap(), + "you are needlessly cloning iterator elements", + "remove the `map` call", + String::new(), + Applicability::MachineApplicable, + ); +} + +fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option) { + let mut applicability = Applicability::MachineApplicable; + + let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { + ("you are using an explicit closure for copying elements", "copied") + } else { + ("you are using an explicit closure for cloning elements", "cloned") + }; + + span_lint_and_sugg( + cx, + MAP_CLONE, + replace, + message, + &format!("consider calling the dedicated `{}` method", sugg_method), + format!( + "{}.{}()", + snippet_with_applicability(cx, root, "..", &mut applicability), + sugg_method, + ), + applicability, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 132f6040a51..02592da1aae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iterator_step_by_zero; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; +mod map_clone; mod map_collect_result_unit; mod map_flatten; mod map_identity; @@ -2511,6 +2512,35 @@ declare_clippy_lint! { "finds patterns that can be encoded more concisely with `Option::ok_or`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `map(|x| x.clone())` or + /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, + /// and suggests `cloned()` or `copied()` instead + /// + /// ### Why is this bad? + /// Readability, this can be written more concisely + /// + /// ### Example + /// ```rust + /// let x = vec![42, 43]; + /// let y = x.iter(); + /// let z = y.map(|i| *i); + /// ``` + /// + /// The correct use would be: + /// + /// ```rust + /// let x = vec![42, 43]; + /// let y = x.iter(); + /// let z = y.cloned(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MAP_CLONE, + style, + "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2620,6 +2650,7 @@ impl_lint_pass!(Methods => [ CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, GET_FIRST, MANUAL_OK_OR, + MAP_CLONE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2949,6 +2980,9 @@ impl Methods { } }, (name @ ("map" | "map_err"), [m_arg]) => { + if name == "map" { + map_clone::check(cx, expr, recv, m_arg, self.msrv); + } 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), -- cgit 1.4.1-3-g733a5 From 2f0ed0a0b1fa7928464b95e0cfd0883699cb9c33 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 15:59:24 -0400 Subject: Move `MapErrIgnore` into `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/map_err_ignore.rs | 154 --------------------------- clippy_lints/src/methods/map_err_ignore.rs | 34 ++++++ clippy_lints/src/methods/mod.rs | 104 ++++++++++++++++++ 6 files changed, 140 insertions(+), 158 deletions(-) delete mode 100644 clippy_lints/src/map_err_ignore.rs create mode 100644 clippy_lints/src/methods/map_err_ignore.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c7ea7f703f2..67fb0d50931 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -246,7 +246,6 @@ store.register_lints(&[ manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, - map_err_ignore::MAP_ERR_IGNORE, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, match_result_ok::MATCH_RESULT_OK, @@ -326,6 +325,7 @@ store.register_lints(&[ methods::MANUAL_STR_REPEAT, methods::MAP_CLONE, methods::MAP_COLLECT_RESULT_UNIT, + methods::MAP_ERR_IGNORE, methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 890ae2792ab..7fc5eef5f8a 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -30,7 +30,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(large_include_file::LARGE_INCLUDE_FILE), LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(map_err_ignore::MAP_ERR_IGNORE), LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), LintId::of(matches::TRY_ERR), LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), @@ -39,6 +38,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::EXPECT_USED), LintId::of(methods::FILETYPE_IS_FILE), LintId::of(methods::GET_UNWRAP), + LintId::of(methods::MAP_ERR_IGNORE), LintId::of(methods::UNWRAP_USED), LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8f31e4b938c..179d630089f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,7 +273,6 @@ mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; mod manual_strip; -mod map_err_ignore; mod map_unit_fn; mod match_result_ok; mod matches; @@ -636,7 +635,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv, )) }); - store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore)); store.register_late_pass(|| Box::new(shadow::Shadow::default())); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); store.register_late_pass(|| Box::new(loops::Loops)); diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs deleted file mode 100644 index 1e542447c96..00000000000 --- a/clippy_lints/src/map_err_ignore.rs +++ /dev/null @@ -1,154 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for instances of `map_err(|_| Some::Enum)` - /// - /// ### Why is this bad? - /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error - /// - /// ### Example - /// Before: - /// ```rust - /// use std::fmt; - /// - /// #[derive(Debug)] - /// enum Error { - /// Indivisible, - /// Remainder(u8), - /// } - /// - /// impl fmt::Display for Error { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match self { - /// Error::Indivisible => write!(f, "could not divide input by three"), - /// Error::Remainder(remainder) => write!( - /// f, - /// "input is not divisible by three, remainder = {}", - /// remainder - /// ), - /// } - /// } - /// } - /// - /// impl std::error::Error for Error {} - /// - /// fn divisible_by_3(input: &str) -> Result<(), Error> { - /// input - /// .parse::() - /// .map_err(|_| Error::Indivisible) - /// .map(|v| v % 3) - /// .and_then(|remainder| { - /// if remainder == 0 { - /// Ok(()) - /// } else { - /// Err(Error::Remainder(remainder as u8)) - /// } - /// }) - /// } - /// ``` - /// - /// After: - /// ```rust - /// use std::{fmt, num::ParseIntError}; - /// - /// #[derive(Debug)] - /// enum Error { - /// Indivisible(ParseIntError), - /// Remainder(u8), - /// } - /// - /// impl fmt::Display for Error { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match self { - /// Error::Indivisible(_) => write!(f, "could not divide input by three"), - /// Error::Remainder(remainder) => write!( - /// f, - /// "input is not divisible by three, remainder = {}", - /// remainder - /// ), - /// } - /// } - /// } - /// - /// impl std::error::Error for Error { - /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - /// match self { - /// Error::Indivisible(source) => Some(source), - /// _ => None, - /// } - /// } - /// } - /// - /// fn divisible_by_3(input: &str) -> Result<(), Error> { - /// input - /// .parse::() - /// .map_err(Error::Indivisible) - /// .map(|v| v % 3) - /// .and_then(|remainder| { - /// if remainder == 0 { - /// Ok(()) - /// } else { - /// Err(Error::Remainder(remainder as u8)) - /// } - /// }) - /// } - /// ``` - #[clippy::version = "1.48.0"] - pub MAP_ERR_IGNORE, - restriction, - "`map_err` should not ignore the original error" -} - -declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]); - -impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { - // do not try to lint if this is from a macro or desugaring - fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { - if e.span.from_expansion() { - return; - } - - // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(method, [_, arg], _) = e.kind { - // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] - // Enum::Variant[2])) - if method.ident.name == sym!(map_err) { - // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span - // fields - if let ExprKind::Closure(&Closure { - capture_clause, - body, - fn_decl_span, - .. - }) = arg.kind - { - // check if this is by Reference (meaning there's no move statement) - if capture_clause == CaptureBy::Ref { - // Get the closure body to check the parameters and values - let closure_body = cx.tcx.hir().body(body); - // make sure there's only one parameter (`|_|`) - if closure_body.params.len() == 1 { - // make sure that parameter is the wild token (`_`) - if let PatKind::Wild = closure_body.params[0].pat.kind { - // span the area of the closure capture and warn that the - // original error will be thrown away - span_lint_and_help( - cx, - MAP_ERR_IGNORE, - fn_decl_span, - "`map_err(|_|...` wildcard pattern discards the original error", - None, - "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", - ); - } - } - } - } - } - } - } -} diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs new file mode 100644 index 00000000000..1fb6617145e --- /dev/null +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::MAP_ERR_IGNORE; + +pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result) + && let ExprKind::Closure(&Closure { + capture_clause: CaptureBy::Ref, + body, + fn_decl_span, + .. + }) = arg.kind + && let closure_body = cx.tcx.hir().body(body) + && let [param] = closure_body.params + && let PatKind::Wild = param.pat.kind + { + // span the area of the closure capture and warn that the + // original error will be thrown away + span_lint_and_help( + cx, + MAP_ERR_IGNORE, + fn_decl_span, + "`map_err(|_|...` wildcard pattern discards the original error", + None, + "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 02592da1aae..e327bdcf578 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -47,6 +47,7 @@ mod manual_saturating_arithmetic; mod manual_str_repeat; mod map_clone; mod map_collect_result_unit; +mod map_err_ignore; mod map_flatten; mod map_identity; mod map_unwrap_or; @@ -2541,6 +2542,106 @@ declare_clippy_lint! { "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" } +declare_clippy_lint! { + /// ### What it does + /// Checks for instances of `map_err(|_| Some::Enum)` + /// + /// ### Why is this bad? + /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + /// + /// ### Example + /// Before: + /// ```rust + /// use std::fmt; + /// + /// #[derive(Debug)] + /// enum Error { + /// Indivisible, + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } + /// } + /// + /// impl std::error::Error for Error {} + /// + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(|_| Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) + /// } + /// ``` + /// + /// After: + /// ```rust + /// use std::{fmt, num::ParseIntError}; + /// + /// #[derive(Debug)] + /// enum Error { + /// Indivisible(ParseIntError), + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible(_) => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + /// match self { + /// Error::Indivisible(source) => Some(source), + /// _ => None, + /// } + /// } + /// } + /// + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) + /// } + /// ``` + #[clippy::version = "1.48.0"] + pub MAP_ERR_IGNORE, + restriction, + "`map_err` should not ignore the original error" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2651,6 +2752,7 @@ impl_lint_pass!(Methods => [ GET_FIRST, MANUAL_OK_OR, MAP_CLONE, + MAP_ERR_IGNORE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2982,6 +3084,8 @@ impl Methods { (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { map_clone::check(cx, expr, recv, m_arg, self.msrv); + } else { + map_err_ignore::check(cx, expr, m_arg); } if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { match (name, args) { -- cgit 1.4.1-3-g733a5 From 508cf6bdbc9d4d97503f2603f86ec4b3aa1db26a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 19:57:58 -0400 Subject: Move `MutMutexLock` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 41 +++++++++++++++++ clippy_lints/src/methods/mut_mutex_lock.rs | 30 +++++++++++++ clippy_lints/src/mut_mutex_lock.rs | 70 ------------------------------ 7 files changed, 74 insertions(+), 75 deletions(-) create mode 100644 clippy_lints/src/methods/mut_mutex_lock.rs delete mode 100644 clippy_lints/src/mut_mutex_lock.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index c496fd289bb..1151cd42e59 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -182,6 +182,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::MUT_MUTEX_LOCK), LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), @@ -226,7 +227,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(misc_early::ZERO_PREFIXED_LITERAL), LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION), LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(needless_bool::BOOL_COMPARISON), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 67fb0d50931..2ae93b49737 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -329,6 +329,7 @@ store.register_lints(&[ methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::MUT_MUTEX_LOCK, methods::NAIVE_BYTECOUNT, methods::NEEDLESS_OPTION_AS_DEREF, methods::NEEDLESS_OPTION_TAKE, @@ -389,7 +390,6 @@ store.register_lints(&[ module_style::SELF_NAMED_MODULE_FILES, mut_key::MUTABLE_KEY_TYPE, mut_mut::MUT_MUT, - mut_mutex_lock::MUT_MUTEX_LOCK, mut_reference::UNNECESSARY_MUT_PASSED, mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, mutex_atomic::MUTEX_ATOMIC, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 52bf019c82e..d34aadd1d37 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -70,6 +70,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MUT_MUTEX_LOCK), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), @@ -89,7 +90,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_late_init::NEEDLESS_LATE_INIT), LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 179d630089f..9f6ea1266d5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -291,7 +291,6 @@ mod mixed_read_write_in_expression; mod module_style; mod mut_key; mod mut_mut; -mod mut_mutex_lock; mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; @@ -815,7 +814,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); - store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero)); store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e327bdcf578..6ad32ae09d7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -51,6 +51,7 @@ mod map_err_ignore; mod map_flatten; mod map_identity; mod map_unwrap_or; +mod mut_mutex_lock; mod needless_option_as_deref; mod needless_option_take; mod no_effect_replace; @@ -2642,6 +2643,42 @@ declare_clippy_lint! { "`map_err` should not ignore the original error" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `&mut Mutex::lock` calls + /// + /// ### Why is this bad? + /// `Mutex::lock` is less efficient than + /// calling `Mutex::get_mut`. In addition you also have a statically + /// guarantee that the mutex isn't locked, instead of just a runtime + /// guarantee. + /// + /// ### Example + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// + /// let mut value_rc = Arc::new(Mutex::new(42_u8)); + /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + /// + /// let mut value = value_mutex.lock().unwrap(); + /// *value += 1; + /// ``` + /// Use instead: + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// + /// let mut value_rc = Arc::new(Mutex::new(42_u8)); + /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + /// + /// let value = value_mutex.get_mut().unwrap(); + /// *value += 1; + /// ``` + #[clippy::version = "1.49.0"] + pub MUT_MUTEX_LOCK, + style, + "`&mut Mutex::lock` does unnecessary locking" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2753,6 +2790,7 @@ impl_lint_pass!(Methods => [ MANUAL_OK_OR, MAP_CLONE, MAP_ERR_IGNORE, + MUT_MUTEX_LOCK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3081,6 +3119,9 @@ impl Methods { } } }, + ("lock", []) => { + mut_mutex_lock::check(cx, expr, recv, span); + }, (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { map_clone::check(cx, expr, recv, m_arg, self.msrv); diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs new file mode 100644 index 00000000000..bd8458a222e --- /dev/null +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -0,0 +1,30 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, Mutability}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::MUT_MUTEX_LOCK; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { + if_chain! { + if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex); + then { + span_lint_and_sugg( + cx, + MUT_MUTEX_LOCK, + name_span, + "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", + "change this to", + "get_mut".to_owned(), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs deleted file mode 100644 index b7f981faa2d..00000000000 --- a/clippy_lints/src/mut_mutex_lock.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `&mut Mutex::lock` calls - /// - /// ### Why is this bad? - /// `Mutex::lock` is less efficient than - /// calling `Mutex::get_mut`. In addition you also have a statically - /// guarantee that the mutex isn't locked, instead of just a runtime - /// guarantee. - /// - /// ### Example - /// ```rust - /// use std::sync::{Arc, Mutex}; - /// - /// let mut value_rc = Arc::new(Mutex::new(42_u8)); - /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); - /// - /// let mut value = value_mutex.lock().unwrap(); - /// *value += 1; - /// ``` - /// Use instead: - /// ```rust - /// use std::sync::{Arc, Mutex}; - /// - /// let mut value_rc = Arc::new(Mutex::new(42_u8)); - /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); - /// - /// let value = value_mutex.get_mut().unwrap(); - /// *value += 1; - /// ``` - #[clippy::version = "1.49.0"] - pub MUT_MUTEX_LOCK, - style, - "`&mut Mutex::lock` does unnecessary locking" -} - -declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]); - -impl<'tcx> LateLintPass<'tcx> for MutMutexLock { - fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &ex.kind; - if path.ident.name == sym!(lock); - let ty = cx.typeck_results().expr_ty(self_arg); - if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind(); - if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex); - then { - span_lint_and_sugg( - cx, - MUT_MUTEX_LOCK, - path.ident.span, - "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", - "change this to", - "get_mut".to_owned(), - Applicability::MaybeIncorrect, - ); - } - } - } -} -- cgit 1.4.1-3-g733a5 From 0cc01cef304838cf4911d2e0e8dee7842a4b645b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:09:55 -0400 Subject: Move `OpenOptions` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 26 ++++ clippy_lints/src/methods/open_options.rs | 178 +++++++++++++++++++++++ clippy_lints/src/open_options.rs | 202 --------------------------- 7 files changed, 207 insertions(+), 207 deletions(-) create mode 100644 clippy_lints/src/methods/open_options.rs delete mode 100644 clippy_lints/src/open_options.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1151cd42e59..9f4d5b728a4 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -187,6 +187,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), @@ -246,7 +247,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(octal_escapes::OCTAL_ESCAPES), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::ASSIGN_OP_PATTERN), LintId::of(operators::BAD_BIT_MASK), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 006275d1383..8ba39cc973e 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -39,12 +39,12 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::BAD_BIT_MASK), LintId::of(operators::CMP_NAN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2ae93b49737..cf58d1bc518 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -335,6 +335,7 @@ store.register_lints(&[ methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, + methods::NONSENSICAL_OPEN_OPTIONS, methods::NO_EFFECT_REPLACE, methods::OBFUSCATED_IF_ELSE, methods::OK_EXPECT, @@ -421,7 +422,6 @@ store.register_lints(&[ nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, - open_options::NONSENSICAL_OPEN_OPTIONS, operators::ABSURD_EXTREME_COMPARISONS, operators::ARITHMETIC, operators::ASSIGN_OP_PATTERN, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9f6ea1266d5..0d2cc07504a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -315,7 +315,6 @@ mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; -mod open_options; mod operators; mod option_env_unwrap; mod option_if_let_else; @@ -641,7 +640,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(lifetimes::Lifetimes)); store.register_late_pass(|| Box::new(entry::HashMapPass)); store.register_late_pass(|| Box::new(minmax::MinMaxPass)); - store.register_late_pass(|| Box::new(open_options::OpenOptions)); store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv)); store.register_late_pass(|| Box::new(mutex_atomic::Mutex)); store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6ad32ae09d7..3532aa17afd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -57,6 +57,7 @@ mod needless_option_take; mod no_effect_replace; mod obfuscated_if_else; mod ok_expect; +mod open_options; mod option_as_ref_deref; mod option_map_or_none; mod option_map_unwrap_or; @@ -2679,6 +2680,27 @@ declare_clippy_lint! { "`&mut Mutex::lock` does unnecessary locking" } +declare_clippy_lint! { + /// ### What it does + /// Checks for duplicate open options as well as combinations + /// that make no sense. + /// + /// ### Why is this bad? + /// In the best case, the code will be harder to read than + /// necessary. I don't know the worst case. + /// + /// ### Example + /// ```rust + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().read(true).truncate(true); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub NONSENSICAL_OPEN_OPTIONS, + correctness, + "nonsensical combination of options for opening a file" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2791,6 +2813,7 @@ impl_lint_pass!(Methods => [ MAP_CLONE, MAP_ERR_IGNORE, MUT_MUTEX_LOCK, + NONSENSICAL_OPEN_OPTIONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3168,6 +3191,9 @@ impl Methods { _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"), + ("open", [_]) => { + open_options::check(cx, expr, recv); + }, ("or_else", [arg]) => { if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs new file mode 100644 index 00000000000..c3112823e34 --- /dev/null +++ b/clippy_lints/src/methods/open_options.rs @@ -0,0 +1,178 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::paths; +use clippy_utils::ty::match_type; +use rustc_ast::ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::{Span, Spanned}; + +use super::NONSENSICAL_OPEN_OPTIONS; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS) + { + let mut options = Vec::new(); + get_open_options(cx, recv, &mut options); + check_open_options(cx, &options, e.span); + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum Argument { + True, + False, + Unknown, +} + +#[derive(Debug)] +enum OpenOption { + Write, + Read, + Truncate, + Create, + Append, +} + +fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { + if let ExprKind::MethodCall(path, arguments, _) = argument.kind { + let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); + + // Only proceed if this is a call on some object of type std::fs::OpenOptions + if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { + let argument_option = match arguments[1].kind { + ExprKind::Lit(ref span) => { + if let Spanned { + node: LitKind::Bool(lit), + .. + } = *span + { + if lit { Argument::True } else { Argument::False } + } else { + // The function is called with a literal which is not a boolean literal. + // This is theoretically possible, but not very likely. + return; + } + }, + _ => Argument::Unknown, + }; + + match path.ident.as_str() { + "create" => { + options.push((OpenOption::Create, argument_option)); + }, + "append" => { + options.push((OpenOption::Append, argument_option)); + }, + "truncate" => { + options.push((OpenOption::Truncate, argument_option)); + }, + "read" => { + options.push((OpenOption::Read, argument_option)); + }, + "write" => { + options.push((OpenOption::Write, argument_option)); + }, + _ => (), + } + + get_open_options(cx, &arguments[0], options); + } + } +} + +fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], span: Span) { + let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false); + let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = + (false, false, false, false, false); + // This code is almost duplicated (oh, the irony), but I haven't found a way to + // unify it. + + for option in options { + match *option { + (OpenOption::Create, arg) => { + if create { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method `create` is called more than once", + ); + } else { + create = true; + } + create_arg = create_arg || (arg == Argument::True); + }, + (OpenOption::Append, arg) => { + if append { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method `append` is called more than once", + ); + } else { + append = true; + } + append_arg = append_arg || (arg == Argument::True); + }, + (OpenOption::Truncate, arg) => { + if truncate { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method `truncate` is called more than once", + ); + } else { + truncate = true; + } + truncate_arg = truncate_arg || (arg == Argument::True); + }, + (OpenOption::Read, arg) => { + if read { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method `read` is called more than once", + ); + } else { + read = true; + } + read_arg = read_arg || (arg == Argument::True); + }, + (OpenOption::Write, arg) => { + if write { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method `write` is called more than once", + ); + } else { + write = true; + } + write_arg = write_arg || (arg == Argument::True); + }, + } + } + + if read && truncate && read_arg && truncate_arg && !(write && write_arg) { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "file opened with `truncate` and `read`", + ); + } + if append && truncate && append_arg && truncate_arg { + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "file opened with `append` and `truncate`", + ); + } +} diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs deleted file mode 100644 index 5a0b5042018..00000000000 --- a/clippy_lints/src/open_options.rs +++ /dev/null @@ -1,202 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::paths; -use clippy_utils::ty::match_type; -use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{Span, Spanned}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for duplicate open options as well as combinations - /// that make no sense. - /// - /// ### Why is this bad? - /// In the best case, the code will be harder to read than - /// necessary. I don't know the worst case. - /// - /// ### Example - /// ```rust - /// use std::fs::OpenOptions; - /// - /// OpenOptions::new().read(true).truncate(true); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub NONSENSICAL_OPEN_OPTIONS, - correctness, - "nonsensical combination of options for opening a file" -} - -declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); - -impl<'tcx> LateLintPass<'tcx> for OpenOptions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &e.kind { - let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { - let mut options = Vec::new(); - get_open_options(cx, self_arg, &mut options); - check_open_options(cx, &options, e.span); - } - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -enum Argument { - True, - False, - Unknown, -} - -#[derive(Debug)] -enum OpenOption { - Write, - Read, - Truncate, - Create, - Append, -} - -fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(path, arguments, _) = argument.kind { - let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); - - // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { - let argument_option = match arguments[1].kind { - ExprKind::Lit(ref span) => { - if let Spanned { - node: LitKind::Bool(lit), - .. - } = *span - { - if lit { Argument::True } else { Argument::False } - } else { - // The function is called with a literal which is not a boolean literal. - // This is theoretically possible, but not very likely. - return; - } - }, - _ => Argument::Unknown, - }; - - match path.ident.as_str() { - "create" => { - options.push((OpenOption::Create, argument_option)); - }, - "append" => { - options.push((OpenOption::Append, argument_option)); - }, - "truncate" => { - options.push((OpenOption::Truncate, argument_option)); - }, - "read" => { - options.push((OpenOption::Read, argument_option)); - }, - "write" => { - options.push((OpenOption::Write, argument_option)); - }, - _ => (), - } - - get_open_options(cx, &arguments[0], options); - } - } -} - -fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], span: Span) { - let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false); - let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = - (false, false, false, false, false); - // This code is almost duplicated (oh, the irony), but I haven't found a way to - // unify it. - - for option in options { - match *option { - (OpenOption::Create, arg) => { - if create { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `create` is called more than once", - ); - } else { - create = true; - } - create_arg = create_arg || (arg == Argument::True); - }, - (OpenOption::Append, arg) => { - if append { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `append` is called more than once", - ); - } else { - append = true; - } - append_arg = append_arg || (arg == Argument::True); - }, - (OpenOption::Truncate, arg) => { - if truncate { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `truncate` is called more than once", - ); - } else { - truncate = true; - } - truncate_arg = truncate_arg || (arg == Argument::True); - }, - (OpenOption::Read, arg) => { - if read { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `read` is called more than once", - ); - } else { - read = true; - } - read_arg = read_arg || (arg == Argument::True); - }, - (OpenOption::Write, arg) => { - if write { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method `write` is called more than once", - ); - } else { - write = true; - } - write_arg = write_arg || (arg == Argument::True); - }, - } - } - - if read && truncate && read_arg && truncate_arg && !(write && write_arg) { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "file opened with `truncate` and `read`", - ); - } - if append && truncate && append_arg && truncate_arg { - span_lint( - cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "file opened with `append` and `truncate`", - ); - } -} -- cgit 1.4.1-3-g733a5 From 226f135a033f48178ffaa629045664a54c23aa0e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:27:36 -0400 Subject: Move `PathBufPushOverwrite` into `Methods` lint group --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_nursery.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 37 +++++++++++ .../src/methods/path_buf_push_overwrite.rs | 37 +++++++++++ clippy_lints/src/path_buf_push_overwrite.rs | 72 ---------------------- 6 files changed, 76 insertions(+), 76 deletions(-) create mode 100644 clippy_lints/src/methods/path_buf_push_overwrite.rs delete mode 100644 clippy_lints/src/path_buf_push_overwrite.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index cf58d1bc518..5750f914ac5 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -344,6 +344,7 @@ store.register_lints(&[ methods::OPTION_MAP_OR_NONE, methods::OR_FUN_CALL, methods::OR_THEN_UNWRAP, + methods::PATH_BUF_PUSH_OVERWRITE, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -460,7 +461,6 @@ store.register_lints(&[ partialeq_to_none::PARTIALEQ_TO_NONE, pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, - path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, pattern_type_mismatch::PATTERN_TYPE_MISMATCH, precedence::PRECEDENCE, ptr::CMP_NULL, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index d6590192655..dc50816452f 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -17,6 +17,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS), LintId::of(methods::ITER_ON_SINGLE_ITEMS), LintId::of(methods::ITER_WITH_DRAIN), + LintId::of(methods::PATH_BUF_PUSH_OVERWRITE), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutex_atomic::MUTEX_ATOMIC), @@ -25,7 +26,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), - LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d2cc07504a..44cfe0d00ec 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -324,7 +324,6 @@ mod panic_unimplemented; mod partialeq_ne_impl; mod partialeq_to_none; mod pass_by_ref_or_value; -mod path_buf_push_overwrite; mod pattern_type_mismatch; mod precedence; mod ptr; @@ -727,7 +726,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); - store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3532aa17afd..545cf7918af 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -63,6 +63,7 @@ mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; +mod path_buf_push_overwrite; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -2701,6 +2702,38 @@ declare_clippy_lint! { "nonsensical combination of options for opening a file" } +declare_clippy_lint! { + /// ### What it does + ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) + /// calls on `PathBuf` that can cause overwrites. + /// + /// ### Why is this bad? + /// Calling `push` with a root path at the start can overwrite the + /// previous defined path. + /// + /// ### Example + /// ```rust + /// use std::path::PathBuf; + /// + /// let mut x = PathBuf::from("/foo"); + /// x.push("/bar"); + /// assert_eq!(x, PathBuf::from("/bar")); + /// ``` + /// Could be written: + /// + /// ```rust + /// use std::path::PathBuf; + /// + /// let mut x = PathBuf::from("/foo"); + /// x.push("bar"); + /// assert_eq!(x, PathBuf::from("/foo/bar")); + /// ``` + #[clippy::version = "1.36.0"] + pub PATH_BUF_PUSH_OVERWRITE, + nursery, + "calling `push` with file system root on `PathBuf` can overwrite it" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2814,6 +2847,7 @@ impl_lint_pass!(Methods => [ MAP_ERR_IGNORE, MUT_MUTEX_LOCK, NONSENSICAL_OPEN_OPTIONS, + PATH_BUF_PUSH_OVERWRITE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3199,6 +3233,9 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + ("push", [arg]) => { + path_buf_push_overwrite::check(cx, expr, arg); + }, ("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); diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs new file mode 100644 index 00000000000..0cc28c0dcb3 --- /dev/null +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use std::path::{Component, Path}; + +use super::PATH_BUF_PUSH_OVERWRITE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf); + if let ExprKind::Lit(ref lit) = arg.kind; + if let LitKind::Str(ref path_lit, _) = lit.node; + if let pushed_path = Path::new(path_lit.as_str()); + if let Some(pushed_path_lit) = pushed_path.to_str(); + if pushed_path.has_root(); + if let Some(root) = pushed_path.components().next(); + if root == Component::RootDir; + then { + span_lint_and_sugg( + cx, + PATH_BUF_PUSH_OVERWRITE, + lit.span, + "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", + "try", + format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs deleted file mode 100644 index bc6a918f703..00000000000 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ /dev/null @@ -1,72 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; -use std::path::{Component, Path}; - -declare_clippy_lint! { - /// ### What it does - ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) - /// calls on `PathBuf` that can cause overwrites. - /// - /// ### Why is this bad? - /// Calling `push` with a root path at the start can overwrite the - /// previous defined path. - /// - /// ### Example - /// ```rust - /// use std::path::PathBuf; - /// - /// let mut x = PathBuf::from("/foo"); - /// x.push("/bar"); - /// assert_eq!(x, PathBuf::from("/bar")); - /// ``` - /// Could be written: - /// - /// ```rust - /// use std::path::PathBuf; - /// - /// let mut x = PathBuf::from("/foo"); - /// x.push("bar"); - /// assert_eq!(x, PathBuf::from("/foo/bar")); - /// ``` - #[clippy::version = "1.36.0"] - pub PATH_BUF_PUSH_OVERWRITE, - nursery, - "calling `push` with file system root on `PathBuf` can overwrite it" -} - -declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); - -impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind; - if path.ident.name == sym!(push); - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf); - if let ExprKind::Lit(ref lit) = get_index_arg.kind; - if let LitKind::Str(ref path_lit, _) = lit.node; - if let pushed_path = Path::new(path_lit.as_str()); - if let Some(pushed_path_lit) = pushed_path.to_str(); - if pushed_path.has_root(); - if let Some(root) = pushed_path.components().next(); - if root == Component::RootDir; - then { - span_lint_and_sugg( - cx, - PATH_BUF_PUSH_OVERWRITE, - lit.span, - "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", - "try", - format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), - Applicability::MachineApplicable, - ); - } - } - } -} -- cgit 1.4.1-3-g733a5 From fd5376194a4b74021ef01b7f2c96898ea204b75d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:39:57 -0400 Subject: Move `range_zip_with_len` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/methods/mod.rs | 34 ++++++++++++ clippy_lints/src/methods/range_zip_with_len.rs | 34 ++++++++++++ clippy_lints/src/ranges.rs | 73 +++----------------------- 6 files changed, 77 insertions(+), 70 deletions(-) create mode 100644 clippy_lints/src/methods/range_zip_with_len.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 9f4d5b728a4..d2c8c44b14f 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -196,6 +196,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::OR_THEN_UNWRAP), + LintId::of(methods::RANGE_ZIP_WITH_LEN), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), @@ -276,7 +277,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(question_mark::QUESTION_MARK), LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(ranges::REVERSED_EMPTY_RANGES), LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT), LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 324b380317f..f77483de4e4 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -51,6 +51,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::OR_THEN_UNWRAP), + LintId::of(methods::RANGE_ZIP_WITH_LEN), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), @@ -76,7 +77,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(reference::DEREF_ADDROF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 5750f914ac5..2e48e344955 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -345,6 +345,7 @@ store.register_lints(&[ methods::OR_FUN_CALL, methods::OR_THEN_UNWRAP, methods::PATH_BUF_PUSH_OVERWRITE, + methods::RANGE_ZIP_WITH_LEN, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -473,7 +474,6 @@ store.register_lints(&[ ranges::MANUAL_RANGE_CONTAINS, ranges::RANGE_MINUS_ONE, ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, ranges::REVERSED_EMPTY_RANGES, rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT, read_zero_byte_vec::READ_ZERO_BYTE_VEC, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 545cf7918af..4a768117296 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -64,6 +64,7 @@ mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; +mod range_zip_with_len; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -2734,6 +2735,31 @@ declare_clippy_lint! { "calling `push` with file system root on `PathBuf` can overwrite it" } +declare_clippy_lint! { + /// ### What it does + /// Checks for zipping a collection with the range of + /// `0.._.len()`. + /// + /// ### Why is this bad? + /// The code is better expressed with `.enumerate()`. + /// + /// ### Example + /// ```rust + /// # let x = vec![1]; + /// let _ = x.iter().zip(0..x.len()); + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = vec![1]; + /// let _ = x.iter().enumerate(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub RANGE_ZIP_WITH_LEN, + complexity, + "zipping iterator with a range when `enumerate()` would do" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2848,6 +2874,7 @@ impl_lint_pass!(Methods => [ MUT_MUTEX_LOCK, NONSENSICAL_OPEN_OPTIONS, PATH_BUF_PUSH_OVERWRITE, + RANGE_ZIP_WITH_LEN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3304,6 +3331,13 @@ impl Methods { ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { no_effect_replace::check(cx, expr, arg1, arg2); }, + ("zip", [arg]) => { + if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind + && name.ident.name == sym::iter + { + range_zip_with_len::check(cx, expr, iter_recv, arg); + } + }, _ => {}, } } diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs new file mode 100644 index 00000000000..00a2a0d14d1 --- /dev/null +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::source::snippet; +use clippy_utils::{higher, SpanlessEq}; +use clippy_utils::{is_integer_const, is_trait_method}; +use if_chain::if_chain; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::RANGE_ZIP_WITH_LEN; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) { + if_chain! { + if is_trait_method(cx, expr, sym::Iterator); + // range expression in `.zip()` call: `0..x.len()` + if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); + if is_integer_const(cx, start, 0); + // `.len()` call + if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind; + if len_path.ident.name == sym::len; + // `.iter()` and `.len()` called on same `Path` + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind; + if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); + then { + span_lint(cx, + RANGE_ZIP_WITH_LEN, + expr.span, + &format!("it is more idiomatic to use `{}.iter().enumerate()`", + snippet(cx, recv.span, "_")) + ); + } + } +} diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index fbf842c339e..490f345d297 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,46 +1,20 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local}; -use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; -use rustc_span::sym; use std::cmp::Ordering; -declare_clippy_lint! { - /// ### What it does - /// Checks for zipping a collection with the range of - /// `0.._.len()`. - /// - /// ### Why is this bad? - /// The code is better expressed with `.enumerate()`. - /// - /// ### Example - /// ```rust - /// # let x = vec![1]; - /// let _ = x.iter().zip(0..x.len()); - /// ``` - /// - /// Use instead: - /// ```rust - /// # let x = vec![1]; - /// let _ = x.iter().enumerate(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub RANGE_ZIP_WITH_LEN, - complexity, - "zipping iterator with a range when `enumerate()` would do" -} - declare_clippy_lint! { /// ### What it does /// Checks for exclusive ranges where 1 is added to the @@ -198,7 +172,6 @@ impl Ranges { } impl_lint_pass!(Ranges => [ - RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE, REVERSED_EMPTY_RANGES, @@ -207,16 +180,10 @@ impl_lint_pass!(Ranges => [ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - match expr.kind { - ExprKind::MethodCall(path, args, _) => { - check_range_zip_with_len(cx, path, args, expr.span); - }, - ExprKind::Binary(ref op, l, r) => { - if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { - check_possible_range_contains(cx, op.node, l, r, expr, expr.span); - } - }, - _ => {}, + if let ExprKind::Binary(ref op, l, r) = expr.kind { + if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { + check_possible_range_contains(cx, op.node, l, r, expr, expr.span); + } } check_exclusive_range_plus_one(cx, expr); @@ -380,34 +347,6 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) { - if_chain! { - if path.ident.as_str() == "zip"; - if let [iter, zip_arg] = args; - // `.iter()` call - if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind; - if iter_path.ident.name == sym::iter; - // range expression in `.zip()` call: `0..x.len()` - if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); - if is_integer_const(cx, start, 0); - // `.len()` call - if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind; - if len_path.ident.name == sym::len; - // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind; - if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); - then { - span_lint(cx, - RANGE_ZIP_WITH_LEN, - span, - &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, iter_caller.span, "_")) - ); - } - } -} - // exclusive range plus one: `x..(y+1)` fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { -- cgit 1.4.1-3-g733a5 From 06d752e28dcc4b343f9d437e59d7ebbedff3fde8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:49:03 -0400 Subject: Move `RepeatOnce` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 37 ++++++++++++ clippy_lints/src/methods/repeat_once.rs | 52 +++++++++++++++++ clippy_lints/src/repeat_once.rs | 89 ----------------------------- 7 files changed, 92 insertions(+), 94 deletions(-) create mode 100644 clippy_lints/src/methods/repeat_once.rs delete mode 100644 clippy_lints/src/repeat_once.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index d2c8c44b14f..812a89d33e5 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -197,6 +197,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::OR_FUN_CALL), LintId::of(methods::OR_THEN_UNWRAP), LintId::of(methods::RANGE_ZIP_WITH_LEN), + LintId::of(methods::REPEAT_ONCE), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), @@ -287,7 +288,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(reference::DEREF_ADDROF), LintId::of(regex::INVALID_REGEX), - LintId::of(repeat_once::REPEAT_ONCE), LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index f77483de4e4..f79105f4960 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -52,6 +52,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::OR_THEN_UNWRAP), LintId::of(methods::RANGE_ZIP_WITH_LEN), + LintId::of(methods::REPEAT_ONCE), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), @@ -80,7 +81,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(reference::DEREF_ADDROF), - LintId::of(repeat_once::REPEAT_ONCE), LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), LintId::of(swap::MANUAL_SWAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2e48e344955..659f0288d17 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -346,6 +346,7 @@ store.register_lints(&[ methods::OR_THEN_UNWRAP, methods::PATH_BUF_PUSH_OVERWRITE, methods::RANGE_ZIP_WITH_LEN, + methods::REPEAT_ONCE, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -489,7 +490,6 @@ store.register_lints(&[ reference::DEREF_ADDROF, regex::INVALID_REGEX, regex::TRIVIAL_REGEX, - repeat_once::REPEAT_ONCE, return_self_not_must_use::RETURN_SELF_NOT_MUST_USE, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 44cfe0d00ec..40c77ede9ad 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -343,7 +343,6 @@ mod redundant_static_lifetimes; mod ref_option_ref; mod reference; mod regex; -mod repeat_once; mod return_self_not_must_use; mod returns; mod same_name_method; @@ -824,7 +823,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); - store.register_late_pass(|| Box::new(repeat_once::RepeatOnce)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4a768117296..bbd6f56c5ea 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -65,6 +65,7 @@ mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; +mod repeat_once; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -2760,6 +2761,38 @@ declare_clippy_lint! { "zipping iterator with a range when `enumerate()` would do" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.repeat(1)` and suggest the following method for each types. + /// - `.to_string()` for `str` + /// - `.clone()` for `String` + /// - `.to_vec()` for `slice` + /// + /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if + /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) + /// + /// ### Why is this bad? + /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning + /// the string is the intention behind this, `clone()` should be used. + /// + /// ### Example + /// ```rust + /// fn main() { + /// let x = String::from("hello world").repeat(1); + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// let x = String::from("hello world").clone(); + /// } + /// ``` + #[clippy::version = "1.47.0"] + pub REPEAT_ONCE, + complexity, + "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2875,6 +2908,7 @@ impl_lint_pass!(Methods => [ NONSENSICAL_OPEN_OPTIONS, PATH_BUF_PUSH_OVERWRITE, RANGE_ZIP_WITH_LEN, + REPEAT_ONCE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3263,6 +3297,9 @@ impl Methods { ("push", [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, + ("repeat", [arg]) => { + repeat_once::check(cx, expr, recv, arg); + }, ("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); diff --git a/clippy_lints/src/methods/repeat_once.rs b/clippy_lints/src/methods/repeat_once.rs new file mode 100644 index 00000000000..0a14f9216ab --- /dev/null +++ b/clippy_lints/src/methods/repeat_once.rs @@ -0,0 +1,52 @@ +use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::REPEAT_ONCE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + repeat_arg: &'tcx Expr<'_>, +) { + if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if ty.is_str() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on str", + "consider using `.to_string()` instead", + format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if ty.builtin_index().is_some() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on slice", + "consider using `.to_vec()` instead", + format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if is_type_diagnostic_item(cx, ty, sym::String) { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on a string literal", + "consider using `.clone()` instead", + format!("{}.clone()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs deleted file mode 100644 index 898c70ace66..00000000000 --- a/clippy_lints/src/repeat_once.rs +++ /dev/null @@ -1,89 +0,0 @@ -use clippy_utils::consts::{constant_context, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `.repeat(1)` and suggest the following method for each types. - /// - `.to_string()` for `str` - /// - `.clone()` for `String` - /// - `.to_vec()` for `slice` - /// - /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if - /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) - /// - /// ### Why is this bad? - /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning - /// the string is the intention behind this, `clone()` should be used. - /// - /// ### Example - /// ```rust - /// fn main() { - /// let x = String::from("hello world").repeat(1); - /// } - /// ``` - /// Use instead: - /// ```rust - /// fn main() { - /// let x = String::from("hello world").clone(); - /// } - /// ``` - #[clippy::version = "1.47.0"] - pub REPEAT_ONCE, - complexity, - "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " -} - -declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]); - -impl<'tcx> LateLintPass<'tcx> for RepeatOnce { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(path, [receiver, count], _) = &expr.kind; - if path.ident.name == sym!(repeat); - if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1)); - if !receiver.span.from_expansion(); - then { - let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if ty.is_str() { - span_lint_and_sugg( - cx, - REPEAT_ONCE, - expr.span, - "calling `repeat(1)` on str", - "consider using `.to_string()` instead", - format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)), - Applicability::MachineApplicable, - ); - } else if ty.builtin_index().is_some() { - span_lint_and_sugg( - cx, - REPEAT_ONCE, - expr.span, - "calling `repeat(1)` on slice", - "consider using `.to_vec()` instead", - format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)), - Applicability::MachineApplicable, - ); - } else if is_type_diagnostic_item(cx, ty, sym::String) { - span_lint_and_sugg( - cx, - REPEAT_ONCE, - expr.span, - "calling `repeat(1)` on a string literal", - "consider using `.clone()` instead", - format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)), - Applicability::MachineApplicable, - ); - } - } - } - } -} -- cgit 1.4.1-3-g733a5 From e834855950701dae9657e7c0dbde195f85a96bf3 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 21:07:29 -0400 Subject: Move `StableSortPrimitive` to `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 43 +++++++ clippy_lints/src/methods/stable_sort_primitive.rs | 31 +++++ clippy_lints/src/stable_sort_primitive.rs | 144 ---------------------- 6 files changed, 76 insertions(+), 148 deletions(-) create mode 100644 clippy_lints/src/methods/stable_sort_primitive.rs delete mode 100644 clippy_lints/src/stable_sort_primitive.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 659f0288d17..e8c796b4e9b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -353,6 +353,7 @@ store.register_lints(&[ methods::SINGLE_CHAR_ADD_STR, methods::SINGLE_CHAR_PATTERN, methods::SKIP_WHILE_NEXT, + methods::STABLE_SORT_PRIMITIVE, methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, methods::SUSPICIOUS_SPLITN, @@ -504,7 +505,6 @@ store.register_lints(&[ single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - stable_sort_primitive::STABLE_SORT_PRIMITIVE, std_instead_of_core::ALLOC_INSTEAD_OF_CORE, std_instead_of_core::STD_INSTEAD_OF_ALLOC, std_instead_of_core::STD_INSTEAD_OF_CORE, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 5c04a331d0a..13474127e8d 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -64,6 +64,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::MANUAL_OK_OR), LintId::of(methods::MAP_UNWRAP_OR), LintId::of(methods::NAIVE_BYTECOUNT), + LintId::of(methods::STABLE_SORT_PRIMITIVE), LintId::of(methods::UNNECESSARY_JOIN), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER), @@ -85,7 +86,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(ref_option_ref::REF_OPTION_REF), LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE), LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(strings::STRING_ADD_ASSIGN), LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(types::LINKEDLIST), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 40c77ede9ad..c424c373d32 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -354,7 +354,6 @@ mod single_char_lifetime_names; mod single_component_path_imports; mod size_of_in_element_count; mod slow_vector_initialization; -mod stable_sort_primitive; mod std_instead_of_core; mod strings; mod strlen_on_c_strings; @@ -822,7 +821,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); - store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bbd6f56c5ea..a47081d8752 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -72,6 +72,7 @@ mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; mod skip_while_next; +mod stable_sort_primitive; mod str_splitn; mod string_extend_chars; mod suspicious_map; @@ -2793,6 +2794,44 @@ declare_clippy_lint! { "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " } +declare_clippy_lint! { + /// ### What it does + /// When sorting primitive values (integers, bools, chars, as well + /// as arrays, slices, and tuples of such items), it is typically better to + /// use an unstable sort than a stable sort. + /// + /// ### Why is this bad? + /// Typically, using a stable sort consumes more memory and cpu cycles. + /// Because values which compare equal are identical, preserving their + /// relative order (the guarantee that a stable sort provides) means + /// nothing, while the extra costs still apply. + /// + /// ### Known problems + /// + /// As pointed out in + /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), + /// a stable sort can instead be significantly faster for certain scenarios + /// (eg. when a sorted vector is extended with new data and resorted). + /// + /// For more information and benchmarking results, please refer to the + /// issue linked above. + /// + /// ### Example + /// ```rust + /// let mut vec = vec![2, 1, 3]; + /// vec.sort(); + /// ``` + /// Use instead: + /// ```rust + /// let mut vec = vec![2, 1, 3]; + /// vec.sort_unstable(); + /// ``` + #[clippy::version = "1.47.0"] + pub STABLE_SORT_PRIMITIVE, + pedantic, + "use of sort() when sort_unstable() is equivalent" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2909,6 +2948,7 @@ impl_lint_pass!(Methods => [ PATH_BUF_PUSH_OVERWRITE, RANGE_ZIP_WITH_LEN, REPEAT_ONCE, + STABLE_SORT_PRIMITIVE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3300,6 +3340,9 @@ impl Methods { ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, + ("sort", []) => { + stable_sort_primitive::check(cx, expr, recv); + }, ("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); diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs new file mode 100644 index 00000000000..91951c65bb3 --- /dev/null +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -0,0 +1,31 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_context; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; + +use super::STABLE_SORT_PRIMITIVE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && cx.tcx.type_of(impl_id).is_slice() + && let Some(slice_type) = is_slice_of_primitives(cx, recv) + { + span_lint_and_then( + cx, + STABLE_SORT_PRIMITIVE, + e.span, + &format!("used `sort` on primitive type `{}`", slice_type), + |diag| { + let mut app = Applicability::MachineApplicable; + let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; + diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app); + diag.note( + "an unstable sort typically performs faster without any observable difference for this data type", + ); + }, + ); + } +} diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs deleted file mode 100644 index 6d54935f81a..00000000000 --- a/clippy_lints/src/stable_sort_primitive.rs +++ /dev/null @@ -1,144 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{is_slice_of_primitives, sugg::Sugg}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// When sorting primitive values (integers, bools, chars, as well - /// as arrays, slices, and tuples of such items), it is typically better to - /// use an unstable sort than a stable sort. - /// - /// ### Why is this bad? - /// Typically, using a stable sort consumes more memory and cpu cycles. - /// Because values which compare equal are identical, preserving their - /// relative order (the guarantee that a stable sort provides) means - /// nothing, while the extra costs still apply. - /// - /// ### Known problems - /// - /// As pointed out in - /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), - /// a stable sort can instead be significantly faster for certain scenarios - /// (eg. when a sorted vector is extended with new data and resorted). - /// - /// For more information and benchmarking results, please refer to the - /// issue linked above. - /// - /// ### Example - /// ```rust - /// let mut vec = vec![2, 1, 3]; - /// vec.sort(); - /// ``` - /// Use instead: - /// ```rust - /// let mut vec = vec![2, 1, 3]; - /// vec.sort_unstable(); - /// ``` - #[clippy::version = "1.47.0"] - pub STABLE_SORT_PRIMITIVE, - pedantic, - "use of sort() when sort_unstable() is equivalent" -} - -declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]); - -/// The three "kinds" of sorts -enum SortingKind { - Vanilla, - /* The other kinds of lint are currently commented out because they - * can map distinct values to equal ones. If the key function is - * provably one-to-one, or if the Cmp function conserves equality, - * then they could be linted on, but I don't know if we can check - * for that. */ - - /* ByKey, - * ByCmp, */ -} -impl SortingKind { - /// The name of the stable version of this kind of sort - fn stable_name(&self) -> &str { - match self { - SortingKind::Vanilla => "sort", - /* SortingKind::ByKey => "sort_by_key", - * SortingKind::ByCmp => "sort_by", */ - } - } - /// The name of the unstable version of this kind of sort - fn unstable_name(&self) -> &str { - match self { - SortingKind::Vanilla => "sort_unstable", - /* SortingKind::ByKey => "sort_unstable_by_key", - * SortingKind::ByCmp => "sort_unstable_by", */ - } - } - /// Takes the name of a function call and returns the kind of sort - /// that corresponds to that function name (or None if it isn't) - fn from_stable_name(name: &str) -> Option { - match name { - "sort" => Some(SortingKind::Vanilla), - // "sort_by" => Some(SortingKind::ByCmp), - // "sort_by_key" => Some(SortingKind::ByKey), - _ => None, - } - } -} - -/// A detected instance of this lint -struct LintDetection { - slice_name: String, - method: SortingKind, - method_args: String, - slice_type: String, -} - -fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if_chain! { - if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind; - if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str()); - if let Some(slice_type) = is_slice_of_primitives(cx, slice); - then { - let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); - Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type }) - } else { - None - } - } -} - -impl LateLintPass<'_> for StableSortPrimitive { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(detection) = detect_stable_sort_primitive(cx, expr) { - span_lint_and_then( - cx, - STABLE_SORT_PRIMITIVE, - expr.span, - format!( - "used `{}` on primitive type `{}`", - detection.method.stable_name(), - detection.slice_type, - ) - .as_str(), - |diag| { - diag.span_suggestion( - expr.span, - "try", - format!( - "{}.{}({})", - detection.slice_name, - detection.method.unstable_name(), - detection.method_args, - ), - Applicability::MachineApplicable, - ); - diag.note( - "an unstable sort typically performs faster without any observable difference for this data type", - ); - }, - ); - } - } -} -- cgit 1.4.1-3-g733a5 From bb0584dfb425f6c1a8bef9faad9ee36f0bbc19fb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 21:41:33 -0400 Subject: Move `UnitHash` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 44 ++++++++++++++++ clippy_lints/src/methods/unit_hash.rs | 29 +++++++++++ clippy_lints/src/unit_hash.rs | 78 ---------------------------- 7 files changed, 76 insertions(+), 83 deletions(-) create mode 100644 clippy_lints/src/methods/unit_hash.rs delete mode 100644 clippy_lints/src/unit_hash.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index aad6a1af200..e51ce0fa254 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -208,6 +208,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNIT_HASH), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FIND_MAP), LintId::of(methods::UNNECESSARY_FOLD), @@ -326,7 +327,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(types::VEC_BOX), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), - LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::LET_UNIT_VALUE), LintId::of(unit_types::UNIT_ARG), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 9d69d4acc90..d30e69b2240 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -42,6 +42,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNIT_HASH), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), @@ -67,7 +68,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), - LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_CMP), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index a2a81052070..8aa1810fbd5 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -358,6 +358,7 @@ store.register_lints(&[ methods::SUSPICIOUS_MAP, methods::SUSPICIOUS_SPLITN, methods::UNINIT_ASSUMED_INIT, + methods::UNIT_HASH, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FIND_MAP, methods::UNNECESSARY_FOLD, @@ -558,7 +559,6 @@ store.register_lints(&[ unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, uninit_vec::UNINIT_VEC, - unit_hash::UNIT_HASH, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e0b6ded0b58..71ba3f18da8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -371,7 +371,6 @@ mod types; mod undocumented_unsafe_blocks; mod unicode; mod uninit_vec; -mod unit_hash; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -582,7 +581,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); store.register_late_pass(|| Box::new(unicode::Unicode)); store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); - store.register_late_pass(|| Box::new(unit_hash::UnitHash)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a47081d8752..ce10b64c948 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -78,6 +78,7 @@ mod string_extend_chars; mod suspicious_map; mod suspicious_splitn; mod uninit_assumed_init; +mod unit_hash; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; @@ -2832,6 +2833,45 @@ declare_clippy_lint! { "use of sort() when sort_unstable() is equivalent" } +declare_clippy_lint! { + /// ### What it does + /// Detects `().hash(_)`. + /// + /// ### Why is this bad? + /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + /// + /// ### Example + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => ().hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => 0_u8.hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + #[clippy::version = "1.58.0"] + pub UNIT_HASH, + correctness, + "hashing a unit value, which does nothing" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2949,6 +2989,7 @@ impl_lint_pass!(Methods => [ RANGE_ZIP_WITH_LEN, REPEAT_ONCE, STABLE_SORT_PRIMITIVE, + UNIT_HASH, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3258,6 +3299,9 @@ impl Methods { get_last_with_len::check(cx, expr, recv, arg); }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), + ("hash", [arg]) => { + 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_none", []) => check_is_some_is_none(cx, expr, recv, false), diff --git a/clippy_lints/src/methods/unit_hash.rs b/clippy_lints/src/methods/unit_hash.rs new file mode 100644 index 00000000000..3c7955bc469 --- /dev/null +++ b/clippy_lints/src/methods/unit_hash.rs @@ -0,0 +1,29 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNIT_HASH; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() { + span_lint_and_then( + cx, + UNIT_HASH, + expr.span, + "this call to `hash` on the unit type will do nothing", + |diag| { + diag.span_suggestion( + expr.span, + "remove the call to `hash` or consider using", + format!("0_u8.hash({})", snippet(cx, arg.span, ".."),), + Applicability::MaybeIncorrect, + ); + diag.note("the implementation of `Hash` for `()` is a no-op"); + }, + ); + } +} diff --git a/clippy_lints/src/unit_hash.rs b/clippy_lints/src/unit_hash.rs deleted file mode 100644 index 88ca0cb20a1..00000000000 --- a/clippy_lints/src/unit_hash.rs +++ /dev/null @@ -1,78 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Detects `().hash(_)`. - /// - /// ### Why is this bad? - /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. - /// - /// ### Example - /// ```rust - /// # use std::hash::Hash; - /// # use std::collections::hash_map::DefaultHasher; - /// # enum Foo { Empty, WithValue(u8) } - /// # use Foo::*; - /// # let mut state = DefaultHasher::new(); - /// # let my_enum = Foo::Empty; - /// match my_enum { - /// Empty => ().hash(&mut state), - /// WithValue(x) => x.hash(&mut state), - /// } - /// ``` - /// Use instead: - /// ```rust - /// # use std::hash::Hash; - /// # use std::collections::hash_map::DefaultHasher; - /// # enum Foo { Empty, WithValue(u8) } - /// # use Foo::*; - /// # let mut state = DefaultHasher::new(); - /// # let my_enum = Foo::Empty; - /// match my_enum { - /// Empty => 0_u8.hash(&mut state), - /// WithValue(x) => x.hash(&mut state), - /// } - /// ``` - #[clippy::version = "1.58.0"] - pub UNIT_HASH, - correctness, - "hashing a unit value, which does nothing" -} -declare_lint_pass!(UnitHash => [UNIT_HASH]); - -impl<'tcx> LateLintPass<'tcx> for UnitHash { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind; - if name_ident.ident.name == sym::hash; - if let [recv, state_param] = args; - if cx.typeck_results().expr_ty(recv).is_unit(); - then { - span_lint_and_then( - cx, - UNIT_HASH, - expr.span, - "this call to `hash` on the unit type will do nothing", - |diag| { - diag.span_suggestion( - expr.span, - "remove the call to `hash` or consider using", - format!( - "0_u8.hash({})", - snippet(cx, state_param.span, ".."), - ), - Applicability::MaybeIncorrect, - ); - diag.note("the implementation of `Hash` for `()` is a no-op"); - } - ); - } - } - } -} -- cgit 1.4.1-3-g733a5 From d8d4a135ea2bc460033c75d4a56d21ae977b9ae2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 23:22:58 -0400 Subject: Move `UnnecessarySortBy` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 42 ++++ clippy_lints/src/methods/unnecessary_sort_by.rs | 224 ++++++++++++++++++++ clippy_lints/src/unnecessary_sort_by.rs | 258 ------------------------ 7 files changed, 269 insertions(+), 263 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_sort_by.rs delete mode 100644 clippy_lints/src/unnecessary_sort_by.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index e51ce0fa254..bb5b2866268 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -213,6 +213,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::UNNECESSARY_FIND_MAP), LintId::of(methods::UNNECESSARY_FOLD), LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNNECESSARY_SORT_BY), LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), @@ -334,7 +335,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(unused_unit::UNUSED_UNIT), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index f79105f4960..0f7433a79be 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -57,6 +57,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FIND_MAP), + LintId::of(methods::UNNECESSARY_SORT_BY), LintId::of(methods::USELESS_ASREF), LintId::of(misc::SHORT_CIRCUIT_STATEMENT), LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), @@ -99,7 +100,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(types::TYPE_COMPLEXITY), LintId::of(types::VEC_BOX), LintId::of(unit_types::UNIT_ARG), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unwrap::UNNECESSARY_UNWRAP), LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 8aa1810fbd5..f5497c6bd6b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -364,6 +364,7 @@ store.register_lints(&[ methods::UNNECESSARY_FOLD, methods::UNNECESSARY_JOIN, methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNNECESSARY_SORT_BY, methods::UNNECESSARY_TO_OWNED, methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, @@ -567,7 +568,6 @@ store.register_lints(&[ unnamed_address::VTABLE_ADDRESS_COMPARISONS, unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS, unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, - unnecessary_sort_by::UNNECESSARY_SORT_BY, unnecessary_wraps::UNNECESSARY_WRAPS, unnested_or_patterns::UNNESTED_OR_PATTERNS, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 71ba3f18da8..cfcd4e3d141 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -376,7 +376,6 @@ mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; -mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; @@ -716,7 +715,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); store.register_late_pass(|| Box::new(redundant_clone::RedundantClone)); store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit)); - store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy)); store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ce10b64c948..54a0275da96 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -84,6 +84,7 @@ mod unnecessary_fold; mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; +mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_or_else_default; mod unwrap_used; @@ -2872,6 +2873,40 @@ declare_clippy_lint! { "hashing a unit value, which does nothing" } +declare_clippy_lint! { + /// ### What it does + /// Detects uses of `Vec::sort_by` passing in a closure + /// which compares the two arguments, either directly or indirectly. + /// + /// ### Why is this bad? + /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if + /// possible) than to use `Vec::sort_by` and a more complicated + /// closure. + /// + /// ### Known problems + /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already + /// imported by a use statement, then it will need to be added manually. + /// + /// ### Example + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); + /// ``` + /// Use instead: + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by_key(|a| a.foo()); + /// ``` + #[clippy::version = "1.46.0"] + pub UNNECESSARY_SORT_BY, + complexity, + "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2990,6 +3025,7 @@ impl_lint_pass!(Methods => [ REPEAT_ONCE, STABLE_SORT_PRIMITIVE, UNIT_HASH, + UNNECESSARY_SORT_BY, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3387,6 +3423,12 @@ impl Methods { ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, + ("sort_by", [arg]) => { + unnecessary_sort_by::check(cx, expr, recv, arg, false); + }, + ("sort_unstable_by", [arg]) => { + unnecessary_sort_by::check(cx, expr, recv, arg, true); + }, ("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); diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs new file mode 100644 index 00000000000..1966990bd77 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -0,0 +1,224 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::implements_trait; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, subst::GenericArgKind}; +use rustc_span::sym; +use rustc_span::symbol::Ident; +use std::iter; + +use super::UNNECESSARY_SORT_BY; + +enum LintTrigger { + Sort(SortDetection), + SortByKey(SortByKeyDetection), +} + +struct SortDetection { + vec_name: String, +} + +struct SortByKeyDetection { + vec_name: String, + closure_arg: String, + closure_body: String, + reverse: bool, +} + +/// Detect if the two expressions are mirrored (identical, except one +/// contains a and the other replaces it with b) +fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { + match (&a_expr.kind, &b_expr.kind) { + // Two boxes with mirrored contents + (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { + mirrored_exprs(left_expr, a_ident, right_expr, b_ident) + }, + // Two arrays with mirrored contents + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { + iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + }, + // The two exprs are function calls. + // Check to see that the function itself and its arguments are mirrored + (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { + mirrored_exprs(left_expr, a_ident, right_expr, b_ident) + && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + }, + // The two exprs are method calls. + // Check to see that the function is the same and the arguments are mirrored + // This is enough because the receiver of the method is listed in the arguments + (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => { + left_segment.ident == right_segment.ident + && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + }, + // Two tuples with mirrored contents + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { + iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + }, + // Two binary ops, which are the same operation and which have mirrored arguments + (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { + left_op.node == right_op.node + && mirrored_exprs(left_left, a_ident, right_left, b_ident) + && mirrored_exprs(left_right, a_ident, right_right, b_ident) + }, + // Two unary ops, which are the same operation and which have the same argument + (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => { + left_op == right_op && mirrored_exprs(left_expr, a_ident, right_expr, b_ident) + }, + // The two exprs are literals of some kind + (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, + (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(left, a_ident, right, b_ident), + (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => { + mirrored_exprs(left_block, a_ident, right_block, b_ident) + }, + (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { + left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, right_ident) + }, + // Two paths: either one is a and the other is b, or they're identical to each other + ( + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: left_segments, + .. + }, + )), + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: right_segments, + .. + }, + )), + ) => { + (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident) + && left_segments + .iter() + .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) + || (left_segments.len() == 1 + && &left_segments[0].ident == a_ident + && right_segments.len() == 1 + && &right_segments[0].ident == b_ident) + }, + // Matching expressions, but one or both is borrowed + ( + ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), + ExprKind::AddrOf(right_kind, Mutability::Not, right_expr), + ) => left_kind == right_kind && mirrored_exprs(left_expr, a_ident, right_expr, b_ident), + (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => mirrored_exprs(a_expr, a_ident, right_expr, b_ident), + (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(left_expr, a_ident, b_expr, b_ident), + _ => false, + } +} + +fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let ExprKind::Closure(&Closure { body, .. }) = arg.kind; + if let closure_body = cx.tcx.hir().body(body); + if let &[ + Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, + Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } + ] = &closure_body.params; + if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind; + if method_path.ident.name == sym::cmp; + if is_trait_method(cx, &closure_body.value, sym::Ord); + then { + let (closure_body, closure_arg, reverse) = if mirrored_exprs( + left_expr, + left_ident, + right_expr, + right_ident + ) { + (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false) + } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { + (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true) + } else { + return None; + }; + let vec_name = Sugg::hir(cx, recv, "..").to_string(); + + if_chain! { + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind; + if left_name == left_ident; + if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) + }); + then { + return Some(LintTrigger::Sort(SortDetection { vec_name })); + } + } + + if !expr_borrows(cx, left_expr) { + return Some(LintTrigger::SortByKey(SortByKeyDetection { + vec_name, + closure_arg, + closure_body, + reverse, + })); + } + } + } + + None +} + +fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) +} + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, + is_unstable: bool, +) { + match detect_lint(cx, expr, recv, arg) { + Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort_by_key here instead", + "try", + format!( + "{}.sort{}_by_key(|{}| {})", + trigger.vec_name, + if is_unstable { "_unstable" } else { "" }, + trigger.closure_arg, + if trigger.reverse { + format!("std::cmp::Reverse({})", trigger.closure_body) + } else { + trigger.closure_body.to_string() + }, + ), + if trigger.reverse { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ), + Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort here instead", + "try", + format!( + "{}.sort{}()", + trigger.vec_name, + if is_unstable { "_unstable" } else { "" }, + ), + Applicability::MachineApplicable, + ), + None => {}, + } +} diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs deleted file mode 100644 index ea5aadbbca1..00000000000 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ /dev/null @@ -1,258 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, subst::GenericArgKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; -use rustc_span::symbol::Ident; -use std::iter; - -declare_clippy_lint! { - /// ### What it does - /// Detects uses of `Vec::sort_by` passing in a closure - /// which compares the two arguments, either directly or indirectly. - /// - /// ### Why is this bad? - /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if - /// possible) than to use `Vec::sort_by` and a more complicated - /// closure. - /// - /// ### Known problems - /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already - /// imported by a use statement, then it will need to be added manually. - /// - /// ### Example - /// ```rust - /// # struct A; - /// # impl A { fn foo(&self) {} } - /// # let mut vec: Vec = Vec::new(); - /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); - /// ``` - /// Use instead: - /// ```rust - /// # struct A; - /// # impl A { fn foo(&self) {} } - /// # let mut vec: Vec = Vec::new(); - /// vec.sort_by_key(|a| a.foo()); - /// ``` - #[clippy::version = "1.46.0"] - pub UNNECESSARY_SORT_BY, - complexity, - "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" -} - -declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]); - -enum LintTrigger { - Sort(SortDetection), - SortByKey(SortByKeyDetection), -} - -struct SortDetection { - vec_name: String, - unstable: bool, -} - -struct SortByKeyDetection { - vec_name: String, - closure_arg: String, - closure_body: String, - reverse: bool, - unstable: bool, -} - -/// Detect if the two expressions are mirrored (identical, except one -/// contains a and the other replaces it with b) -fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { - match (&a_expr.kind, &b_expr.kind) { - // Two boxes with mirrored contents - (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { - mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - }, - // Two arrays with mirrored contents - (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { - iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - }, - // The two exprs are function calls. - // Check to see that the function itself and its arguments are mirrored - (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { - mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - }, - // The two exprs are method calls. - // Check to see that the function is the same and the arguments are mirrored - // This is enough because the receiver of the method is listed in the arguments - (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => { - left_segment.ident == right_segment.ident - && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - }, - // Two tuples with mirrored contents - (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { - iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) - }, - // Two binary ops, which are the same operation and which have mirrored arguments - (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { - left_op.node == right_op.node - && mirrored_exprs(left_left, a_ident, right_left, b_ident) - && mirrored_exprs(left_right, a_ident, right_right, b_ident) - }, - // Two unary ops, which are the same operation and which have the same argument - (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => { - left_op == right_op && mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - }, - // The two exprs are literals of some kind - (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, - (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(left, a_ident, right, b_ident), - (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => { - mirrored_exprs(left_block, a_ident, right_block, b_ident) - }, - (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { - left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, right_ident) - }, - // Two paths: either one is a and the other is b, or they're identical to each other - ( - ExprKind::Path(QPath::Resolved( - _, - Path { - segments: left_segments, - .. - }, - )), - ExprKind::Path(QPath::Resolved( - _, - Path { - segments: right_segments, - .. - }, - )), - ) => { - (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident) - && left_segments - .iter() - .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) - || (left_segments.len() == 1 - && &left_segments[0].ident == a_ident - && right_segments.len() == 1 - && &right_segments[0].ident == b_ident) - }, - // Matching expressions, but one or both is borrowed - ( - ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), - ExprKind::AddrOf(right_kind, Mutability::Not, right_expr), - ) => left_kind == right_kind && mirrored_exprs(left_expr, a_ident, right_expr, b_ident), - (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => mirrored_exprs(a_expr, a_ident, right_expr, b_ident), - (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(left_expr, a_ident, b_expr, b_ident), - _ => false, - } -} - -fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if_chain! { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind; - if let name = name_ident.ident.name.to_ident_string(); - if name == "sort_by" || name == "sort_unstable_by"; - if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec); - if let closure_body = cx.tcx.hir().body(*closure_body_id); - if let &[ - Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, - Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } - ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, [ref left_expr, ref right_expr], _) = &closure_body.value.kind; - if method_path.ident.name == sym::cmp; - then { - let (closure_body, closure_arg, reverse) = if mirrored_exprs( - left_expr, - left_ident, - right_expr, - right_ident - ) { - (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false) - } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { - (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true) - } else { - return None; - }; - let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); - let unstable = name == "sort_unstable_by"; - - if_chain! { - if let ExprKind::Path(QPath::Resolved(_, Path { - segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind; - if left_name == left_ident; - if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) - }); - then { - return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })); - } - } - - if !expr_borrows(cx, left_expr) { - return Some(LintTrigger::SortByKey(SortByKeyDetection { - vec_name, - closure_arg, - closure_body, - reverse, - unstable, - })); - } - } - } - - None -} - -fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); - matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) -} - -impl LateLintPass<'_> for UnnecessarySortBy { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - match detect_lint(cx, expr) { - Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( - cx, - UNNECESSARY_SORT_BY, - expr.span, - "use Vec::sort_by_key here instead", - "try", - format!( - "{}.sort{}_by_key(|{}| {})", - trigger.vec_name, - if trigger.unstable { "_unstable" } else { "" }, - trigger.closure_arg, - if trigger.reverse { - format!("std::cmp::Reverse({})", trigger.closure_body) - } else { - trigger.closure_body.to_string() - }, - ), - if trigger.reverse { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }, - ), - Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( - cx, - UNNECESSARY_SORT_BY, - expr.span, - "use Vec::sort here instead", - "try", - format!( - "{}.sort{}()", - trigger.vec_name, - if trigger.unstable { "_unstable" } else { "" }, - ), - Applicability::MachineApplicable, - ), - None => {}, - } - } -} -- cgit 1.4.1-3-g733a5 From 8acc4d2f1e255e0e97e48b7a285a7d6db4a03bd6 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 6 Jun 2022 11:17:38 -0400 Subject: Move `VecResizeToZero` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 27 +++++++++++ clippy_lints/src/methods/vec_resize_to_zero.rs | 45 ++++++++++++++++++ clippy_lints/src/vec_resize_to_zero.rs | 64 -------------------------- tests/ui/vec_resize_to_zero.rs | 12 +++-- tests/ui/vec_resize_to_zero.stderr | 10 ++-- 9 files changed, 88 insertions(+), 78 deletions(-) create mode 100644 clippy_lints/src/methods/vec_resize_to_zero.rs delete mode 100644 clippy_lints/src/vec_resize_to_zero.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index bb5b2866268..4128096b43a 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -217,6 +217,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), + LintId::of(methods::VEC_RESIZE_TO_ZERO), LintId::of(methods::WRONG_SELF_CONVENTION), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), @@ -344,7 +345,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(vec::USELESS_VEC), LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(write::PRINTLN_EMPTY_STRING), LintId::of(write::PRINT_LITERAL), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index d30e69b2240..bb94037ec2e 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -43,6 +43,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::UNIT_HASH), + LintId::of(methods::VEC_RESIZE_TO_ZERO), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), @@ -74,5 +75,4 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index f5497c6bd6b..1b275516dfc 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -369,6 +369,7 @@ store.register_lints(&[ methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, methods::USELESS_ASREF, + methods::VEC_RESIZE_TO_ZERO, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -584,7 +585,6 @@ store.register_lints(&[ useless_conversion::USELESS_CONVERSION, vec::USELESS_VEC, vec_init_then_push::VEC_INIT_THEN_PUSH, - vec_resize_to_zero::VEC_RESIZE_TO_ZERO, verbose_file_reads::VERBOSE_FILE_READS, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cfcd4e3d141..ff68fbd1964 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -391,7 +391,6 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; -mod vec_resize_to_zero; mod verbose_file_reads; mod wildcard_imports; mod write; @@ -803,7 +802,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); - store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero)); store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 54a0275da96..1a225c9bc95 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -90,6 +90,7 @@ mod unwrap_or_else_default; mod unwrap_used; mod useless_asref; mod utils; +mod vec_resize_to_zero; mod wrong_self_convention; mod zst_offset; @@ -2907,6 +2908,28 @@ declare_clippy_lint! { "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" } +declare_clippy_lint! { + /// ### What it does + /// Finds occurrences of `Vec::resize(0, an_int)` + /// + /// ### Why is this bad? + /// This is probably an argument inversion mistake. + /// + /// ### Example + /// ```rust + /// vec!(1, 2, 3, 4, 5).resize(0, 5) + /// ``` + /// + /// Use instead: + /// ```rust + /// vec!(1, 2, 3, 4, 5).clear() + /// ``` + #[clippy::version = "1.46.0"] + pub VEC_RESIZE_TO_ZERO, + correctness, + "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3026,6 +3049,7 @@ impl_lint_pass!(Methods => [ STABLE_SORT_PRIMITIVE, UNIT_HASH, UNNECESSARY_SORT_BY, + VEC_RESIZE_TO_ZERO, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3420,6 +3444,9 @@ impl Methods { ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, + ("resize", [count_arg, default_arg]) => { + vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); + }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs new file mode 100644 index 00000000000..02d8364cb29 --- /dev/null +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; +use rustc_span::{sym, Span}; + +use super::VEC_RESIZE_TO_ZERO; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + count_arg: &'tcx Expr<'_>, + default_arg: &'tcx Expr<'_>, + name_span: Span, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec); + if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind; + if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind; + then { + let method_call_span = expr.span.with_lo(name_span.lo()); + span_lint_and_then( + cx, + VEC_RESIZE_TO_ZERO, + expr.span, + "emptying a vector with `resize`", + |db| { + db.help("the arguments may be inverted..."); + db.span_suggestion( + method_call_span, + "...or you can empty the vector with", + "clear()".to_string(), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs deleted file mode 100644 index 0fee3e812d2..00000000000 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ /dev/null @@ -1,64 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Finds occurrences of `Vec::resize(0, an_int)` - /// - /// ### Why is this bad? - /// This is probably an argument inversion mistake. - /// - /// ### Example - /// ```rust - /// vec!(1, 2, 3, 4, 5).resize(0, 5) - /// ``` - /// - /// Use instead: - /// ```rust - /// vec!(1, 2, 3, 4, 5).clear() - /// ``` - #[clippy::version = "1.46.0"] - pub VEC_RESIZE_TO_ZERO, - correctness, - "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" -} - -declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]); - -impl<'tcx> LateLintPass<'tcx> for VecResizeToZero { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(path_segment, args, _) = expr.kind; - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3; - if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind; - if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind; - then { - let method_call_span = expr.span.with_lo(path_segment.ident.span.lo()); - span_lint_and_then( - cx, - VEC_RESIZE_TO_ZERO, - expr.span, - "emptying a vector with `resize`", - |db| { - db.help("the arguments may be inverted..."); - db.span_suggestion( - method_call_span, - "...or you can empty the vector with", - "clear()".to_string(), - Applicability::MaybeIncorrect, - ); - }, - ); - } - } - } -} diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs index 7ed27439ec6..a8307e741cf 100644 --- a/tests/ui/vec_resize_to_zero.rs +++ b/tests/ui/vec_resize_to_zero.rs @@ -1,15 +1,19 @@ #![warn(clippy::vec_resize_to_zero)] fn main() { + let mut v = vec![1, 2, 3, 4, 5]; + // applicable here - vec![1, 2, 3, 4, 5].resize(0, 5); + v.resize(0, 5); // not applicable - vec![1, 2, 3, 4, 5].resize(2, 5); + v.resize(2, 5); + + let mut v = vec!["foo", "bar", "baz"]; // applicable here, but only implemented for integer literals for now - vec!["foo", "bar", "baz"].resize(0, "bar"); + v.resize(0, "bar"); // not applicable - vec!["foo", "bar", "baz"].resize(2, "bar") + v.resize(2, "bar") } diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr index feb846298c6..7428cf62d6c 100644 --- a/tests/ui/vec_resize_to_zero.stderr +++ b/tests/ui/vec_resize_to_zero.stderr @@ -1,10 +1,10 @@ error: emptying a vector with `resize` - --> $DIR/vec_resize_to_zero.rs:5:5 + --> $DIR/vec_resize_to_zero.rs:7:5 | -LL | vec![1, 2, 3, 4, 5].resize(0, 5); - | ^^^^^^^^^^^^^^^^^^^^------------ - | | - | help: ...or you can empty the vector with: `clear()` +LL | v.resize(0, 5); + | ^^------------ + | | + | help: ...or you can empty the vector with: `clear()` | = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` = help: the arguments may be inverted... -- cgit 1.4.1-3-g733a5 From d8808db006cf4fde950076f1112ca465bcaf72ef Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 6 Jun 2022 11:58:30 -0400 Subject: Move `VerboseFileReads` into `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 35 ++++++++++ clippy_lints/src/methods/verbose_file_reads.rs | 28 ++++++++ clippy_lints/src/verbose_file_reads.rs | 88 -------------------------- 6 files changed, 65 insertions(+), 92 deletions(-) create mode 100644 clippy_lints/src/methods/verbose_file_reads.rs delete mode 100644 clippy_lints/src/verbose_file_reads.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 1b275516dfc..db475950086 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -370,6 +370,7 @@ store.register_lints(&[ methods::UNWRAP_USED, methods::USELESS_ASREF, methods::VEC_RESIZE_TO_ZERO, + methods::VERBOSE_FILE_READS, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -585,7 +586,6 @@ store.register_lints(&[ useless_conversion::USELESS_CONVERSION, vec::USELESS_VEC, vec_init_then_push::VEC_INIT_THEN_PUSH, - verbose_file_reads::VERBOSE_FILE_READS, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, write::POSITIONAL_NAMED_FORMAT_PARAMETERS, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 7fc5eef5f8a..dd1e1e1a8e3 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -40,6 +40,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::GET_UNWRAP), LintId::of(methods::MAP_ERR_IGNORE), LintId::of(methods::UNWRAP_USED), + LintId::of(methods::VERBOSE_FILE_READS), LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), @@ -81,7 +82,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(unicode::NON_ASCII_LITERAL), LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), - LintId::of(verbose_file_reads::VERBOSE_FILE_READS), LintId::of(write::PRINT_STDERR), LintId::of(write::PRINT_STDOUT), LintId::of(write::USE_DEBUG), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ff68fbd1964..dbea55a04d6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -391,7 +391,6 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; -mod verbose_file_reads; mod wildcard_imports; mod write; mod zero_div_zero; @@ -792,7 +791,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); - store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads)); store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1a225c9bc95..1cfe8c4191e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -91,6 +91,7 @@ mod unwrap_used; mod useless_asref; mod utils; mod vec_resize_to_zero; +mod verbose_file_reads; mod wrong_self_convention; mod zst_offset; @@ -2930,6 +2931,33 @@ declare_clippy_lint! { "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" } +declare_clippy_lint! { + /// ### What it does + /// Checks for use of File::read_to_end and File::read_to_string. + /// + /// ### Why is this bad? + /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. + /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + /// + /// ### Example + /// ```rust,no_run + /// # use std::io::Read; + /// # use std::fs::File; + /// let mut f = File::open("foo.txt").unwrap(); + /// let mut bytes = Vec::new(); + /// f.read_to_end(&mut bytes).unwrap(); + /// ``` + /// Can be written more concisely as + /// ```rust,no_run + /// # use std::fs; + /// let mut bytes = fs::read("foo.txt").unwrap(); + /// ``` + #[clippy::version = "1.44.0"] + pub VERBOSE_FILE_READS, + restriction, + "use of `File::read_to_end` or `File::read_to_string`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3050,6 +3078,7 @@ impl_lint_pass!(Methods => [ UNIT_HASH, UNNECESSARY_SORT_BY, VEC_RESIZE_TO_ZERO, + VERBOSE_FILE_READS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3441,6 +3470,12 @@ impl Methods { ("push", [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, + ("read_to_end", [_]) => { + verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG); + }, + ("read_to_string", [_]) => { + verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); + }, ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, diff --git a/clippy_lints/src/methods/verbose_file_reads.rs b/clippy_lints/src/methods/verbose_file_reads.rs new file mode 100644 index 00000000000..2fe5ae9a9ad --- /dev/null +++ b/clippy_lints/src/methods/verbose_file_reads.rs @@ -0,0 +1,28 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::VERBOSE_FILE_READS; + +pub(super) const READ_TO_END_MSG: (&str, &str) = ("use of `File::read_to_end`", "consider using `fs::read` instead"); +pub(super) const READ_TO_STRING_MSG: (&str, &str) = ( + "use of `File::read_to_string`", + "consider using `fs::read_to_string` instead", +); + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + (msg, help): (&str, &str), +) { + if is_trait_method(cx, expr, sym::IoRead) + && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _))) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File) + { + span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help); + } +} diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs deleted file mode 100644 index afd0077a658..00000000000 --- a/clippy_lints/src/verbose_file_reads.rs +++ /dev/null @@ -1,88 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::paths; -use clippy_utils::ty::match_type; -use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for use of File::read_to_end and File::read_to_string. - /// - /// ### Why is this bad? - /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. - /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) - /// - /// ### Example - /// ```rust,no_run - /// # use std::io::Read; - /// # use std::fs::File; - /// let mut f = File::open("foo.txt").unwrap(); - /// let mut bytes = Vec::new(); - /// f.read_to_end(&mut bytes).unwrap(); - /// ``` - /// Can be written more concisely as - /// ```rust,no_run - /// # use std::fs; - /// let mut bytes = fs::read("foo.txt").unwrap(); - /// ``` - #[clippy::version = "1.44.0"] - pub VERBOSE_FILE_READS, - restriction, - "use of `File::read_to_end` or `File::read_to_string`" -} - -declare_lint_pass!(VerboseFileReads => [VERBOSE_FILE_READS]); - -impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if is_file_read_to_end(cx, expr) { - span_lint_and_help( - cx, - VERBOSE_FILE_READS, - expr.span, - "use of `File::read_to_end`", - None, - "consider using `fs::read` instead", - ); - } else if is_file_read_to_string(cx, expr) { - span_lint_and_help( - cx, - VERBOSE_FILE_READS, - expr.span, - "use of `File::read_to_string`", - None, - "consider using `fs::read_to_string` instead", - ); - } - } -} - -fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - if_chain! { - if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind; - if method_name.ident.as_str() == "read_to_end"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind; - let ty = cx.typeck_results().expr_ty(recv); - if match_type(cx, ty, &paths::FILE); - then { - return true - } - } - false -} - -fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - if_chain! { - if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind; - if method_name.ident.as_str() == "read_to_string"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; - let ty = cx.typeck_results().expr_ty(&exprs[0]); - if match_type(cx, ty, &paths::FILE); - then { - return true - } - } - false -} -- cgit 1.4.1-3-g733a5 From 4f049f5a695b003168125a3251f5c0295e64f261 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 18 Aug 2022 17:25:02 +0000 Subject: Refactor `FormatArgsExpn` --- clippy_lints/src/format.rs | 24 +- clippy_lints/src/format_args.rs | 31 +- clippy_lints/src/format_impl.rs | 11 +- clippy_lints/src/methods/uninit_assumed_init.rs | 4 +- clippy_lints/src/transmute/transmuting_null.rs | 4 +- clippy_utils/Cargo.toml | 1 + clippy_utils/src/lib.rs | 15 +- clippy_utils/src/macros.rs | 674 +++++++++++++++++------- clippy_utils/src/paths.rs | 1 - tests/ui/format_args.fixed | 13 +- tests/ui/format_args.rs | 13 +- tests/ui/format_args.stderr | 42 +- 12 files changed, 580 insertions(+), 253 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 925a8cb8dee..0c5851cdbed 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -56,29 +56,27 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { }; let mut applicability = Applicability::MachineApplicable; - if format_args.value_args.is_empty() { - match *format_args.format_string_parts { + if format_args.args.is_empty() { + match *format_args.format_string.parts { [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), [_] => { - if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) { - // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = s_src.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); - span_useless_format(cx, call_site, sugg, applicability); - } + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let sugg = format!("{}.to_string()", s_expand); + span_useless_format(cx, call_site, sugg, applicability); }, [..] => {}, } - } else if let [value] = *format_args.value_args { + } else if let [arg] = &*format_args.args { + let value = arg.param.value; if_chain! { - if format_args.format_string_parts == [kw::Empty]; + if format_args.format_string.parts == [kw::Empty]; if match cx.typeck_results().expr_ty(value).peel_refs().kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), ty::Str => true, _ => false, }; - if let Some(args) = format_args.args(); - if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting()); + if !arg.format.has_string_formatting(); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 1e6feaac26c..5347ff880ce 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; -use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::macros::{is_format_macro, FormatArgsExpn}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use if_chain::if_chain; +use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; @@ -74,20 +75,16 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if let Some(macro_def_id) = outermost_expn_data.macro_def_id; if is_format_macro(cx, macro_def_id); if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; - if let Some(args) = format_args.args(); then { - for (i, arg) in args.iter().enumerate() { - if arg.format_trait != sym::Display { + for arg in &format_args.args { + if arg.format.has_string_formatting() { continue; } - if arg.has_string_formatting() { + if is_aliased(&format_args, arg.param.value.hir_id) { continue; } - if is_aliased(&args, i) { - continue; - } - check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value); - check_to_string_in_format_args(cx, name, arg.value); + check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); + check_to_string_in_format_args(cx, name, arg.param.value); } } } @@ -167,12 +164,12 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex } } -// Returns true if `args[i]` "refers to" or "is referred to by" another argument. -fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool { - let value = args[i].value; - args.iter() - .enumerate() - .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value)) +// Returns true if `hir_id` is referred to by multiple format params +fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { + args.params() + .filter(|param| param.value.hir_id == hir_id) + .at_most_one() + .is_err() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 04b5be6c80e..d8bc0bf08f2 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -168,10 +168,9 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, if let macro_def_id = outer_macro.def_id; if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); if is_format_macro(cx, macro_def_id); - if let Some(args) = format_args.args(); then { - for arg in args { - if arg.format_trait != impl_trait.name { + for arg in format_args.args { + if arg.format.r#trait != impl_trait.name { continue; } check_format_arg_self(cx, expr, &arg, impl_trait); @@ -180,11 +179,11 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, } } -fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) { +fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) { // Handle multiple dereferencing of references e.g. &&self // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg.value); + let reference = peel_ref_operators(cx, arg.param.value); let map = cx.tcx.hir(); // Is the reference self? if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 77d21f1d373..a1c6294737c 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty}; +use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if_chain! { if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); - if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); + if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index c4981124f39..d8e349af7af 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_expr_diagnostic_item; +use clippy_utils::is_path_diagnostic_item; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // `std::mem::transmute(std::ptr::null::())` if_chain! { if let ExprKind::Call(func1, []) = arg.kind; - if is_expr_diagnostic_item(cx, func1, sym::ptr_null); + if is_path_diagnostic_item(cx, func1, sym::ptr_null); then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index a688050f63a..c36bca06507 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] arrayvec = { version = "0.7", default-features = false } if_chain = "1.0" +itertools = "0.10.1" rustc-semver = "1.1" [features] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dc772e5efee..9308f085214 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -27,6 +27,7 @@ extern crate rustc_infer; extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; +extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -371,15 +372,19 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. /// -/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item. +/// Please use `is_path_diagnostic_item` if the target is a diagnostic item. pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments)) } -/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given -/// diagnostic item. -pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { - path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) +/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if +/// it matches the given diagnostic item. +pub fn is_path_diagnostic_item<'tcx>( + cx: &LateContext<'_>, + maybe_path: &impl MaybePath<'tcx>, + diag_item: Symbol, +) -> bool { + path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) } /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index a268e339bb1..37d8f1e458d 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,16 +1,21 @@ #![allow(clippy::similar_names)] // `expr` and `expn` +use crate::is_path_diagnostic_item; +use crate::source::snippet_opt; use crate::visitors::expr_visitor_no_bodies; use arrayvec::ArrayVec; -use if_chain::if_chain; +use itertools::{izip, Either, Itertools}; use rustc_ast::ast::LitKind; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; +use rustc_lexer::unescape::unescape_literal; +use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lint::LateContext; +use rustc_parse_format::{self as rpf, Alignment}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol}; +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ @@ -332,121 +337,495 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> } } -/// A parsed `format_args!` expansion +/// The format string doesn't exist in the HIR, so we reassemble it from source code #[derive(Debug)] -pub struct FormatArgsExpn<'tcx> { - /// Span of the first argument, the format string - pub format_string_span: Span, - /// The format string split by formatted args like `{..}` - pub format_string_parts: Vec, - /// Values passed after the format string - pub value_args: Vec<&'tcx Expr<'tcx>>, - /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`) - pub formatters: Vec<(usize, Symbol)>, - /// List of `fmt::v1::Argument { .. }` expressions. If this is empty, - /// then `formatters` represents the format args (`{..}`). - /// If this is non-empty, it represents the format args, and the `position` - /// parameters within the struct expressions are indexes of `formatters`. - pub specs: Vec<&'tcx Expr<'tcx>>, +pub struct FormatString { + /// Span of the whole format string literal, including `[r#]"`. + pub span: Span, + /// Snippet of the whole format string literal, including `[r#]"`. + pub snippet: String, + /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side. + pub style: Option, + /// The unescaped value of the format string, e.g. `"val – {}"` for the literal + /// `"val \u{2013} {}"`. + pub unescaped: String, + /// The format string split by format args like `{..}`. + pub parts: Vec, } -impl<'tcx> FormatArgsExpn<'tcx> { - /// Parses an expanded `format_args!` or `format_args_nl!` invocation - pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { - macro_backtrace(expr.span).find(|macro_call| { - matches!( - cx.tcx.item_name(macro_call.def_id), - sym::const_format_args | sym::format_args | sym::format_args_nl - ) - })?; - let mut format_string_span: Option = None; - let mut format_string_parts: Vec = Vec::new(); - let mut value_args: Vec<&Expr<'_>> = Vec::new(); - let mut formatters: Vec<(usize, Symbol)> = Vec::new(); - let mut specs: Vec<&Expr<'_>> = Vec::new(); - expr_visitor_no_bodies(|e| { - // if we're still inside of the macro definition... - if e.span.ctxt() == expr.span.ctxt() { - // ArgumentV1::new_() - if_chain! { - if let ExprKind::Call(callee, [val]) = e.kind; - if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind; - if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind; - if path.segments.last().unwrap().ident.name == sym::ArgumentV1; - if seg.ident.name.as_str().starts_with("new_"); - then { - let val_idx = if_chain! { - if val.span.ctxt() == expr.span.ctxt(); - if let ExprKind::Field(_, field) = val.kind; - if let Ok(idx) = field.name.as_str().parse(); - then { - // tuple index - idx - } else { - // assume the value expression is passed directly - formatters.len() - } - }; - let fmt_trait = match seg.ident.name.as_str() { - "new_display" => "Display", - "new_debug" => "Debug", - "new_lower_exp" => "LowerExp", - "new_upper_exp" => "UpperExp", - "new_octal" => "Octal", - "new_pointer" => "Pointer", - "new_binary" => "Binary", - "new_lower_hex" => "LowerHex", - "new_upper_hex" => "UpperHex", - _ => unreachable!(), - }; - formatters.push((val_idx, Symbol::intern(fmt_trait))); - } - } - if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind { - if path.segments.last().unwrap().ident.name == sym::Argument { - specs.push(e); - } +impl FormatString { + fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option { + // format_args!(r"a {} b \", 1); + // + // expands to + // + // ::core::fmt::Arguments::new_v1(&["a ", " b \\"], + // &[::core::fmt::ArgumentV1::new_display(&1)]); + // + // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"` + let span = pieces.span; + let snippet = snippet_opt(cx, span)?; + + let (inner, style) = match tokenize(&snippet).next()?.kind { + TokenKind::Literal { kind, .. } => { + let style = match kind { + LiteralKind::Str { .. } => None, + LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()), + _ => return None, + }; + + let start = style.map_or(1, |n| 2 + n); + let end = snippet.len() - style.map_or(1, |n| 1 + n); + + (&snippet[start..end], style) + }, + _ => return None, + }; + + let mode = if style.is_some() { + unescape::Mode::RawStr + } else { + unescape::Mode::Str + }; + + let mut unescaped = String::with_capacity(inner.len()); + unescape_literal(inner, mode, &mut |_, ch| { + unescaped.push(ch.unwrap()); + }); + + let mut parts = Vec::new(); + expr_visitor_no_bodies(|expr| { + if let ExprKind::Lit(lit) = &expr.kind { + if let LitKind::Str(symbol, _) = lit.node { + parts.push(symbol); } - // walk through the macro expansion - return true; } - // assume that the first expr with a differing context represents - // (and has the span of) the format string - if format_string_span.is_none() { - format_string_span = Some(e.span); - let span = e.span; - // walk the expr and collect string literals which are format string parts - expr_visitor_no_bodies(|e| { - if e.span.ctxt() != span.ctxt() { - // defensive check, probably doesn't happen - return false; - } - if let ExprKind::Lit(lit) = &e.kind { - if let LitKind::Str(symbol, _s) = lit.node { - format_string_parts.push(symbol); - } - } - true - }) - .visit_expr(e); + + true + }) + .visit_expr(pieces); + + Some(Self { + span, + snippet, + style, + unescaped, + parts, + }) + } +} + +struct FormatArgsValues<'tcx> { + /// See `FormatArgsExpn::value_args` + value_args: Vec<&'tcx Expr<'tcx>>, + /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in + /// `value_args` + pos_to_value_index: Vec, + /// Used to check if a value is declared inline & to resolve `InnerSpan`s. + format_string_span: SpanData, +} + +impl<'tcx> FormatArgsValues<'tcx> { + fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { + let mut pos_to_value_index = Vec::new(); + let mut value_args = Vec::new(); + expr_visitor_no_bodies(|expr| { + if expr.span.ctxt() == args.span.ctxt() { + // ArgumentV1::new_() + // ArgumentV1::from_usize() + if let ExprKind::Call(callee, [val]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind + && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && path.segments.last().unwrap().ident.name == sym::ArgumentV1 + { + let val_idx = if val.span.ctxt() == expr.span.ctxt() + && let ExprKind::Field(_, field) = val.kind + && let Ok(idx) = field.name.as_str().parse() + { + // tuple index + idx + } else { + // assume the value expression is passed directly + pos_to_value_index.len() + }; + + pos_to_value_index.push(val_idx); + } + + true } else { - // assume that any further exprs with a differing context are value args - value_args.push(e); + // assume that any expr with a differing span is a value + value_args.push(expr); + + false } - // don't walk anything not from the macro expansion (e.a. inputs) - false }) - .visit_expr(expr); - Some(FormatArgsExpn { - format_string_span: format_string_span?, - format_string_parts, + .visit_expr(args); + + Self { value_args, - formatters, - specs, + pos_to_value_index, + format_string_span, + } + } +} + +/// The positions of a format argument's value, precision and width +/// +/// A position is an index into the second argument of `Arguments::new_v1[_formatted]` +#[derive(Debug, Default, Copy, Clone)] +struct ParamPosition { + /// The position stored in `rt::v1::Argument::position`. + value: usize, + /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`. + width: Option, + /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`. + precision: Option, +} + +/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` +fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { + fn parse_count(expr: &Expr<'_>) -> Option { + // ::core::fmt::rt::v1::Count::Param(1usize), + if let ExprKind::Call(ctor, [val]) = expr.kind + && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind + && path.segments.last()?.ident.name == sym::Param + && let ExprKind::Lit(lit) = &val.kind + && let LitKind::Int(pos, _) = lit.node + { + Some(pos as usize) + } else { + None + } + } + + if let ExprKind::AddrOf(.., array) = fmt_arg.kind + && let ExprKind::Array(specs) = array.kind + { + Some(specs.iter().map(|spec| { + let mut position = ParamPosition::default(); + + // ::core::fmt::rt::v1::Argument { + // position: 0usize, + // format: ::core::fmt::rt::v1::FormatSpec { + // .. + // precision: ::core::fmt::rt::v1::Count::Implied, + // width: ::core::fmt::rt::v1::Count::Implied, + // }, + // } + + // TODO: this can be made much nicer next sync with `Visitor::visit_expr_field` + if let ExprKind::Struct(_, fields, _) = spec.kind { + for field in fields { + match (field.ident.name, &field.expr.kind) { + (sym::position, ExprKind::Lit(lit)) => { + if let LitKind::Int(pos, _) = lit.node { + position.value = pos as usize; + } + }, + (sym::format, &ExprKind::Struct(_, spec_fields, _)) => { + for spec_field in spec_fields { + match spec_field.ident.name { + sym::precision => { + position.precision = parse_count(spec_field.expr); + }, + sym::width => { + position.width = parse_count(spec_field.expr); + }, + _ => {}, + } + } + }, + _ => {}, + } + } + } + + position + })) + } else { + None + } +} + +/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan` +fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span { + Span::new( + base.lo + BytePos::from_usize(inner.start), + base.lo + BytePos::from_usize(inner.end), + base.ctxt, + base.parent, + ) +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum FormatParamKind { + /// An implicit parameter , such as `{}` or `{:?}`. + Implicit, + /// A parameter with an explicit number, or an asterisk precision. e.g. `{1}`, `{0:?}`, + /// `{:.0$}` or `{:.*}`. + Numbered, + /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`. + Named(Symbol), + /// An implicit named paramter, such as the `y` in `format!("{y}")`. + NamedInline(Symbol), +} + +/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g. +/// +/// ``` +/// let precision = 2; +/// format!("{:.precision$}", 0.1234); +/// ``` +/// +/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234` +/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2` +#[derive(Debug, Copy, Clone)] +pub struct FormatParam<'tcx> { + /// The expression this parameter refers to. + pub value: &'tcx Expr<'tcx>, + /// How this paramter refers to its `value`. + pub kind: FormatParamKind, + /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters. + /// + /// ```text + /// format!("{}, { }, {0}, {name}", ...); + /// ^ ~~ ~ ~~~~ + /// ``` + pub span: Span, +} + +impl<'tcx> FormatParam<'tcx> { + fn new( + mut kind: FormatParamKind, + position: usize, + inner: rpf::InnerSpan, + values: &FormatArgsValues<'tcx>, + ) -> Option { + let value_index = *values.pos_to_value_index.get(position)?; + let value = *values.value_args.get(value_index)?; + let span = span_from_inner(values.format_string_span, inner); + + // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points + // into the format string + if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) { + kind = FormatParamKind::NamedInline(name); + } + + Some(Self { value, kind, span }) + } +} + +/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and +/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. +#[derive(Debug, Copy, Clone)] +pub enum Count<'tcx> { + /// Specified with a literal number, stores the value. + Is(usize, Span), + /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be + /// `FormatParamKind::Numbered`. + Param(FormatParam<'tcx>), + /// Not specified. + Implied, +} + +impl<'tcx> Count<'tcx> { + fn new( + count: rpf::Count<'_>, + position: Option, + inner: Option, + values: &FormatArgsValues<'tcx>, + ) -> Option { + Some(match count { + rpf::Count::CountIs(val) => Self::Is(val, span_from_inner(values.format_string_span, inner?)), + rpf::Count::CountIsName(name, span) => Self::Param(FormatParam::new( + FormatParamKind::Named(Symbol::intern(name)), + position?, + span, + values, + )?), + rpf::Count::CountIsParam(_) => { + Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?) + }, + rpf::Count::CountImplied => Self::Implied, + }) + } + + pub fn is_implied(self) -> bool { + matches!(self, Count::Implied) + } + + pub fn param(self) -> Option> { + match self { + Count::Param(param) => Some(param), + _ => None, + } + } +} + +/// Specification for the formatting of an argument in the format string. See +/// for the precise meanings. +#[derive(Debug)] +pub struct FormatSpec<'tcx> { + /// Optionally specified character to fill alignment with. + pub fill: Option, + /// Optionally specified alignment. + pub align: Alignment, + /// Packed version of various flags provided, see [`rustc_parse_format::Flag`]. + pub flags: u32, + /// Represents either the maximum width or the integer precision. + pub precision: Count<'tcx>, + /// The minimum width, will be padded according to `width`/`align` + pub width: Count<'tcx>, + /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for + /// `{:?}`. + pub r#trait: Symbol, + pub trait_span: Option, +} + +impl<'tcx> FormatSpec<'tcx> { + fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option { + Some(Self { + fill: spec.fill, + align: spec.align, + flags: spec.flags, + precision: Count::new(spec.precision, positions.precision, spec.precision_span, values)?, + width: Count::new(spec.width, positions.width, spec.width_span, values)?, + r#trait: match spec.ty { + "" => sym::Display, + "?" => sym::Debug, + "o" => sym!(Octal), + "x" => sym!(LowerHex), + "X" => sym!(UpperHex), + "p" => sym::Pointer, + "b" => sym!(Binary), + "e" => sym!(LowerExp), + "E" => sym!(UpperExp), + _ => return None, + }, + trait_span: spec + .ty_span + .map(|span| span_from_inner(values.format_string_span, span)), }) } - /// Finds a nested call to `format_args!` within a `format!`-like macro call + /// Returns true if this format spec would change the contents of a string when formatted + pub fn has_string_formatting(&self) -> bool { + self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied() + } +} + +/// A format argument, such as `{}`, `{foo:?}`. +#[derive(Debug)] +pub struct FormatArg<'tcx> { + /// The parameter the argument refers to. + pub param: FormatParam<'tcx>, + /// How to format `param`. + pub format: FormatSpec<'tcx>, + /// span of the whole argument, `{..}`. + pub span: Span, +} + +/// A parsed `format_args!` expansion. +#[derive(Debug)] +pub struct FormatArgsExpn<'tcx> { + /// The format string literal. + pub format_string: FormatString, + // The format arguments, such as `{:?}`. + pub args: Vec>, + /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will + /// include this added newline. + pub newline: bool, + /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for + /// `format!("{x} {} {y}", 1, z + 2)`. + value_args: Vec<&'tcx Expr<'tcx>>, +} + +impl<'tcx> FormatArgsExpn<'tcx> { + pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { + let macro_name = macro_backtrace(expr.span) + .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) + .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; + let newline = macro_name == sym::format_args_nl; + + // ::core::fmt::Arguments::new_v1(pieces, args) + // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) + if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind + && is_path_diagnostic_item(cx, ty, sym::Arguments) + && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted") + { + let format_string = FormatString::new(cx, pieces)?; + + let mut parser = rpf::Parser::new( + &format_string.unescaped, + format_string.style, + Some(format_string.snippet.clone()), + // `format_string.unescaped` does not contain the appended newline + false, + rpf::ParseMode::Format, + ); + + let parsed_args = parser + .by_ref() + .filter_map(|piece| match piece { + rpf::Piece::NextArgument(a) => Some(a), + rpf::Piece::String(_) => None, + }) + .collect_vec(); + if !parser.errors.is_empty() { + return None; + } + + let positions = if let Some(fmt_arg) = rest.first() { + // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse + // them. + + Either::Left(parse_rt_fmt(fmt_arg)?) + } else { + // If no format specs are given, the positions are in the given order and there are + // no `precision`/`width`s to consider. + + Either::Right((0..).map(|n| ParamPosition { + value: n, + width: None, + precision: None, + })) + }; + + let values = FormatArgsValues::new(args, format_string.span.data()); + + let args = izip!(positions, parsed_args, parser.arg_places) + .map(|(position, parsed_arg, arg_span)| { + Some(FormatArg { + param: FormatParam::new( + match parsed_arg.position { + rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit, + rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered, + // NamedInline is handled by `FormatParam::new()` + rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)), + }, + position.value, + parsed_arg.position_span, + &values, + )?, + format: FormatSpec::new(parsed_arg.format, position, &values)?, + span: span_from_inner(values.format_string_span, arg_span), + }) + }) + .collect::>>()?; + + Some(Self { + format_string, + args, + value_args: values.value_args, + newline, + }) + } else { + None + } + } + pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { let mut format_args = None; expr_visitor_no_bodies(|e| { @@ -466,88 +845,23 @@ impl<'tcx> FormatArgsExpn<'tcx> { format_args } - /// Returns a vector of `FormatArgsArg`. - pub fn args(&self) -> Option>> { - if self.specs.is_empty() { - let args = std::iter::zip(&self.value_args, &self.formatters) - .map(|(value, &(_, format_trait))| FormatArgsArg { - value, - format_trait, - spec: None, - }) - .collect(); - return Some(args); - } - self.specs - .iter() - .map(|spec| { - if_chain! { - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = spec.kind; - if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); - if let ExprKind::Lit(lit) = &position_field.expr.kind; - if let LitKind::Int(position, _) = lit.node; - if let Ok(i) = usize::try_from(position); - if let Some(&(j, format_trait)) = self.formatters.get(i); - then { - Some(FormatArgsArg { - value: self.value_args[j], - format_trait, - spec: Some(spec), - }) - } else { - None - } - } - }) - .collect() - } - /// Source callsite span of all inputs pub fn inputs_span(&self) -> Span { match *self.value_args { - [] => self.format_string_span, + [] => self.format_string.span, [.., last] => self - .format_string_span - .to(hygiene::walk_chain(last.span, self.format_string_span.ctxt())), + .format_string + .span + .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())), } } -} -/// Type representing a `FormatArgsExpn`'s format arguments -pub struct FormatArgsArg<'tcx> { - /// An element of `value_args` according to `position` - pub value: &'tcx Expr<'tcx>, - /// An element of `args` according to `position` - pub format_trait: Symbol, - /// An element of `specs` - pub spec: Option<&'tcx Expr<'tcx>>, -} - -impl<'tcx> FormatArgsArg<'tcx> { - /// Returns true if any formatting parameters are used that would have an effect on strings, - /// like `{:+2}` instead of just `{}`. - pub fn has_string_formatting(&self) -> bool { - self.spec.map_or(false, |spec| { - // `!` because these conditions check that `self` is unformatted. - !if_chain! { - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = spec.kind; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); - // struct `core::fmt::rt::v1::FormatSpec` - if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind; - if subfields.iter().all(|field| match field.ident.name { - sym::precision | sym::width => match field.expr.kind { - ExprKind::Path(QPath::Resolved(_, path)) => { - path.segments.last().unwrap().ident.name == sym::Implied - } - _ => false, - } - _ => true, - }); - then { true } else { false } - } - }) + /// Iterator of all format params, both values and those referenced by `width`/`precision`s. + pub fn params(&'tcx self) -> impl Iterator> { + self.args + .iter() + .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()]) + .flatten() } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 8d697a301c4..199a3ab12ae 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -71,7 +71,6 @@ pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 69b5e1c722e..4322891db76 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -1,8 +1,6 @@ // run-rustfix -#![allow(unreachable_code)] -#![allow(unused_macros)] -#![allow(unused_variables)] +#![allow(unused)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] #![allow(clippy::print_literal)] @@ -115,3 +113,12 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{foo:?}", foo = "foo".to_string()); } + +fn issue8643(vendor_id: usize, product_id: usize, name: &str) { + println!( + "{:<9} {:<10} {}", + format!("0x{:x}", vendor_id), + format!("0x{:x}", product_id), + name + ); +} diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index 3a434c5bf00..61ad04612cd 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -1,8 +1,6 @@ // run-rustfix -#![allow(unreachable_code)] -#![allow(unused_macros)] -#![allow(unused_variables)] +#![allow(unused)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] #![allow(clippy::print_literal)] @@ -115,3 +113,12 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{foo:?}", foo = "foo".to_string()); } + +fn issue8643(vendor_id: usize, product_id: usize, name: &str) { + println!( + "{:<9} {:<10} {}", + format!("0x{:x}", vendor_id), + format!("0x{:x}", product_id), + name + ); +} diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr index c0cbca50795..0aca1c1a0df 100644 --- a/tests/ui/format_args.stderr +++ b/tests/ui/format_args.stderr @@ -1,5 +1,5 @@ error: `to_string` applied to a type that implements `Display` in `format!` args - --> $DIR/format_args.rs:76:72 + --> $DIR/format_args.rs:74:72 | LL | let _ = format!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this @@ -7,121 +7,121 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` error: `to_string` applied to a type that implements `Display` in `write!` args - --> $DIR/format_args.rs:80:27 + --> $DIR/format_args.rs:78:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `writeln!` args - --> $DIR/format_args.rs:85:27 + --> $DIR/format_args.rs:83:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> $DIR/format_args.rs:87:63 + --> $DIR/format_args.rs:85:63 | LL | print!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:88:65 + --> $DIR/format_args.rs:86:65 | LL | println!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprint!` args - --> $DIR/format_args.rs:89:64 + --> $DIR/format_args.rs:87:64 | LL | eprint!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprintln!` args - --> $DIR/format_args.rs:90:66 + --> $DIR/format_args.rs:88:66 | LL | eprintln!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format_args!` args - --> $DIR/format_args.rs:91:77 + --> $DIR/format_args.rs:89:77 | LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert!` args - --> $DIR/format_args.rs:92:70 + --> $DIR/format_args.rs:90:70 | LL | assert!(true, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_eq!` args - --> $DIR/format_args.rs:93:73 + --> $DIR/format_args.rs:91:73 | LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_ne!` args - --> $DIR/format_args.rs:94:73 + --> $DIR/format_args.rs:92:73 | LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `panic!` args - --> $DIR/format_args.rs:95:63 + --> $DIR/format_args.rs:93:63 | LL | panic!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:96:20 + --> $DIR/format_args.rs:94:20 | LL | println!("{}", X(1).to_string()); | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:97:20 + --> $DIR/format_args.rs:95:20 | LL | println!("{}", Y(&X(1)).to_string()); | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:98:24 + --> $DIR/format_args.rs:96:24 | LL | println!("{}", Z(1).to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:99:20 + --> $DIR/format_args.rs:97:20 | LL | println!("{}", x.to_string()); | ^^^^^^^^^^^^^ help: use this: `**x` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:100:20 + --> $DIR/format_args.rs:98:20 | LL | println!("{}", x_ref.to_string()); | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:102:39 + --> $DIR/format_args.rs:100:39 | LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:103:52 + --> $DIR/format_args.rs:101:52 | LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:104:39 + --> $DIR/format_args.rs:102:39 | LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:105:52 + --> $DIR/format_args.rs:103:52 | LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); | ^^^^^^^^^^^^ help: remove this -- cgit 1.4.1-3-g733a5 From a4413f75bf829549fdc0f01a834988d1128d6ba9 Mon Sep 17 00:00:00 2001 From: Nahua Kang Date: Tue, 2 Aug 2022 22:37:40 +0200 Subject: Register new lint collapsible_str_replace to methods --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_perf.rs | 1 + .../src/methods/collapsible_str_replace.rs | 6 +++ clippy_lints/src/methods/mod.rs | 29 ++++++++++++ tests/ui/collapsible_str_replace.rs | 55 ++++++++++++++++++++++ 7 files changed, 94 insertions(+) create mode 100644 clippy_lints/src/methods/collapsible_str_replace.rs create mode 100644 tests/ui/collapsible_str_replace.rs (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index edd7bc250a7..6c4a0cc91aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3642,6 +3642,7 @@ Released 2018-09-13 [`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match +[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index fefac7632d8..65eda429989 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -154,6 +154,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::COLLAPSIBLE_STR_REPLACE), LintId::of(methods::ERR_EXPECT), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::EXTEND_WITH_DRAIN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index db475950086..e64a473d068 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -287,6 +287,7 @@ store.register_lints(&[ methods::CLONE_DOUBLE_REF, methods::CLONE_ON_COPY, methods::CLONE_ON_REF_PTR, + methods::COLLAPSIBLE_STR_REPLACE, methods::ERR_EXPECT, methods::EXPECT_FUN_CALL, methods::EXPECT_USED, diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index e1b90acb93c..531fc47f8fa 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -13,6 +13,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(loops::MISSING_SPIN_LOOP), LintId::of(loops::NEEDLESS_COLLECT), LintId::of(manual_retain::MANUAL_RETAIN), + LintId::of(methods::COLLAPSIBLE_STR_REPLACE), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::ITER_NTH), diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs new file mode 100644 index 00000000000..e5547b50471 --- /dev/null +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -0,0 +1,6 @@ +use rustc_hir as hir; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1cfe8c4191e..8f7cb105c22 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -12,6 +12,7 @@ mod chars_next_cmp_with_unwrap; mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; +mod collapsible_str_replace; mod err_expect; mod expect_fun_call; mod expect_used; @@ -137,6 +138,32 @@ declare_clippy_lint! { "used `cloned` where `copied` could be used instead" } +declare_clippy_lint! { + /// ### What it does + /// Checks for consecutive calls to `str::replace` (2 or more) + /// that can be collapsed into a single call. + /// + /// ### Why is this bad? + /// Consecutive `str::replace` calls scan the string multiple times + /// with repetitive code. + /// + /// ### Example + /// ```rust + /// let hello = "hesuo worpd" + /// .replace('s', "l") + /// .replace("u", "l") + /// .replace('p', "l") + /// ``` + /// Use instead: + /// ```rust + /// let hello = "hesuo worpd".replace(|c| matches!(c, 's' | 'u' | 'p'), "l") + /// ``` + #[clippy::version = "1.64.0"] + pub COLLAPSIBLE_STR_REPLACE, + perf, + "collapse consecutive calls to str::replace (2 or more) into a single call" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed. @@ -3001,6 +3028,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_COPY, CLONE_ON_REF_PTR, CLONE_DOUBLE_REF, + COLLAPSIBLE_STR_REPLACE, ITER_OVEREAGER_CLONED, CLONED_INSTEAD_OF_COPIED, FLAT_MAP_OPTION, @@ -3491,6 +3519,7 @@ impl Methods { ("sort_unstable_by", [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, + ("replace", [_, _]) => collapsible_str_replace::check(cx, expr, recv, args), ("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); diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs new file mode 100644 index 00000000000..c91809bc840 --- /dev/null +++ b/tests/ui/collapsible_str_replace.rs @@ -0,0 +1,55 @@ +#![warn(clippy::collapsible_str_replace)] + +fn main() { + let misspelled = "hesuo worpd"; + + let p = 'p'; + let s = 's'; + let u = 'u'; + + // If the first argument to a single `str::replace` call is a slice and none of the chars + // are variables, recommend `collapsible_str_replace` + let replacement = misspelled.replace(&['s', 'u', 'p'], "l"); + println!("{replacement}"); + + // The first iteration of `collapsible_str_replace` will not create lint if the first argument to + // a single `str::replace` call is a slice and one or more of its chars are variables + let replacement = misspelled.replace(&['s', u, 'p'], "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(&[s, u, 'p'], "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(&[s, u, p], "l"); + println!("{replacement}"); + + // If there is a single call to `str::replace` and the first argument is a char or a variable, don't + // not recommend `collapsible_str_replace` + let replacement = misspelled.replace('s', "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(s, "l"); + println!("{replacement}"); + + // If there are consecutive calls to `str::replace` and none of the chars are variables, + // recommend `collapsible_str_replace` + let replacement = misspelled.replace('s', "l").replace('u', "l"); + println!("{replacement}"); + + let replacement = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); + println!("{replacement}"); + + // If there are consecutive calls to `str::replace` and all or any chars are variables, + // recommend the fallback `misspelled.replace(&[s, u, p], "l")` + let replacement = misspelled.replace(s, "l").replace('u', "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); + println!("{replacement}"); +} -- cgit 1.4.1-3-g733a5 From 6e866875294be38b02c1deaf0b1cba181a65109b Mon Sep 17 00:00:00 2001 From: Nahua Kang Date: Fri, 5 Aug 2022 21:08:43 +0200 Subject: Handle replace calls with char slices --- .../src/methods/collapsible_str_replace.rs | 154 ++++++++++++++++++++- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/collapsible_str_replace.rs | 27 ++-- 3 files changed, 167 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index e5547b50471..e2477fb06bd 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,6 +1,154 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +// use clippy_utils::source::snippet_with_context; +use clippy_utils::visitors::for_each_expr; +use core::ops::ControlFlow; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::*; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::source_map::Spanned; +use std::unreachable; +// use rustc_span::Span; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {} +use super::method_call; +use super::COLLAPSIBLE_STR_REPLACE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + name: &str, + recv: &'tcx hir::Expr<'tcx>, + args: &'tcx [hir::Expr<'tcx>], +) { + match (name, args) { + ("replace", [from, to]) => { + // Check for `str::replace` calls with char slice for linting + let original_recv = find_original_recv(recv); + let original_recv_ty = cx.typeck_results().expr_ty(original_recv).peel_refs(); + if_chain! { + // Check the receiver of the method call is `str` type + if matches!(original_recv_ty.kind(), ty::Str); + let from_ty = cx.typeck_results().expr_ty(from).peel_refs(); + if let ty::Array(array_ty, _) = from_ty.kind(); + if matches!(array_ty.kind(), ty::Char); + then { + check_replace_call_with_char_slice(cx, from, to); + } + } + + match method_call(recv) { + // Check if there's an earlier `str::replace` call + Some(("replace", [prev_recv, prev_from, prev_to], prev_span)) => { + println!("Consecutive replace calls"); + // Check that the original receiver is of `ty::Str` type + // Check that all the `from` args are char literals + // Check that all the `to` args are the same variable or has the same &str value + // If so, then lint + }, + _ => {}, + } + }, + _ => {}, + } +} + +fn find_original_recv<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> &'tcx hir::Expr<'tcx> { + let mut original_recv = recv; + + let _: Option<()> = for_each_expr(recv, |e| { + if let Some((name, [prev_recv, args @ ..], _)) = method_call(e) { + match (name, args) { + ("replace", [_, _]) => { + original_recv = prev_recv; + ControlFlow::Continue(()) + }, + _ => ControlFlow::BREAK, + } + } else { + ControlFlow::Continue(()) + } + }); + + original_recv +} + +fn check_replace_call_with_char_slice<'tcx>( + cx: &LateContext<'tcx>, + from_arg: &'tcx hir::Expr<'tcx>, + to_arg: &'tcx hir::Expr<'tcx>, +) { + let mut has_no_var = true; + let mut char_list: Vec = Vec::new(); + // Go through the `from_arg` to collect all char literals + let _: Option<()> = for_each_expr(from_arg, |e| { + if let ExprKind::Lit(Spanned { + node: LitKind::Char(val), + .. + }) = e.kind + { + char_list.push(val); + ControlFlow::Continue(()) + } else if let ExprKind::Path(..) = e.kind { + // If a variable is found in the char slice, no lint for first version of this lint + has_no_var = false; + ControlFlow::BREAK + } else { + ControlFlow::Continue(()) + } + }); + + if has_no_var { + let to_arg_repr = match to_arg.kind { + ExprKind::Lit(Spanned { + node: LitKind::Str(to_arg_val, _), + .. + }) => { + let repr = to_arg_val.as_str(); + let double_quote = "\""; + double_quote.to_owned() + repr + double_quote + }, + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: path_segments, + .. + }, + )) => { + // join the path_segments values by "::" + let path_segment_ident_names: Vec<&str> = path_segments + .iter() + .map(|path_seg| path_seg.ident.name.as_str()) + .collect(); + + path_segment_ident_names.join("::") + }, + _ => unreachable!(), + }; + + let app = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + COLLAPSIBLE_STR_REPLACE, + from_arg.span, + "used slice of chars in `str::replace` call", + "replace with", + format!( + "replace(|c| matches!(c, {}), {})", + format_slice_of_chars_for_sugg(&char_list), + to_arg_repr, + ), + app, + ); + } +} + +fn format_slice_of_chars_for_sugg(chars: &Vec) -> String { + let single_quoted_chars: Vec = chars + .iter() + .map(|c| "'".to_owned() + &c.to_string() + &"'".to_owned()) + .collect(); + single_quoted_chars.join(" | ") +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8f7cb105c22..ec5d5402b0e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3519,7 +3519,7 @@ impl Methods { ("sort_unstable_by", [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, - ("replace", [_, _]) => collapsible_str_replace::check(cx, expr, recv, args), + ("replace", [_, _]) => collapsible_str_replace::check(cx, expr, name, recv, args), ("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); diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index 0f4bdf09480..943fb4473bb 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -10,6 +10,7 @@ fn main() { let p = 'p'; let s = 's'; let u = 'u'; + let l = "l"; // LINT CASES // If the first argument to a single `str::replace` call is a slice and none of the chars @@ -17,6 +18,20 @@ fn main() { let replacement = misspelled.replace(&['s', 'u', 'p'], "l"); println!("{replacement}"); + let replacement = misspelled.replace(&['s', 'u', 'p'], l); + println!("{replacement}"); + + // If multiple `str::replace` calls contain slices and none of the chars are variables, + // recommend `collapsible_str_replace` + let replacement = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); + println!("{replacement}"); + + let replacement = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); + println!("replacement"); + // If there are consecutive calls to `str::replace` and none of the chars are variables, // recommend `collapsible_str_replace` let replacement = misspelled.replace('s', "l").replace('u', "l"); @@ -38,18 +53,6 @@ fn main() { let replacement = misspelled.replace(&get_filter(), "l"); // NO LINT TIL IMPROVEMENT - // If multiple `str::replace` calls contain slices and none of the chars are variables, - // the first iteration does not recommend `collapsible_str_replace` - let replacement = misspelled.replace(&['s', 'u', 'p'], "l").replace(&['s', 'p'], "l"); - println!("{replacement}"); - - // If a mixture of `str::replace` calls with slice and char arguments are used for `from` arg, - // the first iteration does not recommend `collapsible_str_replace` - let replacement = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); - println!("replacement"); - - let replacement = misspelled.replace('p', "l").replace(&['s', 'u'], "l"); - // The first iteration of `collapsible_str_replace` will not create lint if the first argument to // a single `str::replace` call is a slice and one or more of its chars are variables let replacement = misspelled.replace(&['s', u, 'p'], "l"); -- cgit 1.4.1-3-g733a5 From a9bd0bd3214f04e5f3df9cc5cd9f6ecd375e6242 Mon Sep 17 00:00:00 2001 From: Nahua Kang Date: Sun, 7 Aug 2022 14:08:09 +0200 Subject: Handle repeated str::replace calls with single char kind to str --- .../src/methods/collapsible_str_replace.rs | 337 +++++++++++++++------ clippy_lints/src/methods/mod.rs | 8 +- tests/ui/collapsible_str_replace.rs | 4 + 3 files changed, 258 insertions(+), 91 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index e2477fb06bd..b4e97a3bea4 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,17 +1,16 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -// use clippy_utils::source::snippet_with_context; +use clippy_utils::get_parent_expr; use clippy_utils::visitors::for_each_expr; use core::ops::ControlFlow; use if_chain::if_chain; use rustc_ast::ast::LitKind; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::*; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Spanned; -use std::unreachable; -// use rustc_span::Span; use super::method_call; use super::COLLAPSIBLE_STR_REPLACE; @@ -25,28 +24,46 @@ pub(super) fn check<'tcx>( ) { match (name, args) { ("replace", [from, to]) => { - // Check for `str::replace` calls with char slice for linting + // The receiver of the method call must be `str` type to lint `collapsible_str_replace` let original_recv = find_original_recv(recv); - let original_recv_ty = cx.typeck_results().expr_ty(original_recv).peel_refs(); + let original_recv_ty_kind = cx.typeck_results().expr_ty(original_recv).peel_refs().kind(); + let original_recv_is_str_kind = matches!(original_recv_ty_kind, ty::Str); + if_chain! { - // Check the receiver of the method call is `str` type - if matches!(original_recv_ty.kind(), ty::Str); - let from_ty = cx.typeck_results().expr_ty(from).peel_refs(); - if let ty::Array(array_ty, _) = from_ty.kind(); + // Check for `str::replace` calls with char slice for linting + if original_recv_is_str_kind; + let from_ty_kind = cx.typeck_results().expr_ty(from).peel_refs().kind(); + if let ty::Array(array_ty, _) = from_ty_kind; if matches!(array_ty.kind(), ty::Char); then { check_replace_call_with_char_slice(cx, from, to); + return; + } + } + + if_chain! { + if original_recv_is_str_kind; + if let Some(parent) = get_parent_expr(cx, expr); + if let Some((name, [..], _)) = method_call(parent); + + then { + match name { + "replace" => return, + _ => { + check_consecutive_replace_calls(cx, expr); + return; + }, + } } } match method_call(recv) { // Check if there's an earlier `str::replace` call - Some(("replace", [prev_recv, prev_from, prev_to], prev_span)) => { - println!("Consecutive replace calls"); - // Check that the original receiver is of `ty::Str` type - // Check that all the `from` args are char literals - // Check that all the `to` args are the same variable or has the same &str value - // If so, then lint + Some(("replace", [_, _, _], _)) => { + if original_recv_is_str_kind { + check_consecutive_replace_calls(cx, expr); + return; + } }, _ => {}, } @@ -55,100 +72,246 @@ pub(super) fn check<'tcx>( } } -fn find_original_recv<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> &'tcx hir::Expr<'tcx> { - let mut original_recv = recv; - - let _: Option<()> = for_each_expr(recv, |e| { - if let Some((name, [prev_recv, args @ ..], _)) = method_call(e) { - match (name, args) { - ("replace", [_, _]) => { - original_recv = prev_recv; - ControlFlow::Continue(()) - }, - _ => ControlFlow::BREAK, - } - } else { - ControlFlow::Continue(()) - } - }); - - original_recv -} - +/// Check a `str::replace` call that contains a char slice as `from` argument for +/// `collapsible_str_replace` lint. fn check_replace_call_with_char_slice<'tcx>( cx: &LateContext<'tcx>, from_arg: &'tcx hir::Expr<'tcx>, to_arg: &'tcx hir::Expr<'tcx>, ) { - let mut has_no_var = true; - let mut char_list: Vec = Vec::new(); + let mut char_slice_has_no_variables = true; + let mut chars: Vec = Vec::new(); + // Go through the `from_arg` to collect all char literals let _: Option<()> = for_each_expr(from_arg, |e| { if let ExprKind::Lit(Spanned { - node: LitKind::Char(val), - .. + node: LitKind::Char(_), .. }) = e.kind { - char_list.push(val); + chars.push(get_replace_call_char_arg_repr(e).unwrap()); ControlFlow::Continue(()) } else if let ExprKind::Path(..) = e.kind { // If a variable is found in the char slice, no lint for first version of this lint - has_no_var = false; + char_slice_has_no_variables = false; ControlFlow::BREAK } else { ControlFlow::Continue(()) } }); - if has_no_var { - let to_arg_repr = match to_arg.kind { - ExprKind::Lit(Spanned { - node: LitKind::Str(to_arg_val, _), - .. - }) => { - let repr = to_arg_val.as_str(); - let double_quote = "\""; - double_quote.to_owned() + repr + double_quote - }, - ExprKind::Path(QPath::Resolved( - _, - Path { - segments: path_segments, - .. + if char_slice_has_no_variables { + if let Some(to_arg_repr) = get_replace_call_char_arg_repr(to_arg) { + let app = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + COLLAPSIBLE_STR_REPLACE, + from_arg.span, + "used slice of chars in `str::replace` call", + "replace with", + format!("replace(|c| matches!(c, {}), {})", chars.join(" | "), to_arg_repr,), + app, + ); + } + } +} + +/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint. +fn check_consecutive_replace_calls<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if_chain! { + if let Some(from_args) = get_replace_call_from_args_if_all_char_ty(cx, expr); + if let Some(to_arg) = get_replace_call_unique_to_arg_repr(expr); + then { + if replace_call_from_args_are_only_lit_chars(&from_args) { + let from_arg_reprs: Vec = from_args.iter().map(|from_arg| { + get_replace_call_char_arg_repr(from_arg).unwrap() + }).collect(); + let app = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + COLLAPSIBLE_STR_REPLACE, + expr.span, + "used consecutive `str::replace` call", + "replace with", + format!( + "replace(|c| matches!(c, {}), {})", + from_arg_reprs.join(" | "), + to_arg, + ), + app, + ); + } else { + // Use fallback lint + let from_arg_reprs: Vec = from_args.iter().map(|from_arg| { + get_replace_call_char_arg_repr(from_arg).unwrap() + }).collect(); + let app = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + COLLAPSIBLE_STR_REPLACE, + expr.span, + "used consecutive `str::replace` call", + "replace with", + format!( + "replace(&[{}], {})", + from_arg_reprs.join(" , "), + to_arg, + ), + app, + ); + } + } + } +} + +/// Check if all the `from` arguments of a chain of consecutive calls to `str::replace` +/// are all of `ExprKind::Lit` types. If any is not, return false. +fn replace_call_from_args_are_only_lit_chars<'tcx>(from_args: &Vec<&'tcx hir::Expr<'tcx>>) -> bool { + let mut only_lit_chars = true; + + for from_arg in from_args.iter() { + match from_arg.kind { + ExprKind::Lit(..) => {}, + _ => only_lit_chars = false, + } + } + + only_lit_chars +} + +/// Collect and return all of the `from` arguments of a chain of consecutive `str::replace` calls +/// if these `from` arguments's expressions are of the `ty::Char` kind. Otherwise return `None`. +fn get_replace_call_from_args_if_all_char_ty<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, +) -> Option>> { + let mut all_from_args_are_chars = true; + let mut from_args = Vec::new(); + + let _: Option<()> = for_each_expr(expr, |e| { + if let Some((name, [_, args @ ..], _)) = method_call(e) { + match (name, args) { + ("replace", [from, _]) => { + let from_ty_kind = cx.typeck_results().expr_ty(from).peel_refs().kind(); + if matches!(from_ty_kind, ty::Char) { + from_args.push(from); + } else { + all_from_args_are_chars = false; + } + ControlFlow::Continue(()) }, - )) => { - // join the path_segments values by "::" - let path_segment_ident_names: Vec<&str> = path_segments - .iter() - .map(|path_seg| path_seg.ident.name.as_str()) - .collect(); - - path_segment_ident_names.join("::") + _ => ControlFlow::BREAK, + } + } else { + ControlFlow::Continue(()) + } + }); + + if all_from_args_are_chars { + return Some(from_args); + } else { + return None; + } +} + +/// Return a unique String representation of the `to` argument used in a chain of `str::replace` +/// calls if each `str::replace` call's `to` argument is identical to the other `to` arguments in +/// the chain. Otherwise, return `None`. +fn get_replace_call_unique_to_arg_repr<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option { + let mut to_args = Vec::new(); + + let _: Option<()> = for_each_expr(expr, |e| { + if let Some((name, [_, args @ ..], _)) = method_call(e) { + match (name, args) { + ("replace", [_, to]) => { + to_args.push(to); + ControlFlow::Continue(()) + }, + _ => ControlFlow::BREAK, + } + } else { + ControlFlow::Continue(()) + } + }); + + // let mut to_arg_repr_set = FxHashSet::default(); + let mut to_arg_reprs = Vec::new(); + for &to_arg in to_args.iter() { + if let Some(to_arg_repr) = get_replace_call_char_arg_repr(to_arg) { + to_arg_reprs.push(to_arg_repr); + } + } + + let to_arg_repr_set = FxHashSet::from_iter(to_arg_reprs.iter().cloned()); + // Check if the set of `to` argument representations has more than one unique value + if to_arg_repr_set.len() != 1 { + return None; + } + + // Return the single representation value + to_arg_reprs.pop() +} + +/// Get the representation of an argument of a `str::replace` call either of the literal char value +/// or variable name, i.e. the resolved path segments `ident`. +/// Return: +/// - the str literal with double quotes, e.g. "\"l\"" +/// - the char literal with single quotes, e.g. "'l'" +/// - the variable as a String, e.g. "l" +fn get_replace_call_char_arg_repr<'tcx>(arg: &'tcx hir::Expr<'tcx>) -> Option { + match arg.kind { + ExprKind::Lit(Spanned { + node: LitKind::Str(to_arg_val, _), + .. + }) => { + let repr = to_arg_val.as_str(); + let double_quote = "\""; + Some(double_quote.to_owned() + repr + double_quote) + }, + ExprKind::Lit(Spanned { + node: LitKind::Char(to_arg_val), + .. + }) => { + let repr = to_arg_val.to_string(); + let double_quote = "\'"; + Some(double_quote.to_owned() + &repr + double_quote) + }, + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: path_segments, + .. }, - _ => unreachable!(), - }; - - let app = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - COLLAPSIBLE_STR_REPLACE, - from_arg.span, - "used slice of chars in `str::replace` call", - "replace with", - format!( - "replace(|c| matches!(c, {}), {})", - format_slice_of_chars_for_sugg(&char_list), - to_arg_repr, - ), - app, - ); + )) => { + // join the path_segments values by "::" + let path_segment_ident_names: Vec<&str> = path_segments + .iter() + .map(|path_seg| path_seg.ident.name.as_str()) + .collect(); + Some(path_segment_ident_names.join("::")) + }, + _ => None, } } -fn format_slice_of_chars_for_sugg(chars: &Vec) -> String { - let single_quoted_chars: Vec = chars - .iter() - .map(|c| "'".to_owned() + &c.to_string() + &"'".to_owned()) - .collect(); - single_quoted_chars.join(" | ") +/// Find the original receiver of a chain of `str::replace` method calls. +fn find_original_recv<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> &'tcx hir::Expr<'tcx> { + let mut original_recv = recv; + + let _: Option<()> = for_each_expr(recv, |e| { + if let Some((name, [prev_recv, args @ ..], _)) = method_call(e) { + match (name, args) { + ("replace", [_, _]) => { + original_recv = prev_recv; + ControlFlow::Continue(()) + }, + _ => ControlFlow::BREAK, + } + } else { + ControlFlow::Continue(()) + } + }); + + original_recv } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ec5d5402b0e..f9358693623 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3519,7 +3519,10 @@ impl Methods { ("sort_unstable_by", [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, - ("replace", [_, _]) => collapsible_str_replace::check(cx, expr, name, recv, args), + ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { + no_effect_replace::check(cx, expr, arg1, arg2); + collapsible_str_replace::check(cx, expr, name, recv, args); + }, ("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); @@ -3585,9 +3588,6 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); }, }, - ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { - no_effect_replace::check(cx, expr, arg1, arg2); - }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind && name.ident.name == sym::iter diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index 943fb4473bb..4257fce448d 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -49,6 +49,10 @@ fn main() { let replacement = misspelled.replace(s, "l"); println!("{replacement}"); + // If the consecutive `str::replace` calls have different `to` arguments, do not lint + let replacement = misspelled.replace('s', "l").replace('u', "p"); + println!("{replacement}"); + // If the `from` argument is of kind other than a slice or a char, do not lint let replacement = misspelled.replace(&get_filter(), "l"); -- cgit 1.4.1-3-g733a5 From c989746ccfae22dd0f7f6d1e3d4f984ac8889e9f Mon Sep 17 00:00:00 2001 From: Nahua Kang Date: Mon, 8 Aug 2022 22:02:26 +0200 Subject: Remove checks on char slice; improve lint suggestion --- .../src/methods/collapsible_str_replace.rs | 89 +++++++--------------- tests/ui/collapsible_str_replace.rs | 61 ++++++++------- 2 files changed, 59 insertions(+), 91 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index b4e97a3bea4..1760232041a 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -11,6 +11,7 @@ use rustc_hir::*; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Spanned; +use rustc_span::Span; use super::method_call; use super::COLLAPSIBLE_STR_REPLACE; @@ -23,31 +24,20 @@ pub(super) fn check<'tcx>( args: &'tcx [hir::Expr<'tcx>], ) { match (name, args) { - ("replace", [from, to]) => { + ("replace", ..) => { // The receiver of the method call must be `str` type to lint `collapsible_str_replace` let original_recv = find_original_recv(recv); let original_recv_ty_kind = cx.typeck_results().expr_ty(original_recv).peel_refs().kind(); let original_recv_is_str_kind = matches!(original_recv_ty_kind, ty::Str); - if_chain! { - // Check for `str::replace` calls with char slice for linting - if original_recv_is_str_kind; - let from_ty_kind = cx.typeck_results().expr_ty(from).peel_refs().kind(); - if let ty::Array(array_ty, _) = from_ty_kind; - if matches!(array_ty.kind(), ty::Char); - then { - check_replace_call_with_char_slice(cx, from, to); - return; - } - } - if_chain! { if original_recv_is_str_kind; if let Some(parent) = get_parent_expr(cx, expr); - if let Some((name, [..], _)) = method_call(parent); + if let Some((name, ..)) = method_call(parent); then { match name { + // If the parent node is a `str::replace` call, we've already handled the lint, don't lint again "replace" => return, _ => { check_consecutive_replace_calls(cx, expr); @@ -59,7 +49,7 @@ pub(super) fn check<'tcx>( match method_call(recv) { // Check if there's an earlier `str::replace` call - Some(("replace", [_, _, _], _)) => { + Some(("replace", ..)) => { if original_recv_is_str_kind { check_consecutive_replace_calls(cx, expr); return; @@ -72,55 +62,14 @@ pub(super) fn check<'tcx>( } } -/// Check a `str::replace` call that contains a char slice as `from` argument for -/// `collapsible_str_replace` lint. -fn check_replace_call_with_char_slice<'tcx>( - cx: &LateContext<'tcx>, - from_arg: &'tcx hir::Expr<'tcx>, - to_arg: &'tcx hir::Expr<'tcx>, -) { - let mut char_slice_has_no_variables = true; - let mut chars: Vec = Vec::new(); - - // Go through the `from_arg` to collect all char literals - let _: Option<()> = for_each_expr(from_arg, |e| { - if let ExprKind::Lit(Spanned { - node: LitKind::Char(_), .. - }) = e.kind - { - chars.push(get_replace_call_char_arg_repr(e).unwrap()); - ControlFlow::Continue(()) - } else if let ExprKind::Path(..) = e.kind { - // If a variable is found in the char slice, no lint for first version of this lint - char_slice_has_no_variables = false; - ControlFlow::BREAK - } else { - ControlFlow::Continue(()) - } - }); - - if char_slice_has_no_variables { - if let Some(to_arg_repr) = get_replace_call_char_arg_repr(to_arg) { - let app = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - COLLAPSIBLE_STR_REPLACE, - from_arg.span, - "used slice of chars in `str::replace` call", - "replace with", - format!("replace(|c| matches!(c, {}), {})", chars.join(" | "), to_arg_repr,), - app, - ); - } - } -} - /// Check a chain of `str::replace` calls for `collapsible_str_replace` lint. fn check_consecutive_replace_calls<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if_chain! { if let Some(from_args) = get_replace_call_from_args_if_all_char_ty(cx, expr); if let Some(to_arg) = get_replace_call_unique_to_arg_repr(expr); then { + let earliest_replace_call_span = get_earliest_replace_call_span(expr); + if replace_call_from_args_are_only_lit_chars(&from_args) { let from_arg_reprs: Vec = from_args.iter().map(|from_arg| { get_replace_call_char_arg_repr(from_arg).unwrap() @@ -130,7 +79,7 @@ fn check_consecutive_replace_calls<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir span_lint_and_sugg( cx, COLLAPSIBLE_STR_REPLACE, - expr.span, + expr.span.with_lo(earliest_replace_call_span.lo()), "used consecutive `str::replace` call", "replace with", format!( @@ -150,7 +99,7 @@ fn check_consecutive_replace_calls<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir span_lint_and_sugg( cx, COLLAPSIBLE_STR_REPLACE, - expr.span, + expr.span.with_lo(earliest_replace_call_span.lo()), "used consecutive `str::replace` call", "replace with", format!( @@ -295,6 +244,26 @@ fn get_replace_call_char_arg_repr<'tcx>(arg: &'tcx hir::Expr<'tcx>) -> Option(expr: &'tcx hir::Expr<'tcx>) -> Span { + let mut earliest_replace_call_span = expr.span; + + let _: Option<()> = for_each_expr(expr, |e| { + if let Some((name, [_, args @ ..], span)) = method_call(e) { + match (name, args) { + ("replace", [_, _]) => { + earliest_replace_call_span = span; + ControlFlow::Continue(()) + }, + _ => ControlFlow::BREAK, + } + } else { + ControlFlow::Continue(()) + } + }); + + earliest_replace_call_span +} + /// Find the original receiver of a chain of `str::replace` method calls. fn find_original_recv<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> &'tcx hir::Expr<'tcx> { let mut original_recv = recv; diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index 4257fce448d..05a4fd08a32 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -13,36 +13,38 @@ fn main() { let l = "l"; // LINT CASES - // If the first argument to a single `str::replace` call is a slice and none of the chars - // are variables, recommend `collapsible_str_replace` - let replacement = misspelled.replace(&['s', 'u', 'p'], "l"); + let replacement = misspelled.replace('s', "l").replace('u', "l"); println!("{replacement}"); - let replacement = misspelled.replace(&['s', 'u', 'p'], l); + let replacement = misspelled.replace('s', l).replace('u', l); println!("{replacement}"); - // If multiple `str::replace` calls contain slices and none of the chars are variables, - // recommend `collapsible_str_replace` - let replacement = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); + let replacement = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); println!("{replacement}"); - let replacement = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); + let replacement = misspelled + .replace('s', "l") + .replace('u', "l") + .replace('p', "l") + .replace('d', "l"); println!("{replacement}"); - let replacement = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); - println!("replacement"); + // FALLBACK CASES + // If there are consecutive calls to `str::replace` and all or any chars are variables, + // recommend the fallback `misspelled.replace(&[s, u, p], "l")` + let replacement = misspelled.replace(s, "l").replace('u', "l"); + println!("{replacement}"); - // If there are consecutive calls to `str::replace` and none of the chars are variables, - // recommend `collapsible_str_replace` - let replacement = misspelled.replace('s', "l").replace('u', "l"); + let replacement = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); println!("{replacement}"); - let replacement = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); + let replacement = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); + println!("{replacement}"); + + let replacement = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); println!("{replacement}"); // NO LINT CASES - // If there is a single call to `str::replace` and the first argument is a char or a variable, - // do not recommend `collapsible_str_replace` let replacement = misspelled.replace('s', "l"); println!("{replacement}"); @@ -53,36 +55,33 @@ fn main() { let replacement = misspelled.replace('s', "l").replace('u', "p"); println!("{replacement}"); - // If the `from` argument is of kind other than a slice or a char, do not lint let replacement = misspelled.replace(&get_filter(), "l"); + println!("{replacement}"); - // NO LINT TIL IMPROVEMENT - // The first iteration of `collapsible_str_replace` will not create lint if the first argument to - // a single `str::replace` call is a slice and one or more of its chars are variables - let replacement = misspelled.replace(&['s', u, 'p'], "l"); + let replacement = misspelled.replace(&['s', 'u', 'p'], "l"); println!("{replacement}"); - let replacement = misspelled.replace(&[s, u, 'p'], "l"); + let replacement = misspelled.replace(&['s', 'u', 'p'], l); println!("{replacement}"); - let replacement = misspelled.replace(&[s, u, p], "l"); + let replacement = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); println!("{replacement}"); - let replacement = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); + let replacement = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); println!("{replacement}"); - // FALLBACK CASES - // If there are consecutive calls to `str::replace` and all or any chars are variables, - // recommend the fallback `misspelled.replace(&[s, u, p], "l")` - let replacement = misspelled.replace(s, "l").replace('u', "l"); + let replacement = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); + println!("replacement"); + + let replacement = misspelled.replace(&['s', u, 'p'], "l"); println!("{replacement}"); - let replacement = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); + let replacement = misspelled.replace(&[s, u, 'p'], "l"); println!("{replacement}"); - let replacement = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); + let replacement = misspelled.replace(&[s, u, p], "l"); println!("{replacement}"); - let replacement = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); + let replacement = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); println!("{replacement}"); } -- cgit 1.4.1-3-g733a5 From fb30b64f6379eb22880d70bfebce66ceccc75269 Mon Sep 17 00:00:00 2001 From: Nahua Kang Date: Mon, 8 Aug 2022 22:31:53 +0200 Subject: Adjust test cases; run cargo dev bless --- .../src/methods/collapsible_str_replace.rs | 65 +++++++++------------- clippy_lints/src/methods/mod.rs | 6 +- tests/ui/collapsible_str_replace.fixed | 65 ++++++++++++++++++++++ tests/ui/collapsible_str_replace.rs | 65 ++++++++-------------- tests/ui/collapsible_str_replace.stderr | 56 +++++++++++++++++++ 5 files changed, 174 insertions(+), 83 deletions(-) create mode 100644 tests/ui/collapsible_str_replace.fixed create mode 100644 tests/ui/collapsible_str_replace.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 1760232041a..4c6288e798c 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,3 +1,5 @@ +// run-rustfix + use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::visitors::for_each_expr; @@ -7,7 +9,7 @@ use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::*; +use rustc_hir::{ExprKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -21,44 +23,31 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'tcx>, name: &str, recv: &'tcx hir::Expr<'tcx>, - args: &'tcx [hir::Expr<'tcx>], ) { - match (name, args) { - ("replace", ..) => { - // The receiver of the method call must be `str` type to lint `collapsible_str_replace` - let original_recv = find_original_recv(recv); - let original_recv_ty_kind = cx.typeck_results().expr_ty(original_recv).peel_refs().kind(); - let original_recv_is_str_kind = matches!(original_recv_ty_kind, ty::Str); + if name == "replace" { + // The receiver of the method call must be `str` type to lint `collapsible_str_replace` + let original_recv = find_original_recv(recv); + let original_recv_ty_kind = cx.typeck_results().expr_ty(original_recv).peel_refs().kind(); + let original_recv_is_str_kind = matches!(original_recv_ty_kind, ty::Str); - if_chain! { - if original_recv_is_str_kind; - if let Some(parent) = get_parent_expr(cx, expr); - if let Some((name, ..)) = method_call(parent); + if_chain! { + if original_recv_is_str_kind; + if let Some(parent) = get_parent_expr(cx, expr); + if let Some((name, ..)) = method_call(parent); + if name == "replace"; - then { - match name { - // If the parent node is a `str::replace` call, we've already handled the lint, don't lint again - "replace" => return, - _ => { - check_consecutive_replace_calls(cx, expr); - return; - }, - } - } + then { + // If the parent node is a `str::replace` call, we've already handled the lint, don't lint again + return; } + } - match method_call(recv) { - // Check if there's an earlier `str::replace` call - Some(("replace", ..)) => { - if original_recv_is_str_kind { - check_consecutive_replace_calls(cx, expr); - return; - } - }, - _ => {}, + if let Some(("replace", ..)) = method_call(recv) { + // Check if there's an earlier `str::replace` call + if original_recv_is_str_kind { + check_consecutive_replace_calls(cx, expr); } - }, - _ => {}, + } } } @@ -116,7 +105,7 @@ fn check_consecutive_replace_calls<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir /// Check if all the `from` arguments of a chain of consecutive calls to `str::replace` /// are all of `ExprKind::Lit` types. If any is not, return false. -fn replace_call_from_args_are_only_lit_chars<'tcx>(from_args: &Vec<&'tcx hir::Expr<'tcx>>) -> bool { +fn replace_call_from_args_are_only_lit_chars<'tcx>(from_args: &[&'tcx hir::Expr<'tcx>]) -> bool { let mut only_lit_chars = true; for from_arg in from_args.iter() { @@ -159,9 +148,9 @@ fn get_replace_call_from_args_if_all_char_ty<'tcx>( if all_from_args_are_chars { return Some(from_args); - } else { - return None; } + + None } /// Return a unique String representation of the `to` argument used in a chain of `str::replace` @@ -186,13 +175,13 @@ fn get_replace_call_unique_to_arg_repr<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Opt // let mut to_arg_repr_set = FxHashSet::default(); let mut to_arg_reprs = Vec::new(); - for &to_arg in to_args.iter() { + for &to_arg in &to_args { if let Some(to_arg_repr) = get_replace_call_char_arg_repr(to_arg) { to_arg_reprs.push(to_arg_repr); } } - let to_arg_repr_set = FxHashSet::from_iter(to_arg_reprs.iter().cloned()); + let to_arg_repr_set = to_arg_reprs.iter().cloned().collect::>(); // Check if the set of `to` argument representations has more than one unique value if to_arg_repr_set.len() != 1 { return None; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f9358693623..8b2fa8e9457 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -152,11 +152,11 @@ declare_clippy_lint! { /// let hello = "hesuo worpd" /// .replace('s', "l") /// .replace("u", "l") - /// .replace('p', "l") + /// .replace('p', "l"); /// ``` /// Use instead: /// ```rust - /// let hello = "hesuo worpd".replace(|c| matches!(c, 's' | 'u' | 'p'), "l") + /// let hello = "hesuo worpd".replace(|c| matches!(c, 's' | 'u' | 'p'), "l"); /// ``` #[clippy::version = "1.64.0"] pub COLLAPSIBLE_STR_REPLACE, @@ -3521,7 +3521,7 @@ impl Methods { }, ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { no_effect_replace::check(cx, expr, arg1, arg2); - collapsible_str_replace::check(cx, expr, name, recv, args); + collapsible_str_replace::check(cx, expr, name, recv); }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed new file mode 100644 index 00000000000..0bf857d9837 --- /dev/null +++ b/tests/ui/collapsible_str_replace.fixed @@ -0,0 +1,65 @@ +// run-rustfix + +#![warn(clippy::collapsible_str_replace)] + +fn get_filter() -> &'static str { + "u" +} + +fn main() { + let misspelled = "hesuo worpd"; + + let p = 'p'; + let s = 's'; + let u = 'u'; + let l = "l"; + + // LINT CASES + let _ = misspelled.replace(|c| matches!(c, 'u' | 's'), "l"); + + let _ = misspelled.replace(|c| matches!(c, 'u' | 's'), l); + + let _ = misspelled.replace(|c| matches!(c, 'p' | 'u' | 's'), "l"); + + let _ = misspelled + .replace(|c| matches!(c, 'd' | 'p' | 'u' | 's'), "l"); + + // FALLBACK CASES + // If there are consecutive calls to `str::replace` and all or any chars are variables, + // recommend the fallback `misspelled.replace(&[s, u, p], "l")` + let _ = misspelled.replace(&['u' , s], "l"); + + let _ = misspelled.replace(&['p' , 'u' , s], "l"); + + let _ = misspelled.replace(&['p' , u , s], "l"); + + let _ = misspelled.replace(&[p , u , s], "l"); + + // NO LINT CASES + let _ = misspelled.replace('s', "l"); + + let _ = misspelled.replace(s, "l"); + + // If the consecutive `str::replace` calls have different `to` arguments, do not lint + let _ = misspelled.replace('s', "l").replace('u', "p"); + + let _ = misspelled.replace(&get_filter(), "l"); + + let _ = misspelled.replace(&['s', 'u', 'p'], "l"); + + let _ = misspelled.replace(&['s', 'u', 'p'], l); + + let _ = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); + + let _ = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); + + let _ = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); + + let _ = misspelled.replace(&['s', u, 'p'], "l"); + + let _ = misspelled.replace(&[s, u, 'p'], "l"); + + let _ = misspelled.replace(&[s, u, p], "l"); + + let _ = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); +} diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index 05a4fd08a32..45d9fd87e5e 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![warn(clippy::collapsible_str_replace)] fn get_filter() -> &'static str { @@ -13,75 +15,54 @@ fn main() { let l = "l"; // LINT CASES - let replacement = misspelled.replace('s', "l").replace('u', "l"); - println!("{replacement}"); + let _ = misspelled.replace('s', "l").replace('u', "l"); - let replacement = misspelled.replace('s', l).replace('u', l); - println!("{replacement}"); + let _ = misspelled.replace('s', l).replace('u', l); - let replacement = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); - println!("{replacement}"); + let _ = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); - let replacement = misspelled + let _ = misspelled .replace('s', "l") .replace('u', "l") .replace('p', "l") .replace('d', "l"); - println!("{replacement}"); // FALLBACK CASES // If there are consecutive calls to `str::replace` and all or any chars are variables, // recommend the fallback `misspelled.replace(&[s, u, p], "l")` - let replacement = misspelled.replace(s, "l").replace('u', "l"); - println!("{replacement}"); + let _ = misspelled.replace(s, "l").replace('u', "l"); - let replacement = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); - println!("{replacement}"); + let _ = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); - let replacement = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); - println!("{replacement}"); + let _ = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); - let replacement = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); - println!("{replacement}"); + let _ = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); // NO LINT CASES - let replacement = misspelled.replace('s', "l"); - println!("{replacement}"); + let _ = misspelled.replace('s', "l"); - let replacement = misspelled.replace(s, "l"); - println!("{replacement}"); + let _ = misspelled.replace(s, "l"); // If the consecutive `str::replace` calls have different `to` arguments, do not lint - let replacement = misspelled.replace('s', "l").replace('u', "p"); - println!("{replacement}"); + let _ = misspelled.replace('s', "l").replace('u', "p"); - let replacement = misspelled.replace(&get_filter(), "l"); - println!("{replacement}"); + let _ = misspelled.replace(&get_filter(), "l"); - let replacement = misspelled.replace(&['s', 'u', 'p'], "l"); - println!("{replacement}"); + let _ = misspelled.replace(&['s', 'u', 'p'], "l"); - let replacement = misspelled.replace(&['s', 'u', 'p'], l); - println!("{replacement}"); + let _ = misspelled.replace(&['s', 'u', 'p'], l); - let replacement = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); - println!("{replacement}"); + let _ = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); - let replacement = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); - println!("{replacement}"); + let _ = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); - let replacement = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); - println!("replacement"); + let _ = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); - let replacement = misspelled.replace(&['s', u, 'p'], "l"); - println!("{replacement}"); + let _ = misspelled.replace(&['s', u, 'p'], "l"); - let replacement = misspelled.replace(&[s, u, 'p'], "l"); - println!("{replacement}"); + let _ = misspelled.replace(&[s, u, 'p'], "l"); - let replacement = misspelled.replace(&[s, u, p], "l"); - println!("{replacement}"); + let _ = misspelled.replace(&[s, u, p], "l"); - let replacement = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); - println!("{replacement}"); + let _ = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); } diff --git a/tests/ui/collapsible_str_replace.stderr b/tests/ui/collapsible_str_replace.stderr new file mode 100644 index 00000000000..372fe1da448 --- /dev/null +++ b/tests/ui/collapsible_str_replace.stderr @@ -0,0 +1,56 @@ +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:18:24 + | +LL | let _ = misspelled.replace('s', "l").replace('u', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(|c| matches!(c, 'u' | 's'), "l")` + | + = note: `-D clippy::collapsible-str-replace` implied by `-D warnings` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:20:24 + | +LL | let _ = misspelled.replace('s', l).replace('u', l); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(|c| matches!(c, 'u' | 's'), l)` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:22:24 + | +LL | let _ = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(|c| matches!(c, 'p' | 'u' | 's'), "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:25:10 + | +LL | .replace('s', "l") + | __________^ +LL | | .replace('u', "l") +LL | | .replace('p', "l") +LL | | .replace('d', "l"); + | |__________________________^ help: replace with: `replace(|c| matches!(c, 'd' | 'p' | 'u' | 's'), "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:33:24 + | +LL | let _ = misspelled.replace(s, "l").replace('u', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&['u' , s], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:35:24 + | +LL | let _ = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&['p' , 'u' , s], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:37:24 + | +LL | let _ = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&['p' , u , s], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:39:24 + | +LL | let _ = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&[p , u , s], "l")` + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From b070b4045f348f9222008270a435bda17b048c15 Mon Sep 17 00:00:00 2001 From: Nahua Kang Date: Sun, 14 Aug 2022 18:33:55 +0200 Subject: Simplify lint logic and address code review comments --- .../src/methods/collapsible_str_replace.rs | 301 +++++---------------- clippy_lints/src/methods/mod.rs | 14 +- tests/ui/collapsible_str_replace.fixed | 70 ++--- tests/ui/collapsible_str_replace.rs | 68 +++-- tests/ui/collapsible_str_replace.stderr | 78 ++++-- 5 files changed, 201 insertions(+), 330 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 4c6288e798c..561033be5b6 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,19 +1,12 @@ -// run-rustfix - use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::get_parent_expr; +use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr; +use clippy_utils::{eq_expr_value, get_parent_expr}; use core::ops::ControlFlow; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{ExprKind, Path, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_span::source_map::Spanned; -use rustc_span::Span; +use std::collections::VecDeque; use super::method_call; use super::COLLAPSIBLE_STR_REPLACE; @@ -21,255 +14,83 @@ use super::COLLAPSIBLE_STR_REPLACE; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, - name: &str, - recv: &'tcx hir::Expr<'tcx>, + from: &'tcx hir::Expr<'tcx>, + to: &'tcx hir::Expr<'tcx>, ) { - if name == "replace" { - // The receiver of the method call must be `str` type to lint `collapsible_str_replace` - let original_recv = find_original_recv(recv); - let original_recv_ty_kind = cx.typeck_results().expr_ty(original_recv).peel_refs().kind(); - let original_recv_is_str_kind = matches!(original_recv_ty_kind, ty::Str); - - if_chain! { - if original_recv_is_str_kind; - if let Some(parent) = get_parent_expr(cx, expr); - if let Some((name, ..)) = method_call(parent); - if name == "replace"; - - then { - // If the parent node is a `str::replace` call, we've already handled the lint, don't lint again - return; - } + let replace_methods = collect_replace_calls(cx, expr, to); + if replace_methods.methods.len() > 1 { + let from_kind = cx.typeck_results().expr_ty(from).peel_refs().kind(); + // If the parent node's `to` argument is the same as the `to` argument + // of the last replace call in the current chain, don't lint as it was already linted + if let Some(parent) = get_parent_expr(cx, expr) + && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent) + && eq_expr_value(cx, to, current_to) + && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() + { + return; } - if let Some(("replace", ..)) = method_call(recv) { - // Check if there's an earlier `str::replace` call - if original_recv_is_str_kind { - check_consecutive_replace_calls(cx, expr); - } - } + check_consecutive_replace_calls(cx, expr, &replace_methods, to); } } -/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint. -fn check_consecutive_replace_calls<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if_chain! { - if let Some(from_args) = get_replace_call_from_args_if_all_char_ty(cx, expr); - if let Some(to_arg) = get_replace_call_unique_to_arg_repr(expr); - then { - let earliest_replace_call_span = get_earliest_replace_call_span(expr); - - if replace_call_from_args_are_only_lit_chars(&from_args) { - let from_arg_reprs: Vec = from_args.iter().map(|from_arg| { - get_replace_call_char_arg_repr(from_arg).unwrap() - }).collect(); - let app = Applicability::MachineApplicable; - - span_lint_and_sugg( - cx, - COLLAPSIBLE_STR_REPLACE, - expr.span.with_lo(earliest_replace_call_span.lo()), - "used consecutive `str::replace` call", - "replace with", - format!( - "replace(|c| matches!(c, {}), {})", - from_arg_reprs.join(" | "), - to_arg, - ), - app, - ); - } else { - // Use fallback lint - let from_arg_reprs: Vec = from_args.iter().map(|from_arg| { - get_replace_call_char_arg_repr(from_arg).unwrap() - }).collect(); - let app = Applicability::MachineApplicable; - - span_lint_and_sugg( - cx, - COLLAPSIBLE_STR_REPLACE, - expr.span.with_lo(earliest_replace_call_span.lo()), - "used consecutive `str::replace` call", - "replace with", - format!( - "replace(&[{}], {})", - from_arg_reprs.join(" , "), - to_arg, - ), - app, - ); - } - } - } +struct ReplaceMethods<'tcx> { + methods: VecDeque<&'tcx hir::Expr<'tcx>>, + from_args: VecDeque<&'tcx hir::Expr<'tcx>>, } -/// Check if all the `from` arguments of a chain of consecutive calls to `str::replace` -/// are all of `ExprKind::Lit` types. If any is not, return false. -fn replace_call_from_args_are_only_lit_chars<'tcx>(from_args: &[&'tcx hir::Expr<'tcx>]) -> bool { - let mut only_lit_chars = true; - - for from_arg in from_args.iter() { - match from_arg.kind { - ExprKind::Lit(..) => {}, - _ => only_lit_chars = false, - } - } - - only_lit_chars -} - -/// Collect and return all of the `from` arguments of a chain of consecutive `str::replace` calls -/// if these `from` arguments's expressions are of the `ty::Char` kind. Otherwise return `None`. -fn get_replace_call_from_args_if_all_char_ty<'tcx>( +fn collect_replace_calls<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, -) -> Option>> { - let mut all_from_args_are_chars = true; - let mut from_args = Vec::new(); + to_arg: &'tcx hir::Expr<'tcx>, +) -> ReplaceMethods<'tcx> { + let mut methods = VecDeque::new(); + let mut from_args = VecDeque::new(); let _: Option<()> = for_each_expr(expr, |e| { - if let Some((name, [_, args @ ..], _)) = method_call(e) { - match (name, args) { - ("replace", [from, _]) => { - let from_ty_kind = cx.typeck_results().expr_ty(from).peel_refs().kind(); - if matches!(from_ty_kind, ty::Char) { - from_args.push(from); - } else { - all_from_args_are_chars = false; - } - ControlFlow::Continue(()) - }, - _ => ControlFlow::BREAK, - } - } else { - ControlFlow::Continue(()) - } - }); - - if all_from_args_are_chars { - return Some(from_args); - } - - None -} - -/// Return a unique String representation of the `to` argument used in a chain of `str::replace` -/// calls if each `str::replace` call's `to` argument is identical to the other `to` arguments in -/// the chain. Otherwise, return `None`. -fn get_replace_call_unique_to_arg_repr<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option { - let mut to_args = Vec::new(); - - let _: Option<()> = for_each_expr(expr, |e| { - if let Some((name, [_, args @ ..], _)) = method_call(e) { - match (name, args) { - ("replace", [_, to]) => { - to_args.push(to); - ControlFlow::Continue(()) - }, - _ => ControlFlow::BREAK, + if let Some(("replace", [_, from, to], _)) = method_call(e) { + if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { + methods.push_front(e); + from_args.push_front(from); + ControlFlow::Continue(()) + } else { + ControlFlow::BREAK } } else { ControlFlow::Continue(()) } }); - // let mut to_arg_repr_set = FxHashSet::default(); - let mut to_arg_reprs = Vec::new(); - for &to_arg in &to_args { - if let Some(to_arg_repr) = get_replace_call_char_arg_repr(to_arg) { - to_arg_reprs.push(to_arg_repr); - } - } - - let to_arg_repr_set = to_arg_reprs.iter().cloned().collect::>(); - // Check if the set of `to` argument representations has more than one unique value - if to_arg_repr_set.len() != 1 { - return None; - } - - // Return the single representation value - to_arg_reprs.pop() + ReplaceMethods { methods, from_args } } -/// Get the representation of an argument of a `str::replace` call either of the literal char value -/// or variable name, i.e. the resolved path segments `ident`. -/// Return: -/// - the str literal with double quotes, e.g. "\"l\"" -/// - the char literal with single quotes, e.g. "'l'" -/// - the variable as a String, e.g. "l" -fn get_replace_call_char_arg_repr<'tcx>(arg: &'tcx hir::Expr<'tcx>) -> Option { - match arg.kind { - ExprKind::Lit(Spanned { - node: LitKind::Str(to_arg_val, _), - .. - }) => { - let repr = to_arg_val.as_str(); - let double_quote = "\""; - Some(double_quote.to_owned() + repr + double_quote) - }, - ExprKind::Lit(Spanned { - node: LitKind::Char(to_arg_val), - .. - }) => { - let repr = to_arg_val.to_string(); - let double_quote = "\'"; - Some(double_quote.to_owned() + &repr + double_quote) - }, - ExprKind::Path(QPath::Resolved( - _, - Path { - segments: path_segments, - .. - }, - )) => { - // join the path_segments values by "::" - let path_segment_ident_names: Vec<&str> = path_segments - .iter() - .map(|path_seg| path_seg.ident.name.as_str()) - .collect(); - Some(path_segment_ident_names.join("::")) - }, - _ => None, +/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint. +fn check_consecutive_replace_calls<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + replace_methods: &ReplaceMethods<'tcx>, + to_arg: &'tcx hir::Expr<'tcx>, +) { + let from_args = &replace_methods.from_args; + let from_arg_reprs: Vec = from_args + .iter() + .map(|from_arg| snippet(cx, from_arg.span, "..").to_string()) + .collect(); + let app = Applicability::MachineApplicable; + let earliest_replace_call = replace_methods.methods.front().unwrap(); + if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) { + span_lint_and_sugg( + cx, + COLLAPSIBLE_STR_REPLACE, + expr.span.with_lo(span_lo.lo()), + "used consecutive `str::replace` call", + "replace with", + format!( + "replace([{}], {})", + from_arg_reprs.join(", "), + snippet(cx, to_arg.span, ".."), + ), + app, + ); } } - -fn get_earliest_replace_call_span<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Span { - let mut earliest_replace_call_span = expr.span; - - let _: Option<()> = for_each_expr(expr, |e| { - if let Some((name, [_, args @ ..], span)) = method_call(e) { - match (name, args) { - ("replace", [_, _]) => { - earliest_replace_call_span = span; - ControlFlow::Continue(()) - }, - _ => ControlFlow::BREAK, - } - } else { - ControlFlow::Continue(()) - } - }); - - earliest_replace_call_span -} - -/// Find the original receiver of a chain of `str::replace` method calls. -fn find_original_recv<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> &'tcx hir::Expr<'tcx> { - let mut original_recv = recv; - - let _: Option<()> = for_each_expr(recv, |e| { - if let Some((name, [prev_recv, args @ ..], _)) = method_call(e) { - match (name, args) { - ("replace", [_, _]) => { - original_recv = prev_recv; - ControlFlow::Continue(()) - }, - _ => ControlFlow::BREAK, - } - } else { - ControlFlow::Continue(()) - } - }); - - original_recv -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 8b2fa8e9457..49d4900295f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -156,7 +156,7 @@ declare_clippy_lint! { /// ``` /// Use instead: /// ```rust - /// let hello = "hesuo worpd".replace(|c| matches!(c, 's' | 'u' | 'p'), "l"); + /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l"); /// ``` #[clippy::version = "1.64.0"] pub COLLAPSIBLE_STR_REPLACE, @@ -3507,6 +3507,14 @@ impl Methods { ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, + (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => { + no_effect_replace::check(cx, expr, arg1, arg2); + + // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint + if name == "replace" && let Some(("replace", ..)) = method_call(recv) { + collapsible_str_replace::check(cx, expr, arg1, arg2); + } + }, ("resize", [count_arg, default_arg]) => { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, @@ -3519,10 +3527,6 @@ impl Methods { ("sort_unstable_by", [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, - ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { - no_effect_replace::check(cx, expr, arg1, arg2); - collapsible_str_replace::check(cx, expr, name, recv); - }, ("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); diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed index 0bf857d9837..49fc9a9629e 100644 --- a/tests/ui/collapsible_str_replace.fixed +++ b/tests/ui/collapsible_str_replace.fixed @@ -2,64 +2,72 @@ #![warn(clippy::collapsible_str_replace)] -fn get_filter() -> &'static str { - "u" +fn get_filter() -> char { + 'u' } fn main() { - let misspelled = "hesuo worpd"; - + let d = 'd'; let p = 'p'; let s = 's'; let u = 'u'; let l = "l"; + let mut iter = ["l", "z"].iter(); + // LINT CASES - let _ = misspelled.replace(|c| matches!(c, 'u' | 's'), "l"); + let _ = "hesuo worpd".replace(['s', 'u'], "l"); - let _ = misspelled.replace(|c| matches!(c, 'u' | 's'), l); + let _ = "hesuo worpd".replace(['s', 'u'], l); - let _ = misspelled.replace(|c| matches!(c, 'p' | 'u' | 's'), "l"); + let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l"); - let _ = misspelled - .replace(|c| matches!(c, 'd' | 'p' | 'u' | 's'), "l"); + let _ = "hesuo worpd" + .replace(['s', 'u', 'p', 'd'], "l"); - // FALLBACK CASES - // If there are consecutive calls to `str::replace` and all or any chars are variables, - // recommend the fallback `misspelled.replace(&[s, u, p], "l")` - let _ = misspelled.replace(&['u' , s], "l"); + let _ = "hesuo world".replace([s, 'u'], "l"); - let _ = misspelled.replace(&['p' , 'u' , s], "l"); + let _ = "hesuo worpd".replace([s, 'u', 'p'], "l"); - let _ = misspelled.replace(&['p' , u , s], "l"); + let _ = "hesuo worpd".replace([s, u, 'p'], "l"); - let _ = misspelled.replace(&[p , u , s], "l"); + let _ = "hesuo worpd".replace([s, u, p], "l"); - // NO LINT CASES - let _ = misspelled.replace('s', "l"); + let _ = "hesuo worlp".replace(['s', 'u'], "l").replace('p', "d"); + + let _ = "hesuo worpd".replace('s', "x").replace(['u', 'p'], "l"); - let _ = misspelled.replace(s, "l"); + // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")` + let _ = "hesudo worpd".replace("su", "l").replace(['d', 'p'], "l"); - // If the consecutive `str::replace` calls have different `to` arguments, do not lint - let _ = misspelled.replace('s', "l").replace('u', "p"); + let _ = "hesudo worpd".replace([d, 'p'], "l").replace("su", "l"); + + let _ = "hesuo world".replace([get_filter(), 's'], "l"); + + // NO LINT CASES + let _ = "hesuo world".replace('s', "l").replace('u', "p"); - let _ = misspelled.replace(&get_filter(), "l"); + let _ = "hesuo worpd".replace('s', "l").replace('p', l); - let _ = misspelled.replace(&['s', 'u', 'p'], "l"); + let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l"); - let _ = misspelled.replace(&['s', 'u', 'p'], l); + // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]` + let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l"); - let _ = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); + let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l"); - let _ = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); + let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l"); - let _ = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); + let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l"); - let _ = misspelled.replace(&['s', u, 'p'], "l"); + let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l); - let _ = misspelled.replace(&[s, u, 'p'], "l"); + let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l"); - let _ = misspelled.replace(&[s, u, p], "l"); + let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l"); - let _ = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); + // Regression test + let _ = "hesuo worpd" + .replace('u', iter.next().unwrap()) + .replace('s', iter.next().unwrap()); } diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index 45d9fd87e5e..e3e25c4146f 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -2,67 +2,75 @@ #![warn(clippy::collapsible_str_replace)] -fn get_filter() -> &'static str { - "u" +fn get_filter() -> char { + 'u' } fn main() { - let misspelled = "hesuo worpd"; - + let d = 'd'; let p = 'p'; let s = 's'; let u = 'u'; let l = "l"; + let mut iter = ["l", "z"].iter(); + // LINT CASES - let _ = misspelled.replace('s', "l").replace('u', "l"); + let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); - let _ = misspelled.replace('s', l).replace('u', l); + let _ = "hesuo worpd".replace('s', l).replace('u', l); - let _ = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); + let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l"); - let _ = misspelled + let _ = "hesuo worpd" .replace('s', "l") .replace('u', "l") .replace('p', "l") .replace('d', "l"); - // FALLBACK CASES - // If there are consecutive calls to `str::replace` and all or any chars are variables, - // recommend the fallback `misspelled.replace(&[s, u, p], "l")` - let _ = misspelled.replace(s, "l").replace('u', "l"); + let _ = "hesuo world".replace(s, "l").replace('u', "l"); - let _ = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); + let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l"); - let _ = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); + let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l"); - let _ = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); + let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l"); - // NO LINT CASES - let _ = misspelled.replace('s', "l"); + let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d"); + + let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l"); - let _ = misspelled.replace(s, "l"); + // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")` + let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l"); - // If the consecutive `str::replace` calls have different `to` arguments, do not lint - let _ = misspelled.replace('s', "l").replace('u', "p"); + let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l"); + + let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l"); + + // NO LINT CASES + let _ = "hesuo world".replace('s', "l").replace('u', "p"); - let _ = misspelled.replace(&get_filter(), "l"); + let _ = "hesuo worpd".replace('s', "l").replace('p', l); - let _ = misspelled.replace(&['s', 'u', 'p'], "l"); + let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l"); - let _ = misspelled.replace(&['s', 'u', 'p'], l); + // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]` + let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l"); - let _ = misspelled.replace(&['s', 'u'], "l").replace(&['u', 'p'], "l"); + let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l"); - let _ = misspelled.replace('s', "l").replace(&['u', 'p'], "l"); + let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l"); - let _ = misspelled.replace(&['s', 'u'], "l").replace('p', "l"); + let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l"); - let _ = misspelled.replace(&['s', u, 'p'], "l"); + let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l); - let _ = misspelled.replace(&[s, u, 'p'], "l"); + let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l"); - let _ = misspelled.replace(&[s, u, p], "l"); + let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l"); - let _ = misspelled.replace(&[s, u], "l").replace(&[u, p], "l"); + // Regression test + let _ = "hesuo worpd" + .replace('u', iter.next().unwrap()) + .replace('s', iter.next().unwrap()); } diff --git a/tests/ui/collapsible_str_replace.stderr b/tests/ui/collapsible_str_replace.stderr index 372fe1da448..8e3daf3b898 100644 --- a/tests/ui/collapsible_str_replace.stderr +++ b/tests/ui/collapsible_str_replace.stderr @@ -1,56 +1,86 @@ error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:18:24 + --> $DIR/collapsible_str_replace.rs:19:27 | -LL | let _ = misspelled.replace('s', "l").replace('u', "l"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(|c| matches!(c, 'u' | 's'), "l")` +LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")` | = note: `-D clippy::collapsible-str-replace` implied by `-D warnings` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:20:24 + --> $DIR/collapsible_str_replace.rs:21:27 | -LL | let _ = misspelled.replace('s', l).replace('u', l); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(|c| matches!(c, 'u' | 's'), l)` +LL | let _ = "hesuo worpd".replace('s', l).replace('u', l); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:22:24 + --> $DIR/collapsible_str_replace.rs:23:27 | -LL | let _ = misspelled.replace('s', "l").replace('u', "l").replace('p', "l"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(|c| matches!(c, 'p' | 'u' | 's'), "l")` +LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:25:10 + --> $DIR/collapsible_str_replace.rs:26:10 | LL | .replace('s', "l") | __________^ LL | | .replace('u', "l") LL | | .replace('p', "l") LL | | .replace('d', "l"); - | |__________________________^ help: replace with: `replace(|c| matches!(c, 'd' | 'p' | 'u' | 's'), "l")` + | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:33:24 + --> $DIR/collapsible_str_replace.rs:31:27 | -LL | let _ = misspelled.replace(s, "l").replace('u', "l"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&['u' , s], "l")` +LL | let _ = "hesuo world".replace(s, "l").replace('u', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:35:24 + --> $DIR/collapsible_str_replace.rs:33:27 | -LL | let _ = misspelled.replace(s, "l").replace('u', "l").replace('p', "l"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&['p' , 'u' , s], "l")` +LL | let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:37:24 + --> $DIR/collapsible_str_replace.rs:35:27 | -LL | let _ = misspelled.replace(s, "l").replace(u, "l").replace('p', "l"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&['p' , u , s], "l")` +LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:39:24 + --> $DIR/collapsible_str_replace.rs:37:27 | -LL | let _ = misspelled.replace(s, "l").replace(u, "l").replace(p, "l"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(&[p , u , s], "l")` +LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")` -error: aborting due to 8 previous errors +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:39:27 + | +LL | let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:41:45 + | +LL | let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:44:47 + | +LL | let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:46:28 + | +LL | let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")` + +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:48:27 + | +LL | let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")` + +error: aborting due to 13 previous errors -- cgit 1.4.1-3-g733a5 From a0afbdfbec5923850ae20c77a2f466b904dae04c Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Wed, 24 Aug 2022 08:11:29 +0200 Subject: Replace `contains_ty(..)` with `Ty::contains(..)` This removes some code we don't need and the method syntax is also more readable IMO. --- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/escape.rs | 3 +-- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/methods/unnecessary_to_owned.rs | 5 ++--- clippy_lints/src/self_named_constructors.rs | 4 ++-- clippy_utils/src/ty.rs | 8 -------- 6 files changed, 11 insertions(+), 21 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index e38704701ea..abe01d6e2c4 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{contains_ty, expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; +use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; use clippy_utils::{fn_def_id, get_parent_expr, is_lint_allowed, meets_msrv, msrvs, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; @@ -1158,7 +1158,7 @@ fn replace_types<'tcx>( .inputs_and_output .iter() .enumerate() - .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !contains_ty(ty, param_ty.to_ty(cx.tcx))) + .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !ty.contains(param_ty.to_ty(cx.tcx))) { return false; } diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 0a4a0ebb3f9..327865e4c85 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_hir; -use clippy_utils::ty::contains_ty; use rustc_hir::intravisit; use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; use rustc_infer::infer::TyCtxtInferExt; @@ -166,7 +165,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 if let Some(trait_self_ty) = self.trait_self_ty { - if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) { + if map.name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) { return; } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 49d4900295f..0ec35ddc1db 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -99,7 +99,7 @@ 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, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item}; use clippy_utils::{ contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty, }; @@ -3242,7 +3242,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if contains_adt_constructor(ret_ty, self_adt) { return; } - } else if contains_ty(ret_ty, self_ty) { + } else if ret_ty.contains(self_ty) { return; } @@ -3260,7 +3260,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if contains_adt_constructor(assoc_ty, self_adt) { return; } - } else if contains_ty(assoc_ty, self_ty) { + } else if assoc_ty.contains(self_ty) { return; } } @@ -3309,7 +3309,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); - if !contains_ty(ret_ty, self_ty); + if !ret_ty.contains(self_ty); then { span_lint( diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index e4624167ad0..44bf8435294 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,8 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{ - contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, - peel_mid_ty_refs, + get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, }; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; use clippy_utils::{meets_msrv, msrvs}; @@ -304,7 +303,7 @@ fn check_other_call_arg<'tcx>( // (https://github.com/rust-lang/rust-clippy/issues/8507). if (n_refs == 0 && !receiver_ty.is_ref()) || trait_predicate.def_id() != as_ref_trait_id - || !contains_ty(fn_sig.output(), input); + || !fn_sig.output().contains(input); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index d07c26d7c89..9cea4d88067 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::return_ty; -use clippy_utils::ty::{contains_adt_constructor, contains_ty}; +use clippy_utils::ty::contains_adt_constructor; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { if !contains_adt_constructor(ret_ty, self_adt) { return; } - } else if !contains_ty(ret_ty, self_ty) { + } else if !ret_ty.contains(self_ty) { return; } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index edbe9c5a897..00182e739b8 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -43,14 +43,6 @@ pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool } } -/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` -pub fn contains_ty<'tcx>(ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool { - ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => other_ty == inner_ty, - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) -} - /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt /// constructor. pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool { -- cgit 1.4.1-3-g733a5 From de028e2fb9d81d58d62dfc7bc8fd2335a9885641 Mon Sep 17 00:00:00 2001 From: Marco Mastropaolo Date: Fri, 10 Jun 2022 18:28:31 +0200 Subject: Implemented suspicious_to_owned lint to check if `to_owned` is called on a `Cow`. This is done because `to_owned` is very similarly named to `into_owned`, but the effect of calling those two methods is completely different. This creates confusion (stemming from the ambiguity of the 'owned' term in the context of `Cow`s) and might not be what the writer intended. --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 + clippy_lints/src/methods/mod.rs | 58 ++++++++++++++++++++++- clippy_lints/src/methods/suspicious_to_owned.rs | 36 ++++++++++++++ tests/compile-test.rs | 1 + tests/ui/suspicious_to_owned.rs | 62 +++++++++++++++++++++++++ tests/ui/suspicious_to_owned.stderr | 42 +++++++++++++++++ 9 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/suspicious_to_owned.rs create mode 100644 tests/ui/suspicious_to_owned.rs create mode 100644 tests/ui/suspicious_to_owned.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 964f339b26c..a076997eebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4082,6 +4082,7 @@ Released 2018-09-13 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn +[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 61bb5d1337c..64982851b56 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -207,6 +207,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::STRING_EXTEND_CHARS), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::SUSPICIOUS_SPLITN), + LintId::of(methods::SUSPICIOUS_TO_OWNED), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::UNIT_HASH), LintId::of(methods::UNNECESSARY_FILTER_MAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 0ec2884cb6b..fbf77fb734f 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -358,6 +358,7 @@ store.register_lints(&[ methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, methods::SUSPICIOUS_SPLITN, + methods::SUSPICIOUS_TO_OWNED, methods::UNINIT_ASSUMED_INIT, methods::UNIT_HASH, methods::UNNECESSARY_FILTER_MAP, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 6f480c52cc9..aa4e571dbe2 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -24,6 +24,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::MUT_RANGE_BOUND), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::SUSPICIOUS_TO_OWNED), LintId::of(multi_assignments::MULTI_ASSIGNMENTS), LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(octal_escapes::OCTAL_ESCAPES), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0ec35ddc1db..a0d190a58af 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -78,6 +78,7 @@ mod str_splitn; mod string_extend_chars; mod suspicious_map; mod suspicious_splitn; +mod suspicious_to_owned; mod uninit_assumed_init; mod unit_hash; mod unnecessary_filter_map; @@ -2053,6 +2054,55 @@ declare_clippy_lint! { "replace `.iter().count()` with `.len()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`. + /// + /// ### Why is this bad? + /// Calling `to_owned()` on a `Cow` creates a clone of the `Cow` + /// itself, without taking ownership of the `Cow` contents (i.e. + /// it's equivalent to calling `Cow::clone`). + /// The similarly named `into_owned` method, on the other hand, + /// clones the `Cow` contents, effectively turning any `Cow::Borrowed` + /// into a `Cow::Owned`. + /// + /// Given the potential ambiguity, consider replacing `to_owned` + /// with `clone` for better readability or, if getting a `Cow::Owned` + /// was the original intent, using `into_owned` instead. + /// + /// ### Example + /// ```rust + /// # use std::borrow::Cow; + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// let data = cow.to_owned(); + /// assert!(matches!(data, Cow::Borrowed(_))) + /// ``` + /// Use instead: + /// ```rust + /// # use std::borrow::Cow; + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// let data = cow.clone(); + /// assert!(matches!(data, Cow::Borrowed(_))) + /// ``` + /// or + /// ```rust + /// # use std::borrow::Cow; + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// let data = cow.into_owned(); + /// assert!(matches!(data, String)) + /// ``` + #[clippy::version = "1.65.0"] + pub SUSPICIOUS_TO_OWNED, + suspicious, + "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected" +} + declare_clippy_lint! { /// ### What it does /// Checks for calls to [`splitn`] @@ -3075,6 +3125,7 @@ impl_lint_pass!(Methods => [ FROM_ITER_INSTEAD_OF_COLLECT, INSPECT_FOR_EACH, IMPLICIT_CLONE, + SUSPICIOUS_TO_OWNED, SUSPICIOUS_SPLITN, MANUAL_STR_REPEAT, EXTEND_WITH_DRAIN, @@ -3553,7 +3604,12 @@ impl Methods { } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, - ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { + ("to_owned", []) => { + if !suspicious_to_owned::check(cx, expr, recv) { + implicit_clone::check(cx, name, expr, recv); + } + }, + ("to_os_string" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, ("unwrap", []) => { diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs new file mode 100644 index 00000000000..6b306fbf008 --- /dev/null +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -0,0 +1,36 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_diag_trait_item; +use clippy_utils::source::snippet_with_context; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::sym; + +use super::SUSPICIOUS_TO_OWNED; + +pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool { + if_chain! { + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if is_diag_trait_item(cx, method_def_id, sym::ToOwned); + let input_type = cx.typeck_results().expr_ty(expr); + if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind(); + if cx.tcx.is_diagnostic_item(sym::Cow, adt.did()); + then { + let mut app = Applicability::MaybeIncorrect; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; + span_lint_and_sugg( + cx, + SUSPICIOUS_TO_OWNED, + expr.span, + &format!("this `to_owned` call clones the {0} itself and does not cause the {0} contents to become owned", input_type), + "consider using, depending on intent", + format!("{0}.clone()` or `{0}.into_owned()", recv_snip), + app, + ); + return true; + } + } + false +} diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 5431f2ebc0a..ba6186e599e 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -393,6 +393,7 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ "search_is_some.rs", "single_component_path_imports_nested_first.rs", "string_add.rs", + "suspicious_to_owned.rs", "toplevel_ref_arg_non_rustfix.rs", "unit_arg.rs", "unnecessary_clone.rs", diff --git a/tests/ui/suspicious_to_owned.rs b/tests/ui/suspicious_to_owned.rs new file mode 100644 index 00000000000..a90e78a0ea0 --- /dev/null +++ b/tests/ui/suspicious_to_owned.rs @@ -0,0 +1,62 @@ +#![warn(clippy::suspicious_to_owned)] +#![warn(clippy::implicit_clone)] +#![allow(clippy::redundant_clone)] +use std::borrow::Cow; +use std::ffi::CStr; + +fn main() { + let moo = "Moooo"; + let c_moo = b"Moooo\0"; + let c_moo_ptr = c_moo.as_ptr() as *const i8; + let moos = ['M', 'o', 'o']; + let moos_vec = moos.to_vec(); + + // we expect this to be linted + let cow = Cow::Borrowed(moo); + let _ = cow.to_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(moo); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(moo); + let _ = cow.clone(); + + // we expect this to be linted + let cow = Cow::Borrowed(&moos); + let _ = cow.to_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos); + let _ = cow.clone(); + + // we expect this to be linted + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.to_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = Cow::Borrowed(&moos_vec); + let _ = cow.clone(); + + // we expect this to be linted + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.to_owned(); + // we expect no lints for this + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.into_owned(); + // we expect no lints for this + let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); + let _ = cow.clone(); + + // we expect no lints for these + let _ = moo.to_owned(); + let _ = c_moo.to_owned(); + let _ = moos.to_owned(); + + // we expect implicit_clone lints for these + let _ = String::from(moo).to_owned(); + let _ = moos_vec.to_owned(); +} diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr new file mode 100644 index 00000000000..92e1024bf1f --- /dev/null +++ b/tests/ui/suspicious_to_owned.stderr @@ -0,0 +1,42 @@ +error: this `to_owned` call clones the std::borrow::Cow itself and does not cause the std::borrow::Cow contents to become owned + --> $DIR/suspicious_to_owned.rs:16:13 + | +LL | let _ = cow.to_owned(); + | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + | + = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` + +error: this `to_owned` call clones the std::borrow::Cow<[char; 3]> itself and does not cause the std::borrow::Cow<[char; 3]> contents to become owned + --> $DIR/suspicious_to_owned.rs:26:13 + | +LL | let _ = cow.to_owned(); + | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + +error: this `to_owned` call clones the std::borrow::Cow> itself and does not cause the std::borrow::Cow> contents to become owned + --> $DIR/suspicious_to_owned.rs:36:13 + | +LL | let _ = cow.to_owned(); + | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + +error: this `to_owned` call clones the std::borrow::Cow itself and does not cause the std::borrow::Cow contents to become owned + --> $DIR/suspicious_to_owned.rs:46:13 + | +LL | let _ = cow.to_owned(); + | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + +error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type + --> $DIR/suspicious_to_owned.rs:60:13 + | +LL | let _ = String::from(moo).to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()` + | + = note: `-D clippy::implicit-clone` implied by `-D warnings` + +error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type + --> $DIR/suspicious_to_owned.rs:61:13 + | +LL | let _ = moos_vec.to_owned(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `moos_vec.clone()` + +error: aborting due to 6 previous errors + -- cgit 1.4.1-3-g733a5 From ffc75af4cd01740e9daac43ff24d777525e506c1 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Fri, 2 Sep 2022 20:28:00 +0200 Subject: Fix `mut_mutex_lock` for Mutex behind imm deref Fixes #9415 --- clippy_lints/src/methods/mut_mutex_lock.rs | 3 ++- tests/ui/mut_mutex_lock.fixed | 7 +++++++ tests/ui/mut_mutex_lock.rs | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index bd8458a222e..b9593b3687d 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -11,6 +11,7 @@ use super::MUT_MUTEX_LOCK; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { if_chain! { + if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)); if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index 36bc52e3374..ecad10a8290 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -18,4 +18,11 @@ fn no_owned_mutex_lock() { *value += 1; } +fn issue9415() { + let mut arc_mutex = Arc::new(Mutex::new(42_u8)); + let arc_mutex: &mut Arc> = &mut arc_mutex; + let mut guard = arc_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index ea60df5ae1b..f2b1d6fbfbc 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -18,4 +18,11 @@ fn no_owned_mutex_lock() { *value += 1; } +fn issue9415() { + let mut arc_mutex = Arc::new(Mutex::new(42_u8)); + let arc_mutex: &mut Arc> = &mut arc_mutex; + let mut guard = arc_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} -- cgit 1.4.1-3-g733a5 From 750a2d57bde6fca3bbd856410fe4fb54c4c068dc Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 3 Sep 2022 17:00:44 +0200 Subject: Fix `unnecessary_to_owned` false positive Fixes #9351. Note that this commit reworks that fix for #9317. The change is to check that the type implements `AsRef` before regarding `to_string` as an equivalent of `to_owned`. This was suggested by Jarcho in the #9317 issue comments. The benefit of this is that it moves some complexity out of `check_other_call_arg` and simplifies the module as a whole. --- clippy_lints/src/methods/unnecessary_to_owned.rs | 205 +++++++++++++++-------- tests/ui/unnecessary_to_owned.fixed | 60 +++++++ tests/ui/unnecessary_to_owned.rs | 60 +++++++ tests/ui/unnecessary_to_owned.stderr | 8 +- 4 files changed, 262 insertions(+), 71 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 44bf8435294..d59b26c3144 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,21 +1,25 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; +use crate::rustc_middle::ty::Subst; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{ - get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, -}; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::visitors::find_all_ret_expressions; +use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_middle::ty::EarlyBinder; +use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use rustc_typeck::check::{FnCtxt, Inherited}; use std::cmp::max; use super::UNNECESSARY_TO_OWNED; @@ -33,7 +37,7 @@ pub fn check<'tcx>( then { if is_cloned_or_copied(cx, method_name, method_def_id) { unnecessary_iter_cloned::check(cx, expr, method_name, receiver); - } else if is_to_owned_like(cx, method_name, method_def_id) { + } else if is_to_owned_like(cx, expr, method_name, method_def_id) { // At this point, we know the call is of a `to_owned`-like function. The functions // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary // based on its context, that is, whether it is a referent in an `AddrOf` expression, an @@ -245,12 +249,12 @@ fn check_other_call_arg<'tcx>( ) -> bool { if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); - if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call); + if let Some((callee_def_id, _, call_args)) = get_callee_substs_and_args(cx, maybe_call); let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id); if let Some(input) = fn_sig.inputs().get(i); let (input, n_refs) = peel_mid_ty_refs(*input); - if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); + if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input); if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait(); if let [trait_predicate] = trait_predicates .iter() @@ -258,52 +262,13 @@ fn check_other_call_arg<'tcx>( .collect::>()[..]; if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); + if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id; let receiver_ty = cx.typeck_results().expr_ty(receiver); - // If the callee has type parameters, they could appear in `projection_predicate.ty` or the - // types of `trait_predicate.trait_ref.substs`. - if if trait_predicate.def_id() == deref_trait_id { - if let [projection_predicate] = projection_predicates[..] { - let normalized_ty = - cx.tcx - .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); - implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") - .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty) - } else { - false - } - } else if trait_predicate.def_id() == as_ref_trait_id { - let composed_substs = compose_substs( - cx, - &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], - call_substs, - ); - // if `expr` is a `String` and generic target is [u8], skip - // (https://github.com/rust-lang/rust-clippy/issues/9317). - if let [subst] = composed_substs[..] - && let GenericArgKind::Type(arg_ty) = subst.unpack() - && arg_ty.is_slice() - && let inner_ty = arg_ty.builtin_index().unwrap() - && let ty::Uint(ty::UintTy::U8) = inner_ty.kind() - && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs() - && is_type_diagnostic_item(cx, self_ty, sym::String) { - false - } else { - implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) - } - } else { - false - }; + if can_change_type(cx, maybe_arg, receiver_ty); // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); - // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then - // `T` must not be instantiated with a reference - // (https://github.com/rust-lang/rust-clippy/issues/8507). - if (n_refs == 0 && !receiver_ty.is_ref()) - || trait_predicate.def_id() != as_ref_trait_id - || !fn_sig.output().contains(input); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( @@ -389,22 +354,102 @@ fn get_input_traits_and_projections<'tcx>( (trait_predicates, projection_predicates) } -/// Composes two substitutions by applying the latter to the types of the former. -fn compose_substs<'tcx>( - cx: &LateContext<'tcx>, - left: &[GenericArg<'tcx>], - right: SubstsRef<'tcx>, -) -> Vec> { - left.iter() - .map(|arg| { - if let GenericArgKind::Type(arg_ty) = arg.unpack() { - let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty); - GenericArg::from(normalized_ty) - } else { - *arg +fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { + for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { + match node { + Node::Stmt(_) => return true, + Node::Block(..) => continue, + Node::Item(item) => { + if let ItemKind::Fn(_, _, body_id) = &item.kind + && let output_ty = return_ty(cx, item.hir_id()) + && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id()) + && Inherited::build(cx.tcx, local_def_id).enter(|inherited| { + let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id()); + fn_ctxt.can_coerce(ty, output_ty) + }) { + if has_lifetime(output_ty) && has_lifetime(ty) { + return false; + } + let body = cx.tcx.hir().body(*body_id); + let body_expr = &body.value; + let mut count = 0; + return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 }); + } } - }) - .collect() + Node::Expr(parent_expr) => { + if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, parent_expr) { + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + if let Some(arg_index) = call_args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(param_ty) = fn_sig.inputs().get(arg_index) + && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + { + if fn_sig + .inputs() + .iter() + .enumerate() + .filter(|(i, _)| *i != arg_index) + .any(|(_, ty)| ty.contains(*param_ty)) + { + return false; + } + + let mut trait_predicates = cx.tcx.param_env(callee_def_id) + .caller_bounds().iter().filter(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == *param_ty { + true + } else { + false + } + }); + + let new_subst = cx.tcx.mk_substs( + call_substs.iter() + .enumerate() + .map(|(i, t)| + if i == (*param_index as usize) { + GenericArg::from(ty) + } else { + t + })); + + if trait_predicates.any(|predicate| { + let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst); + let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); + !cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + }) { + return false; + } + + let output_ty = fn_sig.output(); + if output_ty.contains(*param_ty) { + if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( + new_subst, cx.param_env, output_ty) { + expr = parent_expr; + ty = new_ty; + continue; + } + return false; + } + + return true; + } + } else if let ExprKind::Block(..) = parent_expr.kind { + continue; + } + return false; + }, + _ => return false, + } + } + + false +} + +fn has_lifetime(ty: Ty<'_>) -> bool { + ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_))) } /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. @@ -415,10 +460,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. -fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { +fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { is_clone_like(cx, method_name.as_str(), method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) - || is_to_string(cx, method_name, method_def_id) + || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) } /// Returns true if the named method is `Cow::into_owned`. @@ -426,7 +471,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) } -/// Returns true if the named method is `ToString::to_string`. -fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString) +/// Returns true if the named method is `ToString::to_string` and it's called on a type that +/// is string-like i.e. implements `AsRef` or `Deref`. +fn is_to_string_on_string_like<'a>( + cx: &LateContext<'_>, + call_expr: &'a Expr<'a>, + method_name: Symbol, + method_def_id: DefId, +) -> bool { + if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) { + return false; + } + + if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id) + && let [generic_arg] = substs.as_slice() + && let GenericArgKind::Type(ty) = generic_arg.unpack() + && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) + && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) + && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) || + implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { + true + } else { + false + } } diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 9cd5bc73b1e..a920c63b199 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -357,3 +357,63 @@ mod issue_9317 { consume(b.to_string()); } } + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc") + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7f62ba3ab5d..2128bdacdda 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -357,3 +357,63 @@ mod issue_9317 { consume(b.to_string()); } } + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc".to_string()) + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 243b4599dba..7deb90b06f3 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -509,5 +509,11 @@ error: unnecessary use of `to_string` LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` -error: aborting due to 78 previous errors +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:381:12 + | +LL | id("abc".to_string()) + | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` + +error: aborting due to 79 previous errors -- cgit 1.4.1-3-g733a5 From f0e586c2511019a58ad3e56be16bba76dfc7eba8 Mon Sep 17 00:00:00 2001 From: relrelb Date: Tue, 16 Aug 2022 23:26:03 +0300 Subject: Suggest `Entry::or_default` for `Entry::or_insert(Default::default())` Unlike past similar work done in #6228, expand the existing `or_fun_call` lint to detect `or_insert` calls with a `T::new()` or `T::default()` argument, much like currently done for `unwrap_or` calls. In that case, suggest the use of `or_default`, which is more idiomatic. Note that even with this change, `or_insert_with(T::default)` calls aren't detected as candidates for `or_default()`, in the same manner that currently `unwrap_or_else(T::default)` calls aren't detected as candidates for `unwrap_or_default()`. Also, as a nearby cleanup, change `KNOW_TYPES` from `static` to `const`, since as far as I understand it's preferred (should Clippy have a lint for that?). Fixes #3812. --- clippy_lints/src/methods/mod.rs | 5 +++-- clippy_lints/src/methods/or_fun_call.rs | 13 +++++++++---- src/docs/or_fun_call.txt | 5 +++-- tests/ui/or_fun_call.fixed | 8 ++++---- tests/ui/or_fun_call.stderr | 26 +++++++++++++++++++++++++- 5 files changed, 44 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a0d190a58af..b7d2d980db8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -825,8 +825,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, - /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or - /// `unwrap_or_default` instead. + /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, + /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` + /// etc. instead. /// /// ### Why is this bad? /// The function will always be called and potentially diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6af134019a4..c97f714680e 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -22,7 +22,8 @@ pub(super) fn check<'tcx>( name: &str, args: &'tcx [hir::Expr<'_>], ) { - /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`, + /// `or_insert(T::new())` or `or_insert(T::default())`. #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, @@ -42,7 +43,11 @@ pub(super) fn check<'tcx>( if_chain! { if !or_has_args; - if name == "unwrap_or"; + if let Some(sugg) = match name { + "unwrap_or" => Some("unwrap_or_default"), + "or_insert" => Some("or_default"), + _ => None, + }; if let hir::ExprKind::Path(ref qpath) = fun.kind; if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); let path = last_path_segment(qpath).ident.name; @@ -58,7 +63,7 @@ pub(super) fn check<'tcx>( method_span.with_hi(span.hi()), &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - "unwrap_or_default()".to_string(), + format!("{}()", sugg), Applicability::MachineApplicable, ); @@ -82,7 +87,7 @@ pub(super) fn check<'tcx>( fun_span: Option, ) { // (path, fn_has_argument, methods, suffix) - static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), diff --git a/src/docs/or_fun_call.txt b/src/docs/or_fun_call.txt index 5605e96c98e..6ce77cc268c 100644 --- a/src/docs/or_fun_call.txt +++ b/src/docs/or_fun_call.txt @@ -1,7 +1,8 @@ ### What it does Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, -etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or -`unwrap_or_default` instead. +`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, +`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` +etc. instead. ### Why is this bad? The function will always be called and potentially diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 18ea4e55029..5991188ab63 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -79,16 +79,16 @@ fn or_fun_call() { without_default.unwrap_or_else(Foo::new); let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); + map.entry(42).or_default(); let mut map_vec = HashMap::>::new(); - map_vec.entry(42).or_insert(vec![]); + map_vec.entry(42).or_default(); let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); + btree.entry(42).or_default(); let mut btree_vec = BTreeMap::>::new(); - btree_vec.entry(42).or_insert(vec![]); + btree_vec.entry(42).or_default(); let stringy = Some(String::new()); let _ = stringy.unwrap_or_default(); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 887f23ac976..e3dab4cb147 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -66,6 +66,30 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:82:19 + | +LL | map.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:85:23 + | +LL | map_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:88:21 + | +LL | btree.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:91:25 + | +LL | btree_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:94:21 | @@ -132,5 +156,5 @@ error: use of `unwrap_or` followed by a call to `new` LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` -error: aborting due to 22 previous errors +error: aborting due to 26 previous errors -- cgit 1.4.1-3-g733a5 From b21d9d307b5fdb1e423d786f9899757b42957b07 Mon Sep 17 00:00:00 2001 From: xphoniex Date: Tue, 6 Sep 2022 04:38:29 +0000 Subject: Suggest `unwrap_or_default` when closure returns `"".to_string` Signed-off-by: xphoniex --- clippy_lints/src/methods/unwrap_or_else_default.rs | 24 ++++++++++++++++++++-- tests/ui/unwrap_or_else_default.fixed | 3 +++ tests/ui/unwrap_or_else_default.rs | 3 +++ tests/ui/unwrap_or_else_default.stderr | 8 +++++++- 4 files changed, 35 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index f3af281d6ca..d3630b7d08e 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -5,10 +5,11 @@ use clippy_utils::{ diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability, ty::is_type_diagnostic_item, }; +use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{sym, symbol}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -25,7 +26,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if is_default_equivalent_call(cx, u_arg); + if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; @@ -44,3 +45,22 @@ pub(super) fn check<'tcx>( } } } + +fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind { + let body = cx.tcx.hir().body(body); + + if body.params.is_empty() + && let hir::Expr{ kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, [self_arg], _) = kind + && ident == &symbol::Ident::from_str("to_string") + && let hir::Expr{ kind, .. } = self_arg + && let hir::ExprKind::Lit(lit) = kind + && let LitKind::Str(symbol::kw::Empty, _) = lit.node + { + return true; + } + } + + false +} diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index c2b9bd2c881..84f779569ff 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -69,6 +69,9 @@ fn unwrap_or_else_default() { let with_default_type: Option> = None; with_default_type.unwrap_or_default(); + + let empty_string = None::; + empty_string.unwrap_or_default(); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index d55664990ae..1735bd5808e 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -69,6 +69,9 @@ fn unwrap_or_else_default() { let with_default_type: Option> = None; with_default_type.unwrap_or_else(Vec::new); + + let empty_string = None::; + empty_string.unwrap_or_else(|| "".to_string()); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index 53e31d85edf..d2b9212223f 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -30,5 +30,11 @@ error: use of `.unwrap_or_else(..)` to construct default value LL | with_default_type.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` -error: aborting due to 5 previous errors +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:74:5 + | +LL | empty_string.unwrap_or_else(|| "".to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()` + +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From bdb13cd887c9068262e230bd38730d360a7db0c5 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sat, 10 Sep 2022 10:39:51 +0200 Subject: refactor: move `has_debug_impl` to `clippy_utils::ty` --- clippy_lints/src/assertions_on_result_states.rs | 9 +-------- clippy_lints/src/methods/err_expect.rs | 11 ++--------- clippy_lints/src/methods/ok_expect.rs | 11 ++--------- clippy_utils/src/ty.rs | 7 +++++++ 4 files changed, 12 insertions(+), 26 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 63664d66662..656dc5feeb5 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; use clippy_utils::{is_expr_final_block_expr, path_res}; use rustc_errors::Applicability; @@ -97,13 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { } } -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} - fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never() } diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 570a1b87358..720d9a68c85 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -1,6 +1,6 @@ use super::ERR_EXPECT; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::implements_trait; +use clippy_utils::ty::has_debug_impl; use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_lint::LateContext; @@ -28,7 +28,7 @@ pub(super) fn check( // Tests if the T type in a `Result` is not None if let Some(data_type) = get_data_type(cx, result_type); // Tests if the T type in a `Result` implements debug - if has_debug_impl(data_type, cx); + if has_debug_impl(cx, data_type); then { span_lint_and_sugg( @@ -51,10 +51,3 @@ fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { _ => None, } } - -/// Given a type, very if the Debug trait has been impl'd -fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index d64a9f320d9..646fc4a7bcf 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let result_type = cx.typeck_results().expr_ty(recv); if let Some(error_type) = get_error_type(cx, result_type); - if has_debug_impl(error_type, cx); + if has_debug_impl(cx, error_type); then { span_lint_and_help( @@ -37,10 +37,3 @@ fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { _ => None, } } - -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { - cx.tcx - .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) -} diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 5a7f9568441..b3eb6d05544 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -31,6 +31,13 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env) } +/// This checks whether a given type is known to implement Debug. +pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + cx.tcx + .get_diagnostic_item(sym::Debug) + .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) +} + /// Checks whether a type can be partially moved. pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if has_drop(cx, ty) || is_copy(cx, ty) { -- cgit 1.4.1-3-g733a5 From 992560087025370e2a0397a67106b0852e238b4e Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 14 Sep 2022 00:27:56 -0600 Subject: dogfood inverse bool_to_int_with_if --- clippy_lints/src/dereference.rs | 7 ++----- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- tests/ui/len_without_is_empty.rs | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 88e28018e5d..d1b25a0f1b5 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -297,13 +297,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id) && position.lint_explicit_deref() => { + let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr))); self.state = Some(( State::DerefMethod { - ty_changed_count: if deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)) { - 0 - } else { - 1 - }, + ty_changed_count, is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)), target_mut, }, diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 763bfafecef..b32e5d8d421 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -269,7 +269,7 @@ fn check_other_call_arg<'tcx>( // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; - let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); + let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty))); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 1e938e72b57..78397c2af34 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -274,7 +274,7 @@ impl AsyncLen { } pub async fn len(&self) -> usize { - if self.async_task().await { 0 } else { 1 } + usize::from(!self.async_task().await) } pub async fn is_empty(&self) -> bool { -- cgit 1.4.1-3-g733a5 From 5afc261c66896ed3d14f9d9eccbc7a1090d379d3 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Tue, 30 Aug 2022 00:09:25 +0530 Subject: Add iter_kv_map lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/methods/iter_kv_map.rs | 87 ++++++++++++++++ clippy_lints/src/methods/mod.rs | 36 +++++++ src/docs.rs | 1 + src/docs/iter_kv_map.txt | 22 +++++ tests/ui/iter_kv_map.fixed | 65 ++++++++++++ tests/ui/iter_kv_map.rs | 65 ++++++++++++ tests/ui/iter_kv_map.stderr | 148 ++++++++++++++++++++++++++++ 11 files changed, 428 insertions(+) create mode 100644 clippy_lints/src/methods/iter_kv_map.rs create mode 100644 src/docs/iter_kv_map.txt create mode 100644 tests/ui/iter_kv_map.fixed create mode 100644 tests/ui/iter_kv_map.rs create mode 100644 tests/ui/iter_kv_map.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index d847e4c7494..044cbff4b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3800,6 +3800,7 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count +[`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1f85382347a..3e9af5a4d45 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -171,6 +171,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::ITERATOR_STEP_BY_ZERO), LintId::of(methods::ITER_CLONED_COLLECT), LintId::of(methods::ITER_COUNT), + LintId::of(methods::ITER_KV_MAP), LintId::of(methods::ITER_NEXT_SLICE), LintId::of(methods::ITER_NTH), LintId::of(methods::ITER_NTH_ZERO), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index aa247352f88..185189a6af5 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -40,6 +40,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::ITER_COUNT), + LintId::of(methods::ITER_KV_MAP), LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SPLIT_ONCE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 962e6722006..446bc762fb4 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -313,6 +313,7 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, + methods::ITER_KV_MAP, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs new file mode 100644 index 00000000000..a7eecabd684 --- /dev/null +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -0,0 +1,87 @@ +#![allow(unused_imports)] + +use super::ITER_KV_MAP; +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::is_local_used; +use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty; +use rustc_span::sym; +use rustc_span::Span; + +/// lint use of: +/// - `hashmap.iter().map(|(_, v)| v)` +/// - `hashmap.into_iter().map(|(_, v)| v)` +/// on `HashMaps` and `BTreeMaps` in std + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + map_type: &'tcx str, // iter / into_iter + expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) + recv: &'tcx Expr<'tcx>, // hashmap + m_arg: &'tcx Expr<'tcx>, // |(_, v)| v +) { + if_chain! { + if !expr.span.from_expansion(); + if let ExprKind::Closure(c) = m_arg.kind; + if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); + if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; + + let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) { + (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value), + (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key), + _ => return, + }; + + let ty = cx.typeck_results().expr_ty(recv); + if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); + + then { + let mut applicability = rustc_errors::Applicability::MachineApplicable; + let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); + let into_prefix = if map_type == "into_iter" {"into_"} else {""}; + + if_chain! { + if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind; + if let [local_ident] = path.segments; + if local_ident.ident.as_str() == binded_ident.as_str(); + + then { + span_lint_and_sugg( + cx, + ITER_KV_MAP, + expr.span, + &format!("iterating on a map's {}s", replacement_kind), + "try", + format!("{}.{}{}s()", recv_snippet, into_prefix, replacement_kind), + applicability, + ); + } else { + span_lint_and_sugg( + cx, + ITER_KV_MAP, + expr.span, + &format!("iterating on a map's {}s", replacement_kind), + "try", + format!("{}.{}{}s().map(|{}| {})", recv_snippet, into_prefix, replacement_kind, binded_ident, + snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), + applicability, + ); + } + } + } + } +} + +/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` +/// that is not locally used. +fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { + match *pat { + PatKind::Wild => true, + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), + _ => false, + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 41942b20ea1..cdde4c54d63 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -35,6 +35,7 @@ mod into_iter_on_ref; mod is_digit_ascii_radix; mod iter_cloned_collect; mod iter_count; +mod iter_kv_map; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; @@ -3036,6 +3037,37 @@ declare_clippy_lint! { "use of `File::read_to_end` or `File::read_to_string`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for iterating a map (`HashMap` or `BTreeMap`) and + /// ignoring either the keys or values. + /// + /// ### Why is this bad? + /// + /// Readability. There are `keys` and `values` methods that + /// can be used to express that we only need the keys or the values. + /// + /// ### Example + /// + /// ``` + /// # use std::collections::HashMap; + /// let map: HashMap = HashMap::new(); + /// let values = map.iter().map(|(_, value)| value).collect::>(); + /// ``` + /// + /// Use instead: + /// ``` + /// # use std::collections::HashMap; + /// let map: HashMap = HashMap::new(); + /// let values = map.values().collect::>(); + /// ``` + #[clippy::version = "1.65.0"] + pub ITER_KV_MAP, + complexity, + "iterating on map using `iter` when `keys` or `values` would do" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3159,6 +3191,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_SORT_BY, VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, + ITER_KV_MAP, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3498,6 +3531,9 @@ 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) { + iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + } } else { map_err_ignore::check(cx, expr, m_arg); } diff --git a/src/docs.rs b/src/docs.rs index f3a5048e7fa..036dd007856 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -221,6 +221,7 @@ docs! { "items_after_statements", "iter_cloned_collect", "iter_count", + "iter_kv_map", "iter_next_loop", "iter_next_slice", "iter_not_returning_iterator", diff --git a/src/docs/iter_kv_map.txt b/src/docs/iter_kv_map.txt new file mode 100644 index 00000000000..a063c8195ef --- /dev/null +++ b/src/docs/iter_kv_map.txt @@ -0,0 +1,22 @@ +### What it does + +Checks for iterating a map (`HashMap` or `BTreeMap`) and +ignoring either the keys or values. + +### Why is this bad? + +Readability. There are `keys` and `values` methods that +can be used to express that we only need the keys or the values. + +### Example + +``` +let map: HashMap = HashMap::new(); +let values = map.iter().map(|(_, value)| value).collect::>(); +``` + +Use instead: +``` +let map: HashMap = HashMap::new(); +let values = map.values().collect::>(); +``` \ No newline at end of file diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed new file mode 100644 index 00000000000..cf1292ecc23 --- /dev/null +++ b/tests/ui/iter_kv_map.fixed @@ -0,0 +1,65 @@ +// run-rustfix + +#![warn(clippy::iter_kv_map)] +#![allow(clippy::redundant_clone)] +#![allow(clippy::suspicious_map)] + +use std::collections::{BTreeMap, HashMap}; + +fn main() { + let get_key = |(key, _val)| key; + + let map: HashMap = HashMap::new(); + + let _ = map.keys().collect::>(); + let _ = map.values().collect::>(); + let _ = map.values().map(|v| v + 2).collect::>(); + let _ = map.values().map(|val| {val}).collect::>(); + + let _ = map.clone().into_keys().collect::>(); + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + + let _ = map.clone().into_values().collect::>(); + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + + let _ = map.clone().values().collect::>(); + map.keys().filter(|x| *x % 2 == 0).count(); + + // Don't lint + map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + map.keys().map(|key| key * 9).count(); + map.values().map(|value| value * 17).count(); + + let map: BTreeMap = BTreeMap::new(); + + let _ = map.keys().collect::>(); + let _ = map.values().collect::>(); + let _ = map.values().map(|v| v + 2).collect::>(); + let _ = map.values().map(|val| {val}).collect::>(); + + let _ = map.clone().into_keys().collect::>(); + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + + let _ = map.clone().into_values().collect::>(); + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + + let _ = map.clone().values().collect::>(); + map.keys().filter(|x| *x % 2 == 0).count(); + + // Don't lint + map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + map.keys().map(|key| key * 9).count(); + map.values().map(|value| value * 17).count(); +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs new file mode 100644 index 00000000000..b27e559e8e5 --- /dev/null +++ b/tests/ui/iter_kv_map.rs @@ -0,0 +1,65 @@ +// run-rustfix + +#![warn(clippy::iter_kv_map)] +#![allow(clippy::redundant_clone)] +#![allow(clippy::suspicious_map)] + +use std::collections::{BTreeMap, HashMap}; + +fn main() { + let get_key = |(key, _val)| key; + + let map: HashMap = HashMap::new(); + + let _ = map.iter().map(|(key, _)| key).collect::>(); + let _ = map.iter().map(|(_, value)| value).collect::>(); + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + let _ = map.iter().map(|(_, val)| val).collect::>(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + + // Don't lint + map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + map.iter().map(|(key, _value)| key * 9).count(); + map.iter().map(|(_key, value)| value * 17).count(); + + let map: BTreeMap = BTreeMap::new(); + + let _ = map.iter().map(|(key, _)| key).collect::>(); + let _ = map.iter().map(|(_, value)| value).collect::>(); + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + let _ = map.iter().map(|(_, val)| val).collect::>(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + + // Don't lint + map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); + map.iter().map(get_key).collect::>(); + + // Linting the following could be an improvement to the lint + // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); + + // Lint + map.iter().map(|(key, _value)| key * 9).count(); + map.iter().map(|(_key, value)| value * 17).count(); +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr new file mode 100644 index 00000000000..a6697e423e7 --- /dev/null +++ b/tests/ui/iter_kv_map.stderr @@ -0,0 +1,148 @@ +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:14:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + | + = note: `-D clippy::iter-kv-map` implied by `-D warnings` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:15:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:16:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:17:13 + | +LL | let _ = map.iter().map(|(_, val)| {val}).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|val| {val})` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:19:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:20:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:22:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:23:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:25:13 + | +LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:26:5 + | +LL | map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:36:5 + | +LL | map.iter().map(|(key, _value)| key * 9).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:37:5 + | +LL | map.iter().map(|(_key, value)| value * 17).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:41:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:42:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:43:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:44:13 + | +LL | let _ = map.iter().map(|(_, val)| {val}).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|val| {val})` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:46:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:47:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:49:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:50:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:52:13 + | +LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:53:5 + | +LL | map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:63:5 + | +LL | map.iter().map(|(key, _value)| key * 9).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:64:5 + | +LL | map.iter().map(|(_key, value)| value * 17).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` + +error: aborting due to 24 previous errors + -- cgit 1.4.1-3-g733a5 From a783d542073497b658d0e57960b612e2f6e0734a Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Wed, 21 Sep 2022 07:02:52 +0200 Subject: Fix ICE in `unnecessary_to_owned` Fixes #9504 Compiler generated call `into_iter` nodes return empty substs which we need when checking it's predicates. Handle this by simply exitting when we encounter one. This change introduces false negatives in place of the ICEs. --- clippy_lints/src/methods/unnecessary_to_owned.rs | 6 +++++- tests/ui/unnecessary_to_owned.fixed | 9 +++++++++ tests/ui/unnecessary_to_owned.rs | 9 +++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index b32e5d8d421..8e9ed33e009 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -8,7 +8,7 @@ use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -380,6 +380,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Expr(parent_expr) => { if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr) { + if cx.tcx.lang_items().require(LangItem::IntoFutureIntoFuture) == Ok(callee_def_id) { + return false; + } + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) && let Some(param_ty) = fn_sig.inputs().get(arg_index) diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index a920c63b199..f97583aa22f 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -417,3 +417,12 @@ mod issue_9351 { predicates_are_satisfied(id("abc".to_string())); } } + +mod issue_9504 { + #![allow(dead_code)] + + async fn foo>(_: S) {} + async fn bar() { + foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 2128bdacdda..aa5394a5657 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -417,3 +417,12 @@ mod issue_9351 { predicates_are_satisfied(id("abc".to_string())); } } + +mod issue_9504 { + #![allow(dead_code)] + + async fn foo>(_: S) {} + async fn bar() { + foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; + } +} -- cgit 1.4.1-3-g733a5 From e67b2bf732876eeb26e0d2fbc4b6c55e1a9f9317 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 23 Sep 2022 13:42:59 -0400 Subject: Apply uninlined_format-args to clippy_lints This change is needed for the uninlined_format-args lint to be merged. See https://github.com/rust-lang/rust-clippy/pull/9233 --- clippy_lints/src/approx_const.rs | 4 +-- clippy_lints/src/asm_syntax.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 4 +-- clippy_lints/src/assertions_on_result_states.rs | 10 +++--- clippy_lints/src/attrs.rs | 7 ++-- clippy_lints/src/bool_assert_comparison.rs | 4 +-- clippy_lints/src/booleans.rs | 5 ++- clippy_lints/src/cargo/common_metadata.rs | 2 +- clippy_lints/src/cargo/feature_name.rs | 4 +-- clippy_lints/src/cargo/mod.rs | 4 +-- clippy_lints/src/cargo/multiple_crate_versions.rs | 2 +- clippy_lints/src/casts/borrow_as_ptr.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 12 ++----- clippy_lints/src/casts/cast_possible_truncation.rs | 16 +++------ clippy_lints/src/casts/cast_possible_wrap.rs | 5 +-- clippy_lints/src/casts/cast_ptr_alignment.rs | 4 +-- clippy_lints/src/casts/cast_sign_loss.rs | 5 +-- .../src/casts/cast_slice_different_sizes.rs | 4 +-- clippy_lints/src/casts/char_lit_as_u8.rs | 2 +- clippy_lints/src/casts/fn_to_numeric_cast.rs | 4 +-- clippy_lints/src/casts/fn_to_numeric_cast_any.rs | 4 +-- .../casts/fn_to_numeric_cast_with_truncation.rs | 7 ++-- clippy_lints/src/casts/ptr_as_ptr.rs | 4 +-- clippy_lints/src/casts/unnecessary_cast.rs | 9 ++--- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 3 +- clippy_lints/src/default.rs | 17 ++++----- clippy_lints/src/default_numeric_fallback.rs | 4 +-- clippy_lints/src/dereference.rs | 14 ++++---- clippy_lints/src/disallowed_methods.rs | 2 +- clippy_lints/src/disallowed_script_idents.rs | 3 +- clippy_lints/src/disallowed_types.rs | 4 +-- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/entry.rs | 28 ++++----------- clippy_lints/src/enum_variants.rs | 7 ++-- clippy_lints/src/equatable_if_let.rs | 3 +- clippy_lints/src/eta_reduction.rs | 4 +-- clippy_lints/src/exhaustive_items.rs | 2 +- clippy_lints/src/explicit_write.rs | 8 ++--- clippy_lints/src/float_literal.rs | 6 ++-- clippy_lints/src/floating_point_arithmetic.rs | 7 ++-- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 17 ++++----- clippy_lints/src/format_impl.rs | 6 ++-- clippy_lints/src/formatting.rs | 25 +++++--------- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- clippy_lints/src/functions/too_many_arguments.rs | 5 +-- clippy_lints/src/functions/too_many_lines.rs | 5 +-- clippy_lints/src/if_then_some_else_none.rs | 9 +++-- clippy_lints/src/implicit_hasher.rs | 7 ++-- clippy_lints/src/implicit_return.rs | 4 +-- clippy_lints/src/implicit_saturating_sub.rs | 2 +- .../src/inconsistent_struct_constructor.rs | 6 ++-- clippy_lints/src/index_refutable_slice.rs | 4 +-- clippy_lints/src/inherent_to_string.rs | 12 +++---- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/int_plus_one.rs | 4 +-- clippy_lints/src/iter_not_returning_iterator.rs | 5 +-- clippy_lints/src/len_zero.rs | 35 ++++++++----------- clippy_lints/src/let_if_seq.rs | 3 +- clippy_lints/src/lib.rs | 11 +++--- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops/explicit_counter_loop.rs | 14 +++----- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/for_kv_map.rs | 4 +-- clippy_lints/src/loops/manual_flatten.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 13 ++----- clippy_lints/src/loops/needless_collect.rs | 6 ++-- clippy_lints/src/loops/needless_range_loop.rs | 10 +++--- clippy_lints/src/loops/never_loop.rs | 6 +--- clippy_lints/src/loops/same_item_push.rs | 5 +-- clippy_lints/src/loops/utils.rs | 3 +- clippy_lints/src/loops/while_let_on_iterator.rs | 2 +- clippy_lints/src/macro_use.rs | 6 ++-- clippy_lints/src/manual_async_fn.rs | 6 ++-- clippy_lints/src/manual_non_exhaustive.rs | 4 +-- clippy_lints/src/manual_retain.rs | 14 +++----- clippy_lints/src/manual_strip.rs | 9 +++-- clippy_lints/src/map_unit_fn.rs | 5 +-- clippy_lints/src/match_result_ok.rs | 6 ++-- clippy_lints/src/matches/manual_map.rs | 14 ++++---- clippy_lints/src/matches/manual_unwrap_or.rs | 6 ++-- clippy_lints/src/matches/match_as_ref.rs | 6 ++-- clippy_lints/src/matches/match_like_matches.rs | 5 ++- clippy_lints/src/matches/match_same_arms.rs | 2 +- clippy_lints/src/matches/match_single_binding.rs | 28 ++++++--------- .../src/matches/match_str_case_mismatch.rs | 4 +-- clippy_lints/src/matches/match_wild_err_arm.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 8 ++--- .../src/matches/significant_drop_in_scrutinee.rs | 6 ++-- clippy_lints/src/matches/single_match.rs | 6 ++-- clippy_lints/src/matches/try_err.rs | 4 +-- clippy_lints/src/methods/bind_instead_of_map.rs | 2 +- clippy_lints/src/methods/bytes_nth.rs | 2 +- clippy_lints/src/methods/chars_cmp.rs | 5 ++- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 5 ++- clippy_lints/src/methods/clone_on_copy.rs | 13 ++++--- clippy_lints/src/methods/clone_on_ref_ptr.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 11 +++--- clippy_lints/src/methods/filetype_is_file.rs | 4 +-- clippy_lints/src/methods/filter_map_next.rs | 2 +- clippy_lints/src/methods/filter_next.rs | 2 +- .../src/methods/from_iter_instead_of_collect.rs | 6 ++-- clippy_lints/src/methods/get_first.rs | 4 +-- clippy_lints/src/methods/get_unwrap.rs | 11 ++---- clippy_lints/src/methods/implicit_clone.rs | 6 ++-- clippy_lints/src/methods/inefficient_to_string.rs | 7 ++-- clippy_lints/src/methods/into_iter_on_ref.rs | 3 +- clippy_lints/src/methods/is_digit_ascii_radix.rs | 7 ++-- clippy_lints/src/methods/iter_cloned_collect.rs | 4 +-- clippy_lints/src/methods/iter_count.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 8 ++--- clippy_lints/src/methods/iter_next_slice.rs | 2 +- clippy_lints/src/methods/iter_nth.rs | 4 +-- clippy_lints/src/methods/iter_with_drain.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 4 +-- .../src/methods/manual_saturating_arithmetic.rs | 5 ++- clippy_lints/src/methods/manual_str_repeat.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 5 ++- clippy_lints/src/methods/map_flatten.rs | 9 ++--- clippy_lints/src/methods/map_identity.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- clippy_lints/src/methods/option_as_ref_deref.rs | 9 +++-- clippy_lints/src/methods/option_map_or_none.rs | 6 ++-- clippy_lints/src/methods/option_map_unwrap_or.rs | 9 +++-- clippy_lints/src/methods/or_fun_call.rs | 10 +++--- clippy_lints/src/methods/search_is_some.rs | 14 +++----- .../src/methods/single_char_insert_string.rs | 2 +- .../src/methods/single_char_push_string.rs | 2 +- clippy_lints/src/methods/stable_sort_primitive.rs | 4 +-- clippy_lints/src/methods/string_extend_chars.rs | 3 +- clippy_lints/src/methods/suspicious_splitn.rs | 4 +-- clippy_lints/src/methods/suspicious_to_owned.rs | 4 +-- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/methods/unnecessary_fold.rs | 7 ++-- .../src/methods/unnecessary_iter_cloned.rs | 2 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 4 +-- clippy_lints/src/methods/unnecessary_to_owned.rs | 21 ++++++------ clippy_lints/src/methods/useless_asref.rs | 2 +- clippy_lints/src/methods/wrong_self_convention.rs | 15 ++++---- clippy_lints/src/misc.rs | 18 ++++------ clippy_lints/src/misc_early/literal_suffix.rs | 8 ++--- clippy_lints/src/misc_early/mod.rs | 5 ++- .../src/misc_early/unneeded_field_pattern.rs | 4 +-- clippy_lints/src/mismatching_type_param_order.rs | 7 ++-- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_enforced_import_rename.rs | 4 +-- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 5 +-- clippy_lints/src/mutex_atomic.rs | 5 ++- clippy_lints/src/needless_continue.rs | 14 +++----- clippy_lints/src/needless_late_init.rs | 10 +++--- clippy_lints/src/needless_pass_by_value.rs | 4 +-- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/neg_multiply.rs | 4 +-- clippy_lints/src/new_without_default.rs | 7 ++-- clippy_lints/src/non_expressive_names.rs | 5 +-- clippy_lints/src/nonstandard_macro_braces.rs | 12 +++---- clippy_lints/src/octal_escapes.rs | 2 +- .../src/operators/absurd_extreme_comparisons.rs | 5 ++- clippy_lints/src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/operators/bit_mask.rs | 40 +++++----------------- clippy_lints/src/operators/cmp_owned.rs | 10 +++--- clippy_lints/src/operators/duration_subsec.rs | 7 ++-- clippy_lints/src/operators/eq_op.rs | 2 +- .../src/operators/misrefactored_assign_op.rs | 12 +++---- .../src/operators/needless_bitwise_bool.rs | 2 +- clippy_lints/src/operators/ptr_eq.rs | 2 +- clippy_lints/src/operators/self_assignment.rs | 2 +- clippy_lints/src/operators/verbose_bit_mask.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 4 +-- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/ptr_offset_with_cast.rs | 4 +-- clippy_lints/src/question_mark.rs | 7 ++-- clippy_lints/src/ranges.rs | 16 ++++----- clippy_lints/src/read_zero_byte_vec.rs | 3 +- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 8 ++--- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/regex.rs | 4 +-- clippy_lints/src/same_name_method.rs | 4 +-- clippy_lints/src/semicolon_if_nothing_returned.rs | 2 +- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/strings.rs | 6 ++-- clippy_lints/src/strlen_on_c_strings.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 9 ++--- clippy_lints/src/swap.rs | 19 +++++----- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 4 +-- clippy_lints/src/trait_bounds.rs | 3 +- .../src/transmute/crosspointer_transmute.rs | 10 ++---- .../src/transmute/transmute_float_to_int.rs | 4 +-- .../src/transmute/transmute_int_to_bool.rs | 2 +- .../src/transmute/transmute_int_to_char.rs | 4 +-- .../src/transmute/transmute_int_to_float.rs | 4 +-- .../src/transmute/transmute_num_to_bytes.rs | 4 +-- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 18 ++++------ clippy_lints/src/transmute/transmute_ref_to_ref.rs | 2 +- .../src/transmute/transmute_undefined_repr.rs | 23 ++++++------- .../transmutes_expressible_as_ptr_casts.rs | 5 +-- .../src/transmute/unsound_collection_transmute.rs | 5 +-- clippy_lints/src/transmute/useless_transmute.rs | 2 +- clippy_lints/src/transmute/wrong_transmute.rs | 2 +- clippy_lints/src/types/borrowed_box.rs | 6 ++-- clippy_lints/src/types/box_collection.rs | 2 +- clippy_lints/src/types/rc_buffer.rs | 4 +-- clippy_lints/src/types/redundant_allocation.rs | 29 +++++----------- clippy_lints/src/unit_return_expecting_ord.rs | 6 ++-- clippy_lints/src/unit_types/unit_arg.rs | 7 ++-- clippy_lints/src/unit_types/unit_cmp.rs | 7 ++-- clippy_lints/src/unnecessary_self_imports.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 7 ++-- clippy_lints/src/unsafe_removed_from_name.rs | 5 +-- clippy_lints/src/unused_rounding.rs | 4 +-- clippy_lints/src/unwrap.rs | 7 ++-- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/useless_conversion.rs | 10 +++--- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/conf.rs | 9 ++--- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 3 +- 225 files changed, 557 insertions(+), 842 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 159f3b0cd01..724490fb495 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -92,7 +92,7 @@ impl ApproxConstant { cx, APPROX_CONSTANT, e.span, - &format!("approximate value of `{}::consts::{}` found", module, &name), + &format!("approximate value of `{module}::consts::{}` found", &name), None, "consider using the constant directly", ); @@ -126,7 +126,7 @@ fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { // The value is a truncated constant true } else { - let round_const = format!("{:.*}", value.len() - 2, constant); + let round_const = format!("{constant:.*}", value.len() - 2); value == round_const } } diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index f419781dbc8..ad31d708f64 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -44,7 +44,7 @@ fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr cx, lint, expr.span, - &format!("{} x86 assembly syntax used", style), + &format!("{style} x86 assembly syntax used"), None, &format!("use {} x86 assembly syntax", !style), ); diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 2705ffffdcb..a36df55d0bd 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -60,9 +60,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { cx, ASSERTIONS_ON_CONSTANTS, macro_call.span, - &format!("`assert!(false{})` should probably be replaced", assert_arg), + &format!("`assert!(false{assert_arg})` should probably be replaced"), None, - &format!("use `panic!({})` or `unreachable!({0})`", panic_arg), + &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"), ); } } diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 656dc5feeb5..f6d6c23bb6e 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -69,9 +69,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { "called `assert!` with `Result::is_ok`", "replace with", format!( - "{}.unwrap(){}", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, - semicolon + "{}.unwrap(){semicolon}", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 ), app, ); @@ -84,9 +83,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { "called `assert!` with `Result::is_err`", "replace with", format!( - "{}.unwrap_err(){}", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0, - semicolon + "{}.unwrap_err(){semicolon}", + snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 ), app, ); diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 732dc2b4330..5f45c69d7f9 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -541,10 +541,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut cx, INLINE_ALWAYS, attr.span, - &format!( - "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", - name - ), + &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), ); } } @@ -720,7 +717,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { let mut unix_suggested = false; for (os, span) in mismatched { - let sugg = format!("target_os = \"{}\"", os); + let sugg = format!("target_os = \"{os}\""); diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); if !unix_suggested && is_unix(os) { diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 95abe8aa59f..4bd55c1429c 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -98,9 +98,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { cx, BOOL_ASSERT_COMPARISON, macro_call.span, - &format!("used `{}!` with a literal bool", macro_name), + &format!("used `{macro_name}!` with a literal bool"), "replace it with", - format!("{}!(..)", non_eq_mac), + format!("{non_eq_mac}!(..)"), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 03d262d5a59..2a15cbc7a3c 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -263,9 +263,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } .and_then(|op| { Some(format!( - "{}{}{}", + "{}{op}{}", snippet_opt(cx, lhs.span)?, - op, snippet_opt(cx, rhs.span)? )) }) @@ -285,7 +284,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method))) + .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?))) }, _ => None, } diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index e0442dda479..805121bcced 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -40,7 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b } fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { - let message = format!("package `{}` is missing `{}` metadata", package.name, field); + let message = format!("package `{}` is missing `{field}` metadata", package.name); span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); } diff --git a/clippy_lints/src/cargo/feature_name.rs b/clippy_lints/src/cargo/feature_name.rs index 79a469a4258..37c169dbd95 100644 --- a/clippy_lints/src/cargo/feature_name.rs +++ b/clippy_lints/src/cargo/feature_name.rs @@ -57,10 +57,8 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { }, DUMMY_SP, &format!( - "the \"{}\" {} in the feature name \"{}\" is {}", - substring, + "the \"{substring}\" {} in the feature name \"{feature}\" is {}", if is_prefix { "prefix" } else { "suffix" }, - feature, if is_negative { "negative" } else { "redundant" } ), None, diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 9f45db86a09..3a872e54c9a 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -196,7 +196,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in NO_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); + span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); } }, } @@ -212,7 +212,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in WITH_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); + span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); } }, } diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 76fd0819a39..f9b17d45e9f 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, - &format!("multiple versions for dependency `{}`: {}", name, versions), + &format!("multiple versions for dependency `{name}`: {versions}"), ); } } diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index 6e1f8cd64f0..294d22d34de 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( expr.span, "borrow as raw pointer", "try", - format!("{}::ptr::{}!({})", core_or_std, macro_name, snip), + format!("{core_or_std}::ptr::{macro_name}!({snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 938458e30ca..13c403234da 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -41,15 +41,9 @@ pub(super) fn check( ); let message = if cast_from.is_bool() { - format!( - "casting `{0:}` to `{1:}` is more cleanly stated with `{1:}::from(_)`", - cast_from, cast_to - ) + format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`") } else { - format!( - "casting `{}` to `{}` may become silently lossy if you later change the type", - cast_from, cast_to - ) + format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type") }; span_lint_and_sugg( @@ -58,7 +52,7 @@ pub(super) fn check( expr.span, &message, "try", - format!("{}::from({})", cast_to, sugg), + format!("{cast_to}::from({sugg})"), applicability, ); } diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 406547a4454..88deb4565eb 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -103,10 +103,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, return; } - format!( - "casting `{}` to `{}` may truncate the value{}", - cast_from, cast_to, suffix, - ) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) }, (ty::Adt(def, _), true) if def.is_enum() => { @@ -142,20 +139,17 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, CAST_ENUM_TRUNCATION, expr.span, &format!( - "casting `{}::{}` to `{}` will truncate the value{}", - cast_from, variant.name, cast_to, suffix, + "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}", + variant.name, ), ); return; } - format!( - "casting `{}` to `{}` may truncate the value{}", - cast_from, cast_to, suffix, - ) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) }, (ty::Float(_), true) => { - format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value") }, (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 2c5c1d7cb46..28ecdea7ea0 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -35,10 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca cx, CAST_POSSIBLE_WRAP, expr.span, - &format!( - "casting `{}` to `{}` may wrap around the value{}", - cast_from, cast_to, suffix, - ), + &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",), ); } } diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index da7b12f6726..97054a0d101 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -49,9 +49,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f CAST_PTR_ALIGNMENT, expr.span, &format!( - "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)", - cast_from, - cast_to, + "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)", from_layout.align.abi.bytes(), to_layout.align.abi.bytes(), ), diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 5b59350be04..a20a97d4e56 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -14,10 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c cx, CAST_SIGN_LOSS, expr.span, - &format!( - "casting `{}` to `{}` may lose the sign of the value", - cast_from, cast_to - ), + &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), ); } } diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 027c660ce3b..d31d10d22b9 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -35,8 +35,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Optio CAST_SLICE_DIFFERENT_SIZES, expr.span, &format!( - "casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count", - start_ty.ty, from_size, end_ty.ty, to_size, + "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count", + start_ty.ty, end_ty.ty, ), |diag| { let ptr_snippet = source::snippet(cx, left_cast.span, ".."); diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index 7cc406018db..82e07c98a7e 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { diag.span_suggestion( expr.span, "use a byte literal instead", - format!("b{}", snippet), + format!("b{snippet}"), applicability, ); } diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index 35350d8a25b..a26bfab4e7c 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -25,9 +25,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST, expr.span, - &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), + &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "try", - format!("{} as usize", from_snippet), + format!("{from_snippet} as usize"), applicability, ); } diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index 03621887a34..75654129408 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -23,9 +23,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_ANY, expr.span, - &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), + &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "did you mean to invoke the function?", - format!("{}() as {}", from_snippet, cast_to), + format!("{from_snippet}() as {cast_to}"), applicability, ); }, diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 6287f479b5b..556be1d1506 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -24,12 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, expr.span, - &format!( - "casting function pointer `{}` to `{}`, which truncates the value", - from_snippet, cast_to - ), + &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), "try", - format!("{} as usize", from_snippet), + format!("{from_snippet} as usize"), applicability, ); } diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 46d45d09661..c2b9253ec35 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option Cow::Borrowed(""), TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""), - _ => Cow::Owned(format!("::<{}>", to_pointee_ty)), + _ => Cow::Owned(format!("::<{to_pointee_ty}>")), }; span_lint_and_sugg( cx, @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option( cx, UNNECESSARY_CAST, expr.span, - &format!( - "casting to the same type is unnecessary (`{}` -> `{}`)", - cast_from, cast_to - ), + &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", literal_str, Applicability::MachineApplicable, @@ -101,9 +98,9 @@ fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st cx, UNNECESSARY_CAST, expr.span, - &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to), + &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), "try", - format!("{}_{}", matchless.trim_end_matches('.'), cast_to), + format!("{}_{cast_to}", matchless.trim_end_matches('.')), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 37b2fdcff09..1d113c7cbee 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { item.span, "checked cast can be simplified", "try", - format!("{}::try_from({}).is_ok()", to_type, snippet), + format!("{to_type}::try_from({snippet}).is_ok()"), applicability, ); } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 33c44f8b2db..fed04ae7f3d 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -107,8 +107,7 @@ impl CognitiveComplexity { COGNITIVE_COMPLEXITY, fn_span, &format!( - "the function has a cognitive complexity of ({}/{})", - rust_cc, + "the function has a cognitive complexity of ({rust_cc}/{})", self.limit.limit() ), None, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 74f7df61177..cb6800c8ba2 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { cx, DEFAULT_TRAIT_ACCESS, expr.span, - &format!("calling `{}` is more clear than this expression", replacement), + &format!("calling `{replacement}` is more clear than this expression"), "try", replacement, Applicability::Unspecified, // First resolve the TODO above @@ -210,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .map(|(field, rhs)| { // extract and store the assigned value for help message let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); - format!("{}: {}", field, value_snippet) + format!("{field}: {value_snippet}") }) .collect::>() .join(", "); @@ -227,7 +227,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .map(ToString::to_string) .collect::>() .join(", "); - format!("{}::<{}>", adt_def_ty_name, &tys_str) + format!("{adt_def_ty_name}::<{}>", &tys_str) } else { binding_type.to_string() } @@ -235,12 +235,12 @@ impl<'tcx> LateLintPass<'tcx> for Default { let sugg = if ext_with_default { if field_list.is_empty() { - format!("{}::default()", binding_type) + format!("{binding_type}::default()") } else { - format!("{} {{ {}, ..Default::default() }}", binding_type, field_list) + format!("{binding_type} {{ {field_list}, ..Default::default() }}") } } else { - format!("{} {{ {} }}", binding_type, field_list) + format!("{binding_type} {{ {field_list} }}") }; // span lint once per statement that binds default @@ -250,10 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { first_assign.unwrap().span, "field assignment outside of initializer for an instance created with Default::default()", Some(local.span), - &format!( - "consider initializing the variable with `{}` and removing relevant reassignments", - sugg - ), + &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"), ); self.reassigned_linted.insert(span); } diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index be02f328e98..3ed9cd36a22 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -95,8 +95,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { src } else { match lit.node { - LitKind::Int(src, _) => format!("{}", src), - LitKind::Float(src, _) => format!("{}", src), + LitKind::Int(src, _) => format!("{src}"), + LitKind::Float(src, _) => format!("{src}"), _ => return, } }; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b965d27afce..e272283152d 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1308,7 +1308,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }; let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { - format!("({})", expr_str) + format!("({expr_str})") } else { expr_str.into_owned() }; @@ -1322,7 +1322,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data Mutability::Mut => "explicit `deref_mut` method call", }, "try this", - format!("{}{}{}", addr_of_str, deref_str, expr_str), + format!("{addr_of_str}{deref_str}{expr_str}"), app, ); }, @@ -1336,7 +1336,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data && !has_enclosing_paren(&snip) && (expr.precedence().order() < data.position.precedence() || calls_field) { - format!("({})", snip) + format!("({snip})") } else { snip.into() }; @@ -1379,9 +1379,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let sugg = if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { - format!("{}({})", prefix, snip) + format!("{prefix}({snip})") } else { - format!("{}{}", prefix, snip) + format!("{prefix}{snip}") }; diag.span_suggestion(data.span, "try this", sugg, app); }, @@ -1460,14 +1460,14 @@ impl Dereferencing { } else { pat.always_deref = false; let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; - pat.replacements.push((e.span, format!("&{}", snip))); + pat.replacements.push((e.span, format!("&{snip}"))); } }, _ if !e.span.from_expansion() => { // Double reference might be needed at this point. pat.always_deref = false; let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); - pat.replacements.push((e.span, format!("&{}", snip))); + pat.replacements.push((e.span, format!("&{snip}"))); }, // Edge case for macros. The span of the identifier will usually match the context of the // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 53973ab792a..b02f87c07db 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { reason: Some(reason), .. } = conf { - diag.note(&format!("{} (from clippy.toml)", reason)); + diag.note(&format!("{reason} (from clippy.toml)")); } }); } diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 0c27c3f9255..084190f0013 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -99,8 +99,7 @@ impl EarlyLintPass for DisallowedScriptIdents { DISALLOWED_SCRIPT_IDENTS, span, &format!( - "identifier `{}` has a Unicode script that is not allowed by configuration: {}", - symbol_str, + "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", script.full_name() ), ); diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 14f89edce61..53451238d9a 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { conf::DisallowedType::Simple(path) => (path, None), conf::DisallowedType::WithReason { path, reason } => ( path, - reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)), + reason.as_ref().map(|reason| format!("{reason} (from clippy.toml)")), ), }; let segs: Vec<_> = path.split("::").collect(); @@ -130,7 +130,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) { cx, DISALLOWED_TYPES, span, - &format!("`{}` is not allowed according to config", name), + &format!("`{name}` is not allowed according to config"), |diag| { if let Some(reason) = reason { diag.note(reason); diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index eb158d850fa..fa50a2d1a2c 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -790,7 +790,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { diag.span_suggestion_with_style( span, "try", - format!("`{}`", snippet), + format!("`{snippet}`"), applicability, // always show the suggestion in a separate line, since the // inline presentation adds another pair of backticks diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index b35f0b8ca52..0ee07fbcc75 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { expr.span, msg, Some(arg.span), - &format!("argument has type `{}`", arg_ty), + &format!("argument has type `{arg_ty}`"), ); } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index e70df3f53c7..9c834cf0144 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -113,13 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { ), }; format!( - "if let {}::{} = {}.entry({}) {} else {}", + "if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}", map_ty.entry_path(), - entry_kind, - map_str, - key_str, - then_str, - else_str, ) } else { // if .. { insert } else { insert } @@ -137,16 +132,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { let indent_str = snippet_indent(cx, expr.span); let indent_str = indent_str.as_deref().unwrap_or(""); format!( - "match {}.entry({}) {{\n{indent} {entry}::{} => {}\n\ - {indent} {entry}::{} => {}\n{indent}}}", - map_str, - key_str, - then_entry, + "match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\ + {indent_str} {entry}::{else_entry} => {}\n{indent_str}}}", reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())), - else_entry, reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())), entry = map_ty.entry_path(), - indent = indent_str, ) } } else { @@ -163,20 +153,16 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { then_search.snippet_occupied(cx, then_expr.span, &mut app) }; format!( - "if let {}::{} = {}.entry({}) {}", + "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}", map_ty.entry_path(), - entry_kind, - map_str, - key_str, - body_str, ) } else if let Some(insertion) = then_search.as_single_insertion() { let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0; if contains_expr.negated { if insertion.value.can_have_side_effects() { - format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, value_str) + format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});") } else { - format!("{}.entry({}).or_insert({});", map_str, key_str, value_str) + format!("{map_str}.entry({key_str}).or_insert({value_str});") } } else { // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. @@ -186,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { } else { let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app); if contains_expr.negated { - format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, block_str) + format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});") } else { // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here. // This would need to be a different lint. diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index cd36f9fcd72..d8c6b4e39ae 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -202,12 +202,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n cx, ENUM_VARIANT_NAMES, span, - &format!("all variants have the same {}fix: `{}`", what, value), + &format!("all variants have the same {what}fix: `{value}`"), None, &format!( - "remove the {}fixes and use full paths to \ - the variants instead of glob imports", - what + "remove the {what}fixes and use full paths to \ + the variants instead of glob imports" ), ); } diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index fdfb821ac78..7917d83c0b9 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -91,9 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { "this pattern matching can be expressed using equality", "try", format!( - "{} == {}", + "{} == {pat_str}", snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0, - pat_str, ), applicability, ); diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 53bc617a4f5..0f9f94a6b54 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { then { // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {}", snippet); + snippet = format!("&mut {snippet}"); } } diag.span_suggestion( @@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { diag.span_suggestion( expr.span, "replace the closure with the method itself", - format!("{}::{}", name, path.ident.name), + format!("{name}::{}", path.ident.name), Applicability::MachineApplicable, ); }) diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 173d41b4b05..218e40f2b5f 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -97,7 +97,7 @@ impl LateLintPass<'_> for ExhaustiveItems { item.span, msg, |diag| { - let sugg = format!("#[non_exhaustive]\n{}", indent); + let sugg = format!("#[non_exhaustive]\n{indent}"); diag.span_suggestion(suggestion_span, "try adding #[non_exhaustive]", sugg, diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index b9ed4af0219..c0ea6f338a2 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -80,12 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { // used. let (used, sugg_mac) = if let Some(macro_name) = calling_macro { ( - format!("{}!({}(), ...)", macro_name, dest_name), + format!("{macro_name}!({dest_name}(), ...)"), macro_name.replace("write", "print"), ) } else { ( - format!("{}().write_fmt(...)", dest_name), + format!("{dest_name}().write_fmt(...)"), "print".into(), ) }; @@ -100,9 +100,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { cx, EXPLICIT_WRITE, expr.span, - &format!("use of `{}.unwrap()`", used), + &format!("use of `{used}.unwrap()`"), "try this", - format!("{}{}!({})", prefix, sugg_mac, inputs_snippet), + format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, ) } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index f2e07980963..6fee7fb308c 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -173,9 +173,9 @@ impl FloatFormat { T: fmt::UpperExp + fmt::LowerExp + fmt::Display, { match self { - Self::LowerExp => format!("{:e}", f), - Self::UpperExp => format!("{:E}", f), - Self::Normal => format!("{}", f), + Self::LowerExp => format!("{f:e}"), + Self::UpperExp => format!("{f:E}"), + Self::Normal => format!("{f}"), } } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index ba53a967880..e71afec12a7 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -142,8 +142,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node; then { let op = format!( - "{}{}{}", - suggestion, + "{suggestion}{}{}", // Check for float literals without numbers following the decimal // separator such as `2.` and adds a trailing zero if sym.as_str().ends_with('.') { @@ -172,7 +171,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, ar expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method), + format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_par()), Applicability::MachineApplicable, ); } @@ -251,7 +250,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", - format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), + format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index f10d8256953..bc0c68f535a 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { [_] => { // Simulate macro expansion, converting {{ and }} to { and }. let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); + let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); }, [..] => {}, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index e1c46fd0bfd..192f6258aa5 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -112,11 +112,10 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb cx, FORMAT_IN_FORMAT_ARGS, call_site, - &format!("`format!` in `{}!` args", name), + &format!("`format!` in `{name}!` args"), |diag| { diag.help(&format!( - "combine the `format!(..)` arguments with the outer `{}!(..)` call", - name + "combine the `format!(..)` arguments with the outer `{name}!(..)` call" )); diag.help("or consider changing `format!` to `format_args!`"); }, @@ -144,8 +143,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex TO_STRING_IN_FORMAT_ARGS, value.span.with_lo(receiver.span.hi()), &format!( - "`to_string` applied to a type that implements `Display` in `{}!` args", - name + "`to_string` applied to a type that implements `Display` in `{name}!` args" ), "remove this", String::new(), @@ -157,16 +155,13 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex TO_STRING_IN_FORMAT_ARGS, value.span, &format!( - "`to_string` applied to a type that implements `Display` in `{}!` args", - name + "`to_string` applied to a type that implements `Display` in `{name}!` args" ), "use this", format!( - "{}{:*>width$}{}", + "{}{:*>n_needed_derefs$}{receiver_snippet}", if needs_ref { "&" } else { "" }, - "", - receiver_snippet, - width = n_needed_derefs + "" ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index b628fd9f758..ed1342a5465 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -214,12 +214,12 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: cx, PRINT_IN_FORMAT_IMPL, macro_call.span, - &format!("use of `{}!` in `{}` impl", name, impl_trait.name), + &format!("use of `{name}!` in `{}` impl", impl_trait.name), "replace with", if let Some(formatter_name) = impl_trait.formatter_name { - format!("{}!({}, ..)", replacement, formatter_name) + format!("{replacement}!({formatter_name}, ..)") } else { - format!("{}!(..)", replacement) + format!("{replacement}!(..)") }, Applicability::HasPlaceholders, ); diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 01cefe4af85..a866a68987d 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -154,11 +154,10 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { eqop_span, &format!( "this looks like you are trying to use `.. {op}= ..`, but you \ - really are doing `.. = ({op} ..)`", - op = op + really are doing `.. = ({op} ..)`" ), None, - &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op), + &format!("to remove this lint, use either `{op}=` or `= {op}`"), ); } } @@ -191,16 +190,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { SUSPICIOUS_UNARY_OP_FORMATTING, eqop_span, &format!( - "by not having a space between `{binop}` and `{unop}` it looks like \ - `{binop}{unop}` is a single operator", - binop = binop_str, - unop = unop_str + "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ + `{binop_str}{unop_str}` is a single operator" ), None, &format!( - "put a space between `{binop}` and `{unop}` and remove the space after `{unop}`", - binop = binop_str, - unop = unop_str + "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`" ), ); } @@ -246,12 +241,11 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this is an `else {}` but the formatting might hide it", else_desc), + &format!("this is an `else {else_desc}` but the formatting might hide it"), None, &format!( "to remove this lint, remove the `else` or remove the new line between \ - `else` and `{}`", - else_desc, + `else` and `{else_desc}`", ), ); } @@ -320,11 +314,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this looks like {} but the `else` is missing", looks_like), + &format!("this looks like {looks_like} but the `else` is missing"), None, &format!( - "to remove this lint, add the missing `else` or add a new line before {}", - next_thing, + "to remove this lint, add the missing `else` or add a new line before {next_thing}", ), ); } diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 74941d817be..2a82473be8c 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { exp.span, "this call to `from_str_radix` can be replaced with a call to `str::parse`", "try", - format!("{}.parse::<{}>()", sugg, prim_ty.name_str()), + format!("{sugg}.parse::<{}>()", prim_ty.name_str()), Applicability::MaybeIncorrect ); } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 00a4937763e..09b97bacd65 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -143,7 +143,7 @@ fn check_must_use_candidate<'tcx>( diag.span_suggestion( fn_span, "add the attribute", - format!("#[must_use] {}", snippet), + format!("#[must_use] {snippet}"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs index 5c8d8b8e755..1e08922a616 100644 --- a/clippy_lints/src/functions/too_many_arguments.rs +++ b/clippy_lints/src/functions/too_many_arguments.rs @@ -59,10 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span, cx, TOO_MANY_ARGUMENTS, fn_span, - &format!( - "this function has too many arguments ({}/{})", - args, too_many_arguments_threshold - ), + &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"), ); } } diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 54bdea7ea25..f83f8b40f94 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -78,10 +78,7 @@ pub(super) fn check_fn( cx, TOO_MANY_LINES, span, - &format!( - "this function has too many lines ({}/{})", - line_count, too_many_lines_threshold - ), + &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), ); } } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 11c43247868..0800e0644f7 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({})", cond_snip) + format!("({cond_snip})") } else { cond_snip.into_owned() }; @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { - format!("{{ /* snippet */ {} }}", arg_snip) + format!("{{ /* snippet */ {arg_snip} }}") }; let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { "then_some" @@ -102,14 +102,13 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { }; let help = format!( - "consider using `bool::{}` like: `{}.{}({})`", - method_name, cond_snip, method_name, method_body, + "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`", ); span_lint_and_help( cx, IF_THEN_SOME_ELSE_NONE, expr.span, - &format!("this could be simplified with `bool::{}`", method_name), + &format!("this could be simplified with `bool::{method_name}`"), None, &help, ); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 4f9680f60fe..067af79152f 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -89,8 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { ( generics_suggestion_span, format!( - "<{}{}S: ::std::hash::BuildHasher{}>", - generics_snip, + "<{generics_snip}{}S: ::std::hash::BuildHasher{}>", if generics_snip.is_empty() { "" } else { ", " }, if vis.suggestions.is_empty() { "" @@ -263,8 +262,8 @@ impl<'tcx> ImplicitHasherType<'tcx> { fn type_arguments(&self) -> String { match *self { - ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v), - ImplicitHasherType::HashSet(.., ref t) => format!("{}", t), + ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{k}, {v}"), + ImplicitHasherType::HashSet(.., ref t) => format!("{t}"), } } diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index feec8ec2e23..cfc988da233 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -53,7 +53,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) { span, "missing `return` statement", |diag| { - diag.span_suggestion(span, "add `return` as shown", format!("return {}", snip), app); + diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app); }, ); } @@ -71,7 +71,7 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp diag.span_suggestion( break_span, "change `break` to `return` as shown", - format!("return {}", snip), + format!("return {snip}"), app, ); }, diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 46654bc61e0..f0dbe17d83a 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -170,7 +170,7 @@ fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) { expr.span, "implicitly performing saturating subtraction", "try", - format!("{} = {}.saturating_sub({});", var_name, var_name, '1'), + format!("{var_name} = {var_name}.saturating_sub({});", '1'), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 14b22d2b50d..e2f2d3d42e6 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { let mut fields_snippet = String::new(); let (last_ident, idents) = ordered_fields.split_last().unwrap(); for ident in idents { - let _ = write!(fields_snippet, "{}, ", ident); + let _ = write!(fields_snippet, "{ident}, "); } fields_snippet.push_str(&last_ident.to_string()); @@ -100,10 +100,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { String::new() }; - let sugg = format!("{} {{ {}{} }}", + let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}", snippet(cx, qpath.span(), ".."), - fields_snippet, - base_snippet, ); span_lint_and_sugg( diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 0dd7f5bf000..c7b5badaae5 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -139,14 +139,14 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) { .map(|(index, _)| *index) .collect::>(); - let value_name = |index| format!("{}_{}", slice.ident.name, index); + let value_name = |index| format!("{}_{index}", slice.ident.name); if let Some(max_index) = used_indices.iter().max() { let opt_ref = if slice.needs_ref { "ref " } else { "" }; let pat_sugg_idents = (0..=*max_index) .map(|index| { if used_indices.contains(&index) { - format!("{}{}", opt_ref, value_name(index)) + format!("{opt_ref}{}", value_name(index)) } else { "_".to_string() } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 17d867aacb5..f171ae2649d 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -131,23 +131,19 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { INHERENT_TO_STRING_SHADOW_DISPLAY, item.span, &format!( - "type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`", - self_type + "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`" ), None, - &format!("remove the inherent method from type `{}`", self_type), + &format!("remove the inherent method from type `{self_type}`"), ); } else { span_lint_and_help( cx, INHERENT_TO_STRING, item.span, - &format!( - "implementation of inherent method `to_string(&self) -> String` for type `{}`", - self_type - ), + &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"), None, - &format!("implement trait `Display` for type `{}` instead", self_type), + &format!("implement trait `Display` for type `{self_type}` instead"), ); } } diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index dd7177e0131..d609a5ca4d4 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { cx, INLINE_FN_WITHOUT_BODY, attr.span, - &format!("use of `#[inline]` on trait method `{}` which has no body", name), + &format!("use of `#[inline]` on trait method `{name}` which has no body"), |diag| { diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); }, diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 9a944def3eb..33491da3fc5 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -138,8 +138,8 @@ impl IntPlusOne { if let Some(snippet) = snippet_opt(cx, node.span) { if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { let rec = match side { - Side::Lhs => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)), - Side::Rhs => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)), + Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), + Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), }; return rec; } diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index b56d87c5348..78815ea5a0a 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -80,10 +80,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI cx, ITER_NOT_RETURNING_ITERATOR, sig.span, - &format!( - "this method is named `{}` but its return type does not implement `Iterator`", - name - ), + &format!("this method is named `{name}` but its return type does not implement `Iterator`"), ); } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 7ae8ef830fa..e94292b9fac 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -278,15 +278,13 @@ impl<'tcx> LenOutput<'tcx> { _ => "", }; match self { - Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref), - Self::Option(_) => format!( - "expected signature: `({}self) -> bool` or `({}self) -> Option", - self_ref, self_ref - ), - Self::Result(..) => format!( - "expected signature: `({}self) -> bool` or `({}self) -> Result", - self_ref, self_ref - ), + Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"), + Self::Option(_) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option") + }, + Self::Result(..) => { + format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result") + }, } } } @@ -326,8 +324,7 @@ fn check_for_is_empty<'tcx>( let (msg, is_empty_span, self_kind) = match is_empty { None => ( format!( - "{} `{}` has a public `len` method, but no `is_empty` method", - item_kind, + "{item_kind} `{}` has a public `len` method, but no `is_empty` method", item_name.as_str(), ), None, @@ -335,8 +332,7 @@ fn check_for_is_empty<'tcx>( ), Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => ( format!( - "{} `{}` has a public `len` method, but a private `is_empty` method", - item_kind, + "{item_kind} `{}` has a public `len` method, but a private `is_empty` method", item_name.as_str(), ), Some(cx.tcx.def_span(is_empty.def_id)), @@ -348,8 +344,7 @@ fn check_for_is_empty<'tcx>( { ( format!( - "{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", - item_kind, + "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature", item_name.as_str(), ), Some(cx.tcx.def_span(is_empty.def_id)), @@ -419,10 +414,9 @@ fn check_len( LEN_ZERO, span, &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), - &format!("using `{}is_empty` is clearer and more explicit", op), + &format!("using `{op}is_empty` is clearer and more explicit"), format!( - "{}{}.is_empty()", - op, + "{op}{}.is_empty()", snippet_with_applicability(cx, receiver.span, "_", &mut applicability) ), applicability, @@ -439,10 +433,9 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex COMPARISON_TO_EMPTY, span, "comparison to empty slice", - &format!("using `{}is_empty` is clearer and more explicit", op), + &format!("using `{op}is_empty` is clearer and more explicit"), format!( - "{}{}.is_empty()", - op, + "{op}{}.is_empty()", snippet_with_applicability(cx, lit1.span, "_", &mut applicability) ), applicability, diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 10fc0f4018e..13071d64441 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -106,8 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { // use mutably after the `if` let sug = format!( - "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", - mut=mutability, + "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", name=ident.name, cond=snippet(cx, cond.span, "_"), then=if then.stmts.len() > 1 { " ..;" } else { "" }, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 83fdc15c9f0..8a2a1682eca 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -417,8 +417,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se let msrv = conf.msrv.as_ref().and_then(|s| { parse_msrv(s, None, None).or_else(|| { sess.err(&format!( - "error reading Clippy's configuration file. `{}` is not a valid Rust version", - s + "error reading Clippy's configuration file. `{s}` is not a valid Rust version" )); None }) @@ -434,8 +433,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option { let clippy_msrv = conf.msrv.as_ref().and_then(|s| { parse_msrv(s, None, None).or_else(|| { sess.err(&format!( - "error reading Clippy's configuration file. `{}` is not a valid Rust version", - s + "error reading Clippy's configuration file. `{s}` is not a valid Rust version" )); None }) @@ -446,8 +444,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option { // if both files have an msrv, let's compare them and emit a warning if they differ if clippy_msrv != cargo_msrv { sess.warn(&format!( - "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{}` from `clippy.toml`", - clippy_msrv + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" )); } @@ -466,7 +463,7 @@ pub fn read_conf(sess: &Session) -> Conf { Ok(Some(path)) => path, Ok(None) => return Conf::default(), Err(error) => { - sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)) + sess.struct_err(&format!("error finding Clippy's configuration file: {error}")) .emit(); return Conf::default(); }, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index fb2104861c8..25f19b9c6e6 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -478,7 +478,7 @@ impl DecimalLiteralRepresentation { if num_lit.radix == Radix::Decimal; if val >= u128::from(self.threshold); then { - let hex = format!("{:#X}", val); + let hex = format!("{val:#X}"); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { warning_type.display(num_lit.format(), cx, lit.span); diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 8e3ab26a947..14f22348132 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -44,11 +44,10 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{}` is used as a loop counter", name), + &format!("the variable `{name}` is used as a loop counter"), "consider using", format!( - "for ({}, {}) in {}.enumerate()", - name, + "for ({name}, {}) in {}.enumerate()", snippet_with_applicability(cx, pat.span, "item", &mut applicability), make_iterator_snippet(cx, arg, &mut applicability), ), @@ -65,24 +64,21 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{}` is used as a loop counter", name), + &format!("the variable `{name}` is used as a loop counter"), |diag| { diag.span_suggestion( span, "consider using", format!( - "for ({}, {}) in (0_{}..).zip({})", - name, + "for ({name}, {}) in (0_{int_name}..).zip({})", snippet_with_applicability(cx, pat.span, "item", &mut applicability), - int_name, make_iterator_snippet(cx, arg, &mut applicability), ), applicability, ); diag.note(&format!( - "`{}` is of type `{}`, making it ineligible for `Iterator::enumerate`", - name, int_name + "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" )); }, ); diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 5f5beccd030..b1f2941622a 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m "it is more concise to loop over references to containers instead of using explicit \ iteration methods", "to write this more concisely, try", - format!("&{}{}", muta, object), + format!("&{muta}{object}"), applicability, ); } diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index bee0e1d7683..ed620460dbe 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx cx, FOR_KV_MAP, arg_span, - &format!("you seem to want to iterate on a map's {}s", kind), + &format!("you seem to want to iterate on a map's {kind}s"), |diag| { let map = sugg::Sugg::hir(cx, arg, "map"); multispan_sugg( @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx "use the corresponding method", vec![ (pat_span, snippet(cx, new_pat_span, kind).into_owned()), - (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)), + (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())), ], ); }, diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 1d6ddf4b99f..1b36d452647 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( then { let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message - let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type); + let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message let mut applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 3fc569af89e..c87fc4f90e2 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -177,13 +177,7 @@ fn build_manual_memcpy_suggestion<'tcx>( let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY { dst_base_str } else { - format!( - "{}[{}..{}]", - dst_base_str, - dst_offset.maybe_par(), - dst_limit.maybe_par() - ) - .into() + format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into() }; let method_str = if is_copy(cx, elem_ty) { @@ -193,10 +187,7 @@ fn build_manual_memcpy_suggestion<'tcx>( }; format!( - "{}.{}(&{}[{}..{}]);", - dst, - method_str, - src_base_str, + "{dst}.{method_str}(&{src_base_str}[{}..{}]);", src_offset.maybe_par(), src_limit.maybe_par() ) diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 6e6faa79adc..66f9e28596e 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -45,7 +45,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont let (arg, pred) = contains_arg .strip_prefix('&') .map_or(("&x", &*contains_arg), |s| ("x", s)); - format!("any(|{}| x == {})", arg, pred) + format!("any(|{arg}| x == {pred})") } _ => return, } @@ -141,9 +141,9 @@ impl IterFunction { IterFunctionKind::Contains(span) => { let s = snippet(cx, *span, ".."); if let Some(stripped) = s.strip_prefix('&') { - format!(".any(|x| x == {})", stripped) + format!(".any(|x| x == {stripped})") } else { - format!(".any(|x| x == *{})", s) + format!(".any(|x| x == *{s})") } }, } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 8ab640051b6..00cfc6d49f1 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -145,7 +145,7 @@ pub(super) fn check<'tcx>( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed), + &format!("the loop variable `{}` is used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, @@ -154,7 +154,7 @@ pub(super) fn check<'tcx>( (pat.span, format!("({}, )", ident.name)), ( arg.span, - format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2), + format!("{indexed}.{method}().enumerate(){method_1}{method_2}"), ), ], ); @@ -162,16 +162,16 @@ pub(super) fn check<'tcx>( ); } else { let repl = if starts_at_zero && take_is_empty { - format!("&{}{}", ref_mut, indexed) + format!("&{ref_mut}{indexed}") } else { - format!("{}.{}(){}{}", indexed, method, method_1, method_2) + format!("{indexed}.{method}(){method_1}{method_2}") }; span_lint_and_then( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed), + &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 2386f4f4f4e..16b00ad6637 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -222,9 +222,5 @@ fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) let pat_snippet = snippet(cx, pat.span, "_"); let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified); - format!( - "if let Some({pat}) = {iter}.next()", - pat = pat_snippet, - iter = iter_snippet - ) + format!("if let Some({pat_snippet}) = {iter_snippet}.next()") } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index aeefe6e33fb..07edee46fa6 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -30,10 +30,7 @@ pub(super) fn check<'tcx>( vec.span, "it looks like the same item is being pushed into this Vec", None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), + &format!("try using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), ); } diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 4801a84eb92..b332e8a923b 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -344,9 +344,8 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic _ => arg, }; format!( - "{}.{}()", + "{}.{method_name}()", sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(), - method_name, ) }, _ => format!( diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index deb21894f36..1c6f0264cb5 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -67,7 +67,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { expr.span.with_hi(scrutinee_expr.span.hi()), "this loop could be written as a `for` loop", "try", - format!("for {} in {}{}", loop_var, iterator, by_ref), + format!("for {loop_var} in {iterator}{by_ref}"), applicability, ); } diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 6b78c162065..f5617a905ff 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -190,9 +190,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let mut suggestions = vec![]; for ((root, span, hir_id), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]), hir_id)); + suggestions.push((span, format!("{root}::{}", path[0]), hir_id)); } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")), hir_id)); + suggestions.push((span, format!("{root}::{{{}}}", path.join(", ")), hir_id)); } } @@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { // such as `std::prelude::v1::foo` or some other macro that expands to an import. if self.mac_refs.is_empty() { for (span, import, hir_id) in suggestions { - let help = format!("use {};", import); + let help = format!("use {import};"); span_lint_hir_and_then( cx, MACRO_USE_IMPORTS, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 2502c8f880d..ddd9f34cbc4 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -74,11 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let Some(ret_pos) = position_before_rarrow(&header_snip); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { - let help = format!("make the function `async` and {}", ret_sugg); + let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, &help, - format!("async {}{}", &header_snip[..ret_pos], ret_snip), + format!("async {}{ret_snip}", &header_snip[..ret_pos]), Applicability::MachineApplicable ); @@ -196,7 +196,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, }, _ => { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip))) + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) }, } } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 2b04475c7a9..7d4f0b02112 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -133,7 +133,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { diag.span_suggestion( header_span, "add the attribute", - format!("#[non_exhaustive] {}", snippet), + format!("#[non_exhaustive] {snippet}"), Applicability::Unspecified, ); } @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { diag.span_suggestion( header_span, "add the attribute", - format!("#[non_exhaustive] {}", snippet), + format!("#[non_exhaustive] {snippet}"), Applicability::Unspecified, ); } diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 8476197bd12..570fe736818 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -153,7 +153,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E && let [filter_params] = filter_body.params && let Some(sugg) = match filter_params.pat.kind { hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, ".."))) + Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) }, hir::PatKind::Tuple([key_pat, value_pat], _) => { make_sugg(cx, key_pat, value_pat, left_expr, filter_body) @@ -161,7 +161,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E hir::PatKind::Ref(pat, _) => { match pat.kind { hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, ".."))) + Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) }, _ => None } @@ -190,23 +190,19 @@ fn make_sugg( match (&key_pat.kind, &value_pat.kind) { (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Binding(_, _, value_param_ident, None)) => { Some(format!( - "{}.retain(|{}, &mut {}| {})", + "{}.retain(|{key_param_ident}, &mut {value_param_ident}| {})", snippet(cx, left_expr.span, ".."), - key_param_ident, - value_param_ident, snippet(cx, filter_body.value.span, "..") )) }, (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Wild) => Some(format!( - "{}.retain(|{}, _| {})", + "{}.retain(|{key_param_ident}, _| {})", snippet(cx, left_expr.span, ".."), - key_param_ident, snippet(cx, filter_body.value.span, "..") )), (hir::PatKind::Wild, hir::PatKind::Binding(_, _, value_param_ident, None)) => Some(format!( - "{}.retain(|_, &mut {}| {})", + "{}.retain(|_, &mut {value_param_ident}| {})", snippet(cx, left_expr.span, ".."), - value_param_ident, snippet(cx, filter_body.value.span, "..") )), _ => None, diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 7941c8c9c7e..0976940afac 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -108,15 +108,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { }; let test_span = expr.span.until(then.span); - span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {} manually", kind_word), |diag| { - diag.span_note(test_span, &format!("the {} was tested here", kind_word)); + span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { + diag.span_note(test_span, &format!("the {kind_word} was tested here")); multispan_sugg( diag, - &format!("try using the `strip_{}` method", kind_word), + &format!("try using the `strip_{kind_word}` method"), vec![(test_span, - format!("if let Some() = {}.strip_{}({}) ", + format!("if let Some() = {}.strip_{kind_word}({}) ", snippet(cx, target_arg.span, ".."), - kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), ); diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 33d74481529..df5684541e9 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -194,10 +194,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String { #[must_use] fn suggestion_msg(function_type: &str, map_type: &str) -> String { - format!( - "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`", - map_type, function_type - ) + format!("called `map(f)` on an `{map_type}` value where `f` is a {function_type} that returns the unit type `()`") } fn lint_map_unit_fn( diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 8588ab1ed8d..a020282d234 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -70,9 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_path.ident.span), "", &mut applicability); let sugg = format!( - "{} let Ok({}) = {}", - ifwhile, - some_expr_string, + "{ifwhile} let Ok({some_expr_string}) = {}", trimmed_ok.trim().trim_end_matches('.'), ); span_lint_and_sugg( @@ -80,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { MATCH_RESULT_OK, expr.span.with_hi(let_expr.span.hi()), "matching on `Some` with `ok()` is redundant", - &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), sugg, applicability, ); diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index b0198e856d5..96b8339550c 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -144,7 +144,7 @@ fn check<'tcx>( let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { - format!("({})", scrutinee_str) + format!("({scrutinee_str})") } else { scrutinee_str.into() }; @@ -172,9 +172,9 @@ fn check<'tcx>( }; let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0; if some_expr.needs_unsafe_block { - format!("|{}{}| unsafe {{ {} }}", annotation, some_binding, expr_snip) + format!("|{annotation}{some_binding}| unsafe {{ {expr_snip} }}") } else { - format!("|{}{}| {}", annotation, some_binding, expr_snip) + format!("|{annotation}{some_binding}| {expr_snip}") } } } @@ -183,9 +183,9 @@ fn check<'tcx>( let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0; let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0; if some_expr.needs_unsafe_block { - format!("|{}| unsafe {{ {} }}", pat_snip, expr_snip) + format!("|{pat_snip}| unsafe {{ {expr_snip} }}") } else { - format!("|{}| {}", pat_snip, expr_snip) + format!("|{pat_snip}| {expr_snip}") } } else { // Refutable bindings and mixed reference annotations can't be handled by `map`. @@ -199,9 +199,9 @@ fn check<'tcx>( "manual implementation of `Option::map`", "try this", if else_pat.is_none() && is_else_clause(cx.tcx, expr) { - format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str) + format!("{{ {scrutinee_str}{as_ref_str}.map({body_str}) }}") } else { - format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str) + format!("{scrutinee_str}{as_ref_str}.map({body_str})") }, app, ); diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index e1111c80f2f..2fe7fe98a2e 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -42,12 +42,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{}::unwrap_or`", ty_name), + &format!("this pattern reimplements `{ty_name}::unwrap_or`"), "replace with", format!( - "{}.unwrap_or({})", - suggestion, - reindented_or_body, + "{suggestion}.unwrap_or({reindented_or_body})", ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 91d17f481e2..39d30212f36 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -45,13 +45,11 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: cx, MATCH_AS_REF, expr.span, - &format!("use `{}()` instead", suggestion), + &format!("use `{suggestion}()` instead"), "try this", format!( - "{}.{}(){}", + "{}.{suggestion}(){cast}", snippet_with_applicability(cx, ex.span, "_", &mut applicability), - suggestion, - cast, ), applicability, ); diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 34cc082687e..107fad32393 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -112,7 +112,7 @@ where .join(" | ") }; let pat_and_guard = if let Some(Guard::If(g)) = first_guard { - format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability)) + format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability)) } else { pat }; @@ -131,10 +131,9 @@ where &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }), "try this", format!( - "{}matches!({}, {})", + "{}matches!({}, {pat_and_guard})", if b0 { "" } else { "!" }, snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - pat_and_guard, ), applicability, ); diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index e32ef9933af..3e11016602b 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -135,7 +135,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { diag.span_suggestion( keep_arm.pat.span, "try merging the arm patterns", - format!("{} | {}", keep_pat_snip, move_pat_snip), + format!("{keep_pat_snip} | {move_pat_snip}"), Applicability::MaybeIncorrect, ) .help("or try changing either arm body") diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 5ae4a65acaf..68682cedf1d 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -75,12 +75,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e Some(AssignmentExpr::Local { span, pat_span }) => ( span, format!( - "let {} = {};\n{}let {} = {};", + "let {} = {};\n{}let {} = {snippet_body};", snippet_with_applicability(cx, bind_names, "..", &mut applicability), snippet_with_applicability(cx, matched_vars, "..", &mut applicability), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut applicability), - snippet_body + snippet_with_applicability(cx, pat_span, "..", &mut applicability) ), ), None => { @@ -110,10 +109,8 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e if ex.can_have_side_effects() { let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0)); let sugg = format!( - "{};\n{}{}", - snippet_with_applicability(cx, ex.span, "..", &mut applicability), - indent, - snippet_body + "{};\n{indent}{snippet_body}", + snippet_with_applicability(cx, ex.span, "..", &mut applicability) ); span_lint_and_sugg( @@ -178,10 +175,10 @@ fn sugg_with_curlies<'a>( let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new()); if let Some(parent_expr) = get_parent_expr(cx, match_expr) { if let ExprKind::Closure { .. } = parent_expr.kind { - cbrace_end = format!("\n{}}}", indent); + cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the closure indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); - cbrace_start = format!("{{\n{}", indent); + cbrace_start = format!("{{\n{indent}"); } } @@ -190,10 +187,10 @@ fn sugg_with_curlies<'a>( let parent_node_id = cx.tcx.hir().get_parent_node(match_expr.hir_id); if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) { if let ExprKind::Match(..) = arm.body.kind { - cbrace_end = format!("\n{}}}", indent); + cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the match indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); - cbrace_start = format!("{{\n{}", indent); + cbrace_start = format!("{{\n{indent}"); } } @@ -204,13 +201,8 @@ fn sugg_with_curlies<'a>( }); format!( - "{}let {} = {};\n{}{}{}{}", - cbrace_start, + "{cbrace_start}let {} = {};\n{indent}{assignment_str}{snippet_body}{cbrace_end}", snippet_with_applicability(cx, bind_names, "..", applicability), - snippet_with_applicability(cx, matched_vars, "..", applicability), - indent, - assignment_str, - snippet_body, - cbrace_end + snippet_with_applicability(cx, matched_vars, "..", applicability) ) } diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 1e80b6cf2d8..6647322caa3 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -118,8 +118,8 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad MATCH_STR_CASE_MISMATCH, bad_case_span, "this `match` arm has a differing case than its expression", - &format!("consider changing the case of this arm to respect `{}`", method_str), - format!("\"{}\"", suggestion), + &format!("consider changing the case of this arm to respect `{method_str}`"), + format!("\"{suggestion}\""), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index a3aa2e4b389..42f1e2629d4 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -38,7 +38,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' span_lint_and_note(cx, MATCH_WILD_ERR_ARM, arm.pat.span, - &format!("`Err({})` matches all errors", ident_bind_name), + &format!("`Err({ident_bind_name})` matches all errors"), None, "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", ); diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index f7443471e31..343b1d058b4 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -138,7 +138,7 @@ fn find_sugg_for_if_let<'tcx>( cx, REDUNDANT_PATTERN_MATCHING, let_pat.span, - &format!("redundant pattern matching, consider using `{}`", good_method), + &format!("redundant pattern matching, consider using `{good_method}`"), |diag| { // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ fn find_sugg_for_if_let<'tcx>( .maybe_par() .to_string(); - diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app); + diag.span_suggestion(span, "try this", format!("{keyword} {sugg}.{good_method}"), app); if needs_drop { diag.note("this will change drop order of the result, as well as all temporaries"); @@ -252,12 +252,12 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op cx, REDUNDANT_PATTERN_MATCHING, expr.span, - &format!("redundant pattern matching, consider using `{}`", good_method), + &format!("redundant pattern matching, consider using `{good_method}`"), |diag| { diag.span_suggestion( span, "try this", - format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method), + format!("{}.{good_method}", snippet(cx, result_expr.span, "_")), Applicability::MaybeIncorrect, // snippet ); }, diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 86a9df03497..85269e533a0 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -50,13 +50,13 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0)); let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy { - format!("let value = *{};\n{}", original, trailing_indent) + format!("let value = *{original};\n{trailing_indent}") } else if found.is_unit_return_val { // If the return value of the expression to be moved is unit, then we don't need to // capture the result in a temporary -- we can just replace it completely with `()`. - format!("{};\n{}", original, trailing_indent) + format!("{original};\n{trailing_indent}") } else { - format!("let value = {};\n{}", original, trailing_indent) + format!("let value = {original};\n{trailing_indent}") }; let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 38df69eeb37..6314959f818 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -99,23 +99,21 @@ fn report_single_pattern( let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`"; let sugg = format!( - "if {} == {}{} {}{}", + "if {} == {}{} {}{els_str}", snippet(cx, ex.span, ".."), // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), expr_block(cx, arms[0].body, None, "..", Some(expr.span)), - els_str, ); (msg, sugg) } else { let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"; let sugg = format!( - "if let {} = {} {}{}", + "if let {} = {} {}{els_str}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), expr_block(cx, arms[0].body, None, "..", Some(expr.span)), - els_str, ); (msg, sugg) } diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 663277d1136..a3ec1ff2482 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -61,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine "return " }; let suggestion = if err_ty == expr_err_ty { - format!("{}{}{}{}", ret_prefix, prefix, origin_snippet, suffix) + format!("{ret_prefix}{prefix}{origin_snippet}{suffix}") } else { - format!("{}{}{}.into(){}", ret_prefix, prefix, origin_snippet, suffix) + format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}") }; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 22f5635a5bc..cc26b0f7fa8 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -85,7 +85,7 @@ pub(crate) trait BindInsteadOfMap { let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); - let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip); + let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME); span_lint_and_sugg( cx, BIND_INSTEAD_OF_MAP, diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index 44857d61fef..2e96346be97 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, expr.span, - &format!("called `.bytes().nth()` on a `{}`", caller_type), + &format!("called `.bytes().nth()` on a `{caller_type}`"), "try", format!( "{}.as_bytes().get({})", diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index b2bc1ad5c9e..56b7fbb9d4b 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -33,12 +33,11 @@ pub(super) fn check( cx, lint, info.expr.span, - &format!("you should use the `{}` method", suggest), + &format!("you should use the `{suggest}` method"), "like this", - format!("{}{}.{}({})", + format!("{}{}.{suggest}({})", if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - suggest, snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), applicability, ); diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index b85bfec2b12..7e808760663 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -26,12 +26,11 @@ pub(super) fn check<'tcx>( cx, lint, info.expr.span, - &format!("you should use the `{}` method", suggest), + &format!("you should use the `{suggest}` method"), "like this", - format!("{}{}.{}('{}')", + format!("{}{}.{suggest}('{}')", if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - suggest, c.escape_default()), applicability, ); diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 7ab6b84c207..7c7938dd2e8 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -49,8 +49,7 @@ pub(super) fn check( expr.span, &format!( "using `clone` on a double-reference; \ - this will copy the reference of type `{}` instead of cloning the inner type", - ty + this will copy the reference of type `{ty}` instead of cloning the inner type" ), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { @@ -62,11 +61,11 @@ pub(super) fn check( } let refs = "&".repeat(n + 1); let derefs = "*".repeat(n); - let explicit = format!("<{}{}>::clone({})", refs, ty, snip); + let explicit = format!("<{refs}{ty}>::clone({snip})"); diag.span_suggestion( expr.span, "try dereferencing it", - format!("{}({}{}).clone()", refs, derefs, snip.deref()), + format!("{refs}({derefs}{}).clone()", snip.deref()), Applicability::MaybeIncorrect, ); diag.span_suggestion( @@ -121,16 +120,16 @@ pub(super) fn check( let (help, sugg) = if deref_count == 0 { ("try removing the `clone` call", snip.into()) } else if parent_is_suffix_expr { - ("try dereferencing it", format!("({}{})", "*".repeat(deref_count), snip)) + ("try dereferencing it", format!("({}{snip})", "*".repeat(deref_count))) } else { - ("try dereferencing it", format!("{}{}", "*".repeat(deref_count), snip)) + ("try dereferencing it", format!("{}{snip}", "*".repeat(deref_count))) }; span_lint_and_sugg( cx, CLONE_ON_COPY, expr.span, - &format!("using `clone` on type `{}` which implements the `Copy` trait", ty), + &format!("using `clone` on type `{ty}` which implements the `Copy` trait"), help, sugg, app, diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index f82ca891200..355f53532e2 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -41,7 +41,7 @@ pub(super) fn check( expr.span, "using `.clone()` on a ref-counted pointer", "try this", - format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet), + format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak ); } diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index bd846d71d46..d0cf411dfd3 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -143,9 +143,9 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{}` followed by a function call", name), + &format!("use of `{name}` followed by a function call"), "try this", - format!("unwrap_or_else({} panic!({}))", closure_args, sugg), + format!("unwrap_or_else({closure_args} panic!({sugg}))"), applicability, ); return; @@ -160,12 +160,9 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{}` followed by a function call", name), + &format!("use of `{name}` followed by a function call"), "try this", - format!( - "unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", - closure_args, arg_root_snippet - ), + format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"), applicability, ); } diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 7b2967feb0f..60f8283c3e0 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -35,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr span = expr.span; } } - let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb); - let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary); + let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files"); + let help_msg = format!("use `{help_unary}FileType::is_dir()` instead"); span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); } diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 38ec4d8e3ab..ddf8a1f09b8 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try this", - format!("{}.find_map({})", iter_snippet, filter_snippet), + format!("{iter_snippet}.find_map({filter_snippet})"), Applicability::MachineApplicable, ); } else { diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index bcf8d93b602..edcec0fc101 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try this", - format!("{}.find({})", iter_snippet, filter_snippet), + format!("{iter_snippet}.find({filter_snippet})"), Applicability::MachineApplicable, ); } else { diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 6436e28a63c..66dfce3682b 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); let turbofish = extract_turbofish(cx, expr, ty); - let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); + let sugg = format!("{iter_expr}.collect::<{turbofish}>()"); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, @@ -63,7 +63,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> if e == type_specifier { None } else { Some((*e).to_string()) } }).collect::>(); // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) - format!("{}{}", without_ts.join("::"), type_specifier) + format!("{}{type_specifier}", without_ts.join("::")) } else { // type is not explicitly specified so wildcards are needed // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` @@ -72,7 +72,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> let end = ty_str.find('>').unwrap_or(ty_str.len()); let nb_wildcard = ty_str[start..end].split(',').count(); let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{}>", elements.join("::"), wildcards) + format!("{}<{wildcards}>", elements.join("::")) } } } diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index 4de77de7404..cb17af608a3 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -29,9 +29,9 @@ pub(super) fn check<'tcx>( cx, GET_FIRST, expr.span, - &format!("accessing first element with `{0}.get(0)`", slice_name), + &format!("accessing first element with `{slice_name}.get(0)`"), "try", - format!("{}.first()", slice_name), + format!("{slice_name}.first()"), app, ); } diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index 18e08d6ee23..ffc3a4d780e 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -71,16 +71,11 @@ pub(super) fn check<'tcx>( cx, GET_UNWRAP, span, - &format!( - "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", - mut_str, caller_type - ), + &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), "try this", format!( - "{}{}[{}]", - borrow_str, - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - get_args_str + "{borrow_str}{}[{get_args_str}]", + snippet_with_applicability(cx, recv.span, "..", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 9651a52be4e..429cdc1918d 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -26,12 +26,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv cx, IMPLICIT_CLONE, expr.span, - &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name), + &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), "consider using", if ref_count > 1 { - format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip) + format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1)) } else { - format!("{}.clone()", recv_snip) + format!("{recv_snip}.clone()") }, app, ); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index e1c9b5248a8..e5dc3711b0b 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -34,18 +34,17 @@ pub fn check<'tcx>( cx, INEFFICIENT_TO_STRING, expr.span, - &format!("calling `to_string` on `{}`", arg_ty), + &format!("calling `to_string` on `{arg_ty}`"), |diag| { diag.help(&format!( - "`{}` implements `ToString` through a slower blanket impl, but `{}` has a fast specialization of `ToString`", - self_ty, deref_self_ty + "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" )); let mut applicability = Applicability::MachineApplicable; let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability); diag.span_suggestion( expr.span, "try dereferencing the receiver", - format!("({}{}).to_string()", "*".repeat(deref_count), arg_snippet), + format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)), applicability, ); }, diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 11e76841e9f..be56b63506a 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -30,8 +30,7 @@ pub(super) fn check( INTO_ITER_ON_REF, method_span, &format!( - "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`", - method_name, kind, + "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`", ), "call directly", method_name.to_string(), diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index aa176dcc8b4..304024e8066 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -37,12 +37,11 @@ pub(super) fn check<'tcx>( cx, IS_DIGIT_ASCII_RADIX, expr.span, - &format!("use of `char::is_digit` with literal radix of {}", num), + &format!("use of `char::is_digit` with literal radix of {num}"), "try", format!( - "{}.{}()", - snippet_with_applicability(cx, self_arg.span, "..", &mut applicability), - replacement + "{}.{replacement}()", + snippet_with_applicability(cx, self_arg.span, "..", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index 30d56113c6c..bde6f92b076 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir: cx, ITER_CLONED_COLLECT, to_replace, - &format!("called `iter().{}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable", method_name), + &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable"), "try", ".to_vec()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index 052be3d8ee7..bcddc7c786a 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -37,7 +37,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, ITER_COUNT, expr.span, - &format!("called `.{}().count()` on a `{}`", iter_method, caller_type), + &format!("called `.{iter_method}().count()` on a `{caller_type}`"), "try", format!( "{}.len()", diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index a7eecabd684..2244ebfb129 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -54,9 +54,9 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {}s", replacement_kind), + &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{}.{}{}s()", recv_snippet, into_prefix, replacement_kind), + format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"), applicability, ); } else { @@ -64,9 +64,9 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {}s", replacement_kind), + &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{}.{}{}s().map(|{}| {})", recv_snippet, into_prefix, replacement_kind, binded_ident, + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index b8d1dabe007..83c1bf20346 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal let suggest = if start_idx == 0 { format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) } else { - format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx) + format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 80ca4c94219..ceee12784cb 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -32,8 +32,8 @@ pub(super) fn check<'tcx>( cx, ITER_NTH, expr.span, - &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type), + &format!("called `.iter{mut_str}().nth()` on a {caller_type}"), None, - &format!("calling `.get{}()` is both faster and more readable", mut_str), + &format!("calling `.get{mut_str}()` is both faster and more readable"), ); } diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index a669cbbbcc6..3da230e12d7 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span cx, ITER_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain(..)` used on a `{}`", ty_name), + &format!("`drain(..)` used on a `{ty_name}`"), "try this", "into_iter()".to_string(), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index ffd2f4a38b8..c5c0ace7729 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -37,9 +37,7 @@ pub(super) fn check<'tcx>( "this pattern reimplements `Option::ok_or`", "replace with", format!( - "{}.ok_or({})", - recv_snippet, - reindented_err_arg_snippet + "{recv_snippet}.ok_or({reindented_err_arg_snippet})" ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 0fe510beaa0..ec694cf6882 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -57,11 +57,10 @@ pub fn check( super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - &format!("try using `saturating_{}`", arith), + &format!("try using `saturating_{arith}`"), format!( - "{}.saturating_{}({})", + "{}.saturating_{arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), - arith, snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), ), applicability, diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 46d2fc493f8..67e504af161 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -91,7 +91,7 @@ pub(super) fn check( collect_expr.span, "manual implementation of `str::repeat` using iterators", "try this", - format!("{}.repeat({})", val_str, count_snip), + format!("{val_str}.repeat({count_snip})"), app ) } diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 8261ef5e1ce..7ce14ec080b 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -111,11 +111,10 @@ fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_cop MAP_CLONE, replace, message, - &format!("consider calling the dedicated `{}` method", sugg_method), + &format!("consider calling the dedicated `{sugg_method}` method"), format!( - "{}.{}()", + "{}.{sugg_method}()", snippet_with_applicability(cx, root, "..", &mut applicability), - sugg_method, ), applicability, ); diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 13853dec99d..361ffcb5ef3 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -20,12 +20,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_ cx, MAP_FLATTEN, expr.span.with_lo(map_span.lo()), - &format!("called `map(..).flatten()` on `{}`", caller_ty_name), - &format!( - "try replacing `map` with `{}` and remove the `.flatten()`", - method_to_use - ), - format!("{}({})", method_to_use, closure_snippet), + &format!("called `map(..).flatten()` on `{caller_ty_name}`"), + &format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), + format!("{method_to_use}({closure_snippet})"), applicability, ); } diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 862a9578e6f..0f25ef82ed4 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -30,7 +30,7 @@ pub(super) fn check( MAP_IDENTITY, sugg_span, "unnecessary map of the identity function", - &format!("remove the call to `{}`", name), + &format!("remove the call to `{name}`"), String::new(), Applicability::MachineApplicable, ) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 4a8e7ce4ddb..74fdead216b 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -65,7 +65,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try this", - format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet), + format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), Applicability::MachineApplicable, ); return true; diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index c409268de76..6fb92d1c663 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -98,13 +98,12 @@ pub(super) fn check<'tcx>( format!(".as_ref().map({})", snippet(cx, map_arg.span, "..")) }; let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; - let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint); - let suggestion = format!("try using {} instead", method_hint); + let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); + let suggestion = format!("try using {method_hint} instead"); let msg = format!( - "called `{0}` on an Option value. This can be done more directly \ - by calling `{1}` instead", - current_method, hint + "called `{current_method}` on an Option value. This can be done more directly \ + by calling `{hint}` instead" ); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 6657cdccd01..76572425346 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -87,7 +87,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `map` instead", - format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet), + format!("{self_snippet}.map({arg_snippet} {func_snippet})"), Applicability::MachineApplicable, ); } @@ -102,7 +102,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `and_then` instead", - format!("{0}.and_then({1})", self_snippet, func_snippet), + format!("{self_snippet}.and_then({func_snippet})"), Applicability::MachineApplicable, ); } else if f_arg_is_some { @@ -115,7 +115,7 @@ pub(super) fn check<'tcx>( expr.span, msg, "try using `ok` instead", - format!("{0}.ok()", self_snippet), + format!("{self_snippet}.ok()"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 3c4002a3aef..30421a6dd5a 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -65,9 +65,8 @@ pub(super) fn check<'tcx>( "map_or(, )" }; let msg = &format!( - "called `map().unwrap_or({})` on an `Option` value. \ - This can be done more directly by calling `{}` instead", - arg, suggest + "called `map().unwrap_or({arg})` on an `Option` value. \ + This can be done more directly by calling `{suggest}` instead" ); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { @@ -82,10 +81,10 @@ pub(super) fn check<'tcx>( ]; if !unwrap_snippet_none { - suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{}, ", unwrap_snippet))); + suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); } - diag.multipart_suggestion(&format!("use `{}` instead", suggest), suggestion, applicability); + diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability); }); } } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b43b9258c47..6a35024d036 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -62,9 +62,9 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, method_span.with_hi(span.hi()), - &format!("use of `{}` followed by a call to `{}`", name, path), + &format!("use of `{name}` followed by a call to `{path}`"), "try this", - format!("{}()", sugg), + format!("{sugg}()"), Applicability::MachineApplicable, ); @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; - format!("|{}| {}", l_arg, snippet).into() + format!("|{l_arg}| {snippet}").into() } else { snippet } @@ -141,9 +141,9 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, span_replace_word, - &format!("use of `{}` followed by a function call", name), + &format!("use of `{name}` followed by a function call"), "try this", - format!("{}_{}({})", name, suffix, sugg), + format!("{name}_{suffix}({sugg})"), Applicability::HasPlaceholders, ); } diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 7572ba3fe9a..324c9c17b5a 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -30,10 +30,7 @@ pub(super) fn check<'tcx>( let option_check_method = if is_some { "is_some" } else { "is_none" }; // lint if caller of search is an Iterator if is_trait_method(cx, is_some_recv, sym::Iterator) { - let msg = format!( - "called `{}()` after searching an `Iterator` with `{}`", - option_check_method, search_method - ); + let msg = format!("called `{option_check_method}()` after searching an `Iterator` with `{search_method}`"); let search_snippet = snippet(cx, search_arg.span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -86,8 +83,7 @@ pub(super) fn check<'tcx>( &msg, "use `!_.any()` instead", format!( - "!{}.any({})", - iter, + "!{iter}.any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) ), applicability, @@ -119,7 +115,7 @@ pub(super) fn check<'tcx>( if is_string_or_str_slice(search_recv); if is_string_or_str_slice(search_arg); then { - let msg = format!("called `{}()` after calling `find()` on a string", option_check_method); + let msg = format!("called `{option_check_method}()` after calling `find()` on a string"); match option_check_method { "is_some" => { let mut applicability = Applicability::MachineApplicable; @@ -130,7 +126,7 @@ pub(super) fn check<'tcx>( method_span.with_hi(expr.span.hi()), &msg, "use `contains()` instead", - format!("contains({})", find_arg), + format!("contains({find_arg})"), applicability, ); }, @@ -144,7 +140,7 @@ pub(super) fn check<'tcx>( expr.span, &msg, "use `!_.contains()` instead", - format!("!{}.contains({})", string, find_arg), + format!("!{string}.contains({find_arg})"), applicability, ); }, diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 18b6b5be175..44a7ad394fa 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); - let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); + let sugg = format!("{base_string_snippet}.insert({pos_arg}, {extension_string})"); span_lint_and_sugg( cx, SINGLE_CHAR_ADD_STR, diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 9ea6751956a..0698bd6a0c5 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); - let sugg = format!("{}.push({})", base_string_snippet, extension_string); + let sugg = format!("{base_string_snippet}.push({extension_string})"); span_lint_and_sugg( cx, SINGLE_CHAR_ADD_STR, diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 91951c65bb3..09c8ca4cbe4 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -17,11 +17,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx cx, STABLE_SORT_PRIMITIVE, e.span, - &format!("used `sort` on primitive type `{}`", slice_type), + &format!("used `sort` on primitive type `{slice_type}`"), |diag| { let mut app = Applicability::MachineApplicable; let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; - diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app); + diag.span_suggestion(e.span, "try", format!("{recv_snip}.sort_unstable()"), app); diag.note( "an unstable sort typically performs faster without any observable difference for this data type", ); diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 143dcee3505..6974260f70d 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -34,9 +34,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr "calling `.extend(_.chars())`", "try this", format!( - "{}.push_str({}{})", + "{}.push_str({ref_str}{})", snippet_with_applicability(cx, recv.span, "..", &mut applicability), - ref_str, snippet_with_applicability(cx, target.span, "..", &mut applicability) ), applicability, diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 55567d8625e..219a9edd657 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -24,10 +24,10 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se } let (msg, note_msg) = if count == 0 { - (format!("`{}` called with `0` splits", method_name), + (format!("`{method_name}` called with `0` splits"), "the resulting iterator will always return `None`") } else { - (format!("`{}` called with `1` split", method_name), + (format!("`{method_name}` called with `1` split"), if self_ty.is_slice() { "the resulting iterator will always return the entire slice followed by `None`" } else { diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 6b306fbf008..15c1c618c51 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -24,9 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &format!("this `to_owned` call clones the {0} itself and does not cause the {0} contents to become owned", input_type), + &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"), "consider using, depending on intent", - format!("{0}.clone()` or `{0}.into_owned()", recv_snip), + format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), app, ); return true; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 4e8c201f470..ee16982d524 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -54,7 +54,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< UNNECESSARY_FIND_MAP }, expr.span, - &format!("this `.{}` can be written more simply using `.{}`", name, sugg), + &format!("this `.{name}` can be written more simply using `.{sugg}`"), ); } } diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index c17ef6809f9..aa87dead38f 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -49,15 +49,12 @@ pub(super) fn check( let mut applicability = Applicability::MachineApplicable; let sugg = if replacement_has_args { format!( - "{replacement}(|{s}| {r})", - replacement = replacement_method_name, - s = second_arg_ident, + "{replacement_method_name}(|{second_arg_ident}| {r})", r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { format!( - "{replacement}()", - replacement = replacement_method_name, + "{replacement_method_name}()", ) }; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 95138c0e25b..1966a85f7a7 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -68,7 +68,7 @@ pub fn check_for_loop_iter( cx, UNNECESSARY_TO_OWNED, expr.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), |diag| { // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to // a `to_owned`-like function was removed, then the next suggestion may be diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index a187a8d6016..ec9859fa298 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -58,8 +58,8 @@ pub(super) fn check<'tcx>( span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( span, - &format!("use `{}(..)` instead", simplify_using), - format!("{}({})", simplify_using, snippet(cx, body_expr.span, "..")), + &format!("use `{simplify_using}(..)` instead"), + format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), applicability, ); }); diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 8e9ed33e009..d27831327ac 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -133,12 +133,11 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", format!( - "{:&>width$}{}", + "{:&>width$}{receiver_snippet}", "", - receiver_snippet, width = n_target_refs - n_receiver_refs ), Applicability::MachineApplicable, @@ -155,7 +154,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", receiver_snippet, Applicability::MachineApplicable, @@ -165,7 +164,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "remove this", String::new(), Applicability::MachineApplicable, @@ -182,9 +181,9 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", - format!("{}.as_ref()", receiver_snippet), + format!("{receiver_snippet}.as_ref()"), Applicability::MachineApplicable, ); return true; @@ -229,9 +228,9 @@ fn check_into_iter_call_arg( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", - format!("{}.iter().{}()", receiver_snippet, cloned_or_copied), + format!("{receiver_snippet}.iter().{cloned_or_copied}()"), Applicability::MaybeIncorrect, ); return true; @@ -276,9 +275,9 @@ fn check_other_call_arg<'tcx>( cx, UNNECESSARY_TO_OWNED, maybe_arg.span, - &format!("unnecessary use of `{}`", method_name), + &format!("unnecessary use of `{method_name}`"), "use", - format!("{:&>width$}{}", "", receiver_snippet, width = n_refs), + format!("{:&>n_refs$}{receiver_snippet}", ""), Applicability::MachineApplicable, ); return true; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index ca5d33ee8b0..0380a82411a 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -35,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, cx, USELESS_ASREF, expr.span, - &format!("this call to `{}` does nothing", call_name), + &format!("this call to `{call_name}` does nothing"), "try this", snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 4b368d3ffae..1fbf783b886 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -61,20 +61,20 @@ impl Convention { impl fmt::Display for Convention { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { - Self::Eq(this) => format!("`{}`", this).fmt(f), - Self::StartsWith(this) => format!("`{}*`", this).fmt(f), - Self::EndsWith(this) => format!("`*{}`", this).fmt(f), - Self::NotEndsWith(this) => format!("`~{}`", this).fmt(f), + Self::Eq(this) => format!("`{this}`").fmt(f), + Self::StartsWith(this) => format!("`{this}*`").fmt(f), + Self::EndsWith(this) => format!("`*{this}`").fmt(f), + Self::NotEndsWith(this) => format!("`~{this}`").fmt(f), Self::IsSelfTypeCopy(is_true) => { format!("`self` type is{} `Copy`", if is_true { "" } else { " not" }).fmt(f) }, Self::ImplementsTrait(is_true) => { let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") }; - format!("method{} implement{} a trait", negation, s_suffix).fmt(f) + format!("method{negation} implement{s_suffix} a trait").fmt(f) }, Self::IsTraitItem(is_true) => { let suffix = if is_true { " is" } else { " is not" }; - format!("method{} a trait item", suffix).fmt(f) + format!("method{suffix} a trait item").fmt(f) }, } } @@ -138,8 +138,7 @@ pub(super) fn check<'tcx>( WRONG_SELF_CONVENTION, first_arg_span, &format!( - "{} usually take {}", - suggestion, + "{suggestion} usually take {}", &self_kinds .iter() .map(|k| k.description()) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index ea245edd770..381458b91e6 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { ("", sugg_init.addr()) }; let tyopt = if let Some(ty) = local.ty { - format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "..")) + format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, "..")) } else { String::new() }; @@ -195,8 +195,6 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { format!( "let {name}{tyopt} = {initref};", name=snippet(cx, name.span, ".."), - tyopt=tyopt, - initref=initref, ), Applicability::MachineApplicable, ); @@ -222,8 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { stmt.span, "replace it with", format!( - "if {} {{ {}; }}", - sugg, + "if {sugg} {{ {}; }}", &snippet(cx, b.span, ".."), ), Applicability::MachineApplicable, // snippet @@ -275,9 +272,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { USED_UNDERSCORE_BINDING, expr.span, &format!( - "used binding `{}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used", - binding + "used binding `{binding}` which is prefixed with an underscore. A leading \ + underscore signals that a binding will not be used" ), ); } @@ -328,12 +324,12 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) }; let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind { - (format!("{}()", sugg_fn), Applicability::MachineApplicable) + (format!("{sugg_fn}()"), Applicability::MachineApplicable) } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) { - (format!("{}::<{}>()", sugg_fn, mut_ty_snip), Applicability::MachineApplicable) + (format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable) } else { // `MaybeIncorrect` as type inference may not work with the suggested code - (format!("{}()", sugg_fn), Applicability::MaybeIncorrect) + (format!("{sugg_fn}()"), Applicability::MaybeIncorrect) }; span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl); } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs index 1165c19a0cf..62c6ca32d31 100644 --- a/clippy_lints/src/misc_early/literal_suffix.rs +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -18,9 +18,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s cx, SEPARATED_LITERAL_SUFFIX, lit.span, - &format!("{} type suffix should not be separated by an underscore", sugg_type), + &format!("{sugg_type} type suffix should not be separated by an underscore"), "remove the underscore", - format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix), + format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), Applicability::MachineApplicable, ); } else { @@ -28,9 +28,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s cx, UNSEPARATED_LITERAL_SUFFIX, lit.span, - &format!("{} type suffix should be separated by an underscore", sugg_type), + &format!("{sugg_type} type suffix should be separated by an underscore"), "add an underscore", - format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), + format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 704918c0b97..c8227ca4450 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -357,9 +357,8 @@ impl EarlyLintPass for MiscEarlyLints { DUPLICATE_UNDERSCORE_ARGUMENT, *correspondence, &format!( - "`{}` already exists, having another argument having almost the same \ - name makes code comprehension and documentation more difficult", - arg_name + "`{arg_name}` already exists, having another argument having almost the same \ + name makes code comprehension and documentation more difficult" ), ); } diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index fff533167ed..676e5d40bb7 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pat.span, "all the struct fields are matched to a wildcard pattern, consider using `..`", None, - &format!("try with `{} {{ .. }}` instead", type_name), + &format!("try with `{type_name} {{ .. }}` instead"), ); return; } @@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` \ instead", None, - &format!("try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")), + &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), ); } } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 020efeaebf0..6dd76a6531e 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -91,10 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { let type_name = segment.ident; for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { - let msg = format!("`{}` has a similarly named generic type parameter `{}` in its declaration, but in a different order", - type_name, impl_param_name); - let help = format!("try `{}`, or a name that does not conflict with `{}`'s generic params", - type_param_names[i], type_name); + let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order"); + let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params", + type_param_names[i]); span_lint_and_help( cx, MISMATCHING_TYPE_PARAM_ORDER, diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ee81f72a0e7..97c8fb17638 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -104,7 +104,7 @@ impl MissingDoc { cx, MISSING_DOCS_IN_PRIVATE_ITEMS, sp, - &format!("missing documentation for {} {}", article, desc), + &format!("missing documentation for {article} {desc}"), ); } } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 3d0a2382283..697e6fd24dd 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -90,9 +90,7 @@ impl LateLintPass<'_> for ImportRename { "this import should be renamed", "try", format!( - "{} as {}", - import, - name, + "{import} as {name}", ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 07bc2ca5d3c..18c45120091 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -65,7 +65,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, - &format!("missing `#[inline]` for {}", desc), + &format!("missing `#[inline]` for {desc}"), ); } } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 82dc03ef5c5..463da11774a 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -88,7 +88,7 @@ fn check_arguments<'tcx>( cx, UNNECESSARY_MUT_PASSED, argument.span, - &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name), + &format!("the {fn_kind} `{name}` doesn't need a mutable reference"), ); } }, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 321db08dfe8..3ef0c663459 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -56,10 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { cx, DEBUG_ASSERT_WITH_MUT_CALL, span, - &format!( - "do not call a function with mutable arguments inside of `{}!`", - macro_name - ), + &format!("do not call a function with mutable arguments inside of `{macro_name}!`"), ); } } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index a98577093ed..09cb5333176 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { let mutex_param = subst.type_at(0); if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!( - "consider using an `{}` instead of a `Mutex` here; if you just want the locking \ - behavior and not the internal type, consider using `Mutex<()>`", - atomic_name + "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \ + behavior and not the internal type, consider using `Mutex<()>`" ); match *mutex_param.kind() { ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 98a3bce1ff3..6f0e755466e 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -309,7 +309,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, expr.span, message, None, - &format!("{}\n{}", header, snip), + &format!("{header}\n{snip}"), ); } @@ -322,10 +322,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &' let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0); format!( - "{indent}if {} {}\n{indent}{}", - cond_code, - continue_code, - else_code, + "{indent}if {cond_code} {continue_code}\n{indent}{else_code}", indent = " ".repeat(indent_if), ) } @@ -349,7 +346,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span); let snip = snippet_block(cx, span, "..", None).into_owned(); snip.lines() - .map(|line| format!("{}{}", " ".repeat(indent), line)) + .map(|line| format!("{}{line}", " ".repeat(indent))) .collect::>() .join("\n") }) @@ -358,10 +355,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0); format!( - "{indent_if}if {} {}\n{indent}// merged code follows:\n{}\n{indent_if}}}", - cond_code, - block_code, - to_annex, + "{indent_if}if {cond_code} {block_code}\n{indent}// merged code follows:\n{to_annex}\n{indent_if}}}", indent = " ".repeat(indent), indent_if = " ".repeat(indent_if), ) diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index de99f1d7078..cbad53f4450 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -287,7 +287,7 @@ fn check<'tcx>( diag.span_suggestion( assign.lhs_span, - &format!("declare `{}` here", binding_name), + &format!("declare `{binding_name}` here"), let_snippet, Applicability::MachineApplicable, ); @@ -307,8 +307,8 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{}` here", binding_name), - format!("{} = ", let_snippet), + &format!("declare `{binding_name}` here"), + format!("{let_snippet} = "), applicability, ); @@ -338,8 +338,8 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{}` here", binding_name), - format!("{} = ", let_snippet), + &format!("declare `{binding_name}` here"), + format!("{let_snippet} = "), applicability, ); diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 6d17c7a7346..d7e6e7de2cc 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { snippet_opt(cx, span) .map_or( "change the call to".into(), - |x| Cow::from(format!("change `{}` to", x)), + |x| Cow::from(format!("change `{x}` to")), ) .as_ref(), suggestion, @@ -266,7 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { snippet_opt(cx, span) .map_or( "change the call to".into(), - |x| Cow::from(format!("change `{}` to", x)) + |x| Cow::from(format!("change `{x}` to")) ) .as_ref(), suggestion, diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 8f85b00596c..59b6492e112 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -134,7 +134,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { NEEDLESS_QUESTION_MARK, expr.span, "question mark operator is useless here", - &format!("try removing question mark and `{}`", sugg_remove), + &format!("try removing question mark and `{sugg_remove}`"), format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index b087cfb36b1..fb9a4abd0b4 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -62,9 +62,9 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { let mut applicability = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, exp.span, "..", &mut applicability); let suggestion = if exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { - format!("-({})", snip) + format!("-({snip})") } else { - format!("-{}", snip) + format!("-{snip}") }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 5c45ee6d94a..cfd24e9b2d3 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -136,8 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { id, impl_item.span, &format!( - "you should consider adding a `Default` implementation for `{}`", - self_type_snip + "you should consider adding a `Default` implementation for `{self_type_snip}`" ), |diag| { diag.suggest_prepend_item( @@ -161,9 +160,9 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { fn create_new_without_default_suggest_msg(self_type_snip: &str, generics_sugg: &str) -> String { #[rustfmt::skip] format!( -"impl{} Default for {} {{ +"impl{generics_sugg} Default for {self_type_snip} {{ fn default() -> Self {{ Self::new() }} -}}", generics_sugg, self_type_snip) +}}") } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index b96af06b8d7..03fddd207ec 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -108,10 +108,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { self.cx, MANY_SINGLE_CHAR_NAMES, span, - &format!( - "{} bindings with single-character names in scope", - num_single_char_names - ), + &format!("{num_single_char_names} bindings with single-character names in scope"), ); } } diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 5e38a95c40b..0ca0befc135 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -107,11 +107,11 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac if let Some(snip) = snippet_opt(cx, span_call_site); // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 - if snip.starts_with(&format!("{}!", name)); + if snip.starts_with(&format!("{name}!")); if unnested_or_local(); // make formatting consistent let c = snip.replace(' ', ""); - if !c.starts_with(&format!("{}!{}", name, braces.0)); + if !c.starts_with(&format!("{name}!{}", braces.0)); if !mac_braces.done.contains(&span_call_site); then { Some((span_call_site, braces, snip)) @@ -131,9 +131,9 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: cx, NONSTANDARD_MACRO_BRACES, span, - &format!("use of irregular braces for `{}!` macro", macro_name), + &format!("use of irregular braces for `{macro_name}!` macro"), "consider writing", - format!("{}!{}{}{}", macro_name, braces.0, macro_args, braces.1), + format!("{macro_name}!{}{macro_args}{}", braces.0, braces.1), Applicability::MachineApplicable, ); } @@ -266,9 +266,7 @@ impl<'de> Deserialize<'de> for MacroMatcher { .iter() .find(|b| b.0 == brace) .map(|(o, c)| ((*o).to_owned(), (*c).to_owned())) - .ok_or_else(|| { - de::Error::custom(&format!("expected one of `(`, `{{`, `[` found `{}`", brace)) - })?, + .ok_or_else(|| de::Error::custom(&format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, }) } } diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index bffbf20b4d2..f380a506582 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -102,7 +102,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { // construct a replacement escape // the maximum value is \077, or \x3f, so u8 is sufficient here if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(suggest_1, "\\x{:02x}", n).unwrap(); + write!(suggest_1, "\\x{n:02x}").unwrap(); } // append the null byte as \x00 and the following digits literally diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index 1ec4240afef..d29ca37eaeb 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -34,13 +34,12 @@ pub(super) fn check<'tcx>( }; let help = format!( - "because `{}` is the {} value for this type, {}", + "because `{}` is the {} value for this type, {conclusion}", snippet(cx, culprit.expr.span, "x"), match culprit.which { ExtremeType::Minimum => "minimum", ExtremeType::Maximum => "maximum", - }, - conclusion + } ); span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 945a09a647c..cb5abfb809e 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -55,7 +55,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( expr.span, "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r), + format!("{snip_a} {}= {snip_r}", op.node.as_str()), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs index 74387fbc87b..1369b3e7462 100644 --- a/clippy_lints/src/operators/bit_mask.rs +++ b/clippy_lints/src/operators/bit_mask.rs @@ -64,10 +64,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), ); } } else if mask_value == 0 { @@ -80,10 +77,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), ); } }, @@ -96,10 +90,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -111,10 +102,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), ); } else { check_ineffective_lt(cx, span, mask_value, cmp_value, "|"); @@ -130,10 +118,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -145,10 +130,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!( - "incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, cmp_value - ), + &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), ); } else { check_ineffective_gt(cx, span, mask_value, cmp_value, "|"); @@ -167,10 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!( - "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c - ), + &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } @@ -181,10 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!( - "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c - ), + &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index 638a514ff9b..c9c777f1bd8 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -99,7 +99,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let expr_snip; let eq_impl; if with_deref.is_implemented() { - expr_snip = format!("*{}", arg_snip); + expr_snip = format!("*{arg_snip}"); eq_impl = with_deref; } else { expr_snip = arg_snip.to_string(); @@ -121,17 +121,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) }; if eq_impl.ty_eq_other { hint = format!( - "{}{}{}", - expr_snip, + "{expr_snip}{}{}", snippet(cx, cmp_span, ".."), snippet(cx, other.span, "..") ); } else { hint = format!( - "{}{}{}", + "{}{}{expr_snip}", snippet(cx, other.span, ".."), - snippet(cx, cmp_span, ".."), - expr_snip + snippet(cx, cmp_span, "..") ); } } diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index 827a2b26709..49e662cacb0 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -31,12 +31,11 @@ pub(crate) fn check<'tcx>( cx, DURATION_SUBSEC, expr.span, - &format!("calling `{}()` is more concise than this calculation", suggested_fn), + &format!("calling `{suggested_fn}()` is more concise than this calculation"), "try", format!( - "{}.{}()", - snippet_with_applicability(cx, self_arg.span, "_", &mut applicability), - suggested_fn + "{}.{suggested_fn}()", + snippet_with_applicability(cx, self_arg.span, "_", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 44cf0bb0612..67913f7392c 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -22,7 +22,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { cx, EQ_OP, lhs.span.to(rhs.span), - &format!("identical args used in this `{}!` macro call", macro_name), + &format!("identical args used in this `{macro_name}!` macro call"), ); } } diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 0024384d927..ae805147f07 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -47,18 +47,14 @@ fn lint_misrefactored_assign_op( if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); - let long = format!("{} = {}", snip_a, sugg::make_binop(op.into(), a, r)); + let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r)); diag.span_suggestion( expr.span, &format!( - "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with", - snip_a, - snip_a, - op.as_str(), - snip_r, - long + "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with", + op.as_str() ), - format!("{} {}= {}", snip_a, op.as_str(), snip_r), + format!("{snip_a} {}= {snip_r}", op.as_str()), Applicability::MaybeIncorrect, ); diag.span_suggestion( diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index e902235a014..ab5fb178700 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp if let Some(lhs_snip) = snippet_opt(cx, lhs.span) && let Some(rhs_snip) = snippet_opt(cx, rhs.span) { - let sugg = format!("{} {} {}", lhs_snip, op_str, rhs_snip); + let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); } }, diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 1aefc2741c2..1229c202f5a 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( expr.span, LINT_MSG, "try", - format!("std::ptr::eq({}, {})", left_snip, right_snip), + format!("std::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/operators/self_assignment.rs b/clippy_lints/src/operators/self_assignment.rs index 9d6bec05bf0..7c9d5320a3a 100644 --- a/clippy_lints/src/operators/self_assignment.rs +++ b/clippy_lints/src/operators/self_assignment.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx cx, SELF_ASSIGNMENT, e.span, - &format!("self-assignment of `{}` to `{}`", rhs, lhs), + &format!("self-assignment of `{rhs}` to `{lhs}`"), ); } } diff --git a/clippy_lints/src/operators/verbose_bit_mask.rs b/clippy_lints/src/operators/verbose_bit_mask.rs index ff85fd55429..fbf65e92b32 100644 --- a/clippy_lints/src/operators/verbose_bit_mask.rs +++ b/clippy_lints/src/operators/verbose_bit_mask.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "try", - format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()), + format!("{sugg}.trailing_zeros() >= {}", n.count_ones()), Applicability::MaybeIncorrect, ); }, diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 0315678bf97..256d2450001 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -163,7 +163,7 @@ fn try_get_option_occurence<'tcx>( return Some(OptionOccurence { option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), method_sugg: method_sugg.to_string(), - some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")), + some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), }); } diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0960b050c24..152e0c5ec9a 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -209,7 +209,7 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size), + &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size), "consider passing by value instead", value_type, Applicability::Unspecified, @@ -237,7 +237,7 @@ impl<'tcx> PassByRefOrValue { cx, LARGE_TYPES_PASSED_BY_VALUE, input.span, - &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size), + &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size), "consider passing by reference instead", format!("&{}", snippet(cx, input.span, "_")), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 41d1baba64f..85e0710eb50 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -463,7 +463,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( diag.span_suggestion( hir_ty.span, "change this to", - format!("&{}{}", mutability.prefix_str(), ty_name), + format!("&{}{ty_name}", mutability.prefix_str()), Applicability::Unspecified, ); } diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 4dc65da3ea1..b0a5d1a6758 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { None => return, }; - let msg = format!("use of `{}` with a `usize` casted to an `isize`", method); + let msg = format!("use of `{method}` with a `usize` casted to an `isize`"); if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) { span_lint_and_sugg( cx, @@ -124,7 +124,7 @@ fn build_suggestion<'tcx>( ) -> Option { let receiver = snippet_opt(cx, receiver_expr.span)?; let cast_lhs = snippet_opt(cx, cast_lhs_expr.span)?; - Some(format!("{}.{}({})", receiver, method.suggestion(), cast_lhs)) + Some(format!("{receiver}.{}({cast_lhs})", method.suggestion())) } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index f4f1fd336df..d53614722aa 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -97,12 +97,12 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { if eq_expr_value(cx, caller, peel_blocks(else_inner)) { - format!("Some({}?)", receiver_str) + format!("Some({receiver_str}?)") } else { return; } } else { - format!("{}{}?;", receiver_str, if by_ref { ".as_ref()" } else { "" }) + format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) }; span_lint_and_sugg( @@ -134,8 +134,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); let sugg = format!( - "{}{}?{}", - receiver_str, + "{receiver_str}{}?{}", if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, if requires_semi { ";" } else { "" } ); diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 918d624eec6..c6fbb5e805a 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -243,9 +243,9 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `{}::contains` implementation", range_type), + &format!("manual `{range_type}::contains` implementation"), "use", - format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), + format!("({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, ); } else if !combine_and && ord == Some(l.ord) { @@ -273,9 +273,9 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `!{}::contains` implementation", range_type), + &format!("manual `!{range_type}::contains` implementation"), "use", - format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), + format!("!({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, ); } @@ -372,14 +372,14 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { diag.span_suggestion( span, "use", - format!("({}..={})", start, end), + format!("({start}..={end})"), Applicability::MaybeIncorrect, ); } else { diag.span_suggestion( span, "use", - format!("{}..={}", start, end), + format!("{start}..={end}"), Applicability::MachineApplicable, // snippet ); } @@ -408,7 +408,7 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { diag.span_suggestion( expr.span, "use", - format!("{}..{}", start, end), + format!("{start}..{end}"), Applicability::MachineApplicable, // snippet ); }, @@ -486,7 +486,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "consider using the following if you are attempting to iterate over this \ range in reverse", - format!("({}{}{}).rev()", end_snippet, dots, start_snippet), + format!("({end_snippet}{dots}{start_snippet}).rev()"), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 94dec191103..ae80b6f1269 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -101,9 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({}, 0); {}", + format!("{}.resize({len}, 0); {}", ident.as_str(), - len, snippet(cx, next_stmt_span, "..") ), applicability, diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 323326381d4..9c71a3daeee 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { cx, REDUNDANT_PUB_CRATE, span, - &format!("pub(crate) {} inside private module", descr), + &format!("pub(crate) {descr} inside private module"), |diag| { diag.span_suggestion( item.vis_span, diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 8693ca9af83..245a02ea26e 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -127,9 +127,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix { - format!("({}{}{})", reborrow_str, "*".repeat(deref_count), snip) + format!("({reborrow_str}{}{snip})", "*".repeat(deref_count)) } else { - format!("{}{}{}", reborrow_str, "*".repeat(deref_count), snip) + format!("{reborrow_str}{}{snip}", "*".repeat(deref_count)) }; (lint, help_str, sugg) @@ -141,9 +141,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; let sugg = if needs_parens_for_prefix { - format!("(&{}{}*{})", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip) + format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count)) } else { - format!("&{}{}*{}", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip) + format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count)) }; (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg) } else { diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 2d751c27467..60ba62c4a43 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -67,7 +67,7 @@ impl RedundantStaticLifetimes { TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => { if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime { let snip = snippet(cx, borrow_type.ty.span, ""); - let sugg = format!("&{}", snip); + let sugg = format!("&{snip}"); span_lint_and_then( cx, REDUNDANT_STATIC_LIFETIMES, diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 6bcae0da8f4..1fda58fa54d 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -172,7 +172,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { ); }, Err(e) => { - span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e)); + span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}")); }, } } @@ -200,7 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { ); }, Err(e) => { - span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e)); + span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}")); }, } } diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 73f8e083b29..dead36e3bea 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { |diag| { diag.span_note( trait_method_span, - &format!("existing `{}` defined here", method_name), + &format!("existing `{method_name}` defined here"), ); }, ); @@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { // iterate on trait_spans? diag.span_note( trait_spans[0], - &format!("existing `{}` defined here", method_name), + &format!("existing `{method_name}` defined here"), ); }, ); diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 729694da46d..66638eed998 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { } let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); - let suggestion = format!("{0};", sugg); + let suggestion = format!("{sugg};"); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index c07aa00a127..e57ab8cd7a3 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -174,7 +174,7 @@ impl SlowVectorInit { diag.span_suggestion( vec_alloc.allocation_expr.span, "consider replace allocation with", - format!("vec![0; {}]", len_expr), + format!("vec![0; {len_expr}]"), Applicability::Unspecified, ); }); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 662d399ca53..d356c99c8fc 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -284,7 +284,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", "try", - format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")), + format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), applicability ) } @@ -500,8 +500,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { cx, TRIM_SPLIT_WHITESPACE, trim_span.with_hi(split_ws_span.lo()), - &format!("found call to `str::{}` before `str::split_whitespace`", trim_fn_name), - &format!("remove `{}()`", trim_fn_name), + &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), + &format!("remove `{trim_fn_name}()`"), String::new(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 78403d9fdb7..03324c66e8e 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { span, "using `libc::strlen` on a `CString` or `CStr` value", "try this", - format!("{}.{}().len()", val_name, method_name), + format!("{val_name}.{method_name}().len()"), app, ); } diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 5d36f0f5ff8..eef9bdc7849 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -326,8 +326,7 @@ fn replace_left_sugg( applicability: &mut Applicability, ) -> String { format!( - "{} {} {}", - left_suggestion, + "{left_suggestion} {} {}", binop.op.to_string(), snippet_with_applicability(cx, binop.right.span, "..", applicability), ) @@ -340,10 +339,9 @@ fn replace_right_sugg( applicability: &mut Applicability, ) -> String { format!( - "{} {} {}", + "{} {} {right_suggestion}", snippet_with_applicability(cx, binop.left.span, "..", applicability), binop.op.to_string(), - right_suggestion, ) } @@ -676,9 +674,8 @@ fn suggestion_with_swapped_ident( } Some(format!( - "{}{}{}", + "{}{new_ident}{}", snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability), - new_ident, snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability), )) }) diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 1885f3ca414..f46c21e1265 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -96,7 +96,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping elements of `{}` manually", slice), + &format!("this looks like you are swapping elements of `{slice}` manually"), "try", format!( "{}.swap({}, {})", @@ -121,16 +121,16 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping `{}` and `{}` manually", first, second), + &format!("this looks like you are swapping `{first}` and `{second}` manually"), |diag| { diag.span_suggestion( span, "try", - format!("{}::mem::swap({}, {})", sugg, first.mut_addr(), second.mut_addr()), + format!("{sugg}::mem::swap({}, {})", first.mut_addr(), second.mut_addr()), applicability, ); if !is_xor_based { - diag.note(&format!("or maybe you should use `{}::mem::replace`?", sugg)); + diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?")); } }, ); @@ -182,7 +182,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { let rhs0 = Sugg::hir_opt(cx, rhs0); let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) { ( - format!(" `{}` and `{}`", first, second), + format!(" `{first}` and `{second}`"), first.mut_addr().to_string(), second.mut_addr().to_string(), ) @@ -196,22 +196,19 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { span_lint_and_then(cx, ALMOST_SWAPPED, span, - &format!("this looks like you are trying to swap{}", what), + &format!("this looks like you are trying to swap{what}"), |diag| { if !what.is_empty() { diag.span_suggestion( span, "try", format!( - "{}::mem::swap({}, {})", - sugg, - lhs, - rhs, + "{sugg}::mem::swap({lhs}, {rhs})", ), Applicability::MaybeIncorrect, ); diag.note( - &format!("or maybe you should use `{}::mem::replace`?", sugg) + &format!("or maybe you should use `{sugg}::mem::replace`?") ); } }); diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 3cbbda80f3a..d085dda3582 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -58,7 +58,7 @@ impl LateLintPass<'_> for SwapPtrToRef { let mut app = Applicability::MachineApplicable; let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0; let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0; - diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({}, {})", snip1, snip2), app); + diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app); } } ); diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 651201f34ed..2512500a6be 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -84,9 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { "use of `.to_digit(..).is_some()`", "try this", if is_method_call { - format!("{}.is_digit({})", char_arg_snip, radix_snip) + format!("{char_arg_snip}.is_digit({radix_snip})") } else { - format!("char::is_digit({}, {})", char_arg_snip, radix_snip) + format!("char::is_digit({char_arg_snip}, {radix_snip})") }, applicability, ); diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index a25be93b8d6..bb146441f87 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -215,9 +215,8 @@ impl TraitBounds { .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability)) .join(" + "); let hint_string = format!( - "consider combining the bounds: `{}: {}`", + "consider combining the bounds: `{}: {trait_bounds}`", snippet(cx, p.bounded_ty.span, "_"), - trait_bounds, ); span_lint_and_help( cx, diff --git a/clippy_lints/src/transmute/crosspointer_transmute.rs b/clippy_lints/src/transmute/crosspointer_transmute.rs index 25d0543c861..c4b9d82fc73 100644 --- a/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -13,10 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!( - "transmute from a type (`{}`) to the type that it points to (`{}`)", - from_ty, to_ty - ), + &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), ); true }, @@ -25,10 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!( - "transmute from a type (`{}`) to a pointer to that type (`{}`)", - from_ty, to_ty - ), + &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), ); true }, diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 1bde977cfa2..5ecba512b0f 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_FLOAT_TO_INT, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let mut sugg = sugg::Sugg::hir(cx, arg, ".."); @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( if let ExprKind::Lit(lit) = &arg.kind; if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node; then { - let op = format!("{}{}", sugg, float_ty.name_str()).into(); + let op = format!("{sugg}{}", float_ty.name_str()).into(); match sugg { sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op), _ => sugg = sugg::Sugg::NonParen(op) diff --git a/clippy_lints/src/transmute/transmute_int_to_bool.rs b/clippy_lints/src/transmute/transmute_int_to_bool.rs index 8c50b58ca4b..58227c53de2 100644 --- a/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_BOOL, e.span, - &format!("transmute from a `{}` to a `bool`", from_ty), + &format!("transmute from a `{from_ty}` to a `bool`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let zero = sugg::Sugg::NonParen(Cow::from("0")); diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 9e1823c373b..7d31c375f8c 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_CHAR, e.span, - &format!("transmute from a `{}` to a `char`", from_ty), + &format!("transmute from a `{from_ty}` to a `char`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(_) = from_ty.kind() { @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("std::char::from_u32({}).unwrap()", arg), + format!("std::char::from_u32({arg}).unwrap()"), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index b8703052e6c..cc3422edbbf 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_FLOAT, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(int_ty) = from_ty.kind() { @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("{}::from_bits({})", to_ty, arg), + format!("{to_ty}::from_bits({arg})"), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 52d193d11e1..009d5a7c8ae 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -31,13 +31,13 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_NUM_TO_BYTES, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( e.span, "consider using `to_ne_bytes()`", - format!("{}.to_ne_bytes()", arg), + format!("{arg}.to_ne_bytes()"), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 5eb03275b8e..12d0b866e1c 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -25,10 +25,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_PTR_TO_REF, e.span, - &format!( - "transmute from a pointer type (`{}`) to a reference type (`{}`)", - from_ty, to_ty - ), + &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = if *mutbl == Mutability::Mut { @@ -41,26 +38,25 @@ pub(super) fn check<'tcx>( let sugg = if let Some(ty) = get_explicit_type(path) { let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); if meets_msrv(msrv, msrvs::POINTER_CAST) { - format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), ty_snip) + format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par()) } else if from_ptr_ty.has_erased_regions() { - sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, ty_snip))) - .to_string() + sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string() } else { - sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, ty_snip))).to_string() + sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string() } } else if from_ptr_ty.ty == *to_ref_ty { if from_ptr_ty.has_erased_regions() { if meets_msrv(msrv, msrvs::POINTER_CAST) { - format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), to_ref_ty) + format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) } else { - sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, to_ref_ty))) + sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))) .to_string() } } else { sugg::make_unop(deref, arg).to_string() } } else { - sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, to_ref_ty))).to_string() + sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string() }; diag.span_suggestion(e.span, "try", sugg, app); diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 707a11d361c..afb7f2e1326 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_BYTES_TO_STR, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { format!("std::str::from_utf8_unchecked{postfix}({snippet})") diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index b6d7d9f5b42..cac620cf8e8 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -75,10 +75,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -89,10 +89,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute to `{}` which has an undefined layout", to_ty_orig), + &format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); } }, ); @@ -116,8 +116,7 @@ pub(super) fn check<'tcx>( TRANSMUTE_UNDEFINED_REPR, e.span, &format!( - "transmute from `{}` to `{}`, both of which have an undefined layout", - from_ty_orig, to_ty_orig + "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout" ), |diag| { if let Some(same_adt_did) = same_adt_did { @@ -127,10 +126,10 @@ pub(super) fn check<'tcx>( )); } else { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); } if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); } } }, @@ -145,10 +144,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -162,10 +161,10 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute into `{}` which has an undefined layout", to_ty_orig), + &format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); } }, ); diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 626d7cd46fc..6b444922a7c 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -21,10 +21,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, e.span, - &format!( - "transmute from `{}` to `{}` which could be expressed as a pointer cast instead", - from_ty, to_ty - ), + &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { let sugg = arg.as_ty(&to_ty.to_string()).to_string(); diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 831b0d450d2..b1445311b71 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -37,10 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, UNSOUND_COLLECTION_TRANSMUTE, e.span, - &format!( - "transmute from `{}` to `{}` with mismatched layout is unsound", - from_ty, to_ty - ), + &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), ); true } else { diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 8122cd716e0..f919bbd5afc 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( cx, USELESS_TRANSMUTE, e.span, - &format!("transmute from a type (`{}`) to itself", from_ty), + &format!("transmute from a type (`{from_ty}`) to itself"), ); true }, diff --git a/clippy_lints/src/transmute/wrong_transmute.rs b/clippy_lints/src/transmute/wrong_transmute.rs index 2118f3d6950..d1965565b92 100644 --- a/clippy_lints/src/transmute/wrong_transmute.rs +++ b/clippy_lints/src/transmute/wrong_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, WRONG_TRANSMUTE, e.span, - &format!("transmute from a `{}` to a pointer", from_ty), + &format!("transmute from a `{from_ty}` to a pointer"), ); true }, diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 94945b2e1a9..0a779b37860 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -49,15 +49,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m let inner_snippet = snippet(cx, inner.span, ".."); let suggestion = match &inner.kind { TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => { - format!("&{}({})", ltopt, &inner_snippet) + format!("&{ltopt}({})", &inner_snippet) }, TyKind::Path(qpath) if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) .map_or(false, |bounds| bounds.len() > 1) => { - format!("&{}({})", ltopt, &inner_snippet) + format!("&{ltopt}({})", &inner_snippet) }, - _ => format!("&{}{}", ltopt, &inner_snippet), + _ => format!("&{ltopt}{}", &inner_snippet), }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index ba51404d214..08020ce6638 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ _ => "<..>", }; - let box_content = format!("{outer}{generic}", outer = item_type); + let box_content = format!("{item_type}{generic}"); span_lint_and_help( cx, BOX_COLLECTION, diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 4d72a29e8c7..6b9de64e24c 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ hir_ty.span, "usage of `Rc` when T is a buffer type", "try", - format!("Rc<{}>", alternate), + format!("Rc<{alternate}>"), Applicability::MachineApplicable, ); } else { @@ -57,7 +57,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ hir_ty.span, "usage of `Arc` when T is a buffer type", "try", - format!("Arc<{}>", alternate), + format!("Arc<{alternate}>"), Applicability::MachineApplicable, ); } else if let Some(ty) = qpath_generic_tys(qpath).next() { diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index a1312fcda0b..b95f0213e0c 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -27,13 +27,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{}<{}>`", outer_sym, generic_snippet), + &format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { - diag.span_suggestion(hir_ty.span, "try", format!("{}", generic_snippet), applicability); + diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); diag.note(&format!( - "`{generic}` is already a pointer, `{outer}<{generic}>` allocates a pointer on the heap", - outer = outer_sym, - generic = generic_snippet + "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap" )); }, ); @@ -72,19 +70,16 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet), + &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.span_suggestion( hir_ty.span, "try", - format!("{}<{}>", outer_sym, generic_snippet), + format!("{outer_sym}<{generic_snippet}>"), applicability, ); diag.note(&format!( - "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation", - outer = outer_sym, - inner = inner_sym, - generic = generic_snippet + "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); }, ); @@ -94,19 +89,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet), + &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.note(&format!( - "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation", - outer = outer_sym, - inner = inner_sym, - generic = generic_snippet + "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); diag.help(&format!( - "consider using just `{outer}<{generic}>` or `{inner}<{generic}>`", - outer = outer_sym, - inner = inner_sym, - generic = generic_snippet + "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`" )); }, ); diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index c0a4f3fbacd..57aff5367dd 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -157,8 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { span, &format!( "this closure returns \ - the unit type which also implements {}", - trait_name + the unit type which also implements {trait_name}" ), ); }, @@ -169,8 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { span, &format!( "this closure returns \ - the unit type which also implements {}", - trait_name + the unit type which also implements {trait_name}" ), Some(last_semi), "probably caused by this trailing semicolon", diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index a6f777abc6e..f6d3fb00f4e 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -74,7 +74,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp cx, UNIT_ARG, expr.span, - &format!("passing {}unit value{} to a function", singular, plural), + &format!("passing {singular}unit value{plural} to a function"), |db| { let mut or = ""; args_to_recover @@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp if arg_snippets_without_empty_blocks.is_empty() { db.multipart_suggestion( - &format!("use {}unit literal{} instead", singular, plural), + &format!("use {singular}unit literal{plural} instead"), args_to_recover .iter() .map(|arg| (arg.span, "()".to_string())) @@ -143,8 +143,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp db.span_suggestion( expr.span, &format!( - "{}move the expression{} in front of the call and replace {} with the unit literal `()`", - or, empty_or_s, it_or_them + "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`" ), sugg, applicability, diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index 1dd8895ebd0..226495dcbda 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, macro_call.span, - &format!("`{}` of unit values detected. This will always {}", macro_name, result), + &format!("`{macro_name}` of unit values detected. This will always {result}"), ); } return; @@ -40,9 +40,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { UNIT_CMP, expr.span, &format!( - "{}-comparison of unit values detected. This will always be {}", - op.as_str(), - result + "{}-comparison of unit values detected. This will always be {result}", + op.as_str() ), ); } diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 839a4bdab09..bc0dd263d88 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -57,7 +57,7 @@ impl EarlyLintPass for UnnecessarySelfImports { format!( "{}{};", last_segment.ident, - if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {}", alias) } else { String::new() }, + if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() }, ), Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 2c40827db0e..83ef3b0fac8 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -153,11 +153,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) } else { ( - format!( - "this function's return value is unnecessarily wrapped by `{}`", - return_type_label - ), - format!("remove `{}` from the return type...", return_type_label), + format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"), + format!("remove `{return_type_label}` from the return type..."), inner_type.to_string(), "...and then change returning expressions", ) diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 64f7a055cd9..32cd4681201 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -65,10 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, cx, UNSAFE_REMOVED_FROM_NAME, span, - &format!( - "removed `unsafe` from the name of `{}` in use as `{}`", - old_str, new_str - ), + &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), ); } } diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index b8a5d4ea8c9..3164937293b 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -58,8 +58,8 @@ impl EarlyLintPass for UnusedRounding { cx, UNUSED_ROUNDING, expr.span, - &format!("used the `{}` method with a whole number float", method_name), - &format!("remove the `{}` method call", method_name), + &format!("used the `{method_name}` method with a whole number float"), + &format!("remove the `{method_name}` method call"), float, Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 7e451b7b7a4..45e2f550236 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -257,9 +257,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { expr.hir_id, expr.span, &format!( - "called `{}` on `{}` after checking its variant with `{}`", + "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", method_name.ident.name, - unwrappable_variable_name, unwrappable.check_name.ident.as_str(), ), |diag| { @@ -268,9 +267,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), "try", format!( - "if let {} = {}", - suggested_pattern, - unwrappable_variable_name, + "if let {suggested_pattern} = {unwrappable_variable_name}", ), // We don't track how the unwrapped value is used inside the // block or suggest deleting the unwrap, so we can't offer a diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 02bf09ed506..378cc427f5a 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -93,7 +93,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { cx, UPPER_CASE_ACRONYMS, span, - &format!("name `{}` contains a capitalized acronym", ident), + &format!("name `{ident}` contains a capitalized acronym"), "consider making the acronym lowercase, except the initial letter", corrected, Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index f1b6463ad0f..50c5a832430 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), None, "consider removing `.try_into()`", ); @@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), None, &hint, ); @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{}`", b), + &format!("useless conversion to the same type: `{b}`"), &sugg_msg, sugg.to_string(), Applicability::MachineApplicable, // snippet diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 4003fff27c0..65576b7203f 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -739,7 +739,7 @@ fn path_to_string(path: &QPath<'_>) -> String { *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); }, - other => write!(s, "/* unimplemented: {:?}*/", other).unwrap(), + other => write!(s, "/* unimplemented: {other:?}*/").unwrap(), }, QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"), } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 2be3fa99c81..6f5a638be12 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -482,16 +482,13 @@ pub fn format_error(error: Box) -> String { let field = fields.get(index).copied().unwrap_or_default(); write!( msg, - "{:separator_width$}{:field_width$}", - " ", - field, - separator_width = SEPARATOR_WIDTH, - field_width = column_width + "{:SEPARATOR_WIDTH$}{field:column_width$}", + " " ) .unwrap(); } } - write!(msg, "\n{}", suffix).unwrap(); + write!(msg, "\n{suffix}").unwrap(); msg } else { s diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5418eca382d..33138551011 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -173,7 +173,7 @@ impl LateLintPass<'_> for WildcardImports { let sugg = if braced_glob { imports_string } else { - format!("{}::{}", import_source_snippet, imports_string) + format!("{import_source_snippet}::{imports_string}") }; let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 50d3c079fe6..9b3de35dbd3 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -57,8 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { "constant division of `0.0` with `0.0` will always result in NaN", None, &format!( - "consider using `{}::NAN` if you would like a constant representing NaN", - float_type, + "consider using `{float_type}::NAN` if you would like a constant representing NaN", ), ); } -- cgit 1.4.1-3-g733a5 From 72898355429c278ea994758805a92e611aecb430 Mon Sep 17 00:00:00 2001 From: kraktus Date: Tue, 27 Sep 2022 22:24:14 +0200 Subject: [`should_implement_trait`] Also lint `default` method --- clippy_lints/src/methods/mod.rs | 83 +++++++++++-------------- tests/ui/should_impl_trait/method_list_1.stderr | 12 +++- 2 files changed, 49 insertions(+), 46 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cdde4c54d63..c43f822e3a3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3255,65 +3255,59 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let self_ty = cx.tcx.type_of(item.def_id); let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); - if_chain! { - if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind; - if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next(); - + if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind { let method_sig = cx.tcx.fn_sig(impl_item.def_id); let method_sig = cx.tcx.erase_late_bound_regions(method_sig); - - let first_arg_ty = method_sig.inputs().iter().next(); - - // check conventions w.r.t. conversion method names and predicates - if let Some(first_arg_ty) = first_arg_ty; - - then { - // if this impl block implements a trait, lint in trait definition instead - if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) { - // check missing trait implementations - for method_config in &TRAIT_METHODS { - if name == method_config.method_name && - sig.decl.inputs.len() == method_config.param_count && - method_config.output_type.matches(&sig.decl.output) && - method_config.self_kind.matches(cx, self_ty, *first_arg_ty) && - fn_header_equals(method_config.fn_header, sig.header) && - method_config.lifetime_param_cond(impl_item) - { - span_lint_and_help( - cx, - SHOULD_IMPLEMENT_TRAIT, - impl_item.span, - &format!( - "method `{}` can be confused for the standard trait method `{}::{}`", - method_config.method_name, - method_config.trait_name, - method_config.method_name - ), - None, - &format!( - "consider implementing the trait `{}` or choosing a less ambiguous method name", - method_config.trait_name - ) - ); - } + let first_arg_ty_opt = method_sig.inputs().iter().next().copied(); + // if this impl block implements a trait, lint in trait definition instead + if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) { + // check missing trait implementations + for method_config in &TRAIT_METHODS { + if name == method_config.method_name + && sig.decl.inputs.len() == method_config.param_count + && method_config.output_type.matches(&sig.decl.output) + // in case there is no first arg, since we already have checked the number of arguments + // it's should be always true + && first_arg_ty_opt.map_or(true, |first_arg_ty| method_config + .self_kind.matches(cx, self_ty, first_arg_ty) + ) + && fn_header_equals(method_config.fn_header, sig.header) + && method_config.lifetime_param_cond(impl_item) + { + span_lint_and_help( + cx, + SHOULD_IMPLEMENT_TRAIT, + impl_item.span, + &format!( + "method `{}` can be confused for the standard trait method `{}::{}`", + method_config.method_name, method_config.trait_name, method_config.method_name + ), + None, + &format!( + "consider implementing the trait `{}` or choosing a less ambiguous method name", + method_config.trait_name + ), + ); } } + } - if sig.decl.implicit_self.has_implicit_self() + if sig.decl.implicit_self.has_implicit_self() && !(self.avoid_breaking_exported_api - && cx.access_levels.is_exported(impl_item.def_id)) + && cx.access_levels.is_exported(impl_item.def_id)) + && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() + && let Some(first_arg_ty) = first_arg_ty_opt { wrong_self_convention::check( cx, name, self_ty, - *first_arg_ty, + first_arg_ty, first_arg.pat.span, implements_trait, false ); } - } } // if this impl block implements a trait, lint in trait definition instead @@ -3799,7 +3793,6 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true), ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true), - // FIXME: default doesn't work ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true), ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true), @@ -3827,7 +3820,7 @@ enum SelfKind { Value, Ref, RefMut, - No, + No, // When we want the first argument type to be different than `Self` } impl SelfKind { diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr index 2b7d4628c3f..e6daedc5654 100644 --- a/tests/ui/should_impl_trait/method_list_1.stderr +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -99,6 +99,16 @@ LL | | } | = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name +error: method `default` can be confused for the standard trait method `std::default::Default::default` + --> $DIR/method_list_1.rs:65:5 + | +LL | / pub fn default() -> Self { +LL | | unimplemented!() +LL | | } + | |_____^ + | + = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name + error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` --> $DIR/method_list_1.rs:69:5 | @@ -139,5 +149,5 @@ LL | | } | = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From 6ec7759c3bff136c1d39bbe0bc8a68ac8b438a55 Mon Sep 17 00:00:00 2001 From: kraktus Date: Thu, 29 Sep 2022 13:45:40 +0200 Subject: [`unnecessary_lazy_eval`] Do not lint in external macros --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 6 +- tests/ui/unnecessary_lazy_eval.fixed | 10 ++++ tests/ui/unnecessary_lazy_eval.rs | 10 ++++ tests/ui/unnecessary_lazy_eval.stderr | 68 +++++++++++------------ 4 files changed, 59 insertions(+), 35 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index ec9859fa298..0e73459ad65 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eager_or_lazy, usage}; +use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -18,6 +18,10 @@ pub(super) fn check<'tcx>( arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { + if is_from_proc_macro(cx, expr) { + return; + } + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 878537050d4..ce4a82e0217 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,9 +1,13 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Deep(Option); #[derive(Copy, Clone)] @@ -141,3 +145,9 @@ fn main() { let _: Result = res.and_then(|x| Err(x)); let _: Result = res.or_else(|err| Ok(err)); } + +#[allow(unused)] +fn issue9485() { + // should not lint, is in proc macro + with_span!(span Some(42).unwrap_or_else(|| 2);); +} diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index f70cf332460..59cdf662854 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,9 +1,13 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Deep(Option); #[derive(Copy, Clone)] @@ -141,3 +145,9 @@ fn main() { let _: Result = res.and_then(|x| Err(x)); let _: Result = res.or_else(|err| Ok(err)); } + +#[allow(unused)] +fn issue9485() { + // should not lint, is in proc macro + with_span!(span Some(42).unwrap_or_else(|| 2);); +} diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index b46fbf56c4b..8a9ece4aa7e 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:44:13 + --> $DIR/unnecessary_lazy_eval.rs:48:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -9,7 +9,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:45:13 + --> $DIR/unnecessary_lazy_eval.rs:49:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -17,7 +17,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:46:13 + --> $DIR/unnecessary_lazy_eval.rs:50:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -25,7 +25,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:48:13 + --> $DIR/unnecessary_lazy_eval.rs:52:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -33,7 +33,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:49:13 + --> $DIR/unnecessary_lazy_eval.rs:53:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -41,7 +41,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:50:13 + --> $DIR/unnecessary_lazy_eval.rs:54:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -49,7 +49,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:51:13 + --> $DIR/unnecessary_lazy_eval.rs:55:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -57,7 +57,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:52:13 + --> $DIR/unnecessary_lazy_eval.rs:56:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -65,7 +65,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:53:13 + --> $DIR/unnecessary_lazy_eval.rs:57:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -73,7 +73,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:54:13 + --> $DIR/unnecessary_lazy_eval.rs:58:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- @@ -81,7 +81,7 @@ LL | let _ = cond.then(|| astronomers_pi); | help: use `then_some(..)` instead: `then_some(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:61:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -89,7 +89,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:62:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -97,7 +97,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:59:28 + --> $DIR/unnecessary_lazy_eval.rs:63:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -105,7 +105,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:60:13 + --> $DIR/unnecessary_lazy_eval.rs:64:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -113,7 +113,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:61:35 + --> $DIR/unnecessary_lazy_eval.rs:65:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -121,7 +121,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:62:28 + --> $DIR/unnecessary_lazy_eval.rs:66:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -129,7 +129,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:65:13 + --> $DIR/unnecessary_lazy_eval.rs:69:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -137,7 +137,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:66:13 + --> $DIR/unnecessary_lazy_eval.rs:70:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -145,7 +145,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:67:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -153,7 +153,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:68:13 + --> $DIR/unnecessary_lazy_eval.rs:72:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -161,7 +161,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -169,7 +169,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:92:28 + --> $DIR/unnecessary_lazy_eval.rs:96:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -177,7 +177,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:93:13 + --> $DIR/unnecessary_lazy_eval.rs:97:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -185,7 +185,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:94:13 + --> $DIR/unnecessary_lazy_eval.rs:98:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -193,7 +193,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:100:13 + --> $DIR/unnecessary_lazy_eval.rs:104:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -201,7 +201,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:101:13 + --> $DIR/unnecessary_lazy_eval.rs:105:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -209,7 +209,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:102:13 + --> $DIR/unnecessary_lazy_eval.rs:106:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -217,7 +217,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:124:35 + --> $DIR/unnecessary_lazy_eval.rs:128:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -225,7 +225,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:125:35 + --> $DIR/unnecessary_lazy_eval.rs:129:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -233,7 +233,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:126:35 + --> $DIR/unnecessary_lazy_eval.rs:130:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -241,7 +241,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:128:35 + --> $DIR/unnecessary_lazy_eval.rs:132:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -249,7 +249,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:129:35 + --> $DIR/unnecessary_lazy_eval.rs:133:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -257,7 +257,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:130:35 + --> $DIR/unnecessary_lazy_eval.rs:134:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -265,7 +265,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:131:35 + --> $DIR/unnecessary_lazy_eval.rs:135:35 | LL | let _: Result = res. | ___________________________________^ -- cgit 1.4.1-3-g733a5 From eef5d477b59a3b68bca9c1f3a5334229fc0ad9b6 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sat, 1 Oct 2022 17:55:22 +0200 Subject: use `is_integer_literal` more --- clippy_lints/src/bool_to_int_with_if.rs | 21 ++--------- clippy_lints/src/checked_conversions.rs | 14 ++------ clippy_lints/src/from_str_radix_10.rs | 4 +-- clippy_lints/src/implicit_saturating_sub.rs | 18 +++------- clippy_lints/src/methods/get_last_with_len.rs | 6 ++-- clippy_lints/src/misc.rs | 6 ++-- .../src/operators/arithmetic_side_effects.rs | 28 ++++++--------- clippy_lints/src/operators/numeric_arithmetic.rs | 9 +++-- clippy_lints/src/slow_vector_initialization.rs | 12 +++---- clippy_lints/src/transmute/transmuting_null.rs | 41 ++++++++-------------- clippy_lints/src/uninit_vec.rs | 15 ++------ 11 files changed, 52 insertions(+), 122 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 51e98cda845..001d74c2605 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -3,7 +3,7 @@ use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, sugg::Sugg}; +use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, is_integer_literal, sugg::Sugg}; use rustc_errors::Applicability; declare_clippy_lint! { @@ -56,13 +56,9 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx && let Some(then_lit) = int_literal(then) && let Some(else_lit) = int_literal(else_) { - let inverted = if - check_int_literal_equals_val(then_lit, 1) - && check_int_literal_equals_val(else_lit, 0) { + let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) { false - } else if - check_int_literal_equals_val(then_lit, 0) - && check_int_literal_equals_val(else_lit, 1) { + } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) { true } else { // Expression isn't boolean, exit @@ -123,14 +119,3 @@ fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hi None } } - -fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Int(val, _) = lit.node - && val == expected_value - { - true - } else { - false - } -} diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1d113c7cbee..78e9921f036 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -2,9 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{in_constant, meets_msrv, msrvs, SpanlessEq}; +use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -223,16 +222,7 @@ fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { /// Check for `expr >= 0` fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option> { - if_chain! { - if let ExprKind::Lit(ref lit) = &check.kind; - if let LitKind::Int(0, _) = &lit.node; - - then { - Some(Conversion::new_any(candidate)) - } else { - None - } - } + is_integer_literal(check, 0).then(|| Conversion::new_any(candidate)) } /// Check for `expr >= (to_type::MIN as from_type)` diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 2a82473be8c..cf8b7acd66d 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_integer_literal; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; @@ -60,8 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { if pathseg.ident.name.as_str() == "from_str_radix"; // check if the second argument is a primitive `10` - if let ExprKind::Lit(lit) = &radix.kind; - if let rustc_ast::ast::LitKind::Int(10, _) = lit.node; + if is_integer_literal(radix, 10); then { let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index f0dbe17d83a..48edbf6ae57 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -131,17 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> { match peel_blocks_with_stmt(expr).kind { ExprKind::AssignOp(ref op1, target, value) => { - if_chain! { - if BinOpKind::Sub == op1.node; - // Check if literal being subtracted is one - if let ExprKind::Lit(ref lit1) = value.kind; - if let LitKind::Int(1, _) = lit1.node; - then { - Some(target) - } else { - None - } - } + // Check if literal being subtracted is one + (BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target) }, ExprKind::Assign(target, value, _) => { if_chain! { @@ -150,8 +141,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp if SpanlessEq::new(cx).eq_expr(left1, target); - if let ExprKind::Lit(ref lit1) = right1.kind; - if let LitKind::Int(1, _) = lit1.node; + if is_integer_literal(right1, 1); then { Some(target) } else { diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs index 02aada87202..3bdc154df04 100644 --- a/clippy_lints/src/methods/get_last_with_len.rs +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::SpanlessEq; -use rustc_ast::LitKind; +use clippy_utils::{is_integer_literal, SpanlessEq}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -26,8 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: && lhs_path.ident.name == sym::len // RHS of subtraction is 1 - && let ExprKind::Lit(rhs_lit) = &rhs.kind - && let LitKind::Int(1, ..) = rhs_lit.node + && is_integer_literal(rhs, 1) // check that recv == lhs_recv `recv.get(lhs_recv.len() - 1)` && SpanlessEq::new(cx).eq_expr(recv, lhs_recv) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 381458b91e6..516dee20f8b 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -15,7 +14,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, iter_input_pats, last_path_segment, SpanlessEq}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq}; declare_clippy_lint! { /// ### What it does @@ -314,8 +313,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool { fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) { if_chain! { if let TyKind::Ptr(ref mut_ty) = ty.kind; - if let ExprKind::Lit(ref lit) = e.kind; - if let LitKind::Int(0, _) = lit.node; + if is_integer_literal(e, 0); if !in_constant(cx, e.hir_id); then { let (msg, sugg_fn) = match mut_ty.mutbl { diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index c8a374d90b5..1f22fbd5387 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -44,25 +44,19 @@ impl ArithmeticSideEffects { /// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a /// non-constant environment that won't overflow. fn has_valid_op(op: &Spanned, expr: &hir::Expr<'_>) -> bool { - if let hir::BinOpKind::Add | hir::BinOpKind::Sub = op.node - && let hir::ExprKind::Lit(ref lit) = expr.kind - && let ast::LitKind::Int(0, _) = lit.node + if let hir::ExprKind::Lit(ref lit) = expr.kind && + let ast::LitKind::Int(value, _) = lit.node { - return true; - } - if let hir::BinOpKind::Div | hir::BinOpKind::Rem = op.node - && let hir::ExprKind::Lit(ref lit) = expr.kind - && !matches!(lit.node, ast::LitKind::Int(0, _)) - { - return true; - } - if let hir::BinOpKind::Mul = op.node - && let hir::ExprKind::Lit(ref lit) = expr.kind - && let ast::LitKind::Int(0 | 1, _) = lit.node - { - return true; + match (&op.node, value) { + (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) | + (hir::BinOpKind::Mul, 0 | 1) => true, + (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false, + (hir::BinOpKind::Div | hir::BinOpKind::Rem, _) => true, + _ => false, + } + } else { + false } - false } /// Checks if the given `expr` has any of the inner `allowed` elements. diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs index b6097710dc6..0830a106f55 100644 --- a/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/clippy_lints/src/operators/numeric_arithmetic.rs @@ -1,5 +1,6 @@ use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_integer_literal; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -50,11 +51,9 @@ impl Context { hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { hir::ExprKind::Lit(_lit) => (), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if let hir::ExprKind::Lit(lit) = &expr.kind { - if let rustc_ast::ast::LitKind::Int(1, _) = lit.node { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } + if is_integer_literal(expr, 1) { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_id = Some(expr.hir_id); } }, _ => { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index e57ab8cd7a3..6e5d88e1b59 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{get_enclosing_block, is_expr_path_def_path, path_to_local, path_to_local_id, paths, SpanlessEq}; +use clippy_utils::{ + get_enclosing_block, is_expr_path_def_path, is_integer_literal, path_to_local, path_to_local_id, paths, SpanlessEq, +}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind}; @@ -219,8 +220,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { && path_to_local_id(self_arg, self.vec_alloc.local_id) && path.ident.name == sym!(resize) // Check that is filled with 0 - && let ExprKind::Lit(ref lit) = fill_arg.kind - && let LitKind::Int(0, _) = lit.node { + && is_integer_literal(fill_arg, 0) { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { self.slow_expression = Some(InitializationType::Resize(expr)); @@ -255,9 +255,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { if_chain! { if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT); - if let ExprKind::Lit(ref lit) = repeat_arg.kind; - if let LitKind::Int(0, _) = lit.node; - + if is_integer_literal(repeat_arg, 0); then { true } else { diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index d8e349af7af..19ce5ae72c2 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,8 +1,6 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_path_diagnostic_item; -use if_chain::if_chain; -use rustc_ast::LitKind; +use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; @@ -19,37 +17,28 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching transmute over constants that resolve to `null`. let mut const_eval_context = constant_context(cx, cx.typeck_results()); - if_chain! { - if let ExprKind::Path(ref _qpath) = arg.kind; - if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); - if x == 0; - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); - return true; - } + if let ExprKind::Path(ref _qpath) = arg.kind && + let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) && + x == 0 + { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; } // Catching: // `std::mem::transmute(0 as *const i32)` - if_chain! { - if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind; - if let ExprKind::Lit(ref lit) = inner_expr.kind; - if let LitKind::Int(0, _) = lit.node; - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); - return true; - } + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; } // Catching: // `std::mem::transmute(std::ptr::null::())` - if_chain! { - if let ExprKind::Call(func1, []) = arg.kind; - if is_path_diagnostic_item(cx, func1, sym::ptr_null); - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); - return true; - } + if let ExprKind::Call(func1, []) = arg.kind && + is_path_diagnostic_item(cx, func1, sym::ptr_null) + { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; } // FIXME: diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index bde7c318f44..1ab0162a881 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; -use rustc_ast::ast::LitKind; +use clippy_utils::{is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -216,7 +215,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" - && !is_literal_zero(arg) + && !is_integer_literal(arg, 0) { Some((self_expr, expr.span)) } else { @@ -226,13 +225,3 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt _ => None, } } - -fn is_literal_zero(arg: &Expr<'_>) -> bool { - if let ExprKind::Lit(lit) = &arg.kind - && let LitKind::Int(0, _) = lit.node - { - true - } else { - false - } -} -- cgit 1.4.1-3-g733a5 From 52a68dc097cc8064a7464598bca959f2706aab18 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 1 Oct 2022 21:54:22 +0000 Subject: lint nested patterns and slice patterns in `needless_borrowed_reference` --- clippy_lints/src/manual_clamp.rs | 6 +- clippy_lints/src/map_unit_fn.rs | 4 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/needless_borrowed_ref.rs | 121 +++++++++++++++++++----------- src/docs/needless_borrowed_reference.txt | 18 ++--- tests/ui/needless_borrowed_ref.fixed | 41 +++++++--- tests/ui/needless_borrowed_ref.rs | 41 +++++++--- tests/ui/needless_borrowed_ref.stderr | 121 +++++++++++++++++++++++++++++- 8 files changed, 266 insertions(+), 88 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index ac5c24ee604..ece4df95505 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -324,7 +324,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) outer_arg: &'tcx Expr<'tcx>, span: Span, ) -> Option> { - if let ExprKind::Call(inner_fn, &[ref first, ref second]) = &inner_call.kind + if let ExprKind::Call(inner_fn, [first, second]) = &inner_call.kind && let Some(inner_seg) = segment(cx, inner_fn) && let Some(outer_seg) = segment(cx, outer_fn) { @@ -377,9 +377,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) /// # ; /// ``` fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { - if let ExprKind::Match(value, &[ref first_arm, ref second_arm, ref last_arm], rustc_hir::MatchSource::Normal) = - &expr.kind - { + if let ExprKind::Match(value, [first_arm, second_arm, last_arm], rustc_hir::MatchSource::Normal) = &expr.kind { // Find possible min/max branches let minmax_values = |a: &'tcx Arm<'tcx>| { if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index df5684541e9..32da37a862d 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -131,12 +131,12 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> }, hir::ExprKind::Block(block, _) => { match (block.stmts, block.expr.as_ref()) { - (&[], Some(inner_expr)) => { + ([], Some(inner_expr)) => { // If block only contains an expression, // reduce `{ X }` to `X` reduce_unit_expression(cx, inner_expr) }, - (&[ref inner_stmt], None) => { + ([inner_stmt], None) => { // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index c5c0ace7729..d9fb4382181 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -55,7 +55,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; let body = cx.tcx.hir().body(body); if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, [ok_arg]) = body.value.kind; if is_lang_ctor(cx, ok_path, ResultOk); then { path_to_local_id(ok_arg, param_id) } else { false } } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index b8855e5adbf..10c3ff026b6 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,6 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -8,36 +6,26 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does - /// Checks for bindings that destructure a reference and borrow the inner + /// Checks for bindings that needlessly destructure a reference and borrow the inner /// value with `&ref`. /// /// ### Why is this bad? /// This pattern has no effect in almost all cases. /// - /// ### Known problems - /// In some cases, `&ref` is needed to avoid a lifetime mismatch error. - /// Example: - /// ```rust - /// fn foo(a: &Option, b: &Option) { - /// match (a, b) { - /// (None, &ref c) | (&ref c, None) => (), - /// (&Some(ref c), _) => (), - /// }; - /// } - /// ``` - /// /// ### Example /// ```rust /// let mut v = Vec::::new(); - /// # #[allow(unused)] /// v.iter_mut().filter(|&ref a| a.is_empty()); + /// + /// if let &[ref first, ref second] = v.as_slice() {} /// ``` /// /// Use instead: /// ```rust /// let mut v = Vec::::new(); - /// # #[allow(unused)] /// v.iter_mut().filter(|a| a.is_empty()); + /// + /// if let [first, second] = v.as_slice() {} /// ``` #[clippy::version = "pre 1.29.0"] pub NEEDLESS_BORROWED_REFERENCE, @@ -54,34 +42,83 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { return; } - if_chain! { - // Only lint immutable refs, because `&mut ref T` may be useful. - if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind; + // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms + for (_, node) in cx.tcx.hir().parent_iter(pat.hir_id) { + let Node::Pat(pat) = node else { break }; + + if matches!(pat.kind, PatKind::Or(_)) { + return; + } + } + + // Only lint immutable refs, because `&mut ref T` may be useful. + let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind else { return }; + match sub_pat.kind { // Check sub_pat got a `ref` keyword (excluding `ref mut`). - if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind; - let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id); - if let Some(parent_node) = cx.tcx.hir().find(parent_id); - then { - // do not recurse within patterns, as they may have other references - // XXXManishearth we can relax this constraint if we only check patterns - // with a single ref pattern inside them - if let Node::Pat(_) = parent_node { - return; + PatKind::Binding(BindingAnnotation::REF, _, ident, None) => { + span_lint_and_then( + cx, + NEEDLESS_BORROWED_REFERENCE, + pat.span, + "this pattern takes a reference on something that is being dereferenced", + |diag| { + // `&ref ident` + // ^^^^^ + let span = pat.span.until(ident.span); + diag.span_suggestion_verbose( + span, + "try removing the `&ref` part", + String::new(), + Applicability::MachineApplicable, + ); + }, + ); + }, + // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]` + PatKind::Slice( + before, + None + | Some(Pat { + kind: PatKind::Wild, .. + }), + after, + ) => { + let mut suggestions = Vec::new(); + + for element_pat in itertools::chain(before, after) { + if let PatKind::Binding(BindingAnnotation::REF, _, ident, None) = element_pat.kind { + // `&[..., ref ident, ...]` + // ^^^^ + let span = element_pat.span.until(ident.span); + suggestions.push((span, String::new())); + } else { + return; + } } - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, - "this pattern takes a reference on something that is being de-referenced", - |diag| { - let hint = snippet_with_applicability(cx, spanned_name.span, "..", &mut applicability).into_owned(); - diag.span_suggestion( - pat.span, - "try removing the `&ref` part and just keep", - hint, - applicability, - ); - }); - } + + if !suggestions.is_empty() { + span_lint_and_then( + cx, + NEEDLESS_BORROWED_REFERENCE, + pat.span, + "dereferencing a slice pattern where every element takes a reference", + |diag| { + // `&[...]` + // ^ + let span = pat.span.until(sub_pat.span); + suggestions.push((span, String::new())); + + diag.multipart_suggestion( + "try removing the `&` and `ref` parts", + suggestions, + Applicability::MachineApplicable, + ); + }, + ); + } + }, + _ => {}, } } } diff --git a/src/docs/needless_borrowed_reference.txt b/src/docs/needless_borrowed_reference.txt index 55faa0cf571..152459ba1c9 100644 --- a/src/docs/needless_borrowed_reference.txt +++ b/src/docs/needless_borrowed_reference.txt @@ -1,30 +1,22 @@ ### What it does -Checks for bindings that destructure a reference and borrow the inner +Checks for bindings that needlessly destructure a reference and borrow the inner value with `&ref`. ### Why is this bad? This pattern has no effect in almost all cases. -### Known problems -In some cases, `&ref` is needed to avoid a lifetime mismatch error. -Example: -``` -fn foo(a: &Option, b: &Option) { - match (a, b) { - (None, &ref c) | (&ref c, None) => (), - (&Some(ref c), _) => (), - }; -} -``` - ### Example ``` let mut v = Vec::::new(); v.iter_mut().filter(|&ref a| a.is_empty()); + +if let &[ref first, ref second] = v.as_slice() {} ``` Use instead: ``` let mut v = Vec::::new(); v.iter_mut().filter(|a| a.is_empty()); + +if let [first, second] = v.as_slice() {} ``` \ No newline at end of file diff --git a/tests/ui/needless_borrowed_ref.fixed b/tests/ui/needless_borrowed_ref.fixed index a0937a2c5f6..bcb4eb2dd48 100644 --- a/tests/ui/needless_borrowed_ref.fixed +++ b/tests/ui/needless_borrowed_ref.fixed @@ -1,17 +1,38 @@ // run-rustfix -#[warn(clippy::needless_borrowed_reference)] -#[allow(unused_variables)] -fn main() { +#![warn(clippy::needless_borrowed_reference)] +#![allow(unused, clippy::needless_borrow)] + +fn main() {} + +fn should_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { let mut v = Vec::::new(); let _ = v.iter_mut().filter(|a| a.is_empty()); - // ^ should be linted let var = 3; let thingy = Some(&var); - if let Some(&ref v) = thingy { - // ^ should be linted - } + if let Some(v) = thingy {} + + if let &[a, ref b] = slice_of_refs {} + + let [a, ..] = &array; + let [a, b, ..] = &array; + + if let [a, b] = slice {} + if let [a, b] = &vec[..] {} + + if let [a, b, ..] = slice {} + if let [a, .., b] = slice {} + if let [.., a, b] = slice {} +} + +fn should_not_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { + if let [ref a] = slice {} + if let &[ref a, b] = slice {} + if let &[ref a, .., b] = slice {} + + // must not be removed as variables must be bound consistently across | patterns + if let (&[ref a], _) | ([], ref a) = (slice_of_refs, &1u8) {} let mut var2 = 5; let thingy2 = Some(&mut var2); @@ -28,17 +49,15 @@ fn main() { } } -#[allow(dead_code)] enum Animal { Cat(u64), Dog(u64), } -#[allow(unused_variables)] -#[allow(dead_code)] fn foo(a: &Animal, b: &Animal) { match (a, b) { - (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' + // lifetime mismatch error if there is no '&ref' before `feature(nll)` stabilization in 1.63 + (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // ^ and ^ should **not** be linted (&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted } diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 500ac448f0d..f6de1a6d83d 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,17 +1,38 @@ // run-rustfix -#[warn(clippy::needless_borrowed_reference)] -#[allow(unused_variables)] -fn main() { +#![warn(clippy::needless_borrowed_reference)] +#![allow(unused, clippy::needless_borrow)] + +fn main() {} + +fn should_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { let mut v = Vec::::new(); let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - // ^ should be linted let var = 3; let thingy = Some(&var); - if let Some(&ref v) = thingy { - // ^ should be linted - } + if let Some(&ref v) = thingy {} + + if let &[&ref a, ref b] = slice_of_refs {} + + let &[ref a, ..] = &array; + let &[ref a, ref b, ..] = &array; + + if let &[ref a, ref b] = slice {} + if let &[ref a, ref b] = &vec[..] {} + + if let &[ref a, ref b, ..] = slice {} + if let &[ref a, .., ref b] = slice {} + if let &[.., ref a, ref b] = slice {} +} + +fn should_not_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec) { + if let [ref a] = slice {} + if let &[ref a, b] = slice {} + if let &[ref a, .., b] = slice {} + + // must not be removed as variables must be bound consistently across | patterns + if let (&[ref a], _) | ([], ref a) = (slice_of_refs, &1u8) {} let mut var2 = 5; let thingy2 = Some(&mut var2); @@ -28,17 +49,15 @@ fn main() { } } -#[allow(dead_code)] enum Animal { Cat(u64), Dog(u64), } -#[allow(unused_variables)] -#[allow(dead_code)] fn foo(a: &Animal, b: &Animal) { match (a, b) { - (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' + // lifetime mismatch error if there is no '&ref' before `feature(nll)` stabilization in 1.63 + (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // ^ and ^ should **not** be linted (&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted } diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index 0a5cfb3db0b..7453542e673 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -1,10 +1,123 @@ -error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:7:34 +error: this pattern takes a reference on something that is being dereferenced + --> $DIR/needless_borrowed_ref.rs:10:34 | LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - | ^^^^^^ help: try removing the `&ref` part and just keep: `a` + | ^^^^^^ | = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` +help: try removing the `&ref` part + | +LL - let _ = v.iter_mut().filter(|&ref a| a.is_empty()); +LL + let _ = v.iter_mut().filter(|a| a.is_empty()); + | + +error: this pattern takes a reference on something that is being dereferenced + --> $DIR/needless_borrowed_ref.rs:14:17 + | +LL | if let Some(&ref v) = thingy {} + | ^^^^^^ + | +help: try removing the `&ref` part + | +LL - if let Some(&ref v) = thingy {} +LL + if let Some(v) = thingy {} + | + +error: this pattern takes a reference on something that is being dereferenced + --> $DIR/needless_borrowed_ref.rs:16:14 + | +LL | if let &[&ref a, ref b] = slice_of_refs {} + | ^^^^^^ + | +help: try removing the `&ref` part + | +LL - if let &[&ref a, ref b] = slice_of_refs {} +LL + if let &[a, ref b] = slice_of_refs {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:18:9 + | +LL | let &[ref a, ..] = &array; + | ^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - let &[ref a, ..] = &array; +LL + let [a, ..] = &array; + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:19:9 + | +LL | let &[ref a, ref b, ..] = &array; + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - let &[ref a, ref b, ..] = &array; +LL + let [a, b, ..] = &array; + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:21:12 + | +LL | if let &[ref a, ref b] = slice {} + | ^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, ref b] = slice {} +LL + if let [a, b] = slice {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:22:12 + | +LL | if let &[ref a, ref b] = &vec[..] {} + | ^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, ref b] = &vec[..] {} +LL + if let [a, b] = &vec[..] {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:24:12 + | +LL | if let &[ref a, ref b, ..] = slice {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, ref b, ..] = slice {} +LL + if let [a, b, ..] = slice {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:25:12 + | +LL | if let &[ref a, .., ref b] = slice {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[ref a, .., ref b] = slice {} +LL + if let [a, .., b] = slice {} + | + +error: dereferencing a slice pattern where every element takes a reference + --> $DIR/needless_borrowed_ref.rs:26:12 + | +LL | if let &[.., ref a, ref b] = slice {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: try removing the `&` and `ref` parts + | +LL - if let &[.., ref a, ref b] = slice {} +LL + if let [.., a, b] = slice {} + | -error: aborting due to previous error +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 8e7af6b42961d6a4b6857c06aa5139a985e0009d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 28 Jun 2022 22:34:02 -0400 Subject: Replace `is_lang_ctor` with `is_res_lang_ctor` --- clippy_lints/src/if_then_some_else_none.rs | 10 +-- clippy_lints/src/loops/manual_find.rs | 9 ++- clippy_lints/src/loops/manual_flatten.rs | 12 ++-- clippy_lints/src/loops/while_let_on_iterator.rs | 10 ++- clippy_lints/src/matches/collapsible_match.rs | 6 +- clippy_lints/src/matches/manual_map.rs | 30 ++++----- clippy_lints/src/matches/manual_unwrap_or.rs | 16 +++-- clippy_lints/src/matches/match_as_ref.rs | 12 ++-- clippy_lints/src/matches/needless_match.rs | 7 +-- .../src/matches/redundant_pattern_match.rs | 23 ++++--- clippy_lints/src/matches/try_err.rs | 5 +- clippy_lints/src/mem_replace.rs | 72 ++++++++++------------ .../methods/iter_on_single_or_empty_collections.rs | 27 ++------ clippy_lints/src/methods/manual_ok_or.rs | 34 +++++----- clippy_lints/src/methods/option_map_or_none.rs | 16 +---- clippy_lints/src/methods/or_then_unwrap.rs | 5 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 20 +++--- clippy_lints/src/needless_question_mark.rs | 14 +++-- clippy_lints/src/option_if_let_else.rs | 10 +-- clippy_lints/src/partialeq_to_none.rs | 5 +- clippy_lints/src/question_mark.rs | 24 +++++--- clippy_lints/src/unnecessary_wraps.rs | 6 +- clippy_utils/src/lib.rs | 34 ++++++---- 23 files changed, 205 insertions(+), 202 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0800e0644f7..0d6718c168a 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks}; +use clippy_utils::{ + contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks, +}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -76,10 +78,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind - && let ExprKind::Path(ref then_call_qpath) = then_call.kind - && is_lang_ctor(cx, then_call_qpath, OptionSome) - && let ExprKind::Path(ref qpath) = peel_blocks(els).kind - && is_lang_ctor(cx, qpath, OptionNone) + && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) + && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !stmts_contains_early_return(then_block.stmts) { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index 09b2376d5c0..4bb9936e9cd 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -1,7 +1,7 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FIND; use clippy_utils::{ - diagnostics::span_lint_and_then, higher, is_lang_ctor, path_res, peel_blocks_with_stmt, + diagnostics::span_lint_and_then, higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt, source::snippet_with_applicability, ty::implements_trait, }; use if_chain::if_chain; @@ -30,8 +30,8 @@ pub(super) fn check<'tcx>( if let [stmt] = block.stmts; if let StmtKind::Semi(semi) = stmt.kind; if let ExprKind::Ret(Some(ret_value)) = semi.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ctor), .. }, [inner_ret]) = ret_value.kind; - if is_lang_ctor(cx, ctor, LangItem::OptionSome); + if let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind; + if is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome); if path_res(cx, inner_ret) == Res::Local(binding_id); if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr); then { @@ -143,8 +143,7 @@ fn last_stmt_and_ret<'tcx>( if let Some((_, Node::Block(block))) = parent_iter.next(); if let Some((last_stmt, last_ret)) = extract(block); if last_stmt.hir_id == node_hir; - if let ExprKind::Path(path) = &last_ret.kind; - if is_lang_ctor(cx, path, LangItem::OptionNone); + if is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone); if let Some((_, Node::Expr(_block))) = parent_iter.next(); // This includes the function header if let Some((_, func)) = parent_iter.next(); diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 1b36d452647..8c27c09404b 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -3,13 +3,13 @@ use super::MANUAL_FLATTEN; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::visitors::is_local_used; -use clippy_utils::{is_lang_ctor, path_to_local_id, peel_blocks_with_stmt}; +use clippy_utils::{path_to_local_id, peel_blocks_with_stmt}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, DefIdTree}; use rustc_span::source_map::Span; /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the @@ -30,8 +30,10 @@ pub(super) fn check<'tcx>( if path_to_local_id(let_expr, pat_hir_id); // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind; - let some_ctor = is_lang_ctor(cx, qpath, OptionSome); - let ok_ctor = is_lang_ctor(cx, qpath, ResultOk); + if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id); + if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); + let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id); + let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id); if some_ctor || ok_ctor; // Ensure expr in `if let` is not used afterwards if !is_local_used(cx, if_then, pat_hir_id); diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 1c6f0264cb5..153f97e4e66 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{ - get_enclosing_loop_or_multi_call_closure, is_refutable, is_trait_method, match_def_path, paths, - visitors::is_res_used, + get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; +use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; @@ -19,9 +18,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! { if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr); // check for `Some(..)` pattern - if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind; - if let Res::Def(_, pat_did) = pat_path.res; - if match_def_path(cx, pat_did, &paths::OPTION_SOME); + if let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind; + if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome); // check for call to `Iterator::next` if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind; if method_name.ident.name == sym::next; diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 07021f1bcad..fd14d868df3 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::visitors::is_local_used; -use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq}; +use clippy_utils::{ + is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq, +}; use if_chain::if_chain; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; @@ -110,7 +112,7 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { } match arm.pat.kind { PatKind::Binding(..) | PatKind::Wild => true, - PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), _ => false, } } diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index 96b8339550c..76f5e1c941c 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -3,8 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ - can_move_expr_to_closure, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id, peel_blocks, - peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, + can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, + peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, }; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; @@ -251,9 +251,11 @@ fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: Syn match pat.kind { PatKind::Wild => Some(OptionPat::Wild), PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt), - PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None), + PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => { + Some(OptionPat::None) + }, PatKind::TupleStruct(ref qpath, [pattern], _) - if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt => + if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt => { Some(OptionPat::Some { pattern, ref_count }) }, @@ -272,16 +274,14 @@ fn get_some_expr<'tcx>( ) -> Option> { // TODO: Allow more complex expressions. match expr.kind { - ExprKind::Call( - Expr { - kind: ExprKind::Path(ref qpath), - .. - }, - [arg], - ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(SomeExpr { - expr: arg, - needs_unsafe_block, - }), + ExprKind::Call(callee, [arg]) + if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) => + { + Some(SomeExpr { + expr: arg, + needs_unsafe_block, + }) + }, ExprKind::Block( Block { stmts: [], @@ -302,5 +302,5 @@ fn get_some_expr<'tcx>( // Checks for the `None` value. fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) + is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone) } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 2fe7fe98a2e..587c926dc01 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -3,12 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{is_lang_ctor, path_to_local_id, sugg}; +use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::LangItem::{OptionNone, ResultErr}; use rustc_hir::{Arm, Expr, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty::DefIdTree; use rustc_span::sym; use super::MANUAL_UNWRAP_OR; @@ -59,15 +61,19 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&' if arms.iter().all(|arm| arm.guard.is_none()); if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| { match arm.pat.kind { - PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), PatKind::TupleStruct(ref qpath, [pat], _) => - matches!(pat.kind, PatKind::Wild) && is_lang_ctor(cx, qpath, ResultErr), + matches!(pat.kind, PatKind::Wild) + && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr), _ => false, } }); let unwrap_arm = &arms[1 - idx]; if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind; - if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); + if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id); + if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); + if cx.tcx.lang_items().option_some_variant() == Some(variant_id) + || cx.tcx.lang_items().result_ok_variant() == Some(variant_id); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty(); diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 39d30212f36..2818f030b7a 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_lang_ctor, peel_blocks}; +use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath}; use rustc_lint::LateContext; @@ -59,18 +59,20 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: // Checks if arm has the form `None => None` fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { - matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, LangItem::OptionNone)) + matches!( + arm.pat.kind, + PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone) + ) } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if_chain! { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind; - if is_lang_ctor(cx, qpath, LangItem::OptionSome); + if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome); if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind; if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind; - if let ExprKind::Path(ref some_path) = e.kind; - if is_lang_ctor(cx, some_path, LangItem::OptionSome); + if is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome); if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 9cbffbe61f1..c4f6852aedc 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{ - eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_lang_ctor, over, + eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_res_lang_ctor, over, path_res, peel_blocks_with_stmt, }; use rustc_errors::Applicability; @@ -112,10 +112,7 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool let ret = strip_return(else_expr); let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr); if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) { - if let ExprKind::Path(ref qpath) = ret.kind { - return is_lang_ctor(cx, qpath, OptionNone) || eq_expr_value(cx, if_let.let_expr, ret); - } - return false; + return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret); } return eq_expr_value(cx, if_let.let_expr, ret); } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 6d6aa43df2a..81bebff34c8 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -4,10 +4,11 @@ use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; -use clippy_utils::{higher, is_lang_ctor, is_trait_method}; +use clippy_utils::{higher, is_trait_method}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; @@ -87,15 +88,21 @@ fn find_sugg_for_if_let<'tcx>( } }, PatKind::Path(ref path) => { - let method = if is_lang_ctor(cx, path, OptionNone) { - "is_none()" - } else if is_lang_ctor(cx, path, PollPending) { - "is_pending()" + if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id) + && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) + { + let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) { + "is_none()" + } else if cx.tcx.lang_items().poll_pending_variant() == Some(variant_id) { + "is_pending()" + } else { + return; + }; + // `None` and `Pending` don't have an inner type. + (method, cx.tcx.types.unit) } else { return; - }; - // `None` and `Pending` don't have an inner type. - (method, cx.tcx.types.unit) + } }, _ => return, }; diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index a3ec1ff2482..c6cba81d871 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths}; +use clippy_utils::{get_parent_expr, is_res_lang_ctor, match_def_path, path_res, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; @@ -27,8 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine if let ExprKind::Path(ref match_fun_path) = match_fun.kind; if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind; - if let ExprKind::Path(ref err_fun_path) = err_fun.kind; - if is_lang_ctor(cx, err_fun_path, ResultErr); + if is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr); if let Some(return_ty) = find_return_type(cx, &expr.kind); then { let prefix; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index cad3ea2a176..0c4d9f100f7 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_lang_ctor, meets_msrv, msrvs}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; @@ -102,40 +102,38 @@ impl_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - if let ExprKind::Path(ref replacement_qpath) = src.kind { - // Check that second argument is `Option::None` - if is_lang_ctor(cx, replacement_qpath, OptionNone) { - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // replacee's path. - let replaced_path = match dest.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { - if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { - replaced_path - } else { - return; - } - }, - ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, - _ => return, - }; + // Check that second argument is `Option::None` + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // replacee's path. + let replaced_path = match dest.kind { + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { + if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { + replaced_path + } else { + return; + } + }, + ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, + _ => return, + }; - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr_span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!( - "{}.take()", - snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) - ), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr_span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!( + "{}.take()", + snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) + ), + applicability, + ); } } @@ -203,10 +201,8 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< return; } // disable lint for Option since it is covered in another lint - if let ExprKind::Path(q) = &src.kind { - if is_lang_ctor(cx, q, OptionNone) { - return; - } + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + return; } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { span_lint_and_then( diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index cea7b0d82ff..4f73b3ec422 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; +use clippy_utils::{get_expr_use_or_unification_node, is_no_std_crate, is_res_lang_ctor, path_res}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -26,26 +26,11 @@ impl IterType { } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { - let item = match &recv.kind { - ExprKind::Array(v) if v.len() <= 1 => v.first(), - ExprKind::Path(p) => { - if is_lang_ctor(cx, p, OptionNone) { - None - } else { - return; - } - }, - ExprKind::Call(f, some_args) if some_args.len() == 1 => { - if let ExprKind::Path(p) = &f.kind { - if is_lang_ctor(cx, p, OptionSome) { - Some(&some_args[0]) - } else { - return; - } - } else { - return; - } - }, + let item = match recv.kind { + ExprKind::Array([]) => None, + ExprKind::Array([e]) => Some(e), + ExprKind::Path(ref p) if is_res_lang_ctor(cx, cx.qpath_res(p, recv.hir_id), OptionNone) => None, + ExprKind::Call(f, [arg]) if is_res_lang_ctor(cx, path_res(cx, f), OptionSome) => Some(arg), _ => return, }; let iter_type = match method_name { diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index d9fb4382181..5b758f1e654 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Closure, Expr, ExprKind, PatKind}; +use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -22,8 +22,8 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option); - if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind; - if is_lang_ctor(cx, err_path, ResultErr); + if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind; + if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr); if is_ok_wrapping(cx, map_expr); if let Some(recv_snippet) = snippet_opt(cx, recv.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); @@ -46,17 +46,19 @@ pub(super) fn check<'tcx>( } fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { - if let ExprKind::Path(ref qpath) = map_expr.kind { - if is_lang_ctor(cx, qpath, ResultOk) { - return true; - } - } - if_chain! { - if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; - let body = cx.tcx.hir().body(body); - if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, [ok_arg]) = body.value.kind; - if is_lang_ctor(cx, ok_path, ResultOk); - then { path_to_local_id(ok_arg, param_id) } else { false } + match map_expr.kind { + ExprKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, map_expr.hir_id), ResultOk) => true, + ExprKind::Closure(closure) => { + let body = cx.tcx.hir().body(closure.body); + if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind + && let ExprKind::Call(callee, [ok_arg]) = body.value.kind + && is_res_lang_ctor(cx, path_res(cx, callee), ResultOk) + { + path_to_local_id(ok_arg, param_id) + } else { + false + } + }, + _ => false, } } diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 76572425346..3a23ecc50dc 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_def_id}; +use clippy_utils::{is_res_lang_ctor, path_def_id, path_res}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -51,22 +51,12 @@ pub(super) fn check<'tcx>( return; } - let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { - is_lang_ctor(cx, qpath, OptionNone) - } else { - return; - }; - - if !default_arg_is_none { + if !is_res_lang_ctor(cx, path_res(cx, def_arg), OptionNone) { // nothing to lint! return; } - let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { - is_lang_ctor(cx, qpath, OptionSome) - } else { - false - }; + let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome); if is_option { let self_snippet = snippet(cx, recv.span, ".."); diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index be5768c3545..55ba6e262df 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -1,6 +1,6 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{diagnostics::span_lint_and_sugg, is_lang_ctor}; +use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res}; use rustc_errors::Applicability; use rustc_hir::{lang_items::LangItem, Expr, ExprKind}; use rustc_lint::LateContext; @@ -58,8 +58,7 @@ pub(super) fn check<'tcx>( fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option { if let ExprKind::Call(some_expr, [arg]) = expr.kind - && let ExprKind::Path(qpath) = &some_expr.kind - && is_lang_ctor(cx, qpath, item) + && is_res_lang_ctor(cx, path_res(cx, some_expr), item) { Some(arg.span) } else { diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index ee16982d524..50434a5658a 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::{is_lang_ctor, is_trait_method, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -61,15 +61,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< // returns (found_mapping, found_filtering) fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) { - match &expr.kind { + match expr.kind { hir::ExprKind::Call(func, args) => { - if let hir::ExprKind::Path(ref path) = func.kind { - if is_lang_ctor(cx, path, OptionSome) { - if path_to_local_id(&args[0], arg_id) { - return (false, false); - } - return (true, false); + if is_res_lang_ctor(cx, path_res(cx, func), OptionSome) { + if path_to_local_id(&args[0], arg_id) { + return (false, false); } + return (true, false); } (true, true) }, @@ -80,7 +78,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc hir::ExprKind::Match(_, arms, _) => { let mut found_mapping = false; let mut found_filtering = false; - for arm in *arms { + for arm in arms { let (m, f) = check_expression(cx, arg_id, arm.body); found_mapping |= m; found_filtering |= f; @@ -93,7 +91,9 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc let else_check = check_expression(cx, arg_id, else_arm); (if_check.0 | else_check.0, if_check.1 | else_check.1) }, - hir::ExprKind::Path(path) if is_lang_ctor(cx, path, OptionNone) => (false, true), + hir::ExprKind::Path(ref path) if is_res_lang_ctor(cx, cx.qpath_res(path, expr.hir_id), OptionNone) => { + (false, true) + }, _ => (true, true), } } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 59b6492e112..97c8cfbd3eb 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; +use clippy_utils::path_res; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::DefIdTree; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -112,11 +113,12 @@ impl LateLintPass<'_> for NeedlessQuestionMark { fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(path, [arg]) = &expr.kind; - if let ExprKind::Path(ref qpath) = &path.kind; - let sugg_remove = if is_lang_ctor(cx, qpath, OptionSome) { + if let ExprKind::Call(path, [arg]) = expr.kind; + if let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path); + if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); + let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { "Some()" - } else if is_lang_ctor(cx, qpath, ResultOk) { + } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) { "Ok()" } else { return; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 2c1e3b855d5..4eb42da1fed 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::{ - can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks, + can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks, peel_hir_expr_while, CaptureKind, }; use if_chain::if_chain; @@ -174,7 +174,8 @@ fn try_get_option_occurrence<'tcx>( fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { - if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk) { + let res = cx.qpath_res(qpath, pat.hir_id); + if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) { return Some(inner_pat); } } @@ -226,9 +227,10 @@ fn try_convert_match<'tcx>( fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { match arm.pat.kind { - PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), PatKind::TupleStruct(ref qpath, [first_pat], _) => { - is_lang_ctor(cx, qpath, ResultErr) && matches!(first_pat.kind, PatKind::Wild) + is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr) + && matches!(first_pat.kind, PatKind::Wild) }, PatKind::Wild => true, _ => false, diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 000b0ba7a14..6810a243175 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -1,5 +1,5 @@ use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg, + diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg, ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; @@ -54,8 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialeqToNone { // If the expression is a literal `Option::None` let is_none_ctor = |expr: &Expr<'_>| { !expr.span.from_expansion() - && matches!(&peel_hir_expr_refs(expr).0.kind, - ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone)) + && is_res_lang_ctor(cx, path_res(cx, peel_hir_expr_refs(expr).0), LangItem::OptionNone) }; let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 0b3d5d17480..328371fd602 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -3,11 +3,12 @@ use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - eq_expr_value, get_parent_node, in_constant, is_else_clause, is_lang_ctor, path_to_local, path_to_local_id, + eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, }; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -58,7 +59,7 @@ enum IfBlockType<'hir> { /// Contains: let_pat_qpath (Xxx), let_pat_type, let_pat_sym (a), let_expr (b), if_then (c), /// if_else (d) IfLet( - &'hir QPath<'hir>, + Res, Ty<'hir>, Symbol, &'hir Expr<'hir>, @@ -126,7 +127,14 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if ddpos.as_opt_usize().is_none(); if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); - let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); + let if_block = IfBlockType::IfLet( + cx.qpath_res(path1, let_pat.hir_id), + caller_ty, + ident.name, + let_expr, + if_then, + if_else + ); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) || is_early_return(sym::Result, cx, &if_block); if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none(); @@ -165,21 +173,21 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_ _ => false, } }, - IfBlockType::IfLet(qpath, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => { + IfBlockType::IfLet(res, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => { is_type_diagnostic_item(cx, let_expr_ty, smbl) && match smbl { sym::Option => { // We only need to check `if let Some(x) = option` not `if let None = option`, // because the later one will be suggested as `if option.is_none()` thus causing conflict. - is_lang_ctor(cx, qpath, OptionSome) + is_res_lang_ctor(cx, res, OptionSome) && if_else.is_some() && expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, None) }, sym::Result => { - (is_lang_ctor(cx, qpath, ResultOk) + (is_res_lang_ctor(cx, res, ResultOk) && if_else.is_some() && expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym))) - || is_lang_ctor(cx, qpath, ResultErr) + || is_res_lang_ctor(cx, res, ResultErr) && expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym)) }, _ => false, @@ -198,7 +206,7 @@ fn expr_return_none_or_err( match peel_blocks_with_stmt(expr).kind { ExprKind::Ret(Some(ret_expr)) => expr_return_none_or_err(smbl, cx, ret_expr, cond_expr, err_sym), ExprKind::Path(ref qpath) => match smbl { - sym::Option => is_lang_ctor(cx, qpath, OptionNone), + sym::Option => is_res_lang_ctor(cx, cx.qpath_res(qpath, expr.hir_id), OptionNone), sym::Result => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr), _ => false, }, diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 83ef3b0fac8..7211e6864f3 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{contains_return, is_lang_ctor, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -120,9 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if !ret_expr.span.from_expansion(); // Check if a function call. if let ExprKind::Call(func, [arg]) = ret_expr.kind; - // Check if OPTION_SOME or RESULT_OK, depending on return type. - if let ExprKind::Path(qpath) = &func.kind; - if is_lang_ctor(cx, qpath, lang_item); + if is_res_lang_ctor(cx, path_res(cx, func), lang_item); // Make sure the function argument does not contain a return expression. if !contains_return(arg); then { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index d67ceaec035..c7cc5d04c85 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -238,17 +238,27 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { } } -/// Checks if a `QPath` resolves to a constructor of a `LangItem`. +/// Checks if a `Res` refers to a constructor of a `LangItem` /// For example, use this to check whether a function call or a pattern is `Some(..)`. -pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool { - if let QPath::Resolved(_, path) = qpath { - if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res { - if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) { - return cx.tcx.parent(ctor_id) == item_id; - } - } +pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool { + if let Res::Def(DefKind::Ctor(..), id) = res + && let Ok(lang_id) = cx.tcx.lang_items().require(lang_item) + && let Some(id) = cx.tcx.opt_parent(id) + { + id == lang_id + } else { + false + } +} + +pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool { + if let Res::Def(DefKind::Ctor(..), id) = res + && let Some(id) = cx.tcx.opt_parent(id) + { + cx.tcx.is_diagnostic_item(diag_item, id) + } else { + false } - false } pub fn is_unit_expr(expr: &Expr<'_>) -> bool { @@ -738,7 +748,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } }, ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func), - ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone), + ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone), ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])), _ => false, } @@ -1553,7 +1563,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc if_chain! { if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind; if ddpos.as_opt_usize().is_none(); - if is_lang_ctor(cx, path, ResultOk); + if is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; if path_to_local_id(arm.body, hir_id); then { @@ -1565,7 +1575,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind { - is_lang_ctor(cx, path, ResultErr) + is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultErr) } else { false } -- cgit 1.4.1-3-g733a5 From 162aa19793f21c99cf7ec2a8c080ee2f8843f7db Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 11 Nov 2021 14:15:01 -0500 Subject: Fix and improve internal lint checking for `match_type` usages * Check for `const`s and `static`s from external crates * Check for `LangItem`s * Handle inherent functions which have the same name as a field * Also check the following functions: * `match_trait_method` * `match_def_path` * `is_expr_path_def_path` * `is_qpath_def_path` * Handle checking for a constructor to a diagnostic item or `LangItem` --- clippy_lints/src/await_holding_invalid.rs | 8 +- clippy_lints/src/infinite_iter.rs | 15 +- clippy_lints/src/inherent_to_string.rs | 7 +- clippy_lints/src/lib.register_internal.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 4 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/methods/filetype_is_file.rs | 7 +- clippy_lints/src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/manual_str_repeat.rs | 8 +- clippy_lints/src/methods/useless_asref.rs | 5 +- clippy_lints/src/minmax.rs | 4 +- clippy_lints/src/non_octal_unix_permissions.rs | 5 +- clippy_lints/src/slow_vector_initialization.rs | 4 +- .../src/unnecessary_owned_empty_strings.rs | 4 +- clippy_lints/src/unused_io_amount.rs | 7 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_lints/src/utils/internal_lints.rs | 277 ++++++++++++++++----- clippy_utils/src/lib.rs | 47 ++++ clippy_utils/src/paths.rs | 3 - tests/ui-internal/auxiliary/paths.rs | 2 + tests/ui-internal/match_type_on_diag_item.rs | 39 --- tests/ui-internal/match_type_on_diag_item.stderr | 27 -- tests/ui-internal/unnecessary_def_path.fixed | 62 +++++ tests/ui-internal/unnecessary_def_path.rs | 62 +++++ tests/ui-internal/unnecessary_def_path.stderr | 101 ++++++++ 26 files changed, 534 insertions(+), 176 deletions(-) create mode 100644 tests/ui-internal/auxiliary/paths.rs delete mode 100644 tests/ui-internal/match_type_on_diag_item.rs delete mode 100644 tests/ui-internal/match_type_on_diag_item.stderr create mode 100644 tests/ui-internal/unnecessary_def_path.fixed create mode 100644 tests/ui-internal/unnecessary_def_path.rs create mode 100644 tests/ui-internal/unnecessary_def_path.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 1761360fb28..24a3588ecf1 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -6,7 +6,7 @@ use rustc_hir::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::GeneratorInteriorTypeCause; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use crate::utils::conf::DisallowedType; @@ -276,9 +276,9 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedTy } fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { - match_def_path(cx, def_id, &paths::MUTEX_GUARD) - || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD) - || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD) + cx.tcx.is_diagnostic_item(sym::MutexGuard, def_id) + || cx.tcx.is_diagnostic_item(sym::RwLockReadGuard, def_id) + || cx.tcx.is_diagnostic_item(sym::RwLockWriteGuard, def_id) || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD) || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD) || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD) diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 8c2c96fa105..d1d2db27c6f 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::higher; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{higher, match_def_path, path_def_id, paths}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -168,9 +168,16 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), - ExprKind::Call(path, _) => path_def_id(cx, path) - .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT)) - .into(), + ExprKind::Call(path, _) => { + if let ExprKind::Path(ref qpath) = path.kind { + cx.qpath_res(qpath, path.hir_id) + .opt_def_id() + .map_or(false, |id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id)) + .into() + } else { + Finite + } + }, ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(), _ => Finite, } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index d0e603dcf4e..676136df572 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; +use clippy_utils::{return_ty, trait_ref_of_method}; use if_chain::if_chain; use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -118,7 +118,10 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { } fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { - let display_trait_id = get_trait_def_id(cx, &paths::DISPLAY_TRAIT).expect("Failed to get trait ID of `Display`!"); + let display_trait_id = cx + .tcx + .get_diagnostic_item(sym::Display) + .expect("Failed to get trait ID of `Display`!"); // Get the real type of 'self' let self_type = cx.tcx.fn_sig(item.def_id).input(0); diff --git a/clippy_lints/src/lib.register_internal.rs b/clippy_lints/src/lib.register_internal.rs index be63646a12f..71dfdab369b 100644 --- a/clippy_lints/src/lib.register_internal.rs +++ b/clippy_lints/src/lib.register_internal.rs @@ -13,10 +13,10 @@ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE), LintId::of(utils::internal_lints::INVALID_PATHS), LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), - LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), LintId::of(utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE), LintId::of(utils::internal_lints::MISSING_MSRV_ATTR_IMPL), LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), LintId::of(utils::internal_lints::PRODUCE_ICE), + LintId::of(utils::internal_lints::UNNECESSARY_DEF_PATH), LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), ]) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index b8a20de9768..307ec40f40b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -24,8 +24,6 @@ store.register_lints(&[ #[cfg(feature = "internal")] utils::internal_lints::LINT_WITHOUT_LINT_PASS, #[cfg(feature = "internal")] - utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, - #[cfg(feature = "internal")] utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE, #[cfg(feature = "internal")] utils::internal_lints::MISSING_MSRV_ATTR_IMPL, @@ -34,6 +32,8 @@ store.register_lints(&[ #[cfg(feature = "internal")] utils::internal_lints::PRODUCE_ICE, #[cfg(feature = "internal")] + utils::internal_lints::UNNECESSARY_DEF_PATH, + #[cfg(feature = "internal")] utils::internal_lints::UNNECESSARY_SYMBOL_STR, almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 05a9e13c9fb..3b78e492baa 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -535,7 +535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); + store.register_late_pass(|_| Box::new(utils::internal_lints::UnnecessaryDefPath)); store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass)); store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl)); } diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 570fe736818..3181bc86d17 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -92,7 +92,7 @@ fn check_into_iter( && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) - && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER) + && cx.tcx.lang_items().require(hir::LangItem::IntoIterIntoIter).ok() == Some(into_iter_def_id) && match_acceptable_type(cx, left_expr, msrv) && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { suggest(cx, parent_expr, left_expr, target_expr); diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 60f8283c3e0..3fef53739fb 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -1,17 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::match_type; -use clippy_utils::{get_parent_expr, paths}; +use clippy_utils::get_parent_expr; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; +use rustc_span::sym; use super::FILETYPE_IS_FILE; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if !match_type(cx, ty, &paths::FILE_TYPE) { + if !is_type_diagnostic_item(cx, ty, sym::FileType) { return; } diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index e5dc3711b0b..ede3b8bb74e 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -65,7 +65,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } if let ty::Adt(adt, substs) = ty.kind() { - match_def_path(cx, adt.did(), &paths::COW) && substs.type_at(1).is_str() + cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && substs.type_at(1).is_str() } else { false } diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 67e504af161..8b6b8f1bf16 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_path_diagnostic_item; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; -use clippy_utils::{is_expr_path_def_path, paths}; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -38,7 +38,7 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { let ty = cx.typeck_results().expr_ty(e); if is_type_diagnostic_item(cx, ty, sym::String) || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str)) - || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, Ty::is_str)) + || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str)) { Some(RepeatKind::String) } else { @@ -57,7 +57,7 @@ pub(super) fn check( ) { if_chain! { if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; - if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT); + if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat); if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String); if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id); if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 0380a82411a..c1139d84e2f 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; -use clippy_utils::{get_parent_expr, match_trait_method, paths}; +use clippy_utils::{get_parent_expr, is_trait_method}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::USELESS_ASREF; @@ -13,7 +14,7 @@ use super::USELESS_ASREF; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" // check if the call is to the actual `AsRef` or `AsMut` trait - if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) { + if is_trait_method(cx, expr, sym::AsRef) || is_trait_method(cx, expr, sym::AsMut) { // check if the type after `as_ref` or `as_mut` is the same as before let rcv_ty = cx.typeck_results().expr_ty(recvr); let res_ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 4d8579135fc..4f967755bfa 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_trait_method, paths}; +use clippy_utils::is_trait_method; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -83,7 +83,7 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { - if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) { + if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) { if path.ident.name == sym!(max) { fetch_const(cx, Some(receiver), args, MinMax::Max) } else if path.ident.name == sym!(min) { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 25fb4f0f4cf..1a765b14892 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use clippy_utils::ty::match_type; +use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -49,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if_chain! { if (path.ident.name == sym!(mode) && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS) - || match_type(cx, obj_ty, &paths::DIR_BUILDER))) + || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder))) || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS)); if let ExprKind::Lit(_) = param.kind; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 6e5d88e1b59..76039923151 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - get_enclosing_block, is_expr_path_def_path, is_integer_literal, path_to_local, path_to_local_id, paths, SpanlessEq, + get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -254,7 +254,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool { if_chain! { if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; - if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT); + if is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat); if is_integer_literal(repeat_arg, 0); then { true diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 8a4f4c0ad97..016aacbf9da 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -3,7 +3,7 @@ use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { ); } else { if_chain! { - if match_def_path(cx, fun_def_id, &paths::FROM_FROM); + if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(fun_def_id); if let [.., last_arg] = args; if let ExprKind::Lit(spanned) = &last_arg.kind; if let LitKind::Str(symbol, _) = spanned.node; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index b38d71784fc..8bcdff66331 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{is_try, match_trait_method, paths}; +use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -116,13 +117,13 @@ fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Exp match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT) } else { - match_trait_method(cx, call, &paths::IO_READ) + is_trait_method(cx, call, sym::IoRead) }; let write_trait = if is_await { match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT) || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT) } else { - match_trait_method(cx, call, &paths::IO_WRITE) + is_trait_method(cx, call, sym::IoWrite) }; match (read_trait, write_trait, symbol, is_await) { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 50c5a832430..a82643a59f9 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } if_chain! { - if match_def_path(cx, def_id, &paths::FROM_FROM); + if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(def_id); if same_type_and_consts(a, b); then { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index bc3f920a087..6309a04c73d 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -2,11 +2,11 @@ use crate::utils::internal_lints::metadata_collector::is_deprecated_lint; use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::match_type; use clippy_utils::{ - def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, - method_calls, paths, peel_blocks_with_stmt, SpanlessEq, + def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_any_def_paths, + match_def_path, method_calls, paths, peel_blocks_with_stmt, peel_hir_expr_refs, SpanlessEq, }; use if_chain::if_chain; use rustc_ast as ast; @@ -20,21 +20,24 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; use rustc_hir::{ - BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, + BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, TyKind, UnOp, }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; -use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, FloatTy}; +use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc}; +use rustc_middle::ty::{ + self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, AssocKind, DefIdTree, FloatTy, Ty, +}; use rustc_semver::RustcVersion; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, BytePos, Span}; use std::borrow::{Borrow, Cow}; +use std::str; #[cfg(feature = "internal")] pub mod metadata_collector; @@ -226,11 +229,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for calls to `utils::match_type()` on a type diagnostic item - /// and suggests to use `utils::is_type_diagnostic_item()` instead. + /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used. /// /// ### Why is this bad? - /// `utils::is_type_diagnostic_item()` does not require hardcoded paths. + /// The path for an item is subject to change and is less efficient to look up than a + /// diagnostic item or a `LangItem`. /// /// ### Example /// ```rust,ignore @@ -241,9 +244,9 @@ declare_clippy_lint! { /// ```rust,ignore /// utils::is_type_diagnostic_item(cx, ty, sym::Vec) /// ``` - pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + pub UNNECESSARY_DEF_PATH, internal, - "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`" + "using a def path when a diagnostic item or a `LangItem` is available" } declare_clippy_lint! { @@ -537,7 +540,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { } } -fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool { +fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Rptr( _, MutTy { @@ -888,89 +891,225 @@ fn suggest_note( ); } -declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]); +declare_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); -impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { +#[allow(clippy::too_many_lines)] +impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) { + enum Item { + LangItem(Symbol), + DiagnosticItem(Symbol), + } + static PATHS: &[&[&str]] = &[ + &["clippy_utils", "match_def_path"], + &["clippy_utils", "match_trait_method"], + &["clippy_utils", "ty", "match_type"], + &["clippy_utils", "is_expr_path_def_path"], + ]; + + if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { return; } if_chain! { - // Check if this is a call to utils::match_type() - if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; - if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]); + if let ExprKind::Call(func, [cx_arg, def_arg, args@..]) = expr.kind; + if let ExprKind::Path(path) = &func.kind; + if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id(); + if let Some(which_path) = match_any_def_paths(cx, id, PATHS); + let item_arg = if which_path == 4 { &args[1] } else { &args[0] }; // Extract the path to the matched type - if let Some(segments) = path_to_matched_type(cx, ty_path); - let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect(); - if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id(); - // Check if the matched type is a diagnostic item - if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did); + if let Some(segments) = path_to_matched_type(cx, item_arg); + let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); + if let Some(def_id) = def_path_res(cx, &segments[..]).opt_def_id(); then { - // TODO: check paths constants from external crates. - let cx_snippet = snippet(cx, context.span, "_"); - let ty_snippet = snippet(cx, ty.span, "_"); + // def_path_res will match field names before anything else, but for this we want to match + // inherent functions first. + let def_id = if cx.tcx.def_kind(def_id) == DefKind::Field { + let method_name = *segments.last().unwrap(); + cx.tcx.def_key(def_id).parent + .and_then(|parent_idx| + cx.tcx.inherent_impls(DefId { index: parent_idx, krate: def_id.krate }).iter() + .find_map(|impl_id| cx.tcx.associated_items(*impl_id) + .find_by_name_and_kind( + cx.tcx, + Ident::from_str(method_name), + AssocKind::Fn, + *impl_id, + ) + ) + ) + .map_or(def_id, |item| item.def_id) + } else { + def_id + }; - span_lint_and_sugg( + // Check if the target item is a diagnostic item or LangItem. + let (msg, item) = if let Some(item_name) + = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) + { + ( + "use of a def path to a diagnostic item", + Item::DiagnosticItem(*item_name), + ) + } else if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) { + let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"]).def_id(); + let item_name = cx.tcx.adt_def(lang_items).variants().iter().nth(lang_item).unwrap().name; + ( + "use of a def path to a `LangItem`", + Item::LangItem(item_name), + ) + } else { + return; + }; + + let has_ctor = match cx.tcx.def_kind(def_id) { + DefKind::Struct => { + let variant = cx.tcx.adt_def(def_id).non_enum_variant(); + variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + } + DefKind::Variant => { + let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); + variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + } + _ => false, + }; + + let mut app = Applicability::MachineApplicable; + let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); + let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); + let (sugg, with_note) = match (which_path, item) { + // match_def_path + (0, Item::DiagnosticItem(item)) => + (format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), has_ctor), + (0, Item::LangItem(item)) => ( + format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"), + has_ctor + ), + // match_trait_method + (1, Item::DiagnosticItem(item)) => + (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false), + // match_type + (2, Item::DiagnosticItem(item)) => + (format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false), + (2, Item::LangItem(item)) => + (format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), false), + // is_expr_path_def_path + (3, Item::DiagnosticItem(item)) if has_ctor => ( + format!( + "is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})", + ), + false, + ), + (3, Item::LangItem(item)) if has_ctor => ( + format!( + "is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})", + ), + false, + ), + (3, Item::DiagnosticItem(item)) => + (format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false), + (3, Item::LangItem(item)) => ( + format!( + "path_res({cx_snip}, {def_snip}).opt_def_id()\ + .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))", + ), + false, + ), + _ => return, + }; + + span_lint_and_then( cx, - MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + UNNECESSARY_DEF_PATH, expr.span, - "usage of `clippy_utils::ty::match_type()` on a type diagnostic item", - "try", - format!("clippy_utils::ty::is_type_diagnostic_item({cx_snippet}, {ty_snippet}, sym::{item_name})"), - Applicability::MaybeIncorrect, + msg, + |diag| { + diag.span_suggestion(expr.span, "try", sugg, app); + if with_note { + diag.help( + "if this `DefId` came from a constructor expression or pattern then the \ + parent `DefId` should be used instead" + ); + } + }, ); } } } } -fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option> { - use rustc_hir::ItemKind; - - match &expr.kind { - ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr), - ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) { +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option> { + match peel_hir_expr_refs(expr).0.kind { + ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { let parent_id = cx.tcx.hir().get_parent_node(hir_id); - if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) { - if let Some(init) = local.init { - return path_to_matched_type(cx, init); - } + if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) { + path_to_matched_type(cx, init) + } else { + None } }, - Res::Def(DefKind::Const | DefKind::Static(..), def_id) => { - if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) { - if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind { - let body = cx.tcx.hir().body(body_id); - return path_to_matched_type(cx, body.value); - } - } + Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path( + cx, + cx.tcx.eval_static_initializer(def_id).ok()?.inner(), + cx.tcx.type_of(def_id), + ), + Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { + ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => { + read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id)) + }, + _ => None, }, - _ => {}, + _ => None, }, - ExprKind::Array(exprs) => { - let segments: Vec = exprs - .iter() - .filter_map(|expr| { - if let ExprKind::Lit(lit) = &expr.kind { - if let LitKind::Str(sym, _) = lit.node { - return Some(sym); - } + ExprKind::Array(exprs) => exprs + .iter() + .map(|expr| { + if let ExprKind::Lit(lit) = &expr.kind { + if let LitKind::Str(sym, _) = lit.node { + return Some((*sym.as_str()).to_owned()); } + } - None - }) - .collect(); - - if segments.len() == exprs.len() { - return Some(segments); - } - }, - _ => {}, + None + }) + .collect(), + _ => None, } +} - None +fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option> { + let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { + let &alloc = alloc.provenance().values().next()?; + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { + (alloc.inner(), ty) + } else { + return None; + } + } else { + (alloc, ty) + }; + + if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind() + && let ty::Ref(_, ty, Mutability::Not) = *ty.kind() + && ty.is_str() + { + alloc + .provenance() + .values() + .map(|&alloc| { + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { + let alloc = alloc.inner(); + str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) + .ok().map(ToOwned::to_owned) + } else { + None + } + }) + .collect() + } else { + None + } } // This is not a complete resolver for paths. It works on all the paths currently used in the paths diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c7cc5d04c85..8f67fa109fc 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -261,6 +261,46 @@ pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) } } +/// Checks if a `QPath` resolves to a constructor of a diagnostic item. +pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool { + if let QPath::Resolved(_, path) = qpath { + if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res { + return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id)); + } + } + false +} + +/// Checks if the `DefId` matches the given diagnostic item or it's constructor. +pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool { + let did = match cx.tcx.def_kind(did) { + DefKind::Ctor(..) => cx.tcx.parent(did), + // Constructors for types in external crates seem to have `DefKind::Variant` + DefKind::Variant => match cx.tcx.opt_parent(did) { + Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did, + _ => did, + }, + _ => did, + }; + + cx.tcx.is_diagnostic_item(item, did) +} + +/// Checks if the `DefId` matches the given `LangItem` or it's constructor. +pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool { + let did = match cx.tcx.def_kind(did) { + DefKind::Ctor(..) => cx.tcx.parent(did), + // Constructors for types in external crates seem to have `DefKind::Variant` + DefKind::Variant => match cx.tcx.opt_parent(did) { + Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did, + _ => did, + }, + _ => did, + }; + + cx.tcx.lang_items().require(item).map_or(false, |id| id == did) +} + pub fn is_unit_expr(expr: &Expr<'_>) -> bool { matches!( expr.kind, @@ -496,6 +536,13 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { .copied() .find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name) .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)), + DefKind::Struct | DefKind::Union => tcx + .adt_def(def_id) + .non_enum_variant() + .fields + .iter() + .find(|f| f.name.as_str() == name) + .map(|f| Res::Def(DefKind::Field, f.did)), _ => None, } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 07170e2df12..13938645fc3 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -34,7 +34,6 @@ pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "defa pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; /// Preferably use the diagnostic item `sym::deref_method` where possible pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; -pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"]; pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; #[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; @@ -64,8 +63,6 @@ pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; -pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; -pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; diff --git a/tests/ui-internal/auxiliary/paths.rs b/tests/ui-internal/auxiliary/paths.rs new file mode 100644 index 00000000000..52fcaec4df3 --- /dev/null +++ b/tests/ui-internal/auxiliary/paths.rs @@ -0,0 +1,2 @@ +pub static OPTION: [&str; 3] = ["core", "option", "Option"]; +pub const RESULT: &[&str] = &["core", "result", "Result"]; diff --git a/tests/ui-internal/match_type_on_diag_item.rs b/tests/ui-internal/match_type_on_diag_item.rs deleted file mode 100644 index 4b41ff15e80..00000000000 --- a/tests/ui-internal/match_type_on_diag_item.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![deny(clippy::internal)] -#![allow(clippy::missing_clippy_version_attribute)] -#![feature(rustc_private)] - -extern crate clippy_utils; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_middle; - -#[macro_use] -extern crate rustc_session; -use clippy_utils::{paths, ty::match_type}; -use rustc_hir::Expr; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; - -declare_lint! { - pub TEST_LINT, - Warn, - "" -} - -declare_lint_pass!(Pass => [TEST_LINT]); - -static OPTION: [&str; 3] = ["core", "option", "Option"]; - -impl<'tcx> LateLintPass<'tcx> for Pass { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) { - let ty = cx.typeck_results().expr_ty(expr); - - let _ = match_type(cx, ty, &OPTION); - let _ = match_type(cx, ty, &["core", "result", "Result"]); - - let rc_path = &["alloc", "rc", "Rc"]; - let _ = clippy_utils::ty::match_type(cx, ty, rc_path); - } -} - -fn main() {} diff --git a/tests/ui-internal/match_type_on_diag_item.stderr b/tests/ui-internal/match_type_on_diag_item.stderr deleted file mode 100644 index e3cb6b6c22e..00000000000 --- a/tests/ui-internal/match_type_on_diag_item.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:31:17 - | -LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Option)` - | -note: the lint level is defined here - --> $DIR/match_type_on_diag_item.rs:1:9 - | -LL | #![deny(clippy::internal)] - | ^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` - -error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:32:17 - | -LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Result)` - -error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:35:17 - | -LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)` - -error: aborting due to 3 previous errors - diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed new file mode 100644 index 00000000000..4c050332f2c --- /dev/null +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -0,0 +1,62 @@ +// run-rustfix +// aux-build:paths.rs +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate clippy_utils; +extern crate paths; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +#[allow(unused)] +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; +#[allow(unused)] +use clippy_utils::{ + is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + match_def_path, match_trait_method, path_res, +}; + +#[allow(unused)] +use rustc_hir::LangItem; +#[allow(unused)] +use rustc_span::sym; + +use rustc_hir::def_id::DefId; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; + +#[allow(unused)] +static OPTION: [&str; 3] = ["core", "option", "Option"]; +#[allow(unused)] +const RESULT: &[&str] = &["core", "result", "Result"]; + +fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) { + let _ = is_type_diagnostic_item(cx, ty, sym::Option); + let _ = is_type_diagnostic_item(cx, ty, sym::Result); + let _ = is_type_diagnostic_item(cx, ty, sym::Result); + + #[allow(unused)] + let rc_path = &["alloc", "rc", "Rc"]; + let _ = is_type_diagnostic_item(cx, ty, sym::Rc); + + let _ = is_type_diagnostic_item(cx, ty, sym::Option); + let _ = is_type_diagnostic_item(cx, ty, sym::Result); + + let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox); + let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit); + + let _ = cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did); + let _ = cx.tcx.is_diagnostic_item(sym::Option, did); + let _ = cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did); + + let _ = is_trait_method(cx, expr, sym::AsRef); + + let _ = is_path_diagnostic_item(cx, expr, sym::Option); + let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id)); + let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome); +} + +fn main() {} diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs new file mode 100644 index 00000000000..6506f1f164a --- /dev/null +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -0,0 +1,62 @@ +// run-rustfix +// aux-build:paths.rs +#![deny(clippy::internal)] +#![feature(rustc_private)] + +extern crate clippy_utils; +extern crate paths; +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +#[allow(unused)] +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; +#[allow(unused)] +use clippy_utils::{ + is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + match_def_path, match_trait_method, path_res, +}; + +#[allow(unused)] +use rustc_hir::LangItem; +#[allow(unused)] +use rustc_span::sym; + +use rustc_hir::def_id::DefId; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; + +#[allow(unused)] +static OPTION: [&str; 3] = ["core", "option", "Option"]; +#[allow(unused)] +const RESULT: &[&str] = &["core", "result", "Result"]; + +fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) { + let _ = match_type(cx, ty, &OPTION); + let _ = match_type(cx, ty, RESULT); + let _ = match_type(cx, ty, &["core", "result", "Result"]); + + #[allow(unused)] + let rc_path = &["alloc", "rc", "Rc"]; + let _ = clippy_utils::ty::match_type(cx, ty, rc_path); + + let _ = match_type(cx, ty, &paths::OPTION); + let _ = match_type(cx, ty, paths::RESULT); + + let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); + let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); + + let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); + let _ = match_def_path(cx, did, &["core", "option", "Option"]); + let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); + + let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); + + let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); + let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); + let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); +} + +fn main() {} diff --git a/tests/ui-internal/unnecessary_def_path.stderr b/tests/ui-internal/unnecessary_def_path.stderr new file mode 100644 index 00000000000..a99a8f71fa6 --- /dev/null +++ b/tests/ui-internal/unnecessary_def_path.stderr @@ -0,0 +1,101 @@ +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:37:13 + | +LL | let _ = match_type(cx, ty, &OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` + | +note: the lint level is defined here + --> $DIR/unnecessary_def_path.rs:3:9 + | +LL | #![deny(clippy::internal)] + | ^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:38:13 + | +LL | let _ = match_type(cx, ty, RESULT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:39:13 + | +LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:43:13 + | +LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:45:13 + | +LL | let _ = match_type(cx, ty, &paths::OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:46:13 + | +LL | let _ = match_type(cx, ty, paths::RESULT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:48:13 + | +LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:49:13 + | +LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:51:13 + | +LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:52:13 + | +LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:53:13 + | +LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did)` + | + = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:55:13 + | +LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)` + +error: use of a def path to a diagnostic item + --> $DIR/unnecessary_def_path.rs:57:13 + | +LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:58:13 + | +LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id))` + +error: use of a def path to a `LangItem` + --> $DIR/unnecessary_def_path.rs:59:13 + | +LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)` + +error: aborting due to 15 previous errors + -- cgit 1.4.1-3-g733a5 From 649d443646e8ca6efad73643dcc11b488ae60a79 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 28 Apr 2022 13:29:44 -0400 Subject: Replace `expr_visitor` with `for_each_expr` --- clippy_lints/src/implicit_return.rs | 12 +-- clippy_lints/src/methods/str_splitn.rs | 20 ++-- clippy_lints/src/needless_late_init.rs | 34 +++---- clippy_lints/src/panic_in_result_fn.rs | 19 ++-- clippy_lints/src/read_zero_byte_vec.rs | 40 ++++---- clippy_utils/src/lib.rs | 19 ++-- clippy_utils/src/macros.rs | 79 +++++++--------- clippy_utils/src/ptr.rs | 37 ++++---- clippy_utils/src/usage.rs | 49 ++++------ clippy_utils/src/visitors.rs | 164 +++++++++++++++------------------ 10 files changed, 206 insertions(+), 267 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index cfc988da233..946d04eff6f 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -2,10 +2,11 @@ use clippy_utils::{ diagnostics::span_lint_hir_and_then, get_async_fn_body, is_async_fn, source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}, - visitors::expr_visitor_no_bodies, + visitors::for_each_expr, }; +use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::intravisit::{FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -152,7 +153,7 @@ fn lint_implicit_returns( ExprKind::Loop(block, ..) => { let mut add_return = false; - expr_visitor_no_bodies(|e| { + let _: Option = for_each_expr(block, |e| { if let ExprKind::Break(dest, sub_expr) = e.kind { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && e.span.ctxt() == ctxt { @@ -167,9 +168,8 @@ fn lint_implicit_returns( } } } - true - }) - .visit_block(block); + ControlFlow::Continue(()) + }); if add_return { #[expect(clippy::option_if_let_else)] if let Some(span) = call_site_span { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 9ca4d65550d..ae3594bd36c 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -2,11 +2,11 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::expr_visitor; +use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::Visitor; use rustc_hir::{ BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, }; @@ -211,7 +211,7 @@ fn indirect_usage<'tcx>( binding: HirId, ctxt: SyntaxContext, ) -> Option> { - if let StmtKind::Local(Local { + if let StmtKind::Local(&Local { pat: Pat { kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), .. @@ -222,14 +222,12 @@ fn indirect_usage<'tcx>( }) = stmt.kind { let mut path_to_binding = None; - expr_visitor(cx, |expr| { - if path_to_local_id(expr, binding) { - path_to_binding = Some(expr); + let _: Option = for_each_expr_with_closures(cx, init_expr, |e| { + if path_to_local_id(e, binding) { + path_to_binding = Some(e); } - - path_to_binding.is_none() - }) - .visit_expr(init_expr); + ControlFlow::Continue(Descend::from(path_to_binding.is_none())) + }); let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id); let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?; @@ -250,7 +248,7 @@ fn indirect_usage<'tcx>( .. } = iter_usage { - if parent_id == *local_hir_id { + if parent_id == local_hir_id { return Some(IndirectUsage { name: ident.name, span: stmt.span, diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index cbad53f4450..9d26e590086 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; use clippy_utils::source::snippet_opt; use clippy_utils::ty::needs_ordered_drop; -use clippy_utils::visitors::{expr_visitor, expr_visitor_no_bodies, is_local_used}; +use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used}; +use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::intravisit::Visitor; use rustc_hir::{ BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, @@ -64,31 +64,25 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - let mut seen = false; - expr_visitor(cx, |expr| { - if let ExprKind::Assign(..) = expr.kind { - seen = true; + for_each_expr_with_closures(cx, stmt, |e| { + if matches!(e.kind, ExprKind::Assign(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - - !seen }) - .visit_stmt(stmt); - - seen + .is_some() } fn contains_let(cond: &Expr<'_>) -> bool { - let mut seen = false; - expr_visitor_no_bodies(|expr| { - if let ExprKind::Let(_) = expr.kind { - seen = true; + for_each_expr(cond, |e| { + if matches!(e.kind, ExprKind::Let(_)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - - !seen }) - .visit_expr(cond); - - seen + .is_some() } fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 4aa0d9227ab..efec12489a9 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -2,9 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::expr_visitor_no_bodies; +use clippy_utils::visitors::{for_each_expr, Descend}; +use core::ops::ControlFlow; use rustc_hir as hir; -use rustc_hir::intravisit::{FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; @@ -58,18 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - expr_visitor_no_bodies(|expr| { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true }; + let _: Option = for_each_expr(body.value, |e| { + let Some(macro_call) = root_macro_call_first_node(cx, e) else { + return ControlFlow::Continue(Descend::Yes); + }; if matches!( cx.tcx.item_name(macro_call.def_id).as_str(), "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne" ) { panics.push(macro_call.span); - return false; + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Continue(Descend::Yes) } - true - }) - .visit_expr(body.value); + }); if !panics.is_empty() { span_lint_and_then( cx, diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index ae80b6f1269..fa107858863 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -2,9 +2,10 @@ use clippy_utils::{ diagnostics::{span_lint, span_lint_and_sugg}, higher::{get_vec_init_kind, VecInitKind}, source::snippet, - visitors::expr_visitor_no_bodies, + visitors::for_each_expr, }; -use hir::{intravisit::Visitor, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; +use core::ops::ControlFlow; +use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -58,10 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { && let PatKind::Binding(_, _, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) { - // finds use of `_.read(&mut v)` - let mut read_found = false; - let mut visitor = expr_visitor_no_bodies(|expr| { - if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind + let visitor = |expr: &Expr<'_>| { + if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind && let PathSegment { ident: read_or_read_exact, .. } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind @@ -69,27 +68,22 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { && let [inner_seg] = inner_path.segments && ident.name == inner_seg.ident.name { - read_found = true; + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !read_found - }); + }; - let next_stmt_span; - if idx == block.stmts.len() - 1 { + let (read_found, next_stmt_span) = + if let Some(next_stmt) = block.stmts.get(idx + 1) { + // case { .. stmt; stmt; .. } + (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) + } else if let Some(e) = block.expr { // case { .. stmt; expr } - if let Some(e) = block.expr { - visitor.visit_expr(e); - next_stmt_span = e.span; - } else { - return; - } + (for_each_expr(e, visitor).is_some(), e.span) } else { - // case { .. stmt; stmt; .. } - let next_stmt = &block.stmts[idx + 1]; - visitor.visit_stmt(next_stmt); - next_stmt_span = next_stmt.span; - } - drop(visitor); + return + }; if read_found && !next_stmt_span.from_expansion() { let applicability = Applicability::MaybeIncorrect; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8f67fa109fc..3caa6380e09 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3,6 +3,7 @@ #![feature(control_flow_enum)] #![feature(let_chains)] #![feature(lint_reasons)] +#![feature(never_type)] #![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] @@ -65,6 +66,7 @@ pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; +use core::ops::ControlFlow; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use std::sync::OnceLock; @@ -113,7 +115,7 @@ use rustc_target::abi::Integer; use crate::consts::{constant, Constant}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; -use crate::visitors::expr_visitor_no_bodies; +use crate::visitors::for_each_expr; pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { if let Ok(version) = RustcVersion::parse(msrv) { @@ -1193,17 +1195,14 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { /// Returns `true` if `expr` contains a return expression pub fn contains_return(expr: &hir::Expr<'_>) -> bool { - let mut found = false; - expr_visitor_no_bodies(|expr| { - if !found { - if let hir::ExprKind::Ret(..) = &expr.kind { - found = true; - } + for_each_expr(expr, |e| { + if matches!(e.kind, hir::ExprKind::Ret(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !found }) - .visit_expr(expr); - found + .is_some() } /// Extends the span to the beginning of the spans line, incl. whitespaces. diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 079c8f50f12..c0b87cd175e 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -2,7 +2,7 @@ use crate::is_path_diagnostic_item; use crate::source::snippet_opt; -use crate::visitors::expr_visitor_no_bodies; +use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; use itertools::{izip, Either, Itertools}; @@ -270,20 +270,19 @@ fn find_assert_args_inner<'a, const N: usize>( }; let mut args = ArrayVec::new(); let mut panic_expn = None; - expr_visitor_no_bodies(|e| { + let _: Option = for_each_expr(expr, |e| { if args.is_full() { if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() { panic_expn = PanicExpn::parse(cx, e); } - panic_expn.is_none() + ControlFlow::Continue(Descend::from(panic_expn.is_none())) } else if is_assert_arg(cx, e, expn) { args.push(e); - false + ControlFlow::Continue(Descend::No) } else { - true + ControlFlow::Continue(Descend::Yes) } - }) - .visit_expr(expr); + }); let args = args.into_inner().ok()?; // if no `panic!(..)` is found, use `PanicExpn::Empty` // to indicate that the default assertion message is used @@ -297,22 +296,19 @@ fn find_assert_within_debug_assert<'a>( expn: ExpnId, assert_name: Symbol, ) -> Option<(&'a Expr<'a>, ExpnId)> { - let mut found = None; - expr_visitor_no_bodies(|e| { - if found.is_some() || !e.span.from_expansion() { - return false; + for_each_expr(expr, |e| { + if !e.span.from_expansion() { + return ControlFlow::Continue(Descend::No); } let e_expn = e.span.ctxt().outer_expn(); if e_expn == expn { - return true; - } - if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) { - found = Some((e, e_expn)); + ControlFlow::Continue(Descend::Yes) + } else if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) { + ControlFlow::Break((e, e_expn)) + } else { + ControlFlow::Continue(Descend::No) } - false }) - .visit_expr(expr); - found } fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> bool { @@ -396,16 +392,14 @@ impl FormatString { }); let mut parts = Vec::new(); - expr_visitor_no_bodies(|expr| { - if let ExprKind::Lit(lit) = &expr.kind { - if let LitKind::Str(symbol, _) = lit.node { - parts.push(symbol); - } + let _: Option = for_each_expr(pieces, |expr| { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(symbol, _) = lit.node + { + parts.push(symbol); } - - true - }) - .visit_expr(pieces); + ControlFlow::Continue(()) + }); Some(Self { span, @@ -431,7 +425,7 @@ impl<'tcx> FormatArgsValues<'tcx> { fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { let mut pos_to_value_index = Vec::new(); let mut value_args = Vec::new(); - expr_visitor_no_bodies(|expr| { + let _: Option = for_each_expr(args, |expr| { if expr.span.ctxt() == args.span.ctxt() { // ArgumentV1::new_() // ArgumentV1::from_usize() @@ -453,16 +447,13 @@ impl<'tcx> FormatArgsValues<'tcx> { pos_to_value_index.push(val_idx); } - - true + ControlFlow::Continue(Descend::Yes) } else { // assume that any expr with a differing span is a value value_args.push(expr); - - false + ControlFlow::Continue(Descend::No) } - }) - .visit_expr(args); + }); Self { value_args, @@ -866,22 +857,18 @@ impl<'tcx> FormatArgsExpn<'tcx> { } pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { - let mut format_args = None; - expr_visitor_no_bodies(|e| { - if format_args.is_some() { - return false; - } + for_each_expr(expr, |e| { let e_ctxt = e.span.ctxt(); if e_ctxt == expr.span.ctxt() { - return true; - } - if e_ctxt.outer_expn().is_descendant_of(expn_id) { - format_args = FormatArgsExpn::parse(cx, e); + ControlFlow::Continue(Descend::Yes) + } else if e_ctxt.outer_expn().is_descendant_of(expn_id) + && let Some(args) = FormatArgsExpn::parse(cx, e) + { + ControlFlow::Break(args) + } else { + ControlFlow::Continue(Descend::No) } - false }) - .visit_expr(expr); - format_args } /// Source callsite span of all inputs diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 0226f74906b..88837d8a143 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,7 +1,7 @@ use crate::source::snippet; -use crate::visitors::expr_visitor_no_bodies; +use crate::visitors::{for_each_expr, Descend}; use crate::{path_to_local_id, strip_pat_refs}; -use rustc_hir::intravisit::Visitor; +use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -30,28 +30,23 @@ fn extract_clone_suggestions<'tcx>( replace: &[(&'static str, &'static str)], body: &'tcx Body<'_>, ) -> Option)>> { - let mut abort = false; let mut spans = Vec::new(); - expr_visitor_no_bodies(|expr| { - if abort { - return false; - } - if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind { - if path_to_local_id(recv, id) { - if seg.ident.name.as_str() == "capacity" { - abort = true; - return false; - } - for &(fn_name, suffix) in replace { - if seg.ident.name.as_str() == fn_name { - spans.push((expr.span, snippet(cx, recv.span, "_") + suffix)); - return false; - } + for_each_expr(body, |e| { + if let ExprKind::MethodCall(seg, recv, [], _) = e.kind + && path_to_local_id(recv, id) + { + if seg.ident.as_str() == "capacity" { + return ControlFlow::Break(()); + } + for &(fn_name, suffix) in replace { + if seg.ident.as_str() == fn_name { + spans.push((e.span, snippet(cx, recv.span, "_") + suffix)); + return ControlFlow::Continue(Descend::No); } } } - !abort + ControlFlow::Continue(Descend::Yes) }) - .visit_body(body); - if abort { None } else { Some(spans) } + .is_none() + .then_some(spans) } diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 3221b82aed4..b5ec3fef3e0 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,5 +1,6 @@ use crate as utils; -use crate::visitors::{expr_visitor, expr_visitor_no_bodies}; +use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend}; +use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirIdSet; @@ -148,28 +149,17 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { } pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { - let mut seen_return_break_continue = false; - expr_visitor_no_bodies(|ex| { - if seen_return_break_continue { - return false; - } - match &ex.kind { - ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => { - seen_return_break_continue = true; - }, + for_each_expr(expression, |e| { + match e.kind { + ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), // Something special could be done here to handle while or for loop // desugaring, as this will detect a break if there's a while loop // or a for loop inside the expression. - _ => { - if ex.span.from_expansion() { - seen_return_break_continue = true; - } - }, + _ if e.span.from_expansion() => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } - !seen_return_break_continue }) - .visit_expr(expression); - seen_return_break_continue + .is_some() } pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool { @@ -200,23 +190,16 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr return true; } - let mut used_after_expr = false; let mut past_expr = false; - expr_visitor(cx, |expr| { - if used_after_expr { - return false; - } - - if expr.hir_id == after.hir_id { + for_each_expr_with_closures(cx, block, |e| { + if e.hir_id == after.hir_id { past_expr = true; - return false; - } - - if past_expr && utils::path_to_local_id(expr, local_id) { - used_after_expr = true; + ControlFlow::Continue(Descend::No) + } else if past_expr && utils::path_to_local_id(e, local_id) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::Yes) } - !used_after_expr }) - .visit_block(block); - used_after_expr + .is_some() } diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 232d571902b..d4294f18fd5 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -5,14 +5,13 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; use rustc_hir::{ - Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath, Stmt, UnOp, - UnsafeSource, Unsafety, + AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath, + Stmt, UnOp, UnsafeSource, Unsafety, }; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, Ty, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults}; use rustc_span::Span; mod internal { @@ -48,6 +47,26 @@ impl Continue for Descend { } } +/// A type which can be visited. +pub trait Visitable<'tcx> { + /// Calls the corresponding `visit_*` function on the visitor. + fn visit>(self, visitor: &mut V); +} +macro_rules! visitable_ref { + ($t:ident, $f:ident) => { + impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { + fn visit>(self, visitor: &mut V) { + visitor.$f(self); + } + } + }; +} +visitable_ref!(Arm, visit_arm); +visitable_ref!(Block, visit_block); +visitable_ref!(Body, visit_body); +visitable_ref!(Expr, visit_expr); +visitable_ref!(Stmt, visit_stmt); + /// Calls the given function once for each expression contained. This does not enter any bodies or /// nested items. pub fn for_each_expr<'tcx, B, C: Continue>( @@ -82,57 +101,63 @@ pub fn for_each_expr<'tcx, B, C: Continue>( v.res } -/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested -/// bodies (i.e. closures) are visited. -/// If the callback returns `true`, the expr just provided to the callback is walked. -#[must_use] -pub fn expr_visitor<'tcx>(cx: &LateContext<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> { - struct V<'tcx, F> { - hir: Map<'tcx>, +/// Calls the given function once for each expression contained. This will enter bodies, but not +/// nested items. +pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( + cx: &LateContext<'tcx>, + node: impl Visitable<'tcx>, + f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, +) -> Option { + struct V<'tcx, B, F> { + tcx: TyCtxt<'tcx>, f: F, + res: Option, } - impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<'tcx, F> { + impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V<'tcx, B, F> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { - self.hir + self.tcx.hir() } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if (self.f)(expr) { - walk_expr(self, expr); + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + if self.res.is_some() { + return; } - } - } - V { hir: cx.tcx.hir(), f } -} - -/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested -/// bodies (i.e. closures) are not visited. -/// If the callback returns `true`, the expr just provided to the callback is walked. -#[must_use] -pub fn expr_visitor_no_bodies<'tcx>(f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> { - struct V(F); - impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if (self.0)(e) { - walk_expr(self, e); + match (self.f)(e) { + ControlFlow::Continue(c) if c.descend() => walk_expr(self, e), + ControlFlow::Break(b) => self.res = Some(b), + ControlFlow::Continue(_) => (), } } + + // Only walk closures + fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} + // Avoid unnecessary `walk_*` calls. + fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {} + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + // Avoid monomorphising all `visit_*` functions. + fn visit_nested_item(&mut self, _: ItemId) {} } - V(f) + let mut v = V { + tcx: cx.tcx, + f, + res: None, + }; + node.visit(&mut v); + v.res } /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &hir::Expr<'_>) -> bool { - let mut found = false; - expr_visitor_no_bodies(|e| { - if !found { - found = matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)); + for_each_expr(expr, |e| { + if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !found }) - .visit_expr(expr); - found + .is_some() } pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool @@ -228,68 +253,29 @@ where } } -/// A type which can be visited. -pub trait Visitable<'tcx> { - /// Calls the corresponding `visit_*` function on the visitor. - fn visit>(self, visitor: &mut V); -} -macro_rules! visitable_ref { - ($t:ident, $f:ident) => { - impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { - fn visit>(self, visitor: &mut V) { - visitor.$f(self); - } - } - }; -} -visitable_ref!(Arm, visit_arm); -visitable_ref!(Block, visit_block); -visitable_ref!(Body, visit_body); -visitable_ref!(Expr, visit_expr); -visitable_ref!(Stmt, visit_stmt); - -// impl<'tcx, I: IntoIterator> Visitable<'tcx> for I -// where -// I::Item: Visitable<'tcx>, -// { -// fn visit>(self, visitor: &mut V) { -// for x in self { -// x.visit(visitor); -// } -// } -// } - /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { - let mut found = false; - expr_visitor(cx, |e| { - if found { - return false; - } - + for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| { if let ExprKind::Path(p) = &e.kind { if cx.qpath_res(p, e.hir_id) == res { - found = true; + return ControlFlow::Break(()); } } - !found + ControlFlow::Continue(()) }) - .visit_expr(cx.tcx.hir().body(body).value); - found + .is_some() } /// Checks if the given local is used. pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { - let mut is_used = false; - let mut visitor = expr_visitor(cx, |expr| { - if !is_used { - is_used = path_to_local_id(expr, id); + for_each_expr_with_closures(cx, visitable, |e| { + if path_to_local_id(e, id) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) } - !is_used - }); - visitable.visit(&mut visitor); - drop(visitor); - is_used + }) + .is_some() } /// Checks if the given expression is a constant. -- cgit 1.4.1-3-g733a5 From 38236a713512d0a70d1f03e995201d9bac63c882 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 29 Apr 2022 00:09:55 -0400 Subject: Use `for_each_expr` in place of some visitors --- clippy_lints/src/blocks_in_if_conditions.rs | 68 +++++++--------- clippy_lints/src/cognitive_complexity.rs | 63 +++++++-------- clippy_lints/src/functions/must_use.rs | 77 ++++++++---------- .../src/functions/not_unsafe_ptr_arg_deref.rs | 91 ++++++++-------------- clippy_lints/src/methods/unnecessary_filter_map.rs | 51 ++++-------- clippy_lints/src/operators/assign_op_pattern.rs | 39 ++++------ clippy_lints/src/returns.rs | 39 ++++------ clippy_lints/src/suspicious_trait_impl.rs | 33 ++++---- clippy_lints/src/unwrap_in_result.rs | 72 +++++++---------- 9 files changed, 205 insertions(+), 328 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 4df4d6ddf41..569bf27c3e7 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -3,10 +3,11 @@ use clippy_utils::get_parent_expr; use clippy_utils::higher; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::{for_each_expr, Descend}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BlockCheckMode, Closure, Expr, ExprKind}; +use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -44,39 +45,6 @@ declare_clippy_lint! { declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]); -struct ExVisitor<'a, 'tcx> { - found_block: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let ExprKind::Closure(&Closure { body, .. }) = expr.kind { - // do not lint if the closure is called using an iterator (see #1141) - if_chain! { - if let Some(parent) = get_parent_expr(self.cx, expr); - if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind; - let caller = self.cx.typeck_results().expr_ty(self_arg); - if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(self.cx, caller, iter_id, &[]); - then { - return; - } - } - - let body = self.cx.tcx.hir().body(body); - let ex = &body.value; - if let ExprKind::Block(block, _) = ex.kind { - if !body.value.span.from_expansion() && !block.stmts.is_empty() { - self.found_block = Some(ex); - return; - } - } - } - walk_expr(self, expr); - } -} - const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition"; const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \ instead, move the block or closure higher and bind it with a `let`"; @@ -144,11 +112,31 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { } } } else { - let mut visitor = ExVisitor { found_block: None, cx }; - walk_expr(&mut visitor, cond); - if let Some(block) = visitor.found_block { - span_lint(cx, BLOCKS_IN_IF_CONDITIONS, block.span, COMPLEX_BLOCK_MESSAGE); - } + let _: Option = for_each_expr(cond, |e| { + if let ExprKind::Closure(closure) = e.kind { + // do not lint if the closure is called using an iterator (see #1141) + if_chain! { + if let Some(parent) = get_parent_expr(cx, e); + if let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind; + let caller = cx.typeck_results().expr_ty(self_arg); + if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + if implements_trait(cx, caller, iter_id, &[]); + then { + return ControlFlow::Continue(Descend::No); + } + } + + let body = cx.tcx.hir().body(closure.body); + let ex = &body.value; + if let ExprKind::Block(block, _) = ex.kind { + if !body.value.span.from_expansion() && !block.stmts.is_empty() { + span_lint(cx, BLOCKS_IN_IF_CONDITIONS, ex.span, COMPLEX_BLOCK_MESSAGE); + return ControlFlow::Continue(Descend::No); + } + } + } + ControlFlow::Continue(Descend::Yes) + }); } } } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index fed04ae7f3d..77af3b53d63 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,10 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; use clippy_utils::LimitStack; +use core::ops::ControlFlow; use rustc_ast::ast::Attribute; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, ExprKind, FnDecl, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -61,11 +63,27 @@ impl CognitiveComplexity { return; } - let expr = &body.value; + let expr = body.value; + + let mut cc = 1u64; + let mut returns = 0u64; + let _: Option = for_each_expr(expr, |e| { + match e.kind { + ExprKind::If(_, _, _) => { + cc += 1; + }, + ExprKind::Match(_, arms, _) => { + if arms.len() > 1 { + cc += 1; + } + cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64; + }, + ExprKind::Ret(_) => returns += 1, + _ => {}, + } + ControlFlow::Continue(()) + }); - let mut helper = CcHelper { cc: 1, returns: 0 }; - helper.visit_expr(expr); - let CcHelper { cc, returns } = helper; let ret_ty = cx.typeck_results().node_type(expr.hir_id); let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) { returns @@ -74,13 +92,12 @@ impl CognitiveComplexity { (returns / 2) }; - let mut rust_cc = cc; // prevent degenerate cases where unreachable code contains `return` statements - if rust_cc >= ret_adjust { - rust_cc -= ret_adjust; + if cc >= ret_adjust { + cc -= ret_adjust; } - if rust_cc > self.limit.limit() { + if cc > self.limit.limit() { let fn_span = match kind { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { @@ -107,7 +124,7 @@ impl CognitiveComplexity { COGNITIVE_COMPLEXITY, fn_span, &format!( - "the function has a cognitive complexity of ({rust_cc}/{})", + "the function has a cognitive complexity of ({cc}/{})", self.limit.limit() ), None, @@ -140,27 +157,3 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity"); } } - -struct CcHelper { - cc: u64, - returns: u64, -} - -impl<'tcx> Visitor<'tcx> for CcHelper { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - walk_expr(self, e); - match e.kind { - ExprKind::If(_, _, _) => { - self.cc += 1; - }, - ExprKind::Match(_, arms, _) => { - if arms.len() > 1 { - self.cc += 1; - } - self.cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64; - }, - ExprKind::Ret(_) => self.returns += 1, - _ => {}, - } - } -} diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 977c8ee594f..d263804f32c 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::def_id::{DefIdSet, LocalDefId}; -use rustc_hir::{self as hir, def::Res, intravisit, QPath}; +use rustc_hir::{self as hir, def::Res, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::{ lint::in_external_macro, @@ -13,8 +13,11 @@ use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{match_def_path, return_ty, trait_ref_of_method}; +use core::ops::ControlFlow; + use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { @@ -200,79 +203,65 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m } } -struct StaticMutVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - mutates_static: bool, +fn is_mutated_static(e: &hir::Expr<'_>) -> bool { + use hir::ExprKind::{Field, Index, Path}; + + match e.kind { + Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), + Path(_) => true, + Field(inner, _) | Index(inner, _) => is_mutated_static(inner), + _ => false, + } } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { +fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { + for_each_expr(body.value, |e| { use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; - if self.mutates_static { - return; - } - match expr.kind { + match e.kind { Call(_, args) => { let mut tys = DefIdSet::default(); for arg in args { - if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) && is_mutable_ty( - self.cx, - self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), + cx, + cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), arg.span, &mut tys, ) && is_mutated_static(arg) { - self.mutates_static = true; - return; + return ControlFlow::Break(()); } tys.clear(); } + ControlFlow::Continue(()) }, MethodCall(_, receiver, args, _) => { let mut tys = DefIdSet::default(); for arg in std::iter::once(receiver).chain(args.iter()) { - if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) && is_mutable_ty( - self.cx, - self.cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), + cx, + cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), arg.span, &mut tys, ) && is_mutated_static(arg) { - self.mutates_static = true; - return; + return ControlFlow::Break(()); } tys.clear(); } + ControlFlow::Continue(()) }, - Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { - self.mutates_static |= is_mutated_static(target); + Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) + if is_mutated_static(target) => + { + ControlFlow::Break(()) }, - _ => {}, + _ => ControlFlow::Continue(()), } - } -} - -fn is_mutated_static(e: &hir::Expr<'_>) -> bool { - use hir::ExprKind::{Field, Index, Path}; - - match e.kind { - Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), - Path(_) => true, - Field(inner, _) | Index(inner, _) => is_mutated_static(inner), - _ => false, - } -} - -fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { - let mut v = StaticMutVisitor { - cx, - mutates_static: false, - }; - intravisit::walk_expr(&mut v, body.value); - v.mutates_static + }) + .is_some() } diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 0b50431fbaa..b7595d101e0 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -5,8 +5,11 @@ use rustc_span::def_id::LocalDefId; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::type_is_unsafe_function; +use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{iter_input_pats, path_to_local}; +use core::ops::ControlFlow; + use super::NOT_UNSAFE_PTR_ARG_DEREF; pub(super) fn check_fn<'tcx>( @@ -39,21 +42,34 @@ fn check_raw_ptr<'tcx>( body: &'tcx hir::Body<'tcx>, def_id: LocalDefId, ) { - let expr = &body.value; if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) { let raw_ptrs = iter_input_pats(decl, body) .filter_map(|arg| raw_ptr_arg(cx, arg)) .collect::(); if !raw_ptrs.is_empty() { - let typeck_results = cx.tcx.typeck_body(body.id()); - let mut v = DerefVisitor { - cx, - ptrs: raw_ptrs, - typeck_results, - }; - - intravisit::walk_expr(&mut v, expr); + let typeck = cx.tcx.typeck_body(body.id()); + let _: Option = for_each_expr_with_closures(cx, body.value, |e| { + match e.kind { + hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => { + for arg in args { + check_arg(cx, &raw_ptrs, arg); + } + }, + hir::ExprKind::MethodCall(_, recv, args, _) => { + let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap(); + if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe { + check_arg(cx, &raw_ptrs, recv); + for arg in args { + check_arg(cx, &raw_ptrs, arg); + } + } + }, + hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => check_arg(cx, &raw_ptrs, ptr), + _ => (), + } + ControlFlow::Continue(()) + }); } } } @@ -70,54 +86,13 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option } } -struct DerefVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - ptrs: HirIdSet, - typeck_results: &'a ty::TypeckResults<'tcx>, -} - -impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - match expr.kind { - hir::ExprKind::Call(f, args) => { - let ty = self.typeck_results.expr_ty(f); - - if type_is_unsafe_function(self.cx, ty) { - for arg in args { - self.check_arg(arg); - } - } - }, - hir::ExprKind::MethodCall(_, receiver, args, _) => { - let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap(); - let base_type = self.cx.tcx.type_of(def_id); - - if type_is_unsafe_function(self.cx, base_type) { - self.check_arg(receiver); - for arg in args { - self.check_arg(arg); - } - } - }, - hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => self.check_arg(ptr), - _ => (), - } - - intravisit::walk_expr(self, expr); - } -} - -impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { - fn check_arg(&self, ptr: &hir::Expr<'_>) { - if let Some(id) = path_to_local(ptr) { - if self.ptrs.contains(&id) { - span_lint( - self.cx, - NOT_UNSAFE_PTR_ARG_DEREF, - ptr.span, - "this public function might dereference a raw pointer but is not marked `unsafe`", - ); - } - } +fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) { + if path_to_local(arg).map_or(false, |id| raw_ptrs.contains(&id)) { + span_lint( + cx, + NOT_UNSAFE_PTR_ARG_DEREF, + arg.span, + "this public function might dereference a raw pointer but is not marked `unsafe`", + ); } } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 50434a5658a..1cef6226ad4 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,9 +2,10 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; +use core::ops::ControlFlow; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -13,7 +14,7 @@ use rustc_span::sym; use super::UNNECESSARY_FILTER_MAP; use super::UNNECESSARY_FIND_MAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, name: &str) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) { if !is_trait_method(cx, expr, sym::Iterator) { return; } @@ -26,10 +27,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); - let mut return_visitor = ReturnVisitor::new(cx, arg_id); - return_visitor.visit_expr(body.value); - found_mapping |= return_visitor.found_mapping; - found_filtering |= return_visitor.found_filtering; + let _: Option = for_each_expr(body.value, |e| { + if let hir::ExprKind::Ret(Some(e)) = &e.kind { + let (found_mapping_res, found_filtering_res) = check_expression(cx, arg_id, e); + found_mapping |= found_mapping_res; + found_filtering |= found_filtering_res; + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Continue(Descend::Yes) + } + }); let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); let sugg = if !found_filtering { @@ -97,35 +104,3 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc _ => (true, true), } } - -struct ReturnVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - arg_id: hir::HirId, - // Found a non-None return that isn't Some(input) - found_mapping: bool, - // Found a return that isn't Some - found_filtering: bool, -} - -impl<'a, 'tcx> ReturnVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'tcx>, arg_id: hir::HirId) -> ReturnVisitor<'a, 'tcx> { - ReturnVisitor { - cx, - arg_id, - found_mapping: false, - found_filtering: false, - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if let hir::ExprKind::Ret(Some(expr)) = &expr.kind { - let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr); - self.found_mapping |= found_mapping; - self.found_filtering |= found_filtering; - } else { - walk_expr(self, expr); - } - } -} diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 2d5d5d143ff..26bca7c306a 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -2,11 +2,12 @@ use clippy_utils::binop_traits; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{eq_expr_value, trait_ref_of_method}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; @@ -65,15 +66,19 @@ pub(super) fn check<'tcx>( } }; - let mut visitor = ExprVisitor { - assignee, - counter: 0, - cx, - }; - - walk_expr(&mut visitor, e); + let mut found = false; + let found_multiple = for_each_expr(e, |e| { + if eq_expr_value(cx, assignee, e) { + if found { + return ControlFlow::Break(()); + } + found = true; + } + ControlFlow::Continue(()) + }) + .is_some(); - if visitor.counter == 1 { + if found && !found_multiple { // a = a op b if eq_expr_value(cx, assignee, l) { lint(assignee, r); @@ -98,22 +103,6 @@ pub(super) fn check<'tcx>( } } -struct ExprVisitor<'a, 'tcx> { - assignee: &'a hir::Expr<'a>, - counter: u8, - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if eq_expr_value(self.cx, self.assignee, expr) { - self.counter += 1; - } - - walk_expr(self, expr); - } -} - fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet { struct S(hir::HirIdSet); impl Delegate<'_> for S { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index f758f4cff8b..2b2a41d1601 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{fn_def_id, path_to_local_id}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -270,33 +272,20 @@ fn emit_return_lint( } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - let mut visitor = BorrowVisitor { cx, borrows: false }; - walk_expr(&mut visitor, expr); - visitor.borrows -} - -struct BorrowVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - borrows: bool, -} - -impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.borrows || expr.span.from_expansion() { - return; - } - - if let Some(def_id) = fn_def_id(self.cx, expr) { - self.borrows = self - .cx + for_each_expr(expr, |e| { + if let Some(def_id) = fn_def_id(cx, e) + && cx .tcx .fn_sig(def_id) - .output() .skip_binder() + .output() .walk() - .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::from(!expr.span.from_expansion())) } - - walk_expr(self, expr); - } + }) + .is_some() } diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index d47ed459387..b57b484bdc8 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -92,25 +93,17 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { } fn count_binops(expr: &hir::Expr<'_>) -> u32 { - let mut visitor = BinaryExprVisitor::default(); - visitor.visit_expr(expr); - visitor.nb_binops -} - -#[derive(Default)] -struct BinaryExprVisitor { - nb_binops: u32, -} - -impl<'tcx> Visitor<'tcx> for BinaryExprVisitor { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - match expr.kind { + let mut count = 0u32; + let _: Option = for_each_expr(expr, |e| { + if matches!( + e.kind, hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _) - | hir::ExprKind::AssignOp(..) => self.nb_binops += 1, - _ => {}, + | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _) + | hir::ExprKind::AssignOp(..) + ) { + count += 1; } - - walk_expr(self, expr); - } + ControlFlow::Continue(()) + }); + count } diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index baa53ba664f..a69719b127b 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{method_chain_args, return_ty}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Expr, ImplItemKind}; +use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; @@ -73,51 +73,37 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { } } -struct FindExpectUnwrap<'a, 'tcx> { - lcx: &'a LateContext<'tcx>, - typeck_results: &'tcx ty::TypeckResults<'tcx>, - result: Vec, -} - -impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - // check for `expect` - if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) - || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) - { - self.result.push(expr.span); +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { + if let ImplItemKind::Fn(_, body_id) = impl_item.kind { + let body = cx.tcx.hir().body(body_id); + let typeck = cx.tcx.typeck(impl_item.def_id.def_id); + let mut result = Vec::new(); + let _: Option = for_each_expr(body.value, |e| { + // check for `expect` + if let Some(arglists) = method_chain_args(e, &["expect"]) { + let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); + if is_type_diagnostic_item(cx, receiver_ty, sym::Option) + || is_type_diagnostic_item(cx, receiver_ty, sym::Result) + { + result.push(e.span); + } } - } - // check for `unwrap` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) - || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) - { - self.result.push(expr.span); + // check for `unwrap` + if let Some(arglists) = method_chain_args(e, &["unwrap"]) { + let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); + if is_type_diagnostic_item(cx, receiver_ty, sym::Option) + || is_type_diagnostic_item(cx, receiver_ty, sym::Result) + { + result.push(e.span); + } } - } - // and check sub-expressions - intravisit::walk_expr(self, expr); - } -} - -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { - if let ImplItemKind::Fn(_, body_id) = impl_item.kind { - let body = cx.tcx.hir().body(body_id); - let mut fpu = FindExpectUnwrap { - lcx: cx, - typeck_results: cx.tcx.typeck(impl_item.def_id.def_id), - result: Vec::new(), - }; - fpu.visit_expr(body.value); + ControlFlow::Continue(()) + }); // if we've found one, lint - if !fpu.result.is_empty() { + if !result.is_empty() { span_lint_and_then( cx, UNWRAP_IN_RESULT, @@ -125,7 +111,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc "used unwrap or expect in a function that returns result or option", move |diag| { diag.help("unwrap and expect should not be used in a function that returns result or option"); - diag.span_note(fpu.result, "potential non-recoverable error(s)"); + diag.span_note(result, "potential non-recoverable error(s)"); }, ); } -- cgit 1.4.1-3-g733a5 From f48d13f8d1b442c38755cfe87c28f56e1dca10cc Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 10 Oct 2022 22:37:42 +0200 Subject: Replace manual let else patterns with let else --- clippy_dev/src/setup/intellij.rs | 17 +++++------------ clippy_dev/src/update_lints.rs | 8 +++----- clippy_lints/src/derive.rs | 5 +---- clippy_lints/src/disallowed_methods.rs | 5 ++--- clippy_lints/src/entry.rs | 20 ++++++++------------ clippy_lints/src/eta_reduction.rs | 5 ++--- clippy_lints/src/functions/too_many_lines.rs | 5 ++--- clippy_lints/src/invalid_upcast_comparisons.rs | 4 +--- clippy_lints/src/large_enum_variant.rs | 5 ++--- clippy_lints/src/loops/while_let_on_iterator.rs | 5 ++--- clippy_lints/src/matches/manual_utils.rs | 5 ++--- clippy_lints/src/matches/match_same_arms.rs | 6 ++---- clippy_lints/src/methods/into_iter_on_ref.rs | 5 ++--- .../src/methods/manual_saturating_arithmetic.rs | 10 ++-------- clippy_lints/src/methods/mod.rs | 5 ++--- clippy_lints/src/methods/str_splitn.rs | 4 +--- clippy_lints/src/misc_early/literal_suffix.rs | 4 +--- .../src/misc_early/mixed_case_hex_literals.rs | 4 +--- clippy_lints/src/mismatching_type_param_order.rs | 5 ++--- clippy_lints/src/mixed_read_write_in_expression.rs | 5 +---- clippy_lints/src/needless_for_each.rs | 5 ++--- clippy_lints/src/non_copy_const.rs | 5 ++--- clippy_lints/src/non_octal_unix_permissions.rs | 17 +++++------------ clippy_lints/src/ptr.rs | 9 +++------ clippy_lints/src/ptr_offset_with_cast.rs | 10 ++++------ clippy_lints/src/shadow.rs | 5 +---- clippy_lints/src/types/rc_buffer.rs | 10 ++-------- clippy_lints/src/types/redundant_allocation.rs | 5 ++--- clippy_lints/src/unnested_or_patterns.rs | 5 ++--- clippy_lints/src/unused_io_amount.rs | 5 ++--- clippy_lints/src/useless_conversion.rs | 5 ++--- clippy_lints/src/utils/internal_lints.rs | 10 ++-------- 32 files changed, 73 insertions(+), 150 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_dev/src/setup/intellij.rs b/clippy_dev/src/setup/intellij.rs index b64e79733eb..efdb158c21e 100644 --- a/clippy_dev/src/setup/intellij.rs +++ b/clippy_dev/src/setup/intellij.rs @@ -36,9 +36,8 @@ impl ClippyProjectInfo { } pub fn setup_rustc_src(rustc_path: &str) { - let rustc_source_dir = match check_and_get_rustc_dir(rustc_path) { - Ok(path) => path, - Err(_) => return, + let Ok(rustc_source_dir) = check_and_get_rustc_dir(rustc_path) else { + return }; for project in CLIPPY_PROJECTS { @@ -172,14 +171,10 @@ pub fn remove_rustc_src() { } fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool { - let mut cargo_content = if let Ok(content) = read_project_file(project.cargo_file) { - content - } else { + let Ok(mut cargo_content) = read_project_file(project.cargo_file) else { return false; }; - let section_start = if let Some(section_start) = cargo_content.find(RUSTC_PATH_SECTION) { - section_start - } else { + let Some(section_start) = cargo_content.find(RUSTC_PATH_SECTION) else { println!( "info: dependencies could not be found in `{}` for {}, skipping file", project.cargo_file, project.name @@ -187,9 +182,7 @@ fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool { return true; }; - let end_point = if let Some(end_point) = cargo_content.find(DEPENDENCIES_SECTION) { - end_point - } else { + let Some(end_point) = cargo_content.find(DEPENDENCIES_SECTION) else { eprintln!( "error: the end of the rustc dependencies section could not be found in `{}`", project.cargo_file diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 8d1bfacd1dc..e690bc369cd 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -869,13 +869,11 @@ fn clippy_lints_src_files() -> impl Iterator { macro_rules! match_tokens { ($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => { { - $($(let $capture =)? if let Some(LintDeclSearchResult { + $(#[allow(clippy::redundant_pattern)] let Some(LintDeclSearchResult { token_kind: TokenKind::$token $({$($fields)*})?, - content: _x, + content: $($capture @)? _, .. - }) = $iter.next() { - _x - } else { + }) = $iter.next() else { continue; };)* #[allow(clippy::unused_unit)] diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 3fac93dcc90..fad984d05ca 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -339,10 +339,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h Some(id) if trait_ref.trait_def_id() == Some(id) => id, _ => return, }; - let copy_id = match cx.tcx.lang_items().copy_trait() { - Some(id) => id, - None => return, - }; + let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return }; let (ty_adt, ty_subs) = match *ty.kind() { // Unions can't derive clone. ty::Adt(adt, subs) if !adt.is_union() => (adt, subs), diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 1a381f92c03..6ac85606d9c 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -94,9 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { } else { path_def_id(cx, expr) }; - let def_id = match uncalled_path.or_else(|| fn_def_id(cx, expr)) { - Some(def_id) => def_id, - None => return, + let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else { + return }; let conf = match self.disallowed.get(&def_id) { Some(&index) => &self.conf_disallowed[index], diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 9c834cf0144..b44e6243588 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -65,28 +65,24 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]); impl<'tcx> LateLintPass<'tcx> for HashMapPass { #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) { - Some(higher::If { cond, then, r#else }) => (cond, then, r#else), - _ => return, + let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else { + return }; - let (map_ty, contains_expr) = match try_parse_contains(cx, cond_expr) { - Some(x) => x, - None => return, + let Some((map_ty, contains_expr)) = try_parse_contains(cx, cond_expr) else { + return }; - let then_search = match find_insert_calls(cx, &contains_expr, then_expr) { - Some(x) => x, - None => return, + let Some(then_search) = find_insert_calls(cx, &contains_expr, then_expr) else { + return }; let mut app = Applicability::MachineApplicable; let map_str = snippet_with_context(cx, contains_expr.map.span, contains_expr.call_ctxt, "..", &mut app).0; let key_str = snippet_with_context(cx, contains_expr.key.span, contains_expr.call_ctxt, "..", &mut app).0; let sugg = if let Some(else_expr) = else_expr { - let else_search = match find_insert_calls(cx, &contains_expr, else_expr) { - Some(search) => search, - None => return, + let Some(else_search) = find_insert_calls(cx, &contains_expr, else_expr) else { + return; }; if then_search.edits.is_empty() && else_search.edits.is_empty() { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 3732410e71e..7b9786d7e57 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -213,9 +213,8 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc if !closure_ty.has_late_bound_regions() { return true; } - let substs = match closure_ty.kind() { - ty::Closure(_, substs) => substs, - _ => return false, + let ty::Closure(_, substs) = closure_ty.kind() else { + return false; }; let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal); cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig) diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index f83f8b40f94..bd473ac7e51 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -22,9 +22,8 @@ pub(super) fn check_fn( return; } - let code_snippet = match snippet_opt(cx, body.value.span) { - Some(s) => s, - _ => return, + let Some(code_snippet) = snippet_opt(cx, body.value.span) else { + return }; let mut line_count: u64 = 0; let mut in_comment = false; diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 36e03e50a8e..0ef77e03de9 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -145,9 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind { let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs); - let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { - val - } else { + let Some((rel, normalized_lhs, normalized_rhs)) = normalized else { return; }; diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index eb13d0869c0..8ed7e4bb196 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -124,9 +124,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { } if let ItemKind::Enum(ref def, _) = item.kind { let ty = cx.tcx.type_of(item.def_id); - let (adt, subst) = match ty.kind() { - Adt(adt, subst) => (adt, subst), - _ => panic!("already checked whether this is an enum"), + let Adt(adt, subst) = ty.kind() else { + panic!("already checked whether this is an enum") }; if adt.variants().len() <= 1 { return; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 153f97e4e66..55989f8a446 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -331,9 +331,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & } if let Some(e) = get_enclosing_loop_or_multi_call_closure(cx, loop_expr) { - let local_id = match iter_expr.path { - Res::Local(id) => id, - _ => return true, + let Res::Local(local_id) = iter_expr.path else { + return true }; let mut v = NestedLoopVisitor { cx, diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index 792908aa7df..5b7644a5383 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -60,9 +60,8 @@ where return None; } - let some_expr = match get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) { - Some(expr) => expr, - None => return None, + let Some(some_expr) = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) else { + return None; }; // These two lints will go back and forth with each other. diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 37049f83577..168c1e4d2e6 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -221,7 +221,6 @@ fn iter_matching_struct_fields<'a>( #[expect(clippy::similar_names)] impl<'a> NormalizedPat<'a> { - #[expect(clippy::too_many_lines)] fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, @@ -235,9 +234,8 @@ impl<'a> NormalizedPat<'a> { Self::Struct(cx.qpath_res(path, pat.hir_id).opt_def_id(), fields) }, PatKind::TupleStruct(ref path, pats, wild_idx) => { - let adt = match cx.typeck_results().pat_ty(pat).ty_adt_def() { - Some(x) => x, - None => return Self::Wild, + let Some(adt) = cx.typeck_results().pat_ty(pat).ty_adt_def() else { + return Self::Wild }; let (var_id, variant) = if adt.is_enum() { match cx.qpath_res(path, pat.hir_id).opt_def_id() { diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index be56b63506a..8adf9e37059 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -42,9 +42,8 @@ pub(super) fn check( fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(Symbol, &'static str)> { has_iter_method(cx, self_ref_ty).map(|ty_name| { - let mutbl = match self_ref_ty.kind() { - ty::Ref(_, _, mutbl) => mutbl, - _ => unreachable!(), + let ty::Ref(_, _, mutbl) = self_ref_ty.kind() else { + unreachable!() }; let method_name = match mutbl { hir::Mutability::Not => "iter", diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index ec694cf6882..b80541b8647 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -21,11 +21,7 @@ pub fn check( return; } - let mm = if let Some(mm) = is_min_or_max(cx, unwrap_arg) { - mm - } else { - return; - }; + let Some(mm) = is_min_or_max(cx, unwrap_arg) else { return }; if ty.is_signed() { use self::{ @@ -33,9 +29,7 @@ pub fn check( Sign::{Neg, Pos}, }; - let sign = if let Some(sign) = lit_sign(arith_rhs) { - sign - } else { + let Some(sign) = lit_sign(arith_rhs) else { return; }; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cfcf9596c50..78c1b33ed97 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3851,9 +3851,8 @@ impl SelfKind { hir::Mutability::Mut => &paths::ASMUT_TRAIT, }; - let trait_def_id = match get_trait_def_id(cx, trait_path) { - Some(did) => did, - None => return false, + let Some(trait_def_id) = get_trait_def_id(cx, trait_path) else { + return false }; implements_trait(cx, ty, trait_def_id, &[parent_ty.into()]) } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index ae3594bd36c..1acac59144c 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -289,9 +289,7 @@ fn parse_iter_usage<'tcx>( ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind { - (name, args) - } else { + let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else { return None; }; let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs index 62c6ca32d31..27e7f8505eb 100644 --- a/clippy_lints/src/misc_early/literal_suffix.rs +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -6,9 +6,7 @@ use rustc_lint::EarlyContext; use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX}; pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { - let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { - val - } else { + let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else { return; // It's useless so shouldn't lint. }; // Do not lint when literal is unsuffixed. diff --git a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs index 80e24213100..263ee1e945a 100644 --- a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs +++ b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs @@ -5,9 +5,7 @@ use rustc_lint::EarlyContext; use super::MIXED_CASE_HEX_LITERALS; pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) { - let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { - val - } else { + let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else { return; // It's useless so shouldn't lint. }; if maybe_last_sep_idx <= 2 { diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 6dd76a6531e..9de4b56b77b 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -70,9 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { // find the type that the Impl is for // only lint on struct/enum/union for now - let defid = match path.res { - Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) => defid, - _ => return, + let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else { + return }; // get the names of the generic parameters in the type diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index a2419c277e9..6752976348f 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -190,10 +190,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) { if parent_id == cur_id { break; } - let parent_node = match map.find(parent_id) { - Some(parent) => parent, - None => break, - }; + let Some(parent_node) = map.find(parent_id) else { break }; let stop_early = match parent_node { Node::Expr(expr) => check_expr(vis, expr), diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 3233d87c073..c3b633fd6a0 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -49,9 +49,8 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]); impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - let expr = match stmt.kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr, - _ => return, + let (StmtKind::Expr(expr) | StmtKind::Semi(expr)) = stmt.kind else { + return }; if_chain! { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 2c839d029c6..a6742824bc5 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -357,9 +357,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } // Make sure it is a const item. - let item_def_id = match cx.qpath_res(qpath, expr.hir_id) { - Res::Def(DefKind::Const | DefKind::AssocConst, did) => did, - _ => return, + let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else { + return }; // Climb up to resolve any field access and explicit referencing. diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 1a765b14892..2ecb0487484 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -55,9 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let ExprKind::Lit(_) = param.kind; then { - let snip = match snippet_opt(cx, param.span) { - Some(s) => s, - _ => return, + let Some(snip) = snippet_opt(cx, param.span) else { + return }; if !snip.starts_with("0o") { @@ -72,16 +71,10 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); if let ExprKind::Lit(_) = param.kind; - + if let Some(snip) = snippet_opt(cx, param.span); + if !snip.starts_with("0o"); then { - let snip = match snippet_opt(cx, param.span) { - Some(s) => s, - _ => return, - }; - - if !snip.starts_with("0o") { - show_error(cx, param); - } + show_error(cx, param); } } }, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d296a150b46..2d80236327a 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -552,9 +552,8 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } // Check if this is local we care about - let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) { - Some(&i) => i, - None => return walk_expr(self, e), + let Some(&args_idx) = path_to_local(e).and_then(|id| self.bindings.get(&id)) else { + return walk_expr(self, e); }; let args = &self.args[args_idx]; let result = &mut self.results[args_idx]; @@ -609,9 +608,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } } - let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) { - x - } else { + let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else { set_skip_flag(); return; }; diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index b0a5d1a6758..72dda67c72b 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -49,15 +49,13 @@ declare_lint_pass!(PtrOffsetWithCast => [PTR_OFFSET_WITH_CAST]); impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Check if the expressions is a ptr.offset or ptr.wrapping_offset method call - let (receiver_expr, arg_expr, method) = match expr_as_ptr_offset_call(cx, expr) { - Some(call_arg) => call_arg, - None => return, + let Some((receiver_expr, arg_expr, method)) = expr_as_ptr_offset_call(cx, expr) else { + return }; // Check if the argument to the method call is a cast from usize - let cast_lhs_expr = match expr_as_cast_from_usize(cx, arg_expr) { - Some(cast_lhs_expr) => cast_lhs_expr, - None => return, + let Some(cast_lhs_expr) = expr_as_cast_from_usize(cx, arg_expr) else { + return }; let msg = format!("use of `{method}` with a `usize` casted to an `isize`"); diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 5dcdab5b8ab..87f966ced0d 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -106,10 +106,7 @@ impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]); impl<'tcx> LateLintPass<'tcx> for Shadow { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - let (id, ident) = match pat.kind { - PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident), - _ => return, - }; + let PatKind::Binding(_, id, ident, _) = pat.kind else { return }; if pat.span.desugaring_kind().is_some() { return; diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 6b9de64e24c..e39fdc1ea70 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -26,10 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ if !cx.tcx.is_diagnostic_item(sym::Vec, id) { return false; } - let qpath = match &ty.kind { - TyKind::Path(qpath) => qpath, - _ => return false, - }; + let TyKind::Path(qpath) = &ty.kind else { return false }; let inner_span = match qpath_generic_tys(qpath).next() { Some(ty) => ty.span, None => return false, @@ -65,10 +62,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ if !cx.tcx.is_diagnostic_item(sym::Vec, id) { return false; } - let qpath = match &ty.kind { - TyKind::Path(qpath) => qpath, - _ => return false, - }; + let TyKind::Path(qpath) = &ty.kind else { return false }; let inner_span = match qpath_generic_tys(qpath).next() { Some(ty) => ty.span, None => return false, diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index ecb67200539..92d2c48a589 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -47,9 +47,8 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ _ => return false, }; - let inner_qpath = match &ty.kind { - TyKind::Path(inner_qpath) => inner_qpath, - _ => return false, + let TyKind::Path(inner_qpath) = &ty.kind else { + return false }; let inner_span = match qpath_generic_tys(inner_qpath).next() { Some(ty) => { diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index fb73c386640..b305dae7608 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -163,9 +163,8 @@ fn unnest_or_patterns(pat: &mut P) -> bool { noop_visit_pat(p, self); // Don't have an or-pattern? Just quit early on. - let alternatives = match &mut p.kind { - Or(ps) => ps, - _ => return, + let Or(alternatives) = &mut p.kind else { + return }; // Collapse or-patterns directly nested in or-patterns. diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 8bcdff66331..92053cec59f 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -47,9 +47,8 @@ declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]); impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - let expr = match s.kind { - hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr, - _ => return, + let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = s.kind else { + return }; match expr.kind { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index a82643a59f9..1f69db1cbca 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -55,9 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { match e.kind { ExprKind::Match(_, arms, MatchSource::TryDesugar) => { - let e = match arms[0].body.kind { - ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e, - _ => return, + let (ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e))) = arms[0].body.kind else { + return }; if let ExprKind::Call(_, [arg, ..]) = e.kind { self.try_desugar_arm.push(arg.hir_id); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 85bcbc7ad23..0d908bf2a83 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1402,18 +1402,12 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { } else { return; }; - let then_block = match then.kind { - ExprKind::Block(block, _) => block, - _ => return, - }; + let ExprKind::Block(then_block, _) = then.kind else { return }; let if_chain_span = is_expn_of(expr.span, "if_chain"); if !els { check_nested_if_chains(cx, expr, then_block, if_chain_span); } - let if_chain_span = match if_chain_span { - None => return, - Some(span) => span, - }; + let Some(if_chain_span) = if_chain_span else { return }; // check for `if a && b;` if_chain! { if let ExprKind::Binary(op, _, _) = cond.kind; -- cgit 1.4.1-3-g733a5 From 2e5e3560e917f2c3adceda6bc40806868c98e04e Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 1 Oct 2022 04:56:55 -0400 Subject: Fix adjacent code --- clippy_lints/src/booleans.rs | 6 +++-- clippy_lints/src/comparison_chain.rs | 8 +++++-- clippy_lints/src/functions/must_use.rs | 10 +++++---- clippy_lints/src/let_underscore.rs | 15 ++++++++----- clippy_lints/src/loops/needless_range_loop.rs | 11 ++++++--- clippy_lints/src/manual_async_fn.rs | 9 +++++--- clippy_lints/src/manual_clamp.rs | 10 ++++++--- clippy_lints/src/matches/single_match.rs | 11 +++++---- clippy_lints/src/methods/mod.rs | 12 +++++----- clippy_lints/src/methods/option_as_ref_deref.rs | 20 +++++++++-------- clippy_lints/src/methods/or_fun_call.rs | 18 +++++++-------- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 ++-- clippy_lints/src/operators/cmp_owned.rs | 18 ++++++++------- clippy_lints/src/unit_return_expecting_ord.rs | 5 ++--- clippy_utils/src/lib.rs | 17 ++++++++++++++ clippy_utils/src/paths.rs | 30 ------------------------- tests/ui-internal/invalid_paths.rs | 2 +- 17 files changed, 108 insertions(+), 98 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 2a15cbc7a3c..08164c0b654 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; +use clippy_utils::eq_expr_value; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{eq_expr_value, get_trait_def_id, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -483,7 +483,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])) + cx.tcx + .get_diagnostic_item(sym::Ord) + .map_or(false, |id| implements_trait(cx, ty, id, &[])) } struct NotSimplificationVisitor<'a, 'tcx> { diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index a05b41eb3ab..0fe973b49a3 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, if_sequence, in_constant, is_else_clause, paths, SpanlessEq}; +use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -106,7 +107,10 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { // Check that the type being compared implements `core::cmp::Ord` let ty = cx.typeck_results().expr_ty(lhs1); - let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])); + let is_ord = cx + .tcx + .get_diagnostic_item(sym::Ord) + .map_or(false, |id| implements_trait(cx, ty, id, &[])); if !is_ord { return; diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index d263804f32c..3064b6c9d22 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -7,14 +7,14 @@ use rustc_middle::{ lint::in_external_macro, ty::{self, Ty}, }; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, Symbol}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{match_def_path, return_ty, trait_ref_of_method}; +use clippy_utils::{return_ty, trait_ref_of_method}; use core::ops::ControlFlow; @@ -181,7 +181,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) } } -static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]]; +static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc]; fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool { match *ty.kind() { @@ -189,7 +189,9 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, substs) => { tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env) - || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did(), path)) + || KNOWN_WRAPPER_TYS + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did())) && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)) }, ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)), diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 176787497eb..6d50dcc8806 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{is_must_use_ty, match_type}; +use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, match_type}; use clippy_utils::{is_must_use_func_call, paths}; use if_chain::if_chain; use rustc_hir::{Local, PatKind}; @@ -7,6 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// ### What it does @@ -99,10 +100,9 @@ declare_clippy_lint! { declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]); -const SYNC_GUARD_PATHS: [&[&str]; 6] = [ - &paths::MUTEX_GUARD, - &paths::RWLOCK_READ_GUARD, - &paths::RWLOCK_WRITE_GUARD, +const SYNC_GUARD_SYMS: [Symbol; 3] = [sym::MutexGuard, sym::RwLockReadGuard, sym::RwLockWriteGuard]; + +const SYNC_GUARD_PATHS: [&[&str]; 3] = [ &paths::PARKING_LOT_MUTEX_GUARD, &paths::PARKING_LOT_RWLOCK_READ_GUARD, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD, @@ -121,7 +121,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => { - SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)) + SYNC_GUARD_SYMS + .iter() + .any(|&sym| is_type_diagnostic_item(cx, inner_ty, sym)) + || SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)) }, GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 00cfc6d49f1..2b1c5688e82 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; -use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq}; +use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -302,8 +302,13 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // a range index op if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind; - if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) - || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); + if let Some(trait_id) = self + .cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .and_then(|def_id| self.cx.tcx.trait_of_item(def_id)); + if (meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id)) + || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id)); if !self.check(args_1, args_0, expr); then { return } } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 9a0a26c0991..570d83c7ea8 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::match_function_call; -use clippy_utils::paths::FUTURE_FROM_GENERATOR; +use clippy_utils::match_function_call_with_def_id; use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -175,7 +174,11 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { if_chain! { if let Some(block_expr) = block.expr; - if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR); + if let Some(args) = cx + .tcx + .lang_items() + .from_generator_fn() + .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id)); if args.len() == 1; if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0]; let closure_body = cx.tcx.hir().body(body); diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index ece4df95505..02dc8755dd6 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -12,9 +12,9 @@ use std::ops::Deref; use clippy_utils::{ diagnostics::{span_lint_and_then, span_lint_hir_and_then}, - eq_expr_value, get_trait_def_id, + eq_expr_value, higher::If, - is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, paths, peel_blocks, + is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt, sugg::Sugg, ty::implements_trait, @@ -190,7 +190,11 @@ impl TypeClampability { fn is_clampable<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { if ty.is_floating_point() { Some(TypeClampability::Float) - } else if get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])) { + } else if cx + .tcx + .get_diagnostic_item(sym::Ord) + .map_or(false, |id| implements_trait(cx, ty, id, &[])) + { Some(TypeClampability::Ord) } else { None diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index d496107ffd6..e5a15b2e1a1 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{expr_block, snippet}; -use clippy_utils::ty::{implements_trait, match_type, peel_mid_ty_refs}; -use clippy_utils::{ - is_lint_allowed, is_unit_expr, is_wild, paths, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, -}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; +use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; use core::cmp::max; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; @@ -156,10 +155,10 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) -> /// Returns `true` if the given type is an enum we know won't be expanded in the future fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool { // list of candidate `Enum`s we know will never get any more members - let candidates = [&paths::COW, &paths::OPTION, &paths::RESULT]; + let candidates = [sym::Cow, sym::Option, sym::Result]; for candidate_ty in candidates { - if match_type(cx, ty, candidate_ty) { + if is_type_diagnostic_item(cx, ty, candidate_ty) { return true; } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 78c1b33ed97..b0677d1a3ae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -102,9 +102,7 @@ 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, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty, -}; +use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -3846,12 +3844,12 @@ impl SelfKind { return m == mutability && t == parent_ty; } - let trait_path = match mutability { - hir::Mutability::Not => &paths::ASREF_TRAIT, - hir::Mutability::Mut => &paths::ASMUT_TRAIT, + let trait_sym = match mutability { + hir::Mutability::Not => sym::AsRef, + hir::Mutability::Mut => sym::AsMut, }; - let Some(trait_def_id) = get_trait_def_id(cx, trait_path) else { + let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else { return false }; implements_trait(cx, ty, trait_def_id, &[parent_ty.into()]) diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 6fb92d1c663..742483e6b2e 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -32,8 +32,7 @@ pub(super) fn check<'tcx>( return; } - let deref_aliases: [&[&str]; 9] = [ - &paths::DEREF_TRAIT_METHOD, + let deref_aliases: [&[&str]; 8] = [ &paths::DEREF_MUT_TRAIT_METHOD, &paths::CSTRING_AS_C_STR, &paths::OS_STRING_AS_OS_STR, @@ -45,12 +44,14 @@ pub(super) fn check<'tcx>( ]; let is_deref = match map_arg.kind { - hir::ExprKind::Path(ref expr_qpath) => cx - .qpath_res(expr_qpath, map_arg.hir_id) - .opt_def_id() - .map_or(false, |fun_def_id| { - deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) - }), + hir::ExprKind::Path(ref expr_qpath) => { + cx.qpath_res(expr_qpath, map_arg.hir_id) + .opt_def_id() + .map_or(false, |fun_def_id| { + cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) + || deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) + }) + }, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(closure_body.value); @@ -68,7 +69,8 @@ pub(super) fn check<'tcx>( if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj; then { let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); - deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) + cx.tcx.is_diagnostic_item(sym::deref_method, method_did) + || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) } else { false } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6a35024d036..6e10445659e 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,14 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; -use clippy_utils::ty::{implements_trait, match_type}; -use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{contains_return, is_trait_item, last_path_segment}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::{kw, sym, Symbol}; use std::borrow::Cow; use super::OR_FUN_CALL; @@ -88,11 +88,11 @@ pub(super) fn check<'tcx>( fun_span: Option, ) { // (path, fn_has_argument, methods, suffix) - const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ - (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else"), + const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [ + (sym::BTreeEntry, false, &["or_insert"], "with"), + (sym::HashMapEntry, false, &["or_insert"], "with"), + (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (sym::Result, true, &["or", "unwrap_or"], "else"), ]; if_chain! { @@ -104,7 +104,7 @@ pub(super) fn check<'tcx>( let self_ty = cx.typeck_results().expr_ty(self_expr); if let Some(&(_, fn_has_arguments, poss, suffix)) = - KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); + KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0)); if poss.contains(&name); diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index a7e0e35787c..c949cede8e1 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::implements_trait; -use clippy_utils::{self, get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { let ty = cx.typeck_results().expr_ty(left); let implements_ord = { - if let Some(id) = get_trait_def_id(cx, &paths::ORD) { + if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) { implements_trait(cx, ty, id, &[]) } else { return; diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index c9c777f1bd8..24aeb82a37f 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{match_any_def_paths, path_def_id, paths}; +use clippy_utils::{match_def_path, path_def_id, paths}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -49,13 +49,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) (arg, arg.span) }, ExprKind::Call(path, [arg]) - if path_def_id(cx, path) - .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM])) - .map_or(false, |idx| match idx { - 0 => true, - 1 => !is_copy(cx, typeck.expr_ty(expr)), - _ => false, - }) => + if path_def_id(cx, path).map_or(false, |id| { + if match_def_path(cx, id, &paths::FROM_STR_METHOD) { + true + } else if cx.tcx.lang_items().from_fn() == Some(id) { + !is_copy(cx, typeck.expr_ty(expr)) + } else { + false + } + }) => { (arg, arg.span) }, diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 57aff5367dd..fc2ee9e5a4d 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; @@ -7,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{BytePos, Span}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -80,7 +79,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve let fn_sig = cx.tcx.fn_sig(def_id); let generics = cx.tcx.predicates_of(def_id); let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait()); - let ord_preds = get_trait_predicates_for_trait_id(cx, generics, get_trait_def_id(cx, &paths::ORD)); + let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord)); let partial_ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait()); // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dbe75b43cb2..cbc2fde69d1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1766,6 +1766,7 @@ pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool /// ```rust,ignore /// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX); /// ``` +/// This function is deprecated. Use [`match_function_call_with_def_id`]. pub fn match_function_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, @@ -1783,6 +1784,22 @@ pub fn match_function_call<'tcx>( None } +pub fn match_function_call_with_def_id<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + fun_def_id: DefId, +) -> Option<&'tcx [Expr<'tcx>]> { + if_chain! { + if let ExprKind::Call(fun, args) = expr.kind; + if let ExprKind::Path(ref qpath) = fun.kind; + if cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id); + then { + return Some(args); + } + }; + None +} + /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if /// any. /// diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 78adc453654..bc851473430 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -16,25 +16,17 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ #[cfg(feature = "internal")] pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; -pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; -pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; -pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; -pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"]; pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; -pub const CORE_ITER_INTO_ITER: [&str; 6] = ["core", "iter", "traits", "collect", "IntoIterator", "into_iter"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; -/// Preferably use the diagnostic item `sym::deref_method` where possible -pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; -pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; #[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; #[cfg(feature = "internal")] @@ -42,30 +34,22 @@ pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"] pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; -pub const FILE: [&str; 3] = ["std", "fs", "File"]; -pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; -pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; -pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"]; -pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"]; pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"]; #[cfg(feature = "internal")] pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; #[cfg(feature = "internal")] pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; -pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; -pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; -pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; @@ -76,13 +60,7 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; -pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; -/// Preferably use the diagnostic item `sym::Option` where possible -pub const OPTION: [&str; 3] = ["core", "option", "Option"]; -pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"]; -pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"]; -pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; @@ -95,8 +73,6 @@ pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; -pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"]; -pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; @@ -125,14 +101,8 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; -/// Preferably use the diagnostic item `sym::Result` where possible -pub const RESULT: [&str; 3] = ["core", "result", "Result"]; -pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"]; -pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"]; #[cfg(feature = "internal")] pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"]; -pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"]; -pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; diff --git a/tests/ui-internal/invalid_paths.rs b/tests/ui-internal/invalid_paths.rs index b823ff7fe37..9a9790a4bae 100644 --- a/tests/ui-internal/invalid_paths.rs +++ b/tests/ui-internal/invalid_paths.rs @@ -1,5 +1,5 @@ #![warn(clippy::internal)] -#![allow(clippy::missing_clippy_version_attribute)] +#![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)] mod paths { // Good path -- cgit 1.4.1-3-g733a5 From 5dc54c60660b2e37c2978c38df9298edcc2988f2 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 9 Oct 2022 07:01:49 -0400 Subject: Format affected files --- clippy_lints/src/let_underscore.rs | 8 +-- clippy_lints/src/loops/needless_range_loop.rs | 24 +++++--- clippy_lints/src/manual_async_fn.rs | 9 ++- clippy_lints/src/methods/mod.rs | 10 +++- clippy_lints/src/methods/or_fun_call.rs | 5 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 +- clippy_lints/src/unit_return_expecting_ord.rs | 12 ++-- .../src/utils/internal_lints/collapsible_calls.rs | 13 ++-- .../internal_lints/compiler_lint_functions.rs | 3 +- .../src/utils/internal_lints/if_chain_style.rs | 5 +- .../src/utils/internal_lints/invalid_paths.rs | 7 ++- .../utils/internal_lints/lint_without_lint_pass.rs | 6 +- .../src/utils/internal_lints/metadata_collector.rs | 6 +- .../utils/internal_lints/outer_expn_data_pass.rs | 2 +- .../utils/internal_lints/unnecessary_def_path.rs | 70 +++++++++++----------- 15 files changed, 104 insertions(+), 80 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 6d50dcc8806..b7798b1c1d7 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a synchronization lock", None, "consider using an underscore-prefixed named \ - binding or dropping explicitly with `std::mem::drop`" + binding or dropping explicitly with `std::mem::drop`", ); } else if init_ty.needs_drop(cx.tcx, cx.param_env) { span_lint_and_help( @@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding `let` on a type that implements `Drop`", None, "consider using an underscore-prefixed named \ - binding or dropping explicitly with `std::mem::drop`" + binding or dropping explicitly with `std::mem::drop`", ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { local.span, "non-binding let on an expression with `#[must_use]` type", None, - "consider explicitly using expression value" + "consider explicitly using expression value", ); } else if is_must_use_func_call(cx, init) { span_lint_and_help( @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { local.span, "non-binding let on a result of a `#[must_use]` function", None, - "consider explicitly using function result" + "consider explicitly using function result", ); } } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 2b1c5688e82..27ba27202bf 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -263,7 +263,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { match res { Res::Local(hir_id) => { let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id); - let extent = self.cx + let extent = self + .cx .tcx .region_scope_tree(parent_def_id) .var_scope(hir_id.local_id) @@ -274,11 +275,12 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), ); } else { - self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent)); + self.indexed_indirectly + .insert(seqvar.segments[0].ident.name, Some(extent)); } - return false; // no need to walk further *on the variable* - } - Res::Def(DefKind::Static (_)| DefKind::Const, ..) => { + return false; // no need to walk further *on the variable* + }, + Res::Def(DefKind::Static(_) | DefKind::Const, ..) => { if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, @@ -287,8 +289,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { } else { self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); } - return false; // no need to walk further *on the variable* - } + return false; // no need to walk further *on the variable* + }, _ => (), } } @@ -310,14 +312,18 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if (meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id)) || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id)); if !self.check(args_1, args_0, expr); - then { return } + then { + return; + } } if_chain! { // an index op if let ExprKind::Index(seqexpr, idx) = expr.kind; if !self.check(idx, seqexpr, expr); - then { return } + then { + return; + } } if_chain! { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 570d83c7ea8..090f9f8ff73 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -139,9 +139,9 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t if args.bindings.len() == 1; let binding = &args.bindings[0]; if binding.ident.name == sym::Output; - if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind; + if let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind; then { - return Some(output) + return Some(output); } } @@ -180,7 +180,10 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .from_generator_fn() .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id)); if args.len() == 1; - if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0]; + if let Expr { + kind: ExprKind::Closure(&Closure { body, .. }), + .. + } = args[0]; let closure_body = cx.tcx.hir().body(body); if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); then { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b0677d1a3ae..fb92779be2a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3370,7 +3370,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()) + .self_ty() + .skip_binder(); wrong_self_convention::check( cx, item.ident.name.as_str(), @@ -3378,7 +3380,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { first_arg_ty, first_arg_span, false, - true + true, ); } } @@ -3387,7 +3389,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()) + .self_ty() + .skip_binder(); if !ret_ty.contains(self_ty); then { diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6e10445659e..991d3dd538b 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -121,10 +121,9 @@ pub(super) fn check<'tcx>( macro_expanded_snipped = snippet(cx, snippet_span, ".."); match macro_expanded_snipped.strip_prefix("$crate::vec::") { Some(stripped) => Cow::from(stripped), - None => macro_expanded_snipped + None => macro_expanded_snipped, } - } - else { + } else { not_macro_argument_snippet } }; diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index c949cede8e1..5c2b96f5b2c 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -47,14 +47,12 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]); impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if !in_external_macro(cx.sess(), expr.span); if let ExprKind::Unary(UnOp::Not, inner) = expr.kind; if let ExprKind::Binary(ref op, left, _) = inner.kind; if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node; then { - let ty = cx.typeck_results().expr_ty(left); let implements_ord = { @@ -81,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { "the use of negated comparison operators on partially ordered \ types produces code that is hard to read and refactor, please \ consider using the `partial_cmp` method instead, to make it \ - clear that the two values could be incomparable" + clear that the two values could be incomparable", ); } } diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index fc2ee9e5a4d..1307288623f 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -98,11 +98,15 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve if trait_pred.self_ty() == inp; if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred); then { - if ord_preds.iter().any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) { + if ord_preds + .iter() + .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) + { args_to_check.push((i, "Ord".to_string())); - } else if partial_ord_preds.iter().any(|pord| { - pord.self_ty() == return_ty_pred.term.ty().unwrap() - }) { + } else if partial_ord_preds + .iter() + .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) + { args_to_check.push((i, "PartialOrd".to_string())); } } diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index c9089aecfa5..d7666b77f6e 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -92,7 +92,12 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { let mut sle = SpanlessEq::new(cx).deny_side_effects(); match ps.ident.as_str() { "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { - suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args)); + suggest_suggestion( + cx, + expr, + &and_then_snippets, + &span_suggestion_snippets(cx, span_call_args), + ); }, "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); @@ -105,12 +110,12 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { "help" => { let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); - } + }, "note" => { let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); - } - _ => (), + }, + _ => (), } } } diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index d7e4a2c4422..cacd05262a2 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -61,8 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { let fn_name = path.ident; if let Some(sugg) = self.map.get(fn_name.as_str()); let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if match_type(cx, ty, &paths::EARLY_CONTEXT) - || match_type(cx, ty, &paths::LATE_CONTEXT); + if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); then { span_lint_and_help( cx, diff --git a/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/clippy_lints/src/utils/internal_lints/if_chain_style.rs index a863fdc9d50..883a5c08e5c 100644 --- a/clippy_lints/src/utils/internal_lints/if_chain_style.rs +++ b/clippy_lints/src/utils/internal_lints/if_chain_style.rs @@ -94,7 +94,10 @@ fn check_nested_if_chains( .iter() .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span)); if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr); - then {} else { return } + then { + } else { + return; + } } let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) { (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"), diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 04f1952e813..25532dd4e26 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -41,14 +41,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { let body = cx.tcx.hir().body(body_id); let typeck_results = cx.tcx.typeck_body(body_id); if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value); - let path: Vec<&str> = path.iter().map(|x| { + let path: Vec<&str> = path + .iter() + .map(|x| { if let Constant::Str(s) = x { s.as_str() } else { // We checked the type of the constant above unreachable!() } - }).collect(); + }) + .collect(); if !check_path(cx, &path[..]); then { span_lint(cx, INVALID_PATHS, item.span, "invalid path"); diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 06dfc6e4360..0dac64376b0 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -317,11 +317,7 @@ pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item< if tool_name.ident.name == sym::clippy; if attr_name.ident.name == sym::version; if let Some(version) = attr.value_str(); - then { - Some(version) - } else { - None - } + then { Some(version) } else { None } } }) } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 8efe170a1e5..d06a616e4b3 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -532,7 +532,11 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec, String)> { // Extract lints doc_comment.make_ascii_lowercase(); - let lints: Vec = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect(); + let lints: Vec = doc_comment + .split_off(DOC_START.len()) + .split(", ") + .map(str::to_string) + .collect(); // Format documentation correctly // split off leading `.` from lint name list and indent for correct formatting diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs index 3bc05d69579..2b13fad8066 100644 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); if_chain! { if let ["expn_data", "outer_expn"] = method_names.as_slice(); - let (self_arg, args)= arg_lists[1]; + let (self_arg, args) = arg_lists[1]; if args.is_empty(); let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 0a3852c98ee..4cf76f53625 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -102,7 +102,7 @@ impl UnnecessaryDefPath { ]; if_chain! { - if let [cx_arg, def_arg, args@..] = args; + if let [cx_arg, def_arg, args @ ..] = args; if let ExprKind::Path(path) = &func.kind; if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if let Some(which_path) = match_any_def_paths(cx, id, PATHS); @@ -113,6 +113,7 @@ impl UnnecessaryDefPath { if let Some(def_id) = inherent_def_path_res(cx, &segments[..]); then { // Check if the target item is a diagnostic item or LangItem. + #[rustfmt::skip] let (msg, item) = if let Some(item_name) = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) { @@ -133,11 +134,11 @@ impl UnnecessaryDefPath { DefKind::Struct => { let variant = cx.tcx.adt_def(def_id).non_enum_variant(); variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - } + }, DefKind::Variant => { let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - } + }, _ => false, }; @@ -146,35 +147,40 @@ impl UnnecessaryDefPath { let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); let (sugg, with_note) = match (which_path, item) { // match_def_path - (0, Item::DiagnosticItem(item)) => - (format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), has_ctor), + (0, Item::DiagnosticItem(item)) => ( + format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), + has_ctor, + ), (0, Item::LangItem(item)) => ( format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"), - has_ctor + has_ctor, ), // match_trait_method - (1, Item::DiagnosticItem(item)) => - (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false), + (1, Item::DiagnosticItem(item)) => { + (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false) + }, // match_type - (2, Item::DiagnosticItem(item)) => - (format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false), - (2, Item::LangItem(item)) => - (format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), false), + (2, Item::DiagnosticItem(item)) => ( + format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), + false, + ), + (2, Item::LangItem(item)) => ( + format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), + false, + ), // is_expr_path_def_path (3, Item::DiagnosticItem(item)) if has_ctor => ( - format!( - "is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})", - ), + format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",), false, ), (3, Item::LangItem(item)) if has_ctor => ( - format!( - "is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})", - ), + format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",), + false, + ), + (3, Item::DiagnosticItem(item)) => ( + format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false, ), - (3, Item::DiagnosticItem(item)) => - (format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false), (3, Item::LangItem(item)) => ( format!( "path_res({cx_snip}, {def_snip}).opt_def_id()\ @@ -185,21 +191,15 @@ impl UnnecessaryDefPath { _ => return, }; - span_lint_and_then( - cx, - UNNECESSARY_DEF_PATH, - span, - msg, - |diag| { - diag.span_suggestion(span, "try", sugg, app); - if with_note { - diag.help( - "if this `DefId` came from a constructor expression or pattern then the \ - parent `DefId` should be used instead" - ); - } - }, - ); + span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| { + diag.span_suggestion(span, "try", sugg, app); + if with_note { + diag.help( + "if this `DefId` came from a constructor expression or pattern then the \ + parent `DefId` should be used instead", + ); + } + }); self.linted_def_ids.insert(def_id); } -- cgit 1.4.1-3-g733a5 From 655175494574265257f52f4f7a1e7eabd85cbe77 Mon Sep 17 00:00:00 2001 From: kraktus Date: Fri, 21 Oct 2022 15:27:25 +0200 Subject: [`unwrap_used`], [`expect_used`] do not lint in `test` cfg --- clippy_lints/src/methods/expect_used.rs | 4 ++-- clippy_lints/src/methods/unwrap_used.rs | 4 ++-- clippy_lints/src/utils/conf.rs | 4 ++-- tests/ui-toml/expect_used/expect_used.rs | 23 ++++++++++++++--------- tests/ui-toml/unwrap_used/unwrap_used.rs | 21 +++++++++++++++++---- tests/ui-toml/unwrap_used/unwrap_used.stderr | 6 +++--- 6 files changed, 40 insertions(+), 22 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index d59fefa1ddc..0d3c8928046 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_cfg_test; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; @@ -27,7 +27,7 @@ pub(super) fn check( let method = if is_err { "expect_err" } else { "expect" }; - if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { + if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index ee17f2d7889..d11830a24b6 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_in_test_function, is_lint_allowed}; +use clippy_utils::{is_in_cfg_test, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; @@ -27,7 +27,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { + if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 668123e4d6e..199dfafebf3 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -373,11 +373,11 @@ define_Conf! { (max_include_file_size: u64 = 1_000_000), /// Lint: EXPECT_USED. /// - /// Whether `expect` should be allowed in test functions + /// Whether `expect` should be allowed in test cfg (allow_expect_in_tests: bool = false), /// Lint: UNWRAP_USED. /// - /// Whether `unwrap` should be allowed in test functions + /// Whether `unwrap` should be allowed in test cfg (allow_unwrap_in_tests: bool = false), /// Lint: DBG_MACRO. /// diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs index 22dcd3ae9d6..bff97d97df7 100644 --- a/tests/ui-toml/expect_used/expect_used.rs +++ b/tests/ui-toml/expect_used/expect_used.rs @@ -16,14 +16,19 @@ fn main() { expect_result(); } -#[test] -fn test_expect_option() { - let opt = Some(0); - let _ = opt.expect(""); -} +#[cfg(test)] +mod issue9612 { + // should not lint in `#[cfg(test)]` modules + #[test] + fn test_fn() { + let _a: u8 = 2.try_into().unwrap(); + let _a: u8 = 3.try_into().expect(""); -#[test] -fn test_expect_result() { - let res: Result = Ok(0); - let _ = res.expect(""); + util(); + } + + fn util() { + let _a: u8 = 4.try_into().unwrap(); + let _a: u8 = 5.try_into().expect(""); + } } diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index 0e82fb20e45..bc8e8c1f070 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -66,8 +66,21 @@ fn main() { } } -#[test] -fn test() { - let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); - let _ = boxed_slice.get(1).unwrap(); +#[cfg(test)] +mod issue9612 { + // should not lint in `#[cfg(test)]` modules + #[test] + fn test_fn() { + let _a: u8 = 2.try_into().unwrap(); + let _a: u8 = 3.try_into().expect(""); + + util(); + } + + fn util() { + let _a: u8 = 4.try_into().unwrap(); + let _a: u8 = 5.try_into().expect(""); + // should still warn + let _ = Box::new([0]).get(1).unwrap(); + } } diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 681b5eaf54d..2bca88660e1 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -188,10 +188,10 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:72:13 + --> $DIR/unwrap_used.rs:84:17 | -LL | let _ = boxed_slice.get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` +LL | let _ = Box::new([0]).get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]` error: aborting due to 27 previous errors -- cgit 1.4.1-3-g733a5 From a41cb7adbeaa1dae9cf5f371bc02061c63caaf81 Mon Sep 17 00:00:00 2001 From: koka Date: Sat, 22 Oct 2022 16:36:36 +0900 Subject: fix: support `map_or` for `or_fun_call` lint * add `rest_arg` to pass second argument from `map_or(U, F)` * extract some procedures into closure refac: rename rest_arg/second_arg refac: organize function argument order * put `second_arg` next to `arg` argument --- clippy_lints/src/methods/or_fun_call.rs | 57 ++++++++++++++++++++++++--------- tests/ui/manual_ok_or.fixed | 1 + tests/ui/manual_ok_or.rs | 1 + tests/ui/manual_ok_or.stderr | 8 ++--- tests/ui/or_fun_call.fixed | 16 +++++++++ tests/ui/or_fun_call.rs | 16 +++++++++ tests/ui/or_fun_call.stderr | 14 +++++++- 7 files changed, 92 insertions(+), 21 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 991d3dd538b..4460f38fcc1 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -83,6 +83,8 @@ pub(super) fn check<'tcx>( method_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, + // `Some` if fn has second argument + second_arg: Option<&hir::Expr<'_>>, span: Span, // None if lambda is required fun_span: Option, @@ -109,30 +111,40 @@ pub(super) fn check<'tcx>( if poss.contains(&name); then { - let macro_expanded_snipped; - let sugg: Cow<'_, str> = { + let sugg = { let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { (false, Some(fun_span)) => (fun_span, false), _ => (arg.span, true), }; - let snippet = { - let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); - if not_macro_argument_snippet == "vec![]" { - macro_expanded_snipped = snippet(cx, snippet_span, ".."); + + let format_span = |span: Span| { + let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, ".."); + let snip = if not_macro_argument_snippet == "vec![]" { + let macro_expanded_snipped = snippet(cx, snippet_span, ".."); match macro_expanded_snipped.strip_prefix("$crate::vec::") { - Some(stripped) => Cow::from(stripped), + Some(stripped) => Cow::Owned(stripped.to_owned()), None => macro_expanded_snipped, } } else { not_macro_argument_snippet - } + }; + + snip.to_string() }; - if use_lambda { + let snip = format_span(snippet_span); + let snip = if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; - format!("|{l_arg}| {snippet}").into() + format!("|{l_arg}| {snip}") } else { - snippet + snip + }; + + if let Some(f) = second_arg { + let f = format_span(f.span); + format!("{snip}, {f}") + } else { + snip } }; let span_replace_word = method_span.with_hi(span.hi()); @@ -149,8 +161,8 @@ pub(super) fn check<'tcx>( } } - if let [arg] = args { - let inner_arg = if let hir::ExprKind::Block( + let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| { + if let hir::ExprKind::Block( hir::Block { stmts: [], expr: Some(expr), @@ -162,19 +174,32 @@ pub(super) fn check<'tcx>( expr } else { arg - }; + } + }; + + if let [arg] = args { + let inner_arg = extract_inner_arg(arg); match inner_arg.kind { hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span); + check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span); } }, hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, receiver, arg, expr.span, None); + check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None); }, _ => (), } } + + // `map_or` takes two arguments + if let [arg, lambda] = args { + let inner_arg = extract_inner_arg(arg); + if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind { + let fun_span = if or_args.is_empty() { Some(fun.span) } else { None }; + check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span); + } + } } diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index d864f855453..fc8511626b3 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] +#![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index 6264768460e..b5303d33f5f 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -1,5 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] +#![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] diff --git a/tests/ui/manual_ok_or.stderr b/tests/ui/manual_ok_or.stderr index 65459a09738..b4a17f143e3 100644 --- a/tests/ui/manual_ok_or.stderr +++ b/tests/ui/manual_ok_or.stderr @@ -1,5 +1,5 @@ error: this pattern reimplements `Option::ok_or` - --> $DIR/manual_ok_or.rs:11:5 + --> $DIR/manual_ok_or.rs:12:5 | LL | foo.map_or(Err("error"), |v| Ok(v)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` @@ -7,19 +7,19 @@ LL | foo.map_or(Err("error"), |v| Ok(v)); = note: `-D clippy::manual-ok-or` implied by `-D warnings` error: this pattern reimplements `Option::ok_or` - --> $DIR/manual_ok_or.rs:14:5 + --> $DIR/manual_ok_or.rs:15:5 | LL | foo.map_or(Err("error"), Ok); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` error: this pattern reimplements `Option::ok_or` - --> $DIR/manual_ok_or.rs:17:5 + --> $DIR/manual_ok_or.rs:18:5 | LL | None::.map_or(Err("error"), |v| Ok(v)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `None::.ok_or("error")` error: this pattern reimplements `Option::ok_or` - --> $DIR/manual_ok_or.rs:21:5 + --> $DIR/manual_ok_or.rs:22:5 | LL | / foo.map_or(Err::( LL | | &format!( diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 23b1aa8bebd..be9a65506e1 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -236,4 +236,20 @@ mod issue9608 { } } +mod issue8993 { + fn g() -> i32 { + 3 + } + + fn f(n: i32) -> i32 { + n + } + + fn test_map_or() { + let _ = Some(4).map_or_else(g, |v| v); + let _ = Some(4).map_or_else(g, f); + let _ = Some(4).map_or(0, f); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 039998f22dd..628c9704638 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -236,4 +236,20 @@ mod issue9608 { } } +mod issue8993 { + fn g() -> i32 { + 3 + } + + fn f(n: i32) -> i32 { + n + } + + fn test_map_or() { + let _ = Some(4).map_or(g(), |v| v); + let _ = Some(4).map_or(g(), f); + let _ = Some(4).map_or(0, f); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 113ba150c61..ba3001db7a5 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -156,5 +156,17 @@ error: use of `unwrap_or` followed by a call to `new` LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` -error: aborting due to 26 previous errors +error: use of `map_or` followed by a function call + --> $DIR/or_fun_call.rs:249:25 + | +LL | let _ = Some(4).map_or(g(), |v| v); + | ^^^^^^^^^^^^^^^^^^ help: try this: `map_or_else(g, |v| v)` + +error: use of `map_or` followed by a function call + --> $DIR/or_fun_call.rs:250:25 + | +LL | let _ = Some(4).map_or(g(), f); + | ^^^^^^^^^^^^^^ help: try this: `map_or_else(g, f)` + +error: aborting due to 28 previous errors -- cgit 1.4.1-3-g733a5 From 8d6ce3177bd5d4d05723dec1cdd869effc926fc3 Mon Sep 17 00:00:00 2001 From: Doru-Florin Blanzeanu Date: Sun, 16 Oct 2022 19:31:03 +0000 Subject: Add new lint `rewind_instead_of_seek_to_start` Signed-off-by: Doru-Florin Blanzeanu --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 36 +++++++++ .../src/methods/rewind_instead_of_seek_to_start.rs | 45 +++++++++++ clippy_utils/src/paths.rs | 2 + src/docs/rewind_instead_of_seek_to_start.txt | 22 +++++ tests/ui/rewind_instead_of_seek_to_start.fixed | 94 ++++++++++++++++++++++ tests/ui/rewind_instead_of_seek_to_start.rs | 94 ++++++++++++++++++++++ tests/ui/rewind_instead_of_seek_to_start.stderr | 16 ++++ 9 files changed, 311 insertions(+) create mode 100644 clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs create mode 100644 src/docs/rewind_instead_of_seek_to_start.txt create mode 100644 tests/ui/rewind_instead_of_seek_to_start.fixed create mode 100644 tests/ui/rewind_instead_of_seek_to_start.rs create mode 100644 tests/ui/rewind_instead_of_seek_to_start.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index cb5a4d4a577..09f914fe0ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4195,6 +4195,7 @@ Released 2018-09-13 [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges +[`rewind_instead_of_seek_to_start`]: https://rust-lang.github.io/rust-clippy/master/index.html#rewind_instead_of_seek_to_start [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index c6ae0bddc5a..ad482cfc2e7 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -361,6 +361,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, + crate::methods::REWIND_INSTEAD_OF_SEEK_TO_START_INFO, crate::methods::SEARCH_IS_SOME_INFO, crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fb92779be2a..e794af7d64b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -68,6 +68,7 @@ mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; mod repeat_once; +mod rewind_instead_of_seek_to_start; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -3066,6 +3067,37 @@ declare_clippy_lint! { "iterating on map using `iter` when `keys` or `values` would do" } +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: &mut T) { + /// t.seek(io::SeekFrom::Start(0)); + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::io; + /// fn foo(t: &mut T) { + /// t.rewind(); + /// } + /// ``` + #[clippy::version = "1.66.0"] + pub REWIND_INSTEAD_OF_SEEK_TO_START, + complexity, + "jumping to the start of stream using `seek` method" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3190,6 +3222,7 @@ impl_lint_pass!(Methods => [ VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, ITER_KV_MAP, + REWIND_INSTEAD_OF_SEEK_TO_START, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3604,6 +3637,9 @@ impl Methods { ("resize", [count_arg, default_arg]) => { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, + ("seek", [arg]) => { + rewind_instead_of_seek_to_start::check(cx, expr, recv, arg, span); + }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, diff --git a/clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs b/clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs new file mode 100644 index 00000000000..97b33dec843 --- /dev/null +++ b/clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::REWIND_INSTEAD_OF_SEEK_TO_START; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, + name_span: Span, +) { + // Get receiver type + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && + implements_trait(cx, ty, seek_trait_id, &[]) && + let ExprKind::Call(func, args1) = arg.kind && + let ExprKind::Path(ref path) = func.kind && + let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && + match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && + args1.len() == 1 && + let ExprKind::Lit(ref lit) = args1[0].kind && + let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + { + let method_call_span = expr.span.with_lo(name_span.lo()); + span_lint_and_then( + cx, + REWIND_INSTEAD_OF_SEEK_TO_START, + method_call_span, + "used `seek` to go to the start of the stream", + |diag| { + let app = Applicability::MachineApplicable; + + diag.span_suggestion(method_call_span, "replace with", "rewind()", app); + }, + ); + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index bc851473430..e37c7e34c0c 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -115,6 +115,8 @@ pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; +pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; +pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; diff --git a/src/docs/rewind_instead_of_seek_to_start.txt b/src/docs/rewind_instead_of_seek_to_start.txt new file mode 100644 index 00000000000..bef11b2312a --- /dev/null +++ b/src/docs/rewind_instead_of_seek_to_start.txt @@ -0,0 +1,22 @@ +### 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 +``` +fn foo(t: &mut T) { + t.seek(io::SeekFrom::Start(0)); +} +``` +Use instead: +``` +fn foo(t: &mut T) { + t.rewind(); +} +``` \ No newline at end of file diff --git a/tests/ui/rewind_instead_of_seek_to_start.fixed b/tests/ui/rewind_instead_of_seek_to_start.fixed new file mode 100644 index 00000000000..037a288b69b --- /dev/null +++ b/tests/ui/rewind_instead_of_seek_to_start.fixed @@ -0,0 +1,94 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::rewind_instead_of_seek_to_start)] + +use std::fs::OpenOptions; +use std::io::{Read, Seek, SeekFrom, Write}; + +struct StructWithSeekMethod {} + +impl StructWithSeekMethod { + fn seek(&mut self, from: SeekFrom) {} +} + +trait MySeekTrait { + fn seek(&mut self, from: SeekFrom) {} +} + +struct StructWithSeekTrait {} +impl MySeekTrait for StructWithSeekTrait {} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_bound(t: &mut T) { + t.seek(SeekFrom::Start(0)); +} + +// This should trigger clippy warning +fn seek_to_start(t: &mut T) { + t.rewind(); +} + +// This should trigger clippy warning +fn owned_seek_to_start(mut t: T) { + t.rewind(); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_5(t: &mut T) { + t.seek(SeekFrom::Start(5)); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_end(t: &mut T) { + t.seek(SeekFrom::End(0)); +} + +fn main() { + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let mut my_struct_trait = StructWithSeekTrait {}; + seek_to_start_false_trait_bound(&mut my_struct_trait); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + seek_to_5(&mut f); + seek_to_end(&mut f); + seek_to_start(&mut f); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} diff --git a/tests/ui/rewind_instead_of_seek_to_start.rs b/tests/ui/rewind_instead_of_seek_to_start.rs new file mode 100644 index 00000000000..2622425128d --- /dev/null +++ b/tests/ui/rewind_instead_of_seek_to_start.rs @@ -0,0 +1,94 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::rewind_instead_of_seek_to_start)] + +use std::fs::OpenOptions; +use std::io::{Read, Seek, SeekFrom, Write}; + +struct StructWithSeekMethod {} + +impl StructWithSeekMethod { + fn seek(&mut self, from: SeekFrom) {} +} + +trait MySeekTrait { + fn seek(&mut self, from: SeekFrom) {} +} + +struct StructWithSeekTrait {} +impl MySeekTrait for StructWithSeekTrait {} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_bound(t: &mut T) { + t.seek(SeekFrom::Start(0)); +} + +// This should trigger clippy warning +fn seek_to_start(t: &mut T) { + t.seek(SeekFrom::Start(0)); +} + +// This should trigger clippy warning +fn owned_seek_to_start(mut t: T) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_5(t: &mut T) { + t.seek(SeekFrom::Start(5)); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_end(t: &mut T) { + t.seek(SeekFrom::End(0)); +} + +fn main() { + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let mut my_struct_trait = StructWithSeekTrait {}; + seek_to_start_false_trait_bound(&mut my_struct_trait); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + seek_to_5(&mut f); + seek_to_end(&mut f); + seek_to_start(&mut f); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} diff --git a/tests/ui/rewind_instead_of_seek_to_start.stderr b/tests/ui/rewind_instead_of_seek_to_start.stderr new file mode 100644 index 00000000000..f985471ac05 --- /dev/null +++ b/tests/ui/rewind_instead_of_seek_to_start.stderr @@ -0,0 +1,16 @@ +error: used `seek` to go to the start of the stream + --> $DIR/rewind_instead_of_seek_to_start.rs:53:7 + | +LL | t.seek(SeekFrom::Start(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` + | + = note: `-D clippy::rewind-instead-of-seek-to-start` implied by `-D warnings` + +error: used `seek` to go to the start of the stream + --> $DIR/rewind_instead_of_seek_to_start.rs:58:7 + | +LL | t.seek(SeekFrom::Start(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From b48a4668f4767412b3d9797ce3d6ee63f351caee Mon Sep 17 00:00:00 2001 From: Doru-Florin Blanzeanu Date: Fri, 21 Oct 2022 16:08:04 +0000 Subject: Add msrv check for `rewind_instead_of_seek_to_start` lint Signed-off-by: Doru-Florin Blanzeanu --- clippy_lints/src/methods/mod.rs | 4 ++- clippy_utils/src/msrvs.rs | 1 + tests/ui/rewind_instead_of_seek_to_start.fixed | 43 +++++++++++++++++++++++++ tests/ui/rewind_instead_of_seek_to_start.rs | 43 +++++++++++++++++++++++++ tests/ui/rewind_instead_of_seek_to_start.stderr | 12 +++++-- 5 files changed, 99 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e794af7d64b..7b0a676e89e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3638,7 +3638,9 @@ impl Methods { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, ("seek", [arg]) => { - rewind_instead_of_seek_to_start::check(cx, expr, recv, arg, span); + if meets_msrv(self.msrv, msrvs::SEEK_REWIND) { + rewind_instead_of_seek_to_start::check(cx, expr, recv, arg, span); + } }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 8b843732a23..6f77155ec3e 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -37,4 +37,5 @@ msrv_aliases! { 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } + 1,55,0 { SEEK_REWIND } } diff --git a/tests/ui/rewind_instead_of_seek_to_start.fixed b/tests/ui/rewind_instead_of_seek_to_start.fixed index 037a288b69b..36853780977 100644 --- a/tests/ui/rewind_instead_of_seek_to_start.fixed +++ b/tests/ui/rewind_instead_of_seek_to_start.fixed @@ -1,5 +1,6 @@ // run-rustfix #![allow(unused)] +#![feature(custom_inner_attributes)] #![warn(clippy::rewind_instead_of_seek_to_start)] use std::fs::OpenOptions; @@ -92,3 +93,45 @@ fn main() { assert_eq!(&buf, hello); } + +fn msrv_1_54() { + #![clippy::msrv = "1.54"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.seek(SeekFrom::Start(0)); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} + +fn msrv_1_55() { + #![clippy::msrv = "1.55"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.rewind(); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} diff --git a/tests/ui/rewind_instead_of_seek_to_start.rs b/tests/ui/rewind_instead_of_seek_to_start.rs index 2622425128d..0d061b58fba 100644 --- a/tests/ui/rewind_instead_of_seek_to_start.rs +++ b/tests/ui/rewind_instead_of_seek_to_start.rs @@ -1,5 +1,6 @@ // run-rustfix #![allow(unused)] +#![feature(custom_inner_attributes)] #![warn(clippy::rewind_instead_of_seek_to_start)] use std::fs::OpenOptions; @@ -92,3 +93,45 @@ fn main() { assert_eq!(&buf, hello); } + +fn msrv_1_54() { + #![clippy::msrv = "1.54"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.seek(SeekFrom::Start(0)); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} + +fn msrv_1_55() { + #![clippy::msrv = "1.55"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.seek(SeekFrom::Start(0)); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} diff --git a/tests/ui/rewind_instead_of_seek_to_start.stderr b/tests/ui/rewind_instead_of_seek_to_start.stderr index f985471ac05..e8086781084 100644 --- a/tests/ui/rewind_instead_of_seek_to_start.stderr +++ b/tests/ui/rewind_instead_of_seek_to_start.stderr @@ -1,5 +1,5 @@ error: used `seek` to go to the start of the stream - --> $DIR/rewind_instead_of_seek_to_start.rs:53:7 + --> $DIR/rewind_instead_of_seek_to_start.rs:54:7 | LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` @@ -7,10 +7,16 @@ LL | t.seek(SeekFrom::Start(0)); = note: `-D clippy::rewind-instead-of-seek-to-start` implied by `-D warnings` error: used `seek` to go to the start of the stream - --> $DIR/rewind_instead_of_seek_to_start.rs:58:7 + --> $DIR/rewind_instead_of_seek_to_start.rs:59:7 | LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` -error: aborting due to 2 previous errors +error: used `seek` to go to the start of the stream + --> $DIR/rewind_instead_of_seek_to_start.rs:131:7 + | +LL | f.seek(SeekFrom::Start(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From b9b9d6a751ca3a9ccdd64f50390361e339f5124f Mon Sep 17 00:00:00 2001 From: Doru-Florin Blanzeanu Date: Mon, 24 Oct 2022 15:54:08 +0000 Subject: Change lint name to `seek_to_start_instead_of_rewind` - This name makes more sense and highlights the issue Signed-off-by: Doru-Florin Blanzeanu --- CHANGELOG.md | 2 +- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/methods/mod.rs | 8 +- .../src/methods/rewind_instead_of_seek_to_start.rs | 45 ------- .../src/methods/seek_to_start_instead_of_rewind.rs | 45 +++++++ src/docs/rewind_instead_of_seek_to_start.txt | 22 ---- src/docs/seek_to_start_instead_of_rewind.txt | 22 ++++ tests/ui/rewind_instead_of_seek_to_start.fixed | 137 --------------------- tests/ui/rewind_instead_of_seek_to_start.rs | 137 --------------------- tests/ui/rewind_instead_of_seek_to_start.stderr | 22 ---- tests/ui/seek_to_start_instead_of_rewind.fixed | 137 +++++++++++++++++++++ tests/ui/seek_to_start_instead_of_rewind.rs | 137 +++++++++++++++++++++ tests/ui/seek_to_start_instead_of_rewind.stderr | 22 ++++ 13 files changed, 369 insertions(+), 369 deletions(-) delete mode 100644 clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs create mode 100644 clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs delete mode 100644 src/docs/rewind_instead_of_seek_to_start.txt create mode 100644 src/docs/seek_to_start_instead_of_rewind.txt delete mode 100644 tests/ui/rewind_instead_of_seek_to_start.fixed delete mode 100644 tests/ui/rewind_instead_of_seek_to_start.rs delete mode 100644 tests/ui/rewind_instead_of_seek_to_start.stderr create mode 100644 tests/ui/seek_to_start_instead_of_rewind.fixed create mode 100644 tests/ui/seek_to_start_instead_of_rewind.rs create mode 100644 tests/ui/seek_to_start_instead_of_rewind.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f914fe0ca..ae9fc46a42f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4195,11 +4195,11 @@ Released 2018-09-13 [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges -[`rewind_instead_of_seek_to_start`]: https://rust-lang.github.io/rust-clippy/master/index.html#rewind_instead_of_seek_to_start [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some +[`seek_to_start_instead_of_rewind`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_to_start_instead_of_rewind [`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ad482cfc2e7..5d963bb5488 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -361,8 +361,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, - crate::methods::REWIND_INSTEAD_OF_SEEK_TO_START_INFO, crate::methods::SEARCH_IS_SOME_INFO, + crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO, crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, crate::methods::SINGLE_CHAR_PATTERN_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7b0a676e89e..4fd1e3e54ae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -68,8 +68,8 @@ mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; mod repeat_once; -mod rewind_instead_of_seek_to_start; mod search_is_some; +mod seek_to_start_instead_of_rewind; mod single_char_add_str; mod single_char_insert_string; mod single_char_pattern; @@ -3093,7 +3093,7 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.66.0"] - pub REWIND_INSTEAD_OF_SEEK_TO_START, + pub SEEK_TO_START_INSTEAD_OF_REWIND, complexity, "jumping to the start of stream using `seek` method" } @@ -3222,7 +3222,7 @@ impl_lint_pass!(Methods => [ VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, ITER_KV_MAP, - REWIND_INSTEAD_OF_SEEK_TO_START, + SEEK_TO_START_INSTEAD_OF_REWIND, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3639,7 +3639,7 @@ impl Methods { }, ("seek", [arg]) => { if meets_msrv(self.msrv, msrvs::SEEK_REWIND) { - rewind_instead_of_seek_to_start::check(cx, expr, recv, arg, span); + seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } }, ("sort", []) => { diff --git a/clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs b/clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs deleted file mode 100644 index 97b33dec843..00000000000 --- a/clippy_lints/src/methods/rewind_instead_of_seek_to_start.rs +++ /dev/null @@ -1,45 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_def_path, paths}; -use rustc_ast::ast::{LitIntType, LitKind}; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::LateContext; -use rustc_span::Span; - -use super::REWIND_INSTEAD_OF_SEEK_TO_START; - -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - recv: &'tcx Expr<'_>, - arg: &'tcx Expr<'_>, - name_span: Span, -) { - // Get receiver type - let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - - if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && - implements_trait(cx, ty, seek_trait_id, &[]) && - let ExprKind::Call(func, args1) = arg.kind && - let ExprKind::Path(ref path) = func.kind && - let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && - args1.len() == 1 && - let ExprKind::Lit(ref lit) = args1[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node - { - let method_call_span = expr.span.with_lo(name_span.lo()); - span_lint_and_then( - cx, - REWIND_INSTEAD_OF_SEEK_TO_START, - method_call_span, - "used `seek` to go to the start of the stream", - |diag| { - let app = Applicability::MachineApplicable; - - diag.span_suggestion(method_call_span, "replace with", "rewind()", app); - }, - ); - } -} diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs new file mode 100644 index 00000000000..7e3bed1e41a --- /dev/null +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::SEEK_TO_START_INSTEAD_OF_REWIND; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, + name_span: Span, +) { + // Get receiver type + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && + implements_trait(cx, ty, seek_trait_id, &[]) && + let ExprKind::Call(func, args1) = arg.kind && + let ExprKind::Path(ref path) = func.kind && + let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && + match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && + args1.len() == 1 && + let ExprKind::Lit(ref lit) = args1[0].kind && + let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + { + let method_call_span = expr.span.with_lo(name_span.lo()); + span_lint_and_then( + cx, + SEEK_TO_START_INSTEAD_OF_REWIND, + method_call_span, + "used `seek` to go to the start of the stream", + |diag| { + let app = Applicability::MachineApplicable; + + diag.span_suggestion(method_call_span, "replace with", "rewind()", app); + }, + ); + } +} diff --git a/src/docs/rewind_instead_of_seek_to_start.txt b/src/docs/rewind_instead_of_seek_to_start.txt deleted file mode 100644 index bef11b2312a..00000000000 --- a/src/docs/rewind_instead_of_seek_to_start.txt +++ /dev/null @@ -1,22 +0,0 @@ -### 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 -``` -fn foo(t: &mut T) { - t.seek(io::SeekFrom::Start(0)); -} -``` -Use instead: -``` -fn foo(t: &mut T) { - t.rewind(); -} -``` \ No newline at end of file diff --git a/src/docs/seek_to_start_instead_of_rewind.txt b/src/docs/seek_to_start_instead_of_rewind.txt new file mode 100644 index 00000000000..bef11b2312a --- /dev/null +++ b/src/docs/seek_to_start_instead_of_rewind.txt @@ -0,0 +1,22 @@ +### 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 +``` +fn foo(t: &mut T) { + t.seek(io::SeekFrom::Start(0)); +} +``` +Use instead: +``` +fn foo(t: &mut T) { + t.rewind(); +} +``` \ No newline at end of file diff --git a/tests/ui/rewind_instead_of_seek_to_start.fixed b/tests/ui/rewind_instead_of_seek_to_start.fixed deleted file mode 100644 index 36853780977..00000000000 --- a/tests/ui/rewind_instead_of_seek_to_start.fixed +++ /dev/null @@ -1,137 +0,0 @@ -// run-rustfix -#![allow(unused)] -#![feature(custom_inner_attributes)] -#![warn(clippy::rewind_instead_of_seek_to_start)] - -use std::fs::OpenOptions; -use std::io::{Read, Seek, SeekFrom, Write}; - -struct StructWithSeekMethod {} - -impl StructWithSeekMethod { - fn seek(&mut self, from: SeekFrom) {} -} - -trait MySeekTrait { - fn seek(&mut self, from: SeekFrom) {} -} - -struct StructWithSeekTrait {} -impl MySeekTrait for StructWithSeekTrait {} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait_bound(t: &mut T) { - t.seek(SeekFrom::Start(0)); -} - -// This should trigger clippy warning -fn seek_to_start(t: &mut T) { - t.rewind(); -} - -// This should trigger clippy warning -fn owned_seek_to_start(mut t: T) { - t.rewind(); -} - -// This should NOT trigger clippy warning because -// it does not seek to start -fn seek_to_5(t: &mut T) { - t.seek(SeekFrom::Start(5)); -} - -// This should NOT trigger clippy warning because -// it does not seek to start -fn seek_to_end(t: &mut T) { - t.seek(SeekFrom::End(0)); -} - -fn main() { - let mut f = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .open("foo.txt") - .unwrap(); - - let mut my_struct_trait = StructWithSeekTrait {}; - seek_to_start_false_trait_bound(&mut my_struct_trait); - - let hello = "Hello!\n"; - write!(f, "{hello}").unwrap(); - seek_to_5(&mut f); - seek_to_end(&mut f); - seek_to_start(&mut f); - - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - - assert_eq!(&buf, hello); -} - -fn msrv_1_54() { - #![clippy::msrv = "1.54"] - - let mut f = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .open("foo.txt") - .unwrap(); - - let hello = "Hello!\n"; - write!(f, "{hello}").unwrap(); - - f.seek(SeekFrom::Start(0)); - - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - - assert_eq!(&buf, hello); -} - -fn msrv_1_55() { - #![clippy::msrv = "1.55"] - - let mut f = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .open("foo.txt") - .unwrap(); - - let hello = "Hello!\n"; - write!(f, "{hello}").unwrap(); - - f.rewind(); - - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - - assert_eq!(&buf, hello); -} diff --git a/tests/ui/rewind_instead_of_seek_to_start.rs b/tests/ui/rewind_instead_of_seek_to_start.rs deleted file mode 100644 index 0d061b58fba..00000000000 --- a/tests/ui/rewind_instead_of_seek_to_start.rs +++ /dev/null @@ -1,137 +0,0 @@ -// run-rustfix -#![allow(unused)] -#![feature(custom_inner_attributes)] -#![warn(clippy::rewind_instead_of_seek_to_start)] - -use std::fs::OpenOptions; -use std::io::{Read, Seek, SeekFrom, Write}; - -struct StructWithSeekMethod {} - -impl StructWithSeekMethod { - fn seek(&mut self, from: SeekFrom) {} -} - -trait MySeekTrait { - fn seek(&mut self, from: SeekFrom) {} -} - -struct StructWithSeekTrait {} -impl MySeekTrait for StructWithSeekTrait {} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait_bound(t: &mut T) { - t.seek(SeekFrom::Start(0)); -} - -// This should trigger clippy warning -fn seek_to_start(t: &mut T) { - t.seek(SeekFrom::Start(0)); -} - -// This should trigger clippy warning -fn owned_seek_to_start(mut t: T) { - t.seek(SeekFrom::Start(0)); -} - -// This should NOT trigger clippy warning because -// it does not seek to start -fn seek_to_5(t: &mut T) { - t.seek(SeekFrom::Start(5)); -} - -// This should NOT trigger clippy warning because -// it does not seek to start -fn seek_to_end(t: &mut T) { - t.seek(SeekFrom::End(0)); -} - -fn main() { - let mut f = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .open("foo.txt") - .unwrap(); - - let mut my_struct_trait = StructWithSeekTrait {}; - seek_to_start_false_trait_bound(&mut my_struct_trait); - - let hello = "Hello!\n"; - write!(f, "{hello}").unwrap(); - seek_to_5(&mut f); - seek_to_end(&mut f); - seek_to_start(&mut f); - - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - - assert_eq!(&buf, hello); -} - -fn msrv_1_54() { - #![clippy::msrv = "1.54"] - - let mut f = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .open("foo.txt") - .unwrap(); - - let hello = "Hello!\n"; - write!(f, "{hello}").unwrap(); - - f.seek(SeekFrom::Start(0)); - - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - - assert_eq!(&buf, hello); -} - -fn msrv_1_55() { - #![clippy::msrv = "1.55"] - - let mut f = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .open("foo.txt") - .unwrap(); - - let hello = "Hello!\n"; - write!(f, "{hello}").unwrap(); - - f.seek(SeekFrom::Start(0)); - - let mut buf = String::new(); - f.read_to_string(&mut buf).unwrap(); - - assert_eq!(&buf, hello); -} diff --git a/tests/ui/rewind_instead_of_seek_to_start.stderr b/tests/ui/rewind_instead_of_seek_to_start.stderr deleted file mode 100644 index e8086781084..00000000000 --- a/tests/ui/rewind_instead_of_seek_to_start.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: used `seek` to go to the start of the stream - --> $DIR/rewind_instead_of_seek_to_start.rs:54:7 - | -LL | t.seek(SeekFrom::Start(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` - | - = note: `-D clippy::rewind-instead-of-seek-to-start` implied by `-D warnings` - -error: used `seek` to go to the start of the stream - --> $DIR/rewind_instead_of_seek_to_start.rs:59:7 - | -LL | t.seek(SeekFrom::Start(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` - -error: used `seek` to go to the start of the stream - --> $DIR/rewind_instead_of_seek_to_start.rs:131:7 - | -LL | f.seek(SeekFrom::Start(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed new file mode 100644 index 00000000000..464b6cdef63 --- /dev/null +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -0,0 +1,137 @@ +// run-rustfix +#![allow(unused)] +#![feature(custom_inner_attributes)] +#![warn(clippy::seek_to_start_instead_of_rewind)] + +use std::fs::OpenOptions; +use std::io::{Read, Seek, SeekFrom, Write}; + +struct StructWithSeekMethod {} + +impl StructWithSeekMethod { + fn seek(&mut self, from: SeekFrom) {} +} + +trait MySeekTrait { + fn seek(&mut self, from: SeekFrom) {} +} + +struct StructWithSeekTrait {} +impl MySeekTrait for StructWithSeekTrait {} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_bound(t: &mut T) { + t.seek(SeekFrom::Start(0)); +} + +// This should trigger clippy warning +fn seek_to_start(t: &mut T) { + t.rewind(); +} + +// This should trigger clippy warning +fn owned_seek_to_start(mut t: T) { + t.rewind(); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_5(t: &mut T) { + t.seek(SeekFrom::Start(5)); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_end(t: &mut T) { + t.seek(SeekFrom::End(0)); +} + +fn main() { + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let mut my_struct_trait = StructWithSeekTrait {}; + seek_to_start_false_trait_bound(&mut my_struct_trait); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + seek_to_5(&mut f); + seek_to_end(&mut f); + seek_to_start(&mut f); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} + +fn msrv_1_54() { + #![clippy::msrv = "1.54"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.seek(SeekFrom::Start(0)); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} + +fn msrv_1_55() { + #![clippy::msrv = "1.55"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.rewind(); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs new file mode 100644 index 00000000000..68e09bd7c1f --- /dev/null +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -0,0 +1,137 @@ +// run-rustfix +#![allow(unused)] +#![feature(custom_inner_attributes)] +#![warn(clippy::seek_to_start_instead_of_rewind)] + +use std::fs::OpenOptions; +use std::io::{Read, Seek, SeekFrom, Write}; + +struct StructWithSeekMethod {} + +impl StructWithSeekMethod { + fn seek(&mut self, from: SeekFrom) {} +} + +trait MySeekTrait { + fn seek(&mut self, from: SeekFrom) {} +} + +struct StructWithSeekTrait {} +impl MySeekTrait for StructWithSeekTrait {} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// StructWithSeekMethod does not implement std::io::Seek; +fn seek_to_start_false_trait_bound(t: &mut T) { + t.seek(SeekFrom::Start(0)); +} + +// This should trigger clippy warning +fn seek_to_start(t: &mut T) { + t.seek(SeekFrom::Start(0)); +} + +// This should trigger clippy warning +fn owned_seek_to_start(mut t: T) { + t.seek(SeekFrom::Start(0)); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_5(t: &mut T) { + t.seek(SeekFrom::Start(5)); +} + +// This should NOT trigger clippy warning because +// it does not seek to start +fn seek_to_end(t: &mut T) { + t.seek(SeekFrom::End(0)); +} + +fn main() { + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let mut my_struct_trait = StructWithSeekTrait {}; + seek_to_start_false_trait_bound(&mut my_struct_trait); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + seek_to_5(&mut f); + seek_to_end(&mut f); + seek_to_start(&mut f); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} + +fn msrv_1_54() { + #![clippy::msrv = "1.54"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.seek(SeekFrom::Start(0)); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} + +fn msrv_1_55() { + #![clippy::msrv = "1.55"] + + let mut f = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open("foo.txt") + .unwrap(); + + let hello = "Hello!\n"; + write!(f, "{hello}").unwrap(); + + f.seek(SeekFrom::Start(0)); + + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + + assert_eq!(&buf, hello); +} diff --git a/tests/ui/seek_to_start_instead_of_rewind.stderr b/tests/ui/seek_to_start_instead_of_rewind.stderr new file mode 100644 index 00000000000..de0eec5d909 --- /dev/null +++ b/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -0,0 +1,22 @@ +error: used `seek` to go to the start of the stream + --> $DIR/seek_to_start_instead_of_rewind.rs:54:7 + | +LL | t.seek(SeekFrom::Start(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` + | + = note: `-D clippy::seek-to-start-instead-of-rewind` implied by `-D warnings` + +error: used `seek` to go to the start of the stream + --> $DIR/seek_to_start_instead_of_rewind.rs:59:7 + | +LL | t.seek(SeekFrom::Start(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` + +error: used `seek` to go to the start of the stream + --> $DIR/seek_to_start_instead_of_rewind.rs:131:7 + | +LL | f.seek(SeekFrom::Start(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 6efb3a2b9ac9e0477b6b222c051c15c98233b424 Mon Sep 17 00:00:00 2001 From: koka Date: Tue, 25 Oct 2022 12:26:06 +0900 Subject: feat: add new lint `seek_from_current` addresses https://github.com/rust-lang/rust-clippy/issues/7886 added `seek_from_current` complexity lint. it checks use of `Seek#seek` with `SeekFrom::Current(0)` and suggests `Seek#stream_position` method fix: add msrv fix: register LintInfo fix: remove unnecessary files fix: add test for msrv fix: remove fix fix: remove docs --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 48 +++++++++++++++++++++++++++ clippy_lints/src/methods/seek_from_current.rs | 48 +++++++++++++++++++++++++++ clippy_utils/src/msrvs.rs | 2 +- clippy_utils/src/paths.rs | 1 + tests/ui/seek_from_current.fixed | 26 +++++++++++++++ tests/ui/seek_from_current.rs | 26 +++++++++++++++ tests/ui/seek_from_current.stderr | 10 ++++++ 9 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/seek_from_current.rs create mode 100644 tests/ui/seek_from_current.fixed create mode 100644 tests/ui/seek_from_current.rs create mode 100644 tests/ui/seek_from_current.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e91365c69a..b47e80f6979 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4200,6 +4200,7 @@ Released 2018-09-13 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some +[`seek_from_current`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current [`seek_to_start_instead_of_rewind`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_to_start_instead_of_rewind [`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a903d46b2a4..fff26307e34 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -363,6 +363,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, crate::methods::SEARCH_IS_SOME_INFO, + crate::methods::SEEK_FROM_CURRENT_INFO, crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO, crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4fd1e3e54ae..b29c7d9f253 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -69,6 +69,7 @@ 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; @@ -3067,6 +3068,49 @@ 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 + /// 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 + /// 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 /// @@ -3222,6 +3266,7 @@ impl_lint_pass!(Methods => [ VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, ITER_KV_MAP, + SEEK_FROM_CURRENT, SEEK_TO_START_INSTEAD_OF_REWIND, ]); @@ -3638,6 +3683,9 @@ impl Methods { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, ("seek", [arg]) => { + if meets_msrv(self.msrv, msrvs::SEEK_FROM_CURRENT) { + seek_from_current::check(cx, expr, recv, arg); + } if meets_msrv(self.msrv, msrvs::SEEK_REWIND) { seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs new file mode 100644 index 00000000000..361a3082f94 --- /dev/null +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -0,0 +1,48 @@ +use rustc_ast::ast::{LitIntType, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; + +use clippy_utils::{ + diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability, + ty::implements_trait, +}; + +use super::SEEK_FROM_CURRENT; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + + if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) { + if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) { + let mut applicability = Applicability::MachineApplicable; + let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability); + + span_lint_and_sugg( + cx, + SEEK_FROM_CURRENT, + expr.span, + "using `SeekFrom::Current` to start from current position", + "replace with", + format!("{snip}.stream_position()"), + applicability, + ); + } + } +} + +fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + if let ExprKind::Call(f, args) = expr.kind && + let ExprKind::Path(ref path) = f.kind && + let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() && + match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) { + // check if argument of `SeekFrom::Current` is `0` + if args.len() == 1 && + let ExprKind::Lit(ref lit) = args[0].kind && + let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { + return true + } + } + + false +} diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 04b504d044d..9a672e2ddfd 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -17,7 +17,7 @@ msrv_aliases! { 1,58,0 { FORMAT_ARGS_CAPTURE } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } - 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } + 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,50,0 { BOOL_THEN, CLAMP } 1,47,0 { TAU } 1,46,0 { CONST_IF_MATCH } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e37c7e34c0c..6c09c146082 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -116,6 +116,7 @@ pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; +pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; diff --git a/tests/ui/seek_from_current.fixed b/tests/ui/seek_from_current.fixed new file mode 100644 index 00000000000..4b5303324bc --- /dev/null +++ b/tests/ui/seek_from_current.fixed @@ -0,0 +1,26 @@ +// run-rustfix +#![warn(clippy::seek_from_current)] +#![feature(custom_inner_attributes)] + +use std::fs::File; +use std::io::{self, Seek, SeekFrom, Write}; + +fn _msrv_1_50() -> io::Result<()> { + #![clippy::msrv = "1.50"] + let mut f = File::create("foo.txt")?; + f.write_all(b"Hi!")?; + f.seek(SeekFrom::Current(0))?; + f.seek(SeekFrom::Current(1))?; + Ok(()) +} + +fn _msrv_1_51() -> io::Result<()> { + #![clippy::msrv = "1.51"] + let mut f = File::create("foo.txt")?; + f.write_all(b"Hi!")?; + f.stream_position()?; + f.seek(SeekFrom::Current(1))?; + Ok(()) +} + +fn main() {} diff --git a/tests/ui/seek_from_current.rs b/tests/ui/seek_from_current.rs new file mode 100644 index 00000000000..f93639261a1 --- /dev/null +++ b/tests/ui/seek_from_current.rs @@ -0,0 +1,26 @@ +// run-rustfix +#![warn(clippy::seek_from_current)] +#![feature(custom_inner_attributes)] + +use std::fs::File; +use std::io::{self, Seek, SeekFrom, Write}; + +fn _msrv_1_50() -> io::Result<()> { + #![clippy::msrv = "1.50"] + let mut f = File::create("foo.txt")?; + f.write_all(b"Hi!")?; + f.seek(SeekFrom::Current(0))?; + f.seek(SeekFrom::Current(1))?; + Ok(()) +} + +fn _msrv_1_51() -> io::Result<()> { + #![clippy::msrv = "1.51"] + let mut f = File::create("foo.txt")?; + f.write_all(b"Hi!")?; + f.seek(SeekFrom::Current(0))?; + f.seek(SeekFrom::Current(1))?; + Ok(()) +} + +fn main() {} diff --git a/tests/ui/seek_from_current.stderr b/tests/ui/seek_from_current.stderr new file mode 100644 index 00000000000..db1125b53cd --- /dev/null +++ b/tests/ui/seek_from_current.stderr @@ -0,0 +1,10 @@ +error: using `SeekFrom::Current` to start from current position + --> $DIR/seek_from_current.rs:21:5 + | +LL | f.seek(SeekFrom::Current(0))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `f.stream_position()` + | + = note: `-D clippy::seek-from-current` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From e27e13c9ad8ff278c0cc3d1e75a6389a2235d5d9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 27 Oct 2022 18:49:07 +0100 Subject: Ensure new_ret_no_self is not fired if `impl Trait` is returned. --- clippy_lints/src/methods/mod.rs | 30 ++---------------------- clippy_utils/src/ty.rs | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b29c7d9f253..6665329d114 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -103,7 +103,7 @@ 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::ty::{contains_ty_adt_constructor_opaque, 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 if_chain::if_chain; use rustc_hir as hir; @@ -3394,36 +3394,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, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index f4a135f2b5b..2dd8c826ab3 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -59,6 +59,58 @@ pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool { }) } +/// Walks into `ty` and returns `true` if any inner type is an instance of the given type, or adt +/// constructor of the same type. +/// +/// This method also recurses into opaque type predicates, so call it with `impl Trait` and `U` +/// will also return `true`. +pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool { + ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => { + if inner_ty == needle { + return true; + } + + if inner_ty.ty_adt_def() == needle.ty_adt_def() { + return true; + } + + if let ty::Opaque(def_id, _) = *inner_ty.kind() { + for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { + match predicate.kind().skip_binder() { + // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through + // and check substituions to find `U`. + ty::PredicateKind::Trait(trait_predicate) => { + if trait_predicate + .trait_ref + .substs + .types() + .skip(1) // Skip the implicit `Self` generic parameter + .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle)) + { + return true; + } + }, + // For `impl Trait`, it will register a predicate of `::Assoc = U`, + // so we check the term for `U`. + ty::PredicateKind::Projection(projection_predicate) => { + if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() { + if contains_ty_adt_constructor_opaque(cx, ty, needle) { + return true; + } + }; + }, + _ => (), + } + } + } + + false + }, + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) +} + /// Resolves `::Item` for `T` /// Do not invoke without first verifying that the type implements `Iterator` pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { -- cgit 1.4.1-3-g733a5 From 7e68c718c0db31c317c77cf776441d695f715f41 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Fri, 28 Oct 2022 17:22:40 +0200 Subject: fix the `string-extend-chars` suggestion on slice This adds the missing `&` to the suggestion if the target is a `str` slice (e.g. extending with `"foo"[..].chars()`). --- clippy_lints/src/methods/string_extend_chars.rs | 6 +++++- tests/ui/string_extend.fixed | 3 +++ tests/ui/string_extend.rs | 3 +++ tests/ui/string_extend.stderr | 8 +++++++- 4 files changed, 18 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 6974260f70d..0e93543fd7e 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -19,7 +19,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let target = &arglists[0].0; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { - "" + if matches!(target.kind, hir::ExprKind::Index(..)) { + "&" + } else { + "" + } } else if is_type_diagnostic_item(cx, self_ty, sym::String) { "&" } else { diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed index 1883a9f8325..d200d7310fc 100644 --- a/tests/ui/string_extend.fixed +++ b/tests/ui/string_extend.fixed @@ -29,4 +29,7 @@ fn main() { let f = HasChars; s.extend(f.chars()); + + // issue #9735 + s.push_str(&abc[0..2]); } diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index 07d0baa1be6..0dd96a3b210 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -29,4 +29,7 @@ fn main() { let f = HasChars; s.extend(f.chars()); + + // issue #9735 + s.extend(abc[0..2].chars()); } diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index 6af8c9e1662..b35c77fd961 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -18,5 +18,11 @@ error: calling `.extend(_.chars())` LL | s.extend(def.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` -error: aborting due to 3 previous errors +error: calling `.extend(_.chars())` + --> $DIR/string_extend.rs:34:5 + | +LL | s.extend(abc[0..2].chars()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&abc[0..2])` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 10b7fabbf36f1ab45c4d33357270d0557822ff90 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Fri, 28 Oct 2022 13:18:07 -0400 Subject: Fix adjacent code --- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/doc.rs | 6 +++--- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 4 ++-- clippy_lints/src/index_refutable_slice.rs | 4 ++-- clippy_lints/src/indexing_slicing.rs | 6 +----- clippy_lints/src/invalid_upcast_comparisons.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 4 ++-- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches/manual_filter.rs | 2 +- clippy_lints/src/matches/significant_drop_in_scrutinee.rs | 2 +- clippy_lints/src/matches/single_match.rs | 2 +- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 4 ++-- clippy_lints/src/methods/chars_last_cmp.rs | 2 +- clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs | 2 +- clippy_lints/src/methods/chars_next_cmp.rs | 2 +- clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs | 2 +- clippy_lints/src/methods/filter_map.rs | 8 ++++---- clippy_lints/src/methods/inefficient_to_string.rs | 4 ++-- clippy_lints/src/methods/iter_nth_zero.rs | 2 +- .../src/methods/iter_on_single_or_empty_collections.rs | 2 +- clippy_lints/src/methods/manual_saturating_arithmetic.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 4 ++-- clippy_lints/src/methods/map_err_ignore.rs | 2 +- clippy_lints/src/methods/option_as_ref_deref.rs | 4 ++-- clippy_lints/src/methods/suspicious_map.rs | 2 +- clippy_lints/src/mixed_read_write_in_expression.rs | 4 ++-- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/needless_continue.rs | 8 ++++---- clippy_lints/src/operators/op_ref.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 4 ++-- clippy_lints/src/ptr_offset_with_cast.rs | 8 ++++---- clippy_lints/src/redundant_closure_call.rs | 4 ++-- clippy_lints/src/slow_vector_initialization.rs | 2 +- .../src/utils/internal_lints/lint_without_lint_pass.rs | 2 +- clippy_utils/src/diagnostics.rs | 12 ++++++------ clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/qualify_min_const_fn.rs | 6 +++--- clippy_utils/src/sugg.rs | 2 +- tests/ui/crashes/ice-2774.stderr | 2 +- tests/ui/crashes/needless_lifetimes_impl_trait.stderr | 2 +- tests/ui/issue_4266.stderr | 4 ++-- 43 files changed, 74 insertions(+), 78 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 08164c0b654..939bdbcdc7c 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -481,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } } -fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { +fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); cx.tcx .get_diagnostic_item(sym::Ord) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7e2e32a20d4..dcbcabf1347 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1231,8 +1231,8 @@ fn is_mixed_projection_predicate<'tcx>( } } -fn referent_used_exactly_once<'a, 'tcx>( - cx: &'a LateContext<'tcx>, +fn referent_used_exactly_once<'tcx>( + cx: &LateContext<'tcx>, possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, reference: &Expr<'tcx>, ) -> bool { diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 36dc7e3396b..cecec520a6d 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -336,8 +336,8 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { } } -fn lint_for_missing_headers<'tcx>( - cx: &LateContext<'tcx>, +fn lint_for_missing_headers( + cx: &LateContext<'_>, def_id: LocalDefId, span: impl Into + Copy, sig: &hir::FnSig<'_>, @@ -467,7 +467,7 @@ struct DocHeaders { panics: bool, } -fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &'a [Attribute]) -> DocHeaders { +fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[Attribute]) -> DocHeaders { use pulldown_cmark::{BrokenLink, CowStr, Options}; /// We don't want the parser to choke on intra doc links. Since we don't /// actually care about rendering them, just pretend that all broken links are diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index ef24a5d06ad..15d693a117a 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom { } } -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) { +fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::ImplItemRef]) { use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, ImplItemKind}; diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 93efe957b1d..c7c3b3f6b94 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -66,8 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { use rustc_span::BytePos; - fn suggestion<'tcx>( - cx: &LateContext<'tcx>, + fn suggestion( + cx: &LateContext<'_>, diag: &mut Diagnostic, generics_span: Span, generics_suggestion_span: Span, diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index c7b5badaae5..0d5099bde6d 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -207,8 +207,8 @@ impl SliceLintInformation { } } -fn filter_lintable_slices<'a, 'tcx>( - cx: &'a LateContext<'tcx>, +fn filter_lintable_slices<'tcx>( + cx: &LateContext<'tcx>, slice_lint_info: FxIndexMap, max_suggested_slice: u64, scope: &'tcx hir::Expr<'tcx>, diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index af40a5a8187..4cd7dff4cfd 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -171,11 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { /// Returns a tuple of options with the start and end (exclusive) values of /// the range. If the start or end is not constant, None is returned. -fn to_const_range<'tcx>( - cx: &LateContext<'tcx>, - range: higher::Range<'_>, - array_size: u128, -) -> (Option, Option) { +fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option, Option) { let s = range .start .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 0ef77e03de9..6ea637412d5 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]); -fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> { +fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(FullInt, FullInt)> { if let ExprKind::Cast(cast_exp, _) = expr.kind { let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp); let cast_ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index db73ab55b37..72ae2b39162 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -52,8 +52,8 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option None } -fn check_for_mutation<'tcx>( - cx: &LateContext<'tcx>, +fn check_for_mutation( + cx: &LateContext<'_>, body: &Expr<'_>, bound_id_start: Option, bound_id_end: Option, diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 32da37a862d..59195d1ae4e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -119,7 +119,7 @@ fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { /// semicolons, which causes problems when generating a suggestion. Given an /// expression that evaluates to '()' or '!', recursively remove useless braces /// and semi-colons until is suitable for including in the suggestion template -fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option { +fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { if !is_unit_expression(cx, expr) { return None; } diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index 66ba1f6f9c5..d521a529e0d 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -62,7 +62,7 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> { // // } // Returns true if resolves to `Some(x)`, `false` otherwise -fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool { +fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &Expr<'_>) -> bool { if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) { // there can be not statements in the block as they would be removed when switching to `.filter` if let ExprKind::Call(callee, [arg]) = inner_expr.kind { diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 93e4160c69b..78c70d1c8d8 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -377,7 +377,7 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> { } } -fn has_significant_drop_in_arms<'tcx, 'a>(cx: &'a LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet { +fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet { let mut helper = ArmSigDropHelper::new(cx); for arm in arms { helper.visit_expr(arm.body); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index e5a15b2e1a1..19b49c44d57 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -153,7 +153,7 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) -> } /// Returns `true` if the given type is an enum we know won't be expanded in the future -fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool { +fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { // list of candidate `Enum`s we know will never get any more members let candidates = [sym::Cow, sym::Option, sym::Result]; diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 7e808760663..27a05337a29 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -9,8 +9,8 @@ use rustc_lint::LateContext; use rustc_lint::Lint; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, +pub(super) fn check( + cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>, chain_methods: &[&str], lint: &'static Lint, diff --git a/clippy_lints/src/methods/chars_last_cmp.rs b/clippy_lints/src/methods/chars_last_cmp.rs index 07bbc5ca1bf..2efff4c3c54 100644 --- a/clippy_lints/src/methods/chars_last_cmp.rs +++ b/clippy_lints/src/methods/chars_last_cmp.rs @@ -4,7 +4,7 @@ use rustc_lint::LateContext; use super::CHARS_LAST_CMP; /// Checks for the `CHARS_LAST_CMP` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { +pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { true } else { diff --git a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs index c29ee0ec8c8..5b8713f7d79 100644 --- a/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs @@ -4,7 +4,7 @@ use rustc_lint::LateContext; use super::CHARS_LAST_CMP; /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { +pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { true } else { diff --git a/clippy_lints/src/methods/chars_next_cmp.rs b/clippy_lints/src/methods/chars_next_cmp.rs index a6701d8830e..b631fecab97 100644 --- a/clippy_lints/src/methods/chars_next_cmp.rs +++ b/clippy_lints/src/methods/chars_next_cmp.rs @@ -3,6 +3,6 @@ use rustc_lint::LateContext; use super::CHARS_NEXT_CMP; /// Checks for the `CHARS_NEXT_CMP` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { +pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") } diff --git a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs index 28ede28e935..caf21d3ff3b 100644 --- a/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs @@ -3,6 +3,6 @@ use rustc_lint::LateContext; use super::CHARS_NEXT_CMP; /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { +pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool { crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") } diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 9719b2f1c51..f888c58a72d 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -17,7 +17,7 @@ use super::MANUAL_FILTER_MAP; use super::MANUAL_FIND_MAP; use super::OPTION_FILTER_MAP; -fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { +fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { match &expr.kind { hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, hir::ExprKind::Path(QPath::Resolved(_, segments)) => { @@ -46,7 +46,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy } } -fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { +fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } @@ -66,8 +66,8 @@ fn is_filter_some_map_unwrap( /// lint use of `filter().map()` or `find().map()` for `Iterators` #[allow(clippy::too_many_arguments)] -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, +pub(super) fn check( + cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_recv: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index ede3b8bb74e..3a8b8cbff47 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -12,8 +12,8 @@ use rustc_span::symbol::{sym, Symbol}; use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint -pub fn check<'tcx>( - cx: &LateContext<'tcx>, +pub fn check( + cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, receiver: &hir::Expr<'_>, diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index 68d906c3ea3..c830958d5c8 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -10,7 +10,7 @@ use rustc_span::sym; use super::ITER_NTH_ZERO; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, expr, sym::Iterator); if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg); diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 4f73b3ec422..70abe4891d9 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -25,7 +25,7 @@ impl IterType { } } -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { let item = match recv.kind { ExprKind::Array([]) => None, ExprKind::Array([e]) => Some(e), diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index b80541b8647..a7284c64497 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -67,7 +67,7 @@ enum MinMax { Max, } -fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option { +fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { // `T::max_value()` `T::min_value()` inherent methods if_chain! { if let hir::ExprKind::Call(func, args) = &expr.kind; diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 7ce14ec080b..6bc783c6d50 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -15,11 +15,11 @@ use rustc_span::{sym, Span}; use super::MAP_CLONE; -pub(super) fn check<'tcx>( +pub(super) fn check( cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, - arg: &'tcx hir::Expr<'_>, + arg: &hir::Expr<'_>, msrv: Option, ) { if_chain! { diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs index 1fb6617145e..b773b3e423f 100644 --- a/clippy_lints/src/methods/map_err_ignore.rs +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -6,7 +6,7 @@ use rustc_span::sym; use super::MAP_ERR_IGNORE; -pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result) diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 742483e6b2e..e6eb64bcbde 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -13,8 +13,8 @@ use rustc_span::sym; use super::OPTION_AS_REF_DEREF; /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, +pub(super) fn check( + cx: &LateContext<'_>, expr: &hir::Expr<'_>, as_ref_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 851cdf54455..2ac0786b37b 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -8,7 +8,7 @@ use rustc_span::sym; use super::SUSPICIOUS_MAP; -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) { +pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, count_recv, sym::Iterator); let closure = expr_or_init(cx, map_arg); diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 6752976348f..321fa4b7f99 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -218,7 +218,7 @@ enum StopEarly { Stop, } -fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly { +fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly { if expr.hir_id == vis.last_expr.hir_id { return StopEarly::KeepGoing; } @@ -265,7 +265,7 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) - StopEarly::KeepGoing } -fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly { +fn check_stmt<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly { match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr), // If the declaration is of a local variable, check its initializer diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 3d643e4e65c..551b6ed1227 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -137,7 +137,7 @@ impl MutableKeyType { } } - fn check_sig<'tcx>(&self, cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) { + fn check_sig(&self, cx: &LateContext<'_>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) { let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id); let fn_sig = cx.tcx.fn_sig(fn_def_id); for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 6f0e755466e..38a75034cd3 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -287,7 +287,7 @@ const DROP_ELSE_BLOCK_MSG: &str = "consider dropping the `else` clause"; const DROP_CONTINUE_EXPRESSION_MSG: &str = "consider dropping the `continue` expression"; -fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) { +fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: LintType) { // snip is the whole *help* message that appears after the warning. // message is the warning message. // expr is the expression which the lint warning message refers to. @@ -313,7 +313,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, ); } -fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String { +fn suggestion_snippet_for_continue_inside_if(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String { let cond_code = snippet(cx, data.if_cond.span, ".."); let continue_code = snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span)); @@ -327,7 +327,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &' ) } -fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String { +fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String { let cond_code = snippet(cx, data.if_cond.span, ".."); // Region B @@ -361,7 +361,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: ) } -fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) { +fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { if_chain! { if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind; if let Some(last_stmt) = loop_block.stmts.last(); diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs index 1085e608944..7de00c53f73 100644 --- a/clippy_lints/src/operators/op_ref.rs +++ b/clippy_lints/src/operators/op_ref.rs @@ -199,7 +199,7 @@ fn in_impl<'tcx>( } } -fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { +fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { if_chain! { if let ty::Adt(adt_def, _) = middle_ty.kind(); if let Some(local_did) = adt_def.did().as_local(); diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index a4d265111f9..97b5a4ce364 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -130,7 +130,7 @@ enum DerefPossible { Impossible, } -fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool { +fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool { let maybe_mismatch = find_first_mismatch(cx, pat); if let Some((span, mutability, level)) = maybe_mismatch { span_lint_and_help( @@ -163,7 +163,7 @@ enum Level { Lower, } -fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> { +fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> { let mut result = None; pat.walk(|p| { if result.is_some() { diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 72dda67c72b..47b8891e123 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -105,17 +105,17 @@ fn expr_as_ptr_offset_call<'tcx>( } // Is the type of the expression a usize? -fn is_expr_ty_usize<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { +fn is_expr_ty_usize(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize } // Is the type of the expression a raw pointer? -fn is_expr_ty_raw_ptr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { +fn is_expr_ty_raw_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { cx.typeck_results().expr_ty(expr).is_unsafe_ptr() } -fn build_suggestion<'tcx>( - cx: &LateContext<'tcx>, +fn build_suggestion( + cx: &LateContext<'_>, method: Method, receiver_expr: &Expr<'_>, cast_lhs_expr: &Expr<'_>, diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 74eea6de4bb..8cc8d5ea629 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -105,8 +105,8 @@ impl EarlyLintPass for RedundantClosureCall { impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - fn count_closure_usage<'a, 'tcx>( - cx: &'a LateContext<'tcx>, + fn count_closure_usage<'tcx>( + cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>, path: &'tcx hir::Path<'tcx>, ) -> usize { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 76039923151..a2109038a05 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -168,7 +168,7 @@ impl SlowVectorInit { }; } - fn emit_lint<'tcx>(cx: &LateContext<'tcx>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) { + fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) { let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len"); span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| { diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 0dac64376b0..1aebb8b3104 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { } } -pub(super) fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool { +pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Rptr( _, MutTy { diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 78f93755b72..16b160b6fd2 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -72,8 +72,8 @@ pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into( - cx: &'a T, +pub fn span_lint_and_help( + cx: &T, lint: &'static Lint, span: impl Into, msg: &str, @@ -114,8 +114,8 @@ pub fn span_lint_and_help<'a, T: LintContext>( /// 10 | forget(&SomeStruct); /// | ^^^^^^^^^^^ /// ``` -pub fn span_lint_and_note<'a, T: LintContext>( - cx: &'a T, +pub fn span_lint_and_note( + cx: &T, lint: &'static Lint, span: impl Into, msg: &str, @@ -192,8 +192,8 @@ pub fn span_lint_hir_and_then( /// = note: `-D fold-any` implied by `-D warnings` /// ``` #[cfg_attr(feature = "internal", allow(clippy::collapsible_span_lint_calls))] -pub fn span_lint_and_sugg<'a, T: LintContext>( - cx: &'a T, +pub fn span_lint_and_sugg( + cx: &T, lint: &'static Lint, sp: Span, msg: &str, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dda4660fb7a..f7d3c91777e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -994,7 +994,7 @@ impl std::ops::BitOrAssign for CaptureKind { /// Note as this will walk up to parent expressions until the capture can be determined it should /// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or /// function argument (other than a receiver). -pub fn capture_local_usage<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind { +pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind { let mut capture = CaptureKind::Ref(Mutability::Not); pat.each_binding_or_first(&mut |_, id, span, _| match cx @@ -1852,7 +1852,7 @@ pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) } /// Checks if the given `DefId` matches the path. -pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { +pub fn match_def_path(cx: &LateContext<'_>, did: DefId, syms: &[&str]) -> bool { // We should probably move to Symbols in Clippy as well rather than interning every time. let path = cx.get_def_path(did); syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied()) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 45b63a4aa5d..65722f142aa 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,7 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { +pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: Option) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -276,9 +276,9 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B Ok(()) } -fn check_terminator<'a, 'tcx>( +fn check_terminator<'tcx>( tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &Body<'tcx>, terminator: &Terminator<'tcx>, msrv: Option, ) -> McfResult { diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 01c2b11f65b..45181d3c7a8 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -801,7 +801,7 @@ pub struct DerefClosure { /// Returns `None` if no such use cases have been triggered in closure body /// /// note: this only works on single line immutable closures with exactly one input parameter. -pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option { +pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option { if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind { let closure_body = cx.tcx.hir().body(body); // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`) diff --git a/tests/ui/crashes/ice-2774.stderr b/tests/ui/crashes/ice-2774.stderr index 0c2d48f938f..1f26c7f4db6 100644 --- a/tests/ui/crashes/ice-2774.stderr +++ b/tests/ui/crashes/ice-2774.stderr @@ -1,4 +1,4 @@ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/ice-2774.rs:15:1 | LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr index d68bbe78802..875d5ab4f21 100644 --- a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr @@ -1,4 +1,4 @@ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes_impl_trait.rs:15:5 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index fb2a93c9580..fd553aa4538 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.stderr @@ -1,4 +1,4 @@ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/issue_4266.rs:4:1 | LL | async fn sink1<'a>(_: &'a str) {} // lint @@ -6,7 +6,7 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/issue_4266.rs:8:1 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { -- cgit 1.4.1-3-g733a5 From 9e7996b14957421320bbcdb9d4b3f3a65b78b223 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 31 Oct 2022 21:28:02 +0100 Subject: Update lint versions for 1.65 --- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/manual_instant_elapsed.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++--- clippy_lints/src/partialeq_to_none.rs | 2 +- clippy_lints/src/unused_peekable.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index b72c4c772f1..7148b5e6ebf 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -593,7 +593,7 @@ declare_clippy_lint! { /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); /// ``` /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety - #[clippy::version = "1.64.0"] + #[clippy::version = "1.65.0"] pub CAST_SLICE_FROM_RAW_PARTS, suspicious, "casting a slice created from a pointer and length to a slice pointer" diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 90911e0bf25..ae0e0833446 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -254,7 +254,7 @@ declare_clippy_lint! { /// Ok(()) /// } /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.65.0"] pub RESULT_LARGE_ERR, perf, "function returning `Result` with large `Err` type" diff --git a/clippy_lints/src/manual_instant_elapsed.rs b/clippy_lints/src/manual_instant_elapsed.rs index 331cda1db89..1e60aa02d3c 100644 --- a/clippy_lints/src/manual_instant_elapsed.rs +++ b/clippy_lints/src/manual_instant_elapsed.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// let prev_instant = Instant::now(); /// let duration = prev_instant.elapsed(); /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.65.0"] pub MANUAL_INSTANT_ELAPSED, pedantic, "subtraction between `Instant::now()` and previous `Instant`" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6665329d114..43a52f15680 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -160,7 +160,7 @@ declare_clippy_lint! { /// ```rust /// 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" @@ -2428,7 +2428,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" @@ -2460,7 +2460,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" diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 6810a243175..456ded3fc02 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// if f.is_some() { "yay" } else { "nay" } /// } /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.65.0"] pub PARTIALEQ_TO_NONE, style, "Binary comparison to `Option::None` relies on `T: PartialEq`, which is unneeded" diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index f1cebf0f992..d086c963c32 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.65.0"] pub UNUSED_PEEKABLE, nursery, "creating a peekable iterator without using any of its methods" -- cgit 1.4.1-3-g733a5 From 05006e58c08d24bf6f7fbe2eca96f3e82d355e26 Mon Sep 17 00:00:00 2001 From: koka Date: Thu, 3 Nov 2022 23:53:29 +0900 Subject: fix turbofish in suggest message --- clippy_lints/src/methods/unnecessary_join.rs | 2 +- tests/ui/unnecessary_join.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_join.rs b/clippy_lints/src/methods/unnecessary_join.rs index 973b8a7e6bf..33efa16c300 100644 --- a/clippy_lints/src/methods/unnecessary_join.rs +++ b/clippy_lints/src/methods/unnecessary_join.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_JOIN, span.with_hi(expr.span.hi()), - r#"called `.collect>().join("")` on an iterator"#, + r#"called `.collect::>().join("")` on an iterator"#, "try using", "collect::()".to_owned(), applicability, diff --git a/tests/ui/unnecessary_join.stderr b/tests/ui/unnecessary_join.stderr index 0b14b143aff..e919a6d1d8a 100644 --- a/tests/ui/unnecessary_join.stderr +++ b/tests/ui/unnecessary_join.stderr @@ -1,4 +1,4 @@ -error: called `.collect>().join("")` on an iterator +error: called `.collect::>().join("")` on an iterator --> $DIR/unnecessary_join.rs:11:10 | LL | .collect::>() @@ -8,7 +8,7 @@ LL | | .join(""); | = note: `-D clippy::unnecessary-join` implied by `-D warnings` -error: called `.collect>().join("")` on an iterator +error: called `.collect::>().join("")` on an iterator --> $DIR/unnecessary_join.rs:20:10 | LL | .collect::>() -- cgit 1.4.1-3-g733a5 From f27ca5c00a96d2dbd1e2b5dceee918d829891bc1 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Fri, 4 Nov 2022 16:01:44 +0000 Subject: Fix #9771 (`unnecessary_to_owned` false positive) --- clippy_lints/src/methods/unnecessary_to_owned.rs | 18 +++++++++++---- tests/ui/unnecessary_to_owned.fixed | 29 ++++++++++++++++++++++++ tests/ui/unnecessary_to_owned.rs | 29 ++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 4b4f2f47b1d..460bd1cfbd3 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -19,7 +19,6 @@ use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitP use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; -use std::cmp::max; use super::UNNECESSARY_TO_OWNED; @@ -263,11 +262,22 @@ fn check_other_call_arg<'tcx>( if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id; let receiver_ty = cx.typeck_results().expr_ty(receiver); - if can_change_type(cx, maybe_arg, receiver_ty); // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. - if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; - let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty))); + if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) { + Some((n_refs, receiver_ty)) + } else if trait_predicate.def_id() != deref_trait_id { + Some((1, cx.tcx.mk_ref( + cx.tcx.lifetimes.re_erased, + ty::TypeAndMut { + ty: receiver_ty, + mutbl: Mutability::Not, + }, + ))) + } else { + None + }; + if can_change_type(cx, maybe_arg, receiver_ty); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index fe09aad06bc..fadcf7f9c9e 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -426,3 +426,32 @@ mod issue_9504 { foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; } } + +mod issue_9771a { + #![allow(dead_code)] + + use std::marker::PhantomData; + + pub struct Key, V: ?Sized>(K, PhantomData); + + impl, V: ?Sized> Key { + pub fn new(key: K) -> Key { + Key(key, PhantomData) + } + } + + pub fn pkh(pkh: &[u8]) -> Key, String> { + Key::new([b"pkh-", pkh].concat().to_vec()) + } +} + +mod issue_9771b { + #![allow(dead_code)] + + pub struct Key>(K); + + pub fn from(c: &[u8]) -> Key> { + let v = [c].concat(); + Key(v.to_vec()) + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 3de6d0903c0..fe6864b9e07 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -426,3 +426,32 @@ mod issue_9504 { foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; } } + +mod issue_9771a { + #![allow(dead_code)] + + use std::marker::PhantomData; + + pub struct Key, V: ?Sized>(K, PhantomData); + + impl, V: ?Sized> Key { + pub fn new(key: K) -> Key { + Key(key, PhantomData) + } + } + + pub fn pkh(pkh: &[u8]) -> Key, String> { + Key::new([b"pkh-", pkh].concat().to_vec()) + } +} + +mod issue_9771b { + #![allow(dead_code)] + + pub struct Key>(K); + + pub fn from(c: &[u8]) -> Key> { + let v = [c].concat(); + Key(v.to_vec()) + } +} -- cgit 1.4.1-3-g733a5 From f86c35c326006d2406192985e49085a3a828a1fc Mon Sep 17 00:00:00 2001 From: bebecue <109153518+bebecue@users.noreply.github.com> Date: Sat, 5 Nov 2022 04:44:02 +0800 Subject: Update lint `suspicious_to_owned` `matches!(data, String)` will matches any type, replace it with explicit type annotation. --- clippy_lints/src/methods/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 43a52f15680..26834dc4fcc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2096,8 +2096,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, -- cgit 1.4.1-3-g733a5 From b0dcb862c60c87c55f4e34c2ecce8914ffe3c4c7 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 22 Apr 2022 18:49:15 -0400 Subject: Move `needless_collect` into the `methods` lint pass --- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/loops/mod.rs | 26 -- clippy_lints/src/loops/needless_collect.rs | 401 --------------------------- clippy_lints/src/methods/mod.rs | 26 ++ clippy_lints/src/methods/needless_collect.rs | 401 +++++++++++++++++++++++++++ 5 files changed, 428 insertions(+), 428 deletions(-) delete mode 100644 clippy_lints/src/loops/needless_collect.rs create mode 100644 clippy_lints/src/methods/needless_collect.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 747636b7ec3..e9094ca3a09 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -237,7 +237,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::MANUAL_MEMCPY_INFO, crate::loops::MISSING_SPIN_LOOP_INFO, crate::loops::MUT_RANGE_BOUND_INFO, - crate::loops::NEEDLESS_COLLECT_INFO, crate::loops::NEEDLESS_RANGE_LOOP_INFO, crate::loops::NEVER_LOOP_INFO, crate::loops::SAME_ITEM_PUSH_INFO, @@ -346,6 +345,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MAP_UNWRAP_OR_INFO, crate::methods::MUT_MUTEX_LOCK_INFO, crate::methods::NAIVE_BYTECOUNT_INFO, + crate::methods::NEEDLESS_COLLECT_INFO, crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO, crate::methods::NEEDLESS_OPTION_TAKE_INFO, crate::methods::NEEDLESS_SPLITN_INFO, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 821fe173023..8e52cac4323 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -9,7 +9,6 @@ mod manual_flatten; mod manual_memcpy; mod missing_spin_loop; mod mut_range_bound; -mod needless_collect; mod needless_range_loop; mod never_loop; mod same_item_push; @@ -205,28 +204,6 @@ declare_clippy_lint! { "`loop { if let { ... } else break }`, which can be written as a `while let` loop" } -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::>().len(); - /// // should be - /// let len = iterator.count(); - /// ``` - #[clippy::version = "1.30.0"] - pub NEEDLESS_COLLECT, - nursery, - "collecting an iterator when collect is not needed" -} - declare_clippy_lint! { /// ### What it does /// Checks `for` loops over slices with an explicit counter @@ -605,7 +582,6 @@ declare_lint_pass!(Loops => [ EXPLICIT_INTO_ITER_LOOP, ITER_NEXT_LOOP, WHILE_LET_LOOP, - NEEDLESS_COLLECT, EXPLICIT_COUNTER_LOOP, EMPTY_LOOP, WHILE_LET_ON_ITERATOR, @@ -667,8 +643,6 @@ impl<'tcx> LateLintPass<'tcx> for Loops { while_immutable_condition::check(cx, condition, body); missing_spin_loop::check(cx, condition, body); } - - needless_collect::check(expr, cx); } } diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs deleted file mode 100644 index 66f9e28596e..00000000000 --- a/clippy_lints/src/loops/needless_collect.rs +++ /dev/null @@ -1,401 +0,0 @@ -use super::NEEDLESS_COLLECT; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::higher; -use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind}; -use if_chain::if_chain; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind}; -use rustc_lint::LateContext; -use rustc_middle::hir::nested_filter; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; -use rustc_span::Span; - -const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; - -pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - check_needless_collect_direct_usage(expr, cx); - check_needless_collect_indirect_usage(expr, cx); -} -fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind; - if let ExprKind::MethodCall(chain_method, ..) = receiver.kind; - if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator); - then { - let ty = cx.typeck_results().expr_ty(receiver); - let mut applicability = Applicability::MaybeIncorrect; - let is_empty_sugg = "next().is_none()".to_string(); - let method_name = method.ident.name.as_str(); - let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) || - is_type_diagnostic_item(cx, ty, sym::VecDeque) || - is_type_diagnostic_item(cx, ty, sym::LinkedList) || - is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { - match method_name { - "len" => "count()".to_string(), - "is_empty" => is_empty_sugg, - "contains" => { - let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability); - let (arg, pred) = contains_arg - .strip_prefix('&') - .map_or(("&x", &*contains_arg), |s| ("x", s)); - format!("any(|{arg}| x == {pred})") - } - _ => return, - } - } - else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) || - is_type_diagnostic_item(cx, ty, sym::HashMap) { - match method_name { - "is_empty" => is_empty_sugg, - _ => return, - } - } - else { - return; - }; - span_lint_and_sugg( - cx, - NEEDLESS_COLLECT, - chain_method.ident.span.with_hi(expr.span.hi()), - NEEDLESS_COLLECT_MSG, - "replace with", - sugg, - applicability, - ); - } - } -} - -fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - if let ExprKind::Block(block, _) = expr.kind { - for stmt in block.stmts { - if_chain! { - if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(_, id, ..) = local.pat.kind; - if let Some(init_expr) = local.init; - if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind; - if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); - let ty = cx.typeck_results().expr_ty(init_expr); - if is_type_diagnostic_item(cx, ty, sym::Vec) || - is_type_diagnostic_item(cx, ty, sym::VecDeque) || - is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || - is_type_diagnostic_item(cx, ty, sym::LinkedList); - let iter_ty = cx.typeck_results().expr_ty(iter_source); - if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)); - if let [iter_call] = &*iter_calls; - then { - let mut used_count_visitor = UsedCountVisitor { - cx, - id, - count: 0, - }; - walk_block(&mut used_count_visitor, block); - if used_count_visitor.count > 1 { - return; - } - - // Suggest replacing iter_call with iter_replacement, and removing stmt - let mut span = MultiSpan::from_span(method_name.ident.span); - span.push_span_label(iter_call.span, "the iterator could be used here instead"); - span_lint_hir_and_then( - cx, - super::NEEDLESS_COLLECT, - init_expr.hir_id, - span, - NEEDLESS_COLLECT_MSG, - |diag| { - let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx)); - diag.multipart_suggestion( - iter_call.get_suggestion_text(), - vec![ - (stmt.span, String::new()), - (iter_call.span, iter_replacement) - ], - Applicability::MaybeIncorrect, - ); - }, - ); - } - } - } - } -} - -struct IterFunction { - func: IterFunctionKind, - span: Span, -} -impl IterFunction { - fn get_iter_method(&self, cx: &LateContext<'_>) -> String { - match &self.func { - IterFunctionKind::IntoIter => String::new(), - IterFunctionKind::Len => String::from(".count()"), - IterFunctionKind::IsEmpty => String::from(".next().is_none()"), - IterFunctionKind::Contains(span) => { - let s = snippet(cx, *span, ".."); - if let Some(stripped) = s.strip_prefix('&') { - format!(".any(|x| x == {stripped})") - } else { - format!(".any(|x| x == *{s})") - } - }, - } - } - fn get_suggestion_text(&self) -> &'static str { - match &self.func { - IterFunctionKind::IntoIter => { - "use the original Iterator instead of collecting it and then producing a new one" - }, - IterFunctionKind::Len => { - "take the original Iterator's count instead of collecting it and finding the length" - }, - IterFunctionKind::IsEmpty => { - "check if the original Iterator has anything instead of collecting it and seeing if it's empty" - }, - IterFunctionKind::Contains(_) => { - "check if the original Iterator contains an element instead of collecting then checking" - }, - } - } -} -enum IterFunctionKind { - IntoIter, - Len, - IsEmpty, - Contains(Span), -} - -struct IterFunctionVisitor<'a, 'tcx> { - illegal_mutable_capture_ids: HirIdSet, - current_mutably_captured_ids: HirIdSet, - cx: &'a LateContext<'tcx>, - uses: Vec>, - hir_id_uses_map: FxHashMap, - current_statement_hir_id: Option, - seen_other: bool, - target: HirId, -} -impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { - for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) { - if check_loop_kind(expr).is_some() { - continue; - } - self.visit_block_expr(expr, hir_id); - } - if let Some(expr) = block.expr { - if let Some(loop_kind) = check_loop_kind(expr) { - if let LoopKind::Conditional(block_expr) = loop_kind { - self.visit_block_expr(block_expr, None); - } - } else { - self.visit_block_expr(expr, None); - } - } - } - - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - // Check function calls on our collection - if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { - if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { - self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); - self.visit_expr(recv); - return; - } - - if path_to_local_id(recv, self.target) { - if self - .illegal_mutable_capture_ids - .intersection(&self.current_mutably_captured_ids) - .next() - .is_none() - { - if let Some(hir_id) = self.current_statement_hir_id { - self.hir_id_uses_map.insert(hir_id, self.uses.len()); - } - match method_name.ident.name.as_str() { - "into_iter" => self.uses.push(Some(IterFunction { - func: IterFunctionKind::IntoIter, - span: expr.span, - })), - "len" => self.uses.push(Some(IterFunction { - func: IterFunctionKind::Len, - span: expr.span, - })), - "is_empty" => self.uses.push(Some(IterFunction { - func: IterFunctionKind::IsEmpty, - span: expr.span, - })), - "contains" => self.uses.push(Some(IterFunction { - func: IterFunctionKind::Contains(args[0].span), - span: expr.span, - })), - _ => { - self.seen_other = true; - if let Some(hir_id) = self.current_statement_hir_id { - self.hir_id_uses_map.remove(&hir_id); - } - }, - } - } - return; - } - - if let Some(hir_id) = path_to_local(recv) { - if let Some(index) = self.hir_id_uses_map.remove(&hir_id) { - if self - .illegal_mutable_capture_ids - .intersection(&self.current_mutably_captured_ids) - .next() - .is_none() - { - if let Some(hir_id) = self.current_statement_hir_id { - self.hir_id_uses_map.insert(hir_id, index); - } - } else { - self.uses[index] = None; - } - } - } - } - // Check if the collection is used for anything else - if path_to_local_id(expr, self.target) { - self.seen_other = true; - } else { - walk_expr(self, expr); - } - } -} - -enum LoopKind<'tcx> { - Conditional(&'tcx Expr<'tcx>), - Loop, -} - -fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option> { - if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) { - return Some(LoopKind::Conditional(let_expr)); - } - if let Some(higher::While { condition, .. }) = higher::While::hir(expr) { - return Some(LoopKind::Conditional(condition)); - } - if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) { - return Some(LoopKind::Conditional(arg)); - } - if let ExprKind::Loop { .. } = expr.kind { - return Some(LoopKind::Loop); - } - - None -} - -impl<'tcx> IterFunctionVisitor<'_, 'tcx> { - fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option) { - self.current_statement_hir_id = hir_id; - self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(expr)); - self.visit_expr(expr); - } -} - -fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v>, Option)> { - match stmt.kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)), - StmtKind::Item(..) => None, - StmtKind::Local(Local { init, pat, .. }) => { - if let PatKind::Binding(_, hir_id, ..) = pat.kind { - init.map(|init_expr| (init_expr, Some(hir_id))) - } else { - init.map(|init_expr| (init_expr, None)) - } - }, - } -} - -struct UsedCountVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - id: HirId, - count: usize, -} - -impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if path_to_local_id(expr, self.id) { - self.count += 1; - } else { - walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } -} - -/// Detect the occurrences of calls to `iter` or `into_iter` for the -/// given identifier -fn detect_iter_and_into_iters<'tcx: 'a, 'a>( - block: &'tcx Block<'tcx>, - id: HirId, - cx: &'a LateContext<'tcx>, - captured_ids: HirIdSet, -) -> Option> { - let mut visitor = IterFunctionVisitor { - uses: Vec::new(), - target: id, - seen_other: false, - cx, - current_mutably_captured_ids: HirIdSet::default(), - illegal_mutable_capture_ids: captured_ids, - hir_id_uses_map: FxHashMap::default(), - current_statement_hir_id: None, - }; - visitor.visit_block(block); - if visitor.seen_other { - None - } else { - Some(visitor.uses.into_iter().flatten().collect()) - } -} - -fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet { - fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: Ty<'_>, set: &mut HirIdSet) { - match ty.kind() { - ty::Adt(_, generics) => { - for generic in *generics { - if let GenericArgKind::Type(ty) = generic.unpack() { - get_captured_ids_recursive(cx, ty, set); - } - } - }, - ty::Closure(def_id, _) => { - let closure_hir_node = cx.tcx.hir().get_if_local(*def_id).unwrap(); - if let Node::Expr(closure_expr) = closure_hir_node { - can_move_expr_to_closure(cx, closure_expr) - .unwrap() - .into_iter() - .for_each(|(hir_id, capture_kind)| { - if matches!(capture_kind, CaptureKind::Ref(Mutability::Mut)) { - set.insert(hir_id); - } - }); - } - }, - _ => (), - } - } - - let mut set = HirIdSet::default(); - - get_captured_ids_recursive(cx, ty, &mut set); - - set -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 26834dc4fcc..c413d9baf17 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/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; @@ -3141,6 +3142,28 @@ declare_clippy_lint! { "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::>().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, @@ -3267,6 +3290,7 @@ impl_lint_pass!(Methods => [ 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. @@ -3317,6 +3341,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, _ => (), } + + needless_collect::check(expr, cx); } #[allow(clippy::too_many_lines)] diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs new file mode 100644 index 00000000000..66f9e28596e --- /dev/null +++ b/clippy_lints/src/methods/needless_collect.rs @@ -0,0 +1,401 @@ +use super::NEEDLESS_COLLECT; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; +use clippy_utils::higher; +use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind}; +use if_chain::if_chain; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{Applicability, MultiSpan}; +use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; +use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind}; +use rustc_lint::LateContext; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; +use rustc_span::Span; + +const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; + +pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { + check_needless_collect_direct_usage(expr, cx); + check_needless_collect_indirect_usage(expr, cx); +} +fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { + if_chain! { + if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind; + if let ExprKind::MethodCall(chain_method, ..) = receiver.kind; + if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator); + then { + let ty = cx.typeck_results().expr_ty(receiver); + let mut applicability = Applicability::MaybeIncorrect; + let is_empty_sugg = "next().is_none()".to_string(); + let method_name = method.ident.name.as_str(); + let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) || + is_type_diagnostic_item(cx, ty, sym::VecDeque) || + is_type_diagnostic_item(cx, ty, sym::LinkedList) || + is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { + match method_name { + "len" => "count()".to_string(), + "is_empty" => is_empty_sugg, + "contains" => { + let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability); + let (arg, pred) = contains_arg + .strip_prefix('&') + .map_or(("&x", &*contains_arg), |s| ("x", s)); + format!("any(|{arg}| x == {pred})") + } + _ => return, + } + } + else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) || + is_type_diagnostic_item(cx, ty, sym::HashMap) { + match method_name { + "is_empty" => is_empty_sugg, + _ => return, + } + } + else { + return; + }; + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + chain_method.ident.span.with_hi(expr.span.hi()), + NEEDLESS_COLLECT_MSG, + "replace with", + sugg, + applicability, + ); + } + } +} + +fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { + if let ExprKind::Block(block, _) = expr.kind { + for stmt in block.stmts { + if_chain! { + if let StmtKind::Local(local) = stmt.kind; + if let PatKind::Binding(_, id, ..) = local.pat.kind; + if let Some(init_expr) = local.init; + if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind; + if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); + let ty = cx.typeck_results().expr_ty(init_expr); + if is_type_diagnostic_item(cx, ty, sym::Vec) || + is_type_diagnostic_item(cx, ty, sym::VecDeque) || + is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || + is_type_diagnostic_item(cx, ty, sym::LinkedList); + let iter_ty = cx.typeck_results().expr_ty(iter_source); + if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)); + if let [iter_call] = &*iter_calls; + then { + let mut used_count_visitor = UsedCountVisitor { + cx, + id, + count: 0, + }; + walk_block(&mut used_count_visitor, block); + if used_count_visitor.count > 1 { + return; + } + + // Suggest replacing iter_call with iter_replacement, and removing stmt + let mut span = MultiSpan::from_span(method_name.ident.span); + span.push_span_label(iter_call.span, "the iterator could be used here instead"); + span_lint_hir_and_then( + cx, + super::NEEDLESS_COLLECT, + init_expr.hir_id, + span, + NEEDLESS_COLLECT_MSG, + |diag| { + let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx)); + diag.multipart_suggestion( + iter_call.get_suggestion_text(), + vec![ + (stmt.span, String::new()), + (iter_call.span, iter_replacement) + ], + Applicability::MaybeIncorrect, + ); + }, + ); + } + } + } + } +} + +struct IterFunction { + func: IterFunctionKind, + span: Span, +} +impl IterFunction { + fn get_iter_method(&self, cx: &LateContext<'_>) -> String { + match &self.func { + IterFunctionKind::IntoIter => String::new(), + IterFunctionKind::Len => String::from(".count()"), + IterFunctionKind::IsEmpty => String::from(".next().is_none()"), + IterFunctionKind::Contains(span) => { + let s = snippet(cx, *span, ".."); + if let Some(stripped) = s.strip_prefix('&') { + format!(".any(|x| x == {stripped})") + } else { + format!(".any(|x| x == *{s})") + } + }, + } + } + fn get_suggestion_text(&self) -> &'static str { + match &self.func { + IterFunctionKind::IntoIter => { + "use the original Iterator instead of collecting it and then producing a new one" + }, + IterFunctionKind::Len => { + "take the original Iterator's count instead of collecting it and finding the length" + }, + IterFunctionKind::IsEmpty => { + "check if the original Iterator has anything instead of collecting it and seeing if it's empty" + }, + IterFunctionKind::Contains(_) => { + "check if the original Iterator contains an element instead of collecting then checking" + }, + } + } +} +enum IterFunctionKind { + IntoIter, + Len, + IsEmpty, + Contains(Span), +} + +struct IterFunctionVisitor<'a, 'tcx> { + illegal_mutable_capture_ids: HirIdSet, + current_mutably_captured_ids: HirIdSet, + cx: &'a LateContext<'tcx>, + uses: Vec>, + hir_id_uses_map: FxHashMap, + current_statement_hir_id: Option, + seen_other: bool, + target: HirId, +} +impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { + fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) { + if check_loop_kind(expr).is_some() { + continue; + } + self.visit_block_expr(expr, hir_id); + } + if let Some(expr) = block.expr { + if let Some(loop_kind) = check_loop_kind(expr) { + if let LoopKind::Conditional(block_expr) = loop_kind { + self.visit_block_expr(block_expr, None); + } + } else { + self.visit_block_expr(expr, None); + } + } + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + // Check function calls on our collection + if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { + if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { + self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); + self.visit_expr(recv); + return; + } + + if path_to_local_id(recv, self.target) { + if self + .illegal_mutable_capture_ids + .intersection(&self.current_mutably_captured_ids) + .next() + .is_none() + { + if let Some(hir_id) = self.current_statement_hir_id { + self.hir_id_uses_map.insert(hir_id, self.uses.len()); + } + match method_name.ident.name.as_str() { + "into_iter" => self.uses.push(Some(IterFunction { + func: IterFunctionKind::IntoIter, + span: expr.span, + })), + "len" => self.uses.push(Some(IterFunction { + func: IterFunctionKind::Len, + span: expr.span, + })), + "is_empty" => self.uses.push(Some(IterFunction { + func: IterFunctionKind::IsEmpty, + span: expr.span, + })), + "contains" => self.uses.push(Some(IterFunction { + func: IterFunctionKind::Contains(args[0].span), + span: expr.span, + })), + _ => { + self.seen_other = true; + if let Some(hir_id) = self.current_statement_hir_id { + self.hir_id_uses_map.remove(&hir_id); + } + }, + } + } + return; + } + + if let Some(hir_id) = path_to_local(recv) { + if let Some(index) = self.hir_id_uses_map.remove(&hir_id) { + if self + .illegal_mutable_capture_ids + .intersection(&self.current_mutably_captured_ids) + .next() + .is_none() + { + if let Some(hir_id) = self.current_statement_hir_id { + self.hir_id_uses_map.insert(hir_id, index); + } + } else { + self.uses[index] = None; + } + } + } + } + // Check if the collection is used for anything else + if path_to_local_id(expr, self.target) { + self.seen_other = true; + } else { + walk_expr(self, expr); + } + } +} + +enum LoopKind<'tcx> { + Conditional(&'tcx Expr<'tcx>), + Loop, +} + +fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option> { + if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) { + return Some(LoopKind::Conditional(let_expr)); + } + if let Some(higher::While { condition, .. }) = higher::While::hir(expr) { + return Some(LoopKind::Conditional(condition)); + } + if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) { + return Some(LoopKind::Conditional(arg)); + } + if let ExprKind::Loop { .. } = expr.kind { + return Some(LoopKind::Loop); + } + + None +} + +impl<'tcx> IterFunctionVisitor<'_, 'tcx> { + fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option) { + self.current_statement_hir_id = hir_id; + self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(expr)); + self.visit_expr(expr); + } +} + +fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v>, Option)> { + match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)), + StmtKind::Item(..) => None, + StmtKind::Local(Local { init, pat, .. }) => { + if let PatKind::Binding(_, hir_id, ..) = pat.kind { + init.map(|init_expr| (init_expr, Some(hir_id))) + } else { + init.map(|init_expr| (init_expr, None)) + } + }, + } +} + +struct UsedCountVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + id: HirId, + count: usize, +} + +impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if path_to_local_id(expr, self.id) { + self.count += 1; + } else { + walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } +} + +/// Detect the occurrences of calls to `iter` or `into_iter` for the +/// given identifier +fn detect_iter_and_into_iters<'tcx: 'a, 'a>( + block: &'tcx Block<'tcx>, + id: HirId, + cx: &'a LateContext<'tcx>, + captured_ids: HirIdSet, +) -> Option> { + let mut visitor = IterFunctionVisitor { + uses: Vec::new(), + target: id, + seen_other: false, + cx, + current_mutably_captured_ids: HirIdSet::default(), + illegal_mutable_capture_ids: captured_ids, + hir_id_uses_map: FxHashMap::default(), + current_statement_hir_id: None, + }; + visitor.visit_block(block); + if visitor.seen_other { + None + } else { + Some(visitor.uses.into_iter().flatten().collect()) + } +} + +fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet { + fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: Ty<'_>, set: &mut HirIdSet) { + match ty.kind() { + ty::Adt(_, generics) => { + for generic in *generics { + if let GenericArgKind::Type(ty) = generic.unpack() { + get_captured_ids_recursive(cx, ty, set); + } + } + }, + ty::Closure(def_id, _) => { + let closure_hir_node = cx.tcx.hir().get_if_local(*def_id).unwrap(); + if let Node::Expr(closure_expr) = closure_hir_node { + can_move_expr_to_closure(cx, closure_expr) + .unwrap() + .into_iter() + .for_each(|(hir_id, capture_kind)| { + if matches!(capture_kind, CaptureKind::Ref(Mutability::Mut)) { + set.insert(hir_id); + } + }); + } + }, + _ => (), + } + } + + let mut set = HirIdSet::default(); + + get_captured_ids_recursive(cx, ty, &mut set); + + set +} -- cgit 1.4.1-3-g733a5 From 9c69e93595e581a92c8385b633e687393cb07471 Mon Sep 17 00:00:00 2001 From: kraktus Date: Fri, 28 Oct 2022 14:54:59 +0200 Subject: Rewrite `ExcessiveBools` to be a `LateLintPass` lint changelog: [`fn_params_excessive_bools`] Make it possible to allow the lint at the method level --- clippy_lints/src/excessive_bools.rs | 126 ++++++++++++++++-------------- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/methods/mod.rs | 13 +-- clippy_utils/src/hir_utils.rs | 10 ++- clippy_utils/src/lib.rs | 2 +- tests/ui/fn_params_excessive_bools.rs | 1 + tests/ui/fn_params_excessive_bools.stderr | 20 ++--- 7 files changed, 90 insertions(+), 84 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index e1911449242..08164955c6a 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -1,8 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use clippy_utils::{get_parent_node, is_bool}; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl, HirId, Item, ItemKind, Node, Ty}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; +use rustc_target::spec::abi::Abi; declare_clippy_lint! { /// ### What it does @@ -83,6 +86,12 @@ pub struct ExcessiveBools { max_fn_params_bools: u64, } +#[derive(Eq, PartialEq, Debug)] +enum Kind { + Struct, + Fn, +} + impl ExcessiveBools { #[must_use] pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self { @@ -92,21 +101,20 @@ impl ExcessiveBools { } } - fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) { - match fn_sig.header.ext { - Extern::Implicit(_) | Extern::Explicit(_, _) => return, - Extern::None => (), + fn too_many_bools<'tcx>(&self, tys: impl Iterator>, kind: Kind) -> bool { + if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() { + (if Kind::Fn == kind { + self.max_fn_params_bools + } else { + self.max_struct_bools + }) < bools + } else { + false } + } - let fn_sig_bools = fn_sig - .decl - .inputs - .iter() - .filter(|param| is_bool_ty(¶m.ty)) - .count() - .try_into() - .unwrap(); - if self.max_fn_params_bools < fn_sig_bools { + fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) { + if self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) { span_lint_and_help( cx, FN_PARAMS_EXCESSIVE_BOOLS, @@ -121,55 +129,53 @@ impl ExcessiveBools { impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]); -fn is_bool_ty(ty: &Ty) -> bool { - if let TyKind::Path(None, path) = &ty.kind { - if let [name] = path.segments.as_slice() { - return name.ident.name == sym::bool; - } - } - false -} - -impl EarlyLintPass for ExcessiveBools { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { +impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if item.span.from_expansion() { return; } - match &item.kind { - ItemKind::Struct(variant_data, _) => { - if item.attrs.iter().any(|attr| attr.has_name(sym::repr)) { - return; - } + if let ItemKind::Struct(variant_data, _) = &item.kind { + if cx + .tcx + .hir() + .attrs(item.hir_id()) + .iter() + .any(|attr| attr.has_name(sym::repr)) + { + return; + } + + if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) { + span_lint_and_help( + cx, + STRUCT_EXCESSIVE_BOOLS, + item.span, + &format!("more than {} bools in a struct", self.max_struct_bools), + None, + "consider using a state machine or refactoring bools into two-variant enums", + ) + } + } + } - if let Ok(struct_bools) = variant_data - .fields() - .iter() - .filter(|field| is_bool_ty(&field.ty)) - .count() - .try_into() && self.max_struct_bools < struct_bools - { - span_lint_and_help( - cx, - STRUCT_EXCESSIVE_BOOLS, - item.span, - &format!("more than {} bools in a struct", self.max_struct_bools), - None, - "consider using a state machine or refactoring bools into two-variant enums", - ) - } - }, - ItemKind::Impl(box Impl { - of_trait: None, items, .. - }) - | ItemKind::Trait(box Trait { items, .. }) => { - for item in items { - if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.check_fn_sig(cx, sig, item.span); - } - } - }, - ItemKind::Fn(box Fn { sig, .. }) => self.check_fn_sig(cx, sig, item.span), - _ => (), + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, + _: &'tcx Body<'tcx>, + span: Span, + hir_id: HirId, + ) { + if let Some(fn_header) = fn_kind.header() + && fn_header.abi == Abi::Rust + && if let Some(Node::Item(item)) = get_parent_node(cx.tcx, hir_id) { + !matches!(item.kind, ItemKind::ExternCrate(..)) + } else { + true + } + && !span.from_expansion() { + self.check_fn_sig(cx, fn_decl, span) } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 01da11958e2..e96075a2673 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -793,7 +793,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports)); let max_fn_params_bools = conf.max_fn_params_bools; let max_struct_bools = conf.max_struct_bools; - store.register_early_pass(move || { + store.register_late_pass(move |_| { Box::new(excessive_bools::ExcessiveBools::new( max_struct_bools, max_fn_params_bools, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6665329d114..996d4cb4123 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -104,11 +104,10 @@ 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_ty_adt_constructor_opaque, 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::{contains_return, is_bool, is_trait_method, iter_input_pats, meets_msrv, msrvs, 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; @@ -3966,14 +3965,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 diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 02b973e5b27..da8c976c952 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::HirIdMap; use rustc_hir::{ ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, - PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, + PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -1030,6 +1030,14 @@ pub fn hash_stmt(cx: &LateContext<'_>, s: &Stmt<'_>) -> u64 { h.finish() } +pub fn is_bool(ty: &Ty<'_>) -> bool { + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + matches!(path.res, Res::PrimTy(PrimTy::Bool)) + } else { + false + } +} + pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 { let mut h = SpanlessHash::new(cx); h.hash_expr(e); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dda4660fb7a..0000896fdb6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -66,7 +66,7 @@ pub mod visitors; pub use self::attrs::*; pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ - both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, + both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; use core::ops::ControlFlow; diff --git a/tests/ui/fn_params_excessive_bools.rs b/tests/ui/fn_params_excessive_bools.rs index f805bcc9ba8..4fcd4d54ce6 100644 --- a/tests/ui/fn_params_excessive_bools.rs +++ b/tests/ui/fn_params_excessive_bools.rs @@ -2,6 +2,7 @@ #![allow(clippy::too_many_arguments)] extern "C" { + // Should not lint, most of the time users have no control over extern function signatures fn f(_: bool, _: bool, _: bool, _: bool); } diff --git a/tests/ui/fn_params_excessive_bools.stderr b/tests/ui/fn_params_excessive_bools.stderr index 11627105691..9d22d3851d2 100644 --- a/tests/ui/fn_params_excessive_bools.stderr +++ b/tests/ui/fn_params_excessive_bools.stderr @@ -1,5 +1,5 @@ error: more than 3 bools in function parameters - --> $DIR/fn_params_excessive_bools.rs:18:1 + --> $DIR/fn_params_excessive_bools.rs:19:1 | LL | fn g(_: bool, _: bool, _: bool, _: bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn g(_: bool, _: bool, _: bool, _: bool) {} = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` error: more than 3 bools in function parameters - --> $DIR/fn_params_excessive_bools.rs:21:1 + --> $DIR/fn_params_excessive_bools.rs:22:1 | LL | fn t(_: S, _: S, _: Box, _: Vec, _: bool, _: bool, _: bool, _: bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,23 +16,23 @@ LL | fn t(_: S, _: S, _: Box, _: Vec, _: bool, _: bool, _: bool, _: bool = help: consider refactoring bools into two-variant enums error: more than 3 bools in function parameters - --> $DIR/fn_params_excessive_bools.rs:25:5 + --> $DIR/fn_params_excessive_bools.rs:31:5 | -LL | fn f(_: bool, _: bool, _: bool, _: bool); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn f(&self, _: bool, _: bool, _: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider refactoring bools into two-variant enums error: more than 3 bools in function parameters - --> $DIR/fn_params_excessive_bools.rs:30:5 + --> $DIR/fn_params_excessive_bools.rs:38:5 | -LL | fn f(&self, _: bool, _: bool, _: bool, _: bool) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn f(_: bool, _: bool, _: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider refactoring bools into two-variant enums error: more than 3 bools in function parameters - --> $DIR/fn_params_excessive_bools.rs:42:5 + --> $DIR/fn_params_excessive_bools.rs:43:5 | LL | / fn n(_: bool, _: u32, _: bool, _: Box, _: bool, _: bool) { LL | | fn nn(_: bool, _: bool, _: bool, _: bool) {} @@ -42,7 +42,7 @@ LL | | } = help: consider refactoring bools into two-variant enums error: more than 3 bools in function parameters - --> $DIR/fn_params_excessive_bools.rs:43:9 + --> $DIR/fn_params_excessive_bools.rs:44:9 | LL | fn nn(_: bool, _: bool, _: bool, _: bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 8bfc8bc5e0210dabd2976edad5bf285a96dcb360 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 20 Apr 2022 16:10:18 -0400 Subject: Lint `needless_collect` on non-std collection types --- .../src/methods/collapsible_str_replace.rs | 6 +- clippy_lints/src/methods/manual_str_repeat.rs | 2 - .../src/methods/map_collect_result_unit.rs | 15 +- clippy_lints/src/methods/mod.rs | 95 ++++----- clippy_lints/src/methods/needless_collect.rs | 223 +++++++++++++-------- clippy_utils/src/ty.rs | 134 ++++++++++++- tests/ui/needless_collect.fixed | 29 +++ tests/ui/needless_collect.rs | 29 +++ tests/ui/needless_collect.stderr | 26 ++- 9 files changed, 408 insertions(+), 151 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 501646863fe..ac61b437788 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( // If the parent node's `to` argument is the same as the `to` argument // of the last replace call in the current chain, don't lint as it was already linted if let Some(parent) = get_parent_expr(cx, expr) - && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent) + && let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent) && eq_expr_value(cx, to, current_to) && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() { @@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>( let mut from_args = VecDeque::new(); let _: Option<()> = for_each_expr(expr, |e| { - if let Some(("replace", _, [from, to], _)) = method_call(e) { + if let Some(("replace", _, [from, to], _, _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); from_args.push_front(from); @@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>( .collect(); let app = Applicability::MachineApplicable; let earliest_replace_call = replace_methods.methods.front().unwrap(); - if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) { + if let Some((_, _, [..], span_lo, _)) = method_call(earliest_replace_call) { span_lint_and_sugg( cx, COLLAPSIBLE_STR_REPLACE, diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 8b6b8f1bf16..8b798fdb12f 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -59,10 +59,8 @@ pub(super) fn check( if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat); if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String); - if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id); if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id); if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id); if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg); let ctxt = collect_expr.span.ctxt(); diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index d420f144eea..a0300d27870 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; @@ -11,18 +10,10 @@ use rustc_span::symbol::sym; use super::MAP_COLLECT_RESULT_UNIT; -pub(super) fn check( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - iter: &hir::Expr<'_>, - map_fn: &hir::Expr<'_>, - collect_recv: &hir::Expr<'_>, -) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) { + // return of collect `Result<(),_>` + let collect_ret_ty = cx.typeck_results().expr_ty(expr); if_chain! { - // called on Iterator - if is_trait_method(cx, collect_recv, sym::Iterator); - // return of collect `Result<(),_>` - let collect_ret_ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result); if let ty::Adt(_, substs) = collect_ret_ty.kind(); if let Some(result_t) = substs.types().next(); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c413d9baf17..1c0bbe086f7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3296,11 +3296,11 @@ impl_lint_pass!(Methods => [ /// 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 @@ -3341,8 +3341,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { }, _ => (), } - - needless_collect::check(expr, cx); } #[allow(clippy::too_many_lines)] @@ -3488,7 +3486,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); @@ -3507,28 +3505,31 @@ impl Methods { ("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); - } - }, - _ => {}, + ("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 meets_msrv(self.msrv, 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]) => { @@ -3540,8 +3541,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, self.msrv, span, err_span), _ => 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), @@ -3561,13 +3562,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); } }, @@ -3587,12 +3588,12 @@ impl Methods { 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); } @@ -3604,13 +3605,13 @@ 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) { + 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), @@ -3630,7 +3631,7 @@ 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), @@ -3643,10 +3644,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"), @@ -3711,7 +3712,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); } @@ -3734,13 +3735,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); }, _ => {}, @@ -3749,19 +3750,19 @@ 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], _)) + 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); @@ -3782,7 +3783,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); } } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 66f9e28596e..b088e642e0e 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -3,94 +3,99 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind}; -use if_chain::if_chain; +use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; +use clippy_utils::{ + can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, + CaptureKind, +}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind}; +use rustc_hir::{ + BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind, +}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; -use rustc_span::Span; +use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span, Symbol}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; -pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - check_needless_collect_direct_usage(expr, cx); - check_needless_collect_indirect_usage(expr, cx); -} -fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind; - if let ExprKind::MethodCall(chain_method, ..) = receiver.kind; - if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator); - then { - let ty = cx.typeck_results().expr_ty(receiver); - let mut applicability = Applicability::MaybeIncorrect; - let is_empty_sugg = "next().is_none()".to_string(); - let method_name = method.ident.name.as_str(); - let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) || - is_type_diagnostic_item(cx, ty, sym::VecDeque) || - is_type_diagnostic_item(cx, ty, sym::LinkedList) || - is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { - match method_name { - "len" => "count()".to_string(), - "is_empty" => is_empty_sugg, - "contains" => { - let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability); - let (arg, pred) = contains_arg - .strip_prefix('&') - .map_or(("&x", &*contains_arg), |s| ("x", s)); - format!("any(|{arg}| x == {pred})") - } - _ => return, - } - } - else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) || - is_type_diagnostic_item(cx, ty, sym::HashMap) { - match method_name { - "is_empty" => is_empty_sugg, - _ => return, - } - } - else { - return; - }; - span_lint_and_sugg( - cx, - NEEDLESS_COLLECT, - chain_method.ident.span.with_hi(expr.span.hi()), - NEEDLESS_COLLECT_MSG, - "replace with", - sugg, - applicability, - ); - } - } -} +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + name_span: Span, + collect_expr: &'tcx Expr<'_>, + iter_expr: &'tcx Expr<'tcx>, + call_span: Span, +) { + if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) { + match parent { + Node::Expr(parent) => { + if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { + let mut app = Applicability::MachineApplicable; + let name = name.ident.as_str(); + let collect_ty = cx.typeck_results().expr_ty(collect_expr); -fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { - if let ExprKind::Block(block, _) = expr.kind { - for stmt in block.stmts { - if_chain! { - if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(_, id, ..) = local.pat.kind; - if let Some(init_expr) = local.init; - if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind; - if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); - let ty = cx.typeck_results().expr_ty(init_expr); - if is_type_diagnostic_item(cx, ty, sym::Vec) || - is_type_diagnostic_item(cx, ty, sym::VecDeque) || - is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || - is_type_diagnostic_item(cx, ty, sym::LinkedList); - let iter_ty = cx.typeck_results().expr_ty(iter_source); - if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)); - if let [iter_call] = &*iter_calls; - then { + let sugg: String = match name { + "len" => { + if let Some(adt) = collect_ty.ty_adt_def() + && matches!( + cx.tcx.get_diagnostic_name(adt.did()), + Some(sym::Vec | sym::VecDeque | sym::LinkedList | sym::BinaryHeap) + ) + { + "count()".into() + } else { + return; + } + }, + "is_empty" + if is_is_empty_sig(cx, parent.hir_id) + && iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) => + { + "next().is_none()".into() + }, + "contains" => { + if is_contains_sig(cx, parent.hir_id, iter_expr) + && let Some(arg) = args.first() + { + let (span, prefix) = if let ExprKind::AddrOf(_, _, arg) = arg.kind { + (arg.span, "") + } else { + (arg.span, "*") + }; + let snip = snippet_with_applicability(cx, span, "??", &mut app); + format!("any(|x| x == {prefix}{snip})") + } else { + return; + } + }, + _ => return, + }; + + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + call_span.with_hi(parent.span.hi()), + NEEDLESS_COLLECT_MSG, + "replace with", + sugg, + app, + ); + } + }, + Node::Local(l) => { + if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) + = l.pat.kind + && let ty = cx.typeck_results().expr_ty(collect_expr) + && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter() + .any(|item| is_type_diagnostic_item(cx, ty, item)) + && let iter_ty = cx.typeck_results().expr_ty(iter_expr) + && let Some(block) = get_enclosing_block(cx, l.hir_id) + && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) + && let [iter_call] = &*iter_calls + { let mut used_count_visitor = UsedCountVisitor { cx, id, @@ -102,20 +107,20 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo } // Suggest replacing iter_call with iter_replacement, and removing stmt - let mut span = MultiSpan::from_span(method_name.ident.span); + let mut span = MultiSpan::from_span(name_span); span.push_span_label(iter_call.span, "the iterator could be used here instead"); span_lint_hir_and_then( cx, super::NEEDLESS_COLLECT, - init_expr.hir_id, + collect_expr.hir_id, span, NEEDLESS_COLLECT_MSG, |diag| { - let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx)); + let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); diag.multipart_suggestion( iter_call.get_suggestion_text(), vec![ - (stmt.span, String::new()), + (l.span, String::new()), (iter_call.span, iter_replacement) ], Applicability::MaybeIncorrect, @@ -123,11 +128,61 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo }, ); } - } + }, + _ => (), } } } +/// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` +fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { + cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { + let sig = cx.tcx.fn_sig(id).skip_binder(); + sig.inputs().len() == 1 && sig.output().is_bool() + }) +} + +/// Checks if `::Item` is the same as `::Item` +fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool { + let item = Symbol::intern("Item"); + if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty]) + && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty]) + && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( + cx.param_env, + cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs) + ) + { + iter_item_ty == into_iter_item_ty + } else { + false + } +} + +/// Checks if the given method call matches the expected signature of +/// `([&[mut]] self, &::Item) -> bool` +fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool { + let typeck = cx.typeck_results(); + if let Some(id) = typeck.type_dependent_def_id(call_id) + && let sig = cx.tcx.fn_sig(id) + && sig.skip_binder().output().is_bool() + && let [_, search_ty] = *sig.skip_binder().inputs() + && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind() + && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let Some(iter_item) = cx.tcx + .associated_items(iter_trait) + .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait) + && let substs = cx.tcx.mk_substs([GenericArg::from(typeck.expr_ty_adjusted(iter_expr))].into_iter()) + && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) + && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) + { + item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) + } else { + false + } +} + struct IterFunction { func: IterFunctionKind, span: Span, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2dd8c826ab3..a022aac4bfe 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -13,8 +13,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ - self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, - Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, + self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, GenericParamDefKind, IntTy, ParamEnv, Predicate, + PredicateKind, ProjectionTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; @@ -938,3 +939,132 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { (Err(_), _) => 0, } } + +/// Makes the projection type for the named associated type in the given impl or trait impl. +/// +/// This function is for associated types which are "known" to exist, and as such, will only return +/// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions +/// enabled this will check that the named associated type exists, the correct number of +/// substitutions are given, and that the correct kinds of substitutions are given (lifetime, +/// constant or type). This will not check if type normalization would succeed. +pub fn make_projection<'tcx>( + tcx: TyCtxt<'tcx>, + container_id: DefId, + assoc_ty: Symbol, + substs: impl IntoIterator>>, +) -> Option> { + fn helper<'tcx>( + tcx: TyCtxt<'tcx>, + container_id: DefId, + assoc_ty: Symbol, + substs: SubstsRef<'tcx>, + ) -> Option> { + let Some(assoc_item) = tcx + .associated_items(container_id) + .find_by_name_and_kind(tcx, Ident::with_dummy_span(assoc_ty), AssocKind::Type, container_id) + else { + debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`"); + return None; + }; + #[cfg(debug_assertions)] + { + let generics = tcx.generics_of(assoc_item.def_id); + let generic_count = generics.parent_count + generics.params.len(); + let params = generics + .parent + .map_or([].as_slice(), |id| &*tcx.generics_of(id).params) + .iter() + .chain(&generics.params) + .map(|x| &x.kind); + + debug_assert!( + generic_count == substs.len(), + "wrong number of substs for `{:?}`: found `{}` expected `{}`.\n\ + note: the expected parameters are: {:#?}\n\ + the given arguments are: `{:#?}`", + assoc_item.def_id, + substs.len(), + generic_count, + params.map(GenericParamDefKind::descr).collect::>(), + substs, + ); + + if let Some((idx, (param, arg))) = params + .clone() + .zip(substs.iter().map(GenericArg::unpack)) + .enumerate() + .find(|(_, (param, arg))| { + !matches!( + (param, arg), + (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_)) + | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_)) + | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) + ) + }) + { + debug_assert!( + false, + "mismatched subst type at index {}: expected a {}, found `{:?}`\n\ + note: the expected parameters are {:#?}\n\ + the given arguments are {:#?}", + idx, + param.descr(), + arg, + params.map(GenericParamDefKind::descr).collect::>(), + substs, + ); + } + } + + Some(ProjectionTy { + substs, + item_def_id: assoc_item.def_id, + }) + } + helper( + tcx, + container_id, + assoc_ty, + tcx.mk_substs(substs.into_iter().map(Into::into)), + ) +} + +/// Normalizes the named associated type in the given impl or trait impl. +/// +/// This function is for associated types which are "known" to be valid with the given +/// substitutions, and as such, will only return `None` when debug assertions are disabled in order +/// to prevent ICE's. With debug assertions enabled this will check that that type normalization +/// succeeds as well as everything checked by `make_projection`. +pub fn make_normalized_projection<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + container_id: DefId, + assoc_ty: Symbol, + substs: impl IntoIterator>>, +) -> Option> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { + #[cfg(debug_assertions)] + if let Some((i, subst)) = ty + .substs + .iter() + .enumerate() + .find(|(_, subst)| subst.has_late_bound_regions()) + { + debug_assert!( + false, + "substs contain late-bound region at index `{i}` which can't be normalized.\n\ + use `TyCtxt::erase_late_bound_regions`\n\ + note: subst is `{subst:#?}`", + ); + return None; + } + match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.item_def_id, ty.substs)) { + Ok(ty) => Some(ty), + Err(e) => { + debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); + None + }, + } + } + helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?) +} diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index 6ecbbcb6249..2659ad38488 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -33,4 +33,33 @@ fn main() { // `BinaryHeap` doesn't have `contains` method sample.iter().count(); sample.iter().next().is_none(); + + // Don't lint string from str + let _ = ["", ""].into_iter().collect::().is_empty(); + + let _ = sample.iter().next().is_none(); + let _ = sample.iter().any(|x| x == &0); + + struct VecWrapper(Vec); + impl core::ops::Deref for VecWrapper { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl IntoIterator for VecWrapper { + type IntoIter = as IntoIterator>::IntoIter; + type Item = as IntoIterator>::Item; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } + } + impl FromIterator for VecWrapper { + fn from_iter>(iter: I) -> Self { + Self(Vec::from_iter(iter)) + } + } + + let _ = sample.iter().next().is_none(); + let _ = sample.iter().any(|x| x == &0); } diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 8dc69bcf5b3..535ec82982b 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -33,4 +33,33 @@ fn main() { // `BinaryHeap` doesn't have `contains` method sample.iter().collect::>().len(); sample.iter().collect::>().is_empty(); + + // Don't lint string from str + let _ = ["", ""].into_iter().collect::().is_empty(); + + let _ = sample.iter().collect::>().is_empty(); + let _ = sample.iter().collect::>().contains(&&0); + + struct VecWrapper(Vec); + impl core::ops::Deref for VecWrapper { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl IntoIterator for VecWrapper { + type IntoIter = as IntoIterator>::IntoIter; + type Item = as IntoIterator>::Item; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } + } + impl FromIterator for VecWrapper { + fn from_iter>(iter: I) -> Self { + Self(Vec::from_iter(iter)) + } + } + + let _ = sample.iter().collect::>().is_empty(); + let _ = sample.iter().collect::>().contains(&&0); } diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 039091627a8..584d2a1d835 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -66,5 +66,29 @@ error: avoid using `collect()` when not needed LL | sample.iter().collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` -error: aborting due to 11 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:40:27 + | +LL | let _ = sample.iter().collect::>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:41:27 + | +LL | let _ = sample.iter().collect::>().contains(&&0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:63:27 + | +LL | let _ = sample.iter().collect::>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:64:27 + | +LL | let _ = sample.iter().collect::>().contains(&&0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` + +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From 70010850e498de0b9b2a0b1874ab8271bb7da180 Mon Sep 17 00:00:00 2001 From: Grachev Mikhail Date: Tue, 8 Nov 2022 15:33:50 +0300 Subject: Update lint example for `collapsible_str_replace` --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1c0bbe086f7..686930a0bbe 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -159,7 +159,7 @@ 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.65.0"] pub COLLAPSIBLE_STR_REPLACE, -- cgit 1.4.1-3-g733a5 From 43a6d0b39ce5403c12264065a1619b49a1670a94 Mon Sep 17 00:00:00 2001 From: Ryan Scheidter Date: Tue, 8 Nov 2022 07:48:39 -0600 Subject: Fixed Typo --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1c0bbe086f7..0a240bbee6c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1731,7 +1731,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 -- cgit 1.4.1-3-g733a5 From 243661b739b122f51a17e64161d9f3a1324b8d6a Mon Sep 17 00:00:00 2001 From: hrxi Date: Sat, 12 Nov 2022 22:26:09 +0100 Subject: Make it clear that `or_fun_call` can be a false-positive Also move it to nursery so that the false-positives can be dealt with. CC #8574 --- clippy_lints/src/methods/mod.rs | 22 ++++++++++------------ tests/ui/unwrap_or.rs | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 82a2cc62d82..53f9c355c5d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -832,32 +832,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`" } diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index bfb41e43947..a0c003f5b1e 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -1,4 +1,4 @@ -#![warn(clippy::all)] +#![warn(clippy::all, clippy::or_fun_call)] fn main() { let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); -- cgit 1.4.1-3-g733a5 From 3f015a363020d3811e1f028c9ce4b0705c728289 Mon Sep 17 00:00:00 2001 From: koka Date: Thu, 17 Nov 2022 00:02:22 +0900 Subject: Avoid generating files via doctest When we run `cargo test` in `clippy_lints` directory, it will generate `foo.txt` in the directory. In order to avoid that, add `no_run` to rustdoc which contains `File::create`. --- clippy_lints/foo.txt | 1 - clippy_lints/src/methods/mod.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 clippy_lints/foo.txt (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/foo.txt b/clippy_lints/foo.txt deleted file mode 100644 index 5ab2f8a4323..00000000000 --- a/clippy_lints/foo.txt +++ /dev/null @@ -1 +0,0 @@ -Hello \ No newline at end of file diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 43507f17e35..acb3b20a61b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3077,7 +3077,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,no_run /// use std::fs::File; /// use std::io::{self, Write, Seek, SeekFrom}; /// @@ -3090,7 +3090,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```rust,no_run /// use std::fs::File; /// use std::io::{self, Write, Seek, SeekFrom}; /// -- cgit 1.4.1-3-g733a5 From 00ae5e15a8f2fde216a09751454f5e98cf241f21 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Thu, 17 Nov 2022 14:57:39 +0000 Subject: Fix typo in `expect_used` and `unwrap_used` warning messages --- clippy_lints/src/methods/expect_used.rs | 6 +++--- clippy_lints/src/methods/unwrap_used.rs | 6 +++--- tests/ui-toml/expect_used/expect_used.stderr | 4 ++-- tests/ui-toml/unwrap_used/unwrap_used.stderr | 26 +++++++++++++------------- tests/ui/expect.stderr | 6 +++--- tests/ui/get_unwrap.stderr | 26 +++++++++++++------------- tests/ui/unwrap.stderr | 6 +++--- tests/ui/unwrap_expect_used.stderr | 12 ++++++------ 8 files changed, 46 insertions(+), 46 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 0d3c8928046..cce8f797e98 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -18,9 +18,9 @@ pub(super) fn check( let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { - Some((EXPECT_USED, "an Option", "None", "")) + Some((EXPECT_USED, "an `Option`", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) + Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; @@ -36,7 +36,7 @@ pub(super) fn check( cx, lint, expr.span, - &format!("used `{method}()` on `{kind}` value"), + &format!("used `{method}()` on {kind} value"), None, &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index d11830a24b6..90983f249cd 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -18,9 +18,9 @@ pub(super) fn check( let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { - Some((UNWRAP_USED, "an Option", "None", "")) + Some((UNWRAP_USED, "an `Option`", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) + Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; @@ -45,7 +45,7 @@ pub(super) fn check( cx, lint, expr.span, - &format!("used `unwrap{method_suffix}()` on `{kind}` value"), + &format!("used `unwrap{method_suffix}()` on {kind} value"), None, &help, ); diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index 28a08599c67..1e9bb48c333 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -1,4 +1,4 @@ -error: used `expect()` on `an Option` value +error: used `expect()` on an `Option` value --> $DIR/expect_used.rs:6:13 | LL | let _ = opt.expect(""); @@ -7,7 +7,7 @@ LL | let _ = opt.expect(""); = help: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` -error: used `expect()` on `a Result` value +error: used `expect()` on a `Result` value --> $DIR/expect_used.rs:11:13 | LL | let _ = res.expect(""); diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 2bca88660e1..94b5ef663ad 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(clippy::get_unwrap)] | ^^^^^^^^^^^^^^^^^^ -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:35:17 | LL | let _ = boxed_slice.get(1).unwrap(); @@ -25,7 +25,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:36:17 | LL | let _ = some_slice.get(0).unwrap(); @@ -39,7 +39,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:37:17 | LL | let _ = some_vec.get(0).unwrap(); @@ -53,7 +53,7 @@ error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:38:17 | LL | let _ = some_vecdeque.get(0).unwrap(); @@ -67,7 +67,7 @@ error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:39:17 | LL | let _ = some_hashmap.get(&1).unwrap(); @@ -81,7 +81,7 @@ error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:40:17 | LL | let _ = some_btreemap.get(&1).unwrap(); @@ -95,7 +95,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:44:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); @@ -109,7 +109,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:49:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; @@ -123,7 +123,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:50:10 | LL | *some_slice.get_mut(0).unwrap() = 1; @@ -137,7 +137,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:51:10 | LL | *some_vec.get_mut(0).unwrap() = 1; @@ -151,7 +151,7 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:52:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; @@ -165,7 +165,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:64:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); @@ -179,7 +179,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:65:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index f6738865cac..c08e0dbbf74 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -1,4 +1,4 @@ -error: used `expect()` on `an Option` value +error: used `expect()` on an `Option` value --> $DIR/expect.rs:5:13 | LL | let _ = opt.expect(""); @@ -7,7 +7,7 @@ LL | let _ = opt.expect(""); = help: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` -error: used `expect()` on `a Result` value +error: used `expect()` on a `Result` value --> $DIR/expect.rs:10:13 | LL | let _ = res.expect(""); @@ -15,7 +15,7 @@ LL | let _ = res.expect(""); | = help: if this value is an `Err`, it will panic -error: used `expect_err()` on `a Result` value +error: used `expect_err()` on a `Result` value --> $DIR/expect.rs:11:13 | LL | let _ = res.expect_err(""); diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index 937f8590408..6dee4d5b4b6 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(clippy::get_unwrap)] | ^^^^^^^^^^^^^^^^^^ -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:35:17 | LL | let _ = boxed_slice.get(1).unwrap(); @@ -25,7 +25,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:36:17 | LL | let _ = some_slice.get(0).unwrap(); @@ -39,7 +39,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:37:17 | LL | let _ = some_vec.get(0).unwrap(); @@ -53,7 +53,7 @@ error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:38:17 | LL | let _ = some_vecdeque.get(0).unwrap(); @@ -67,7 +67,7 @@ error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:39:17 | LL | let _ = some_hashmap.get(&1).unwrap(); @@ -81,7 +81,7 @@ error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:40:17 | LL | let _ = some_btreemap.get(&1).unwrap(); @@ -95,7 +95,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:44:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); @@ -109,7 +109,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:49:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; @@ -123,7 +123,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:50:10 | LL | *some_slice.get_mut(0).unwrap() = 1; @@ -137,7 +137,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:51:10 | LL | *some_vec.get_mut(0).unwrap() = 1; @@ -151,7 +151,7 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:52:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; @@ -165,7 +165,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:64:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); @@ -179,7 +179,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:65:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index e88d580f7bd..d49bf2b3228 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -1,4 +1,4 @@ -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap.rs:5:13 | LL | let _ = opt.unwrap(); @@ -7,7 +7,7 @@ LL | let _ = opt.unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` -error: used `unwrap()` on `a Result` value +error: used `unwrap()` on a `Result` value --> $DIR/unwrap.rs:10:13 | LL | let _ = res.unwrap(); @@ -15,7 +15,7 @@ LL | let _ = res.unwrap(); | = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message -error: used `unwrap_err()` on `a Result` value +error: used `unwrap_err()` on a `Result` value --> $DIR/unwrap.rs:11:13 | LL | let _ = res.unwrap_err(); diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index 211d2be1834..fe4ecef1145 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -1,4 +1,4 @@ -error: used `unwrap()` on `an Option` value +error: used `unwrap()` on an `Option` value --> $DIR/unwrap_expect_used.rs:23:5 | LL | Some(3).unwrap(); @@ -7,7 +7,7 @@ LL | Some(3).unwrap(); = help: if this value is `None`, it will panic = note: `-D clippy::unwrap-used` implied by `-D warnings` -error: used `expect()` on `an Option` value +error: used `expect()` on an `Option` value --> $DIR/unwrap_expect_used.rs:24:5 | LL | Some(3).expect("Hello world!"); @@ -16,7 +16,7 @@ LL | Some(3).expect("Hello world!"); = help: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` -error: used `unwrap()` on `a Result` value +error: used `unwrap()` on a `Result` value --> $DIR/unwrap_expect_used.rs:31:5 | LL | a.unwrap(); @@ -24,7 +24,7 @@ LL | a.unwrap(); | = help: if this value is an `Err`, it will panic -error: used `expect()` on `a Result` value +error: used `expect()` on a `Result` value --> $DIR/unwrap_expect_used.rs:32:5 | LL | a.expect("Hello world!"); @@ -32,7 +32,7 @@ LL | a.expect("Hello world!"); | = help: if this value is an `Err`, it will panic -error: used `unwrap_err()` on `a Result` value +error: used `unwrap_err()` on a `Result` value --> $DIR/unwrap_expect_used.rs:33:5 | LL | a.unwrap_err(); @@ -40,7 +40,7 @@ LL | a.unwrap_err(); | = help: if this value is an `Ok`, it will panic -error: used `expect_err()` on `a Result` value +error: used `expect_err()` on a `Result` value --> $DIR/unwrap_expect_used.rs:34:5 | LL | a.expect_err("Hello error!"); -- cgit 1.4.1-3-g733a5 From 637139d2ff4202f9296777f8f4750bcc233b09f8 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 21 Nov 2022 14:37:51 +0000 Subject: Add `clippy_utils::msrv::Msrv` to keep track of the current MSRV --- book/src/development/adding_lints.md | 8 +- clippy_dev/src/new_lint.rs | 16 ++- clippy_lints/src/almost_complete_letter_range.rs | 11 +-- clippy_lints/src/approx_const.rs | 8 +- clippy_lints/src/attrs.rs | 12 +-- clippy_lints/src/casts/cast_abs_to_unsigned.rs | 7 +- clippy_lints/src/casts/cast_lossless.rs | 16 +-- .../src/casts/cast_slice_different_sizes.rs | 8 +- .../src/casts/cast_slice_from_raw_parts.rs | 14 +-- clippy_lints/src/casts/mod.rs | 22 ++--- clippy_lints/src/casts/ptr_as_ptr.rs | 7 +- clippy_lints/src/checked_conversions.rs | 10 +- clippy_lints/src/dereference.rs | 18 ++-- clippy_lints/src/format_args.rs | 10 +- clippy_lints/src/from_over_into.rs | 10 +- clippy_lints/src/if_then_some_else_none.rs | 14 ++- clippy_lints/src/index_refutable_slice.rs | 11 +-- clippy_lints/src/instant_subtraction.rs | 18 ++-- clippy_lints/src/lib.rs | 108 +++++++-------------- clippy_lints/src/manual_bits.rs | 10 +- clippy_lints/src/manual_clamp.rs | 33 +++---- clippy_lints/src/manual_is_ascii_check.rs | 15 ++- clippy_lints/src/manual_let_else.rs | 10 +- clippy_lints/src/manual_non_exhaustive.rs | 16 +-- clippy_lints/src/manual_rem_euclid.rs | 12 +-- clippy_lints/src/manual_retain.rs | 24 ++--- clippy_lints/src/manual_strip.rs | 10 +- clippy_lints/src/matches/mod.rs | 14 ++- clippy_lints/src/mem_replace.rs | 10 +- .../src/methods/cloned_instead_of_copied.rs | 10 +- clippy_lints/src/methods/err_expect.rs | 8 +- clippy_lints/src/methods/filter_map_next.rs | 8 +- clippy_lints/src/methods/is_digit_ascii_radix.rs | 9 +- clippy_lints/src/methods/map_clone.rs | 16 +-- clippy_lints/src/methods/map_unwrap_or.rs | 7 +- clippy_lints/src/methods/mod.rs | 36 +++---- clippy_lints/src/methods/option_as_ref_deref.rs | 8 +- clippy_lints/src/methods/str_splitn.rs | 8 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 9 +- clippy_lints/src/missing_const_for_fn.rs | 14 ++- clippy_lints/src/ranges.rs | 10 +- clippy_lints/src/redundant_field_names.rs | 9 +- clippy_lints/src/redundant_static_lifetimes.rs | 9 +- clippy_lints/src/transmute/mod.rs | 8 +- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 10 +- clippy_lints/src/unnested_or_patterns.rs | 17 ++-- clippy_lints/src/use_self.rs | 14 +-- .../src/utils/internal_lints/msrv_attr_impl.rs | 2 +- clippy_utils/src/lib.rs | 33 ++----- clippy_utils/src/msrvs.rs | 101 +++++++++++++++++++ clippy_utils/src/paths.rs | 4 +- clippy_utils/src/qualify_min_const_fn.rs | 18 ++-- tests/ui-internal/invalid_msrv_attr_impl.fixed | 4 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 4 +- tests/ui/min_rust_version_attr.rs | 23 +++++ tests/ui/min_rust_version_attr.stderr | 18 +++- 56 files changed, 466 insertions(+), 433 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 3c3f368a529..29d0d45dcc9 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -443,22 +443,22 @@ value is passed to the constructor in `clippy_lints/lib.rs`. ```rust pub struct ManualStrip { - msrv: Option, + msrv: Msrv, } impl ManualStrip { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } ``` The project's MSRV can then be matched against the feature MSRV in the LintPass -using the `meets_msrv` utility function. +using the `Msrv::meets` method. ``` rust -if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) { +if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) { return; } ``` diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 9e15f1504fa..ec7f1dd0d84 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -120,7 +120,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ", lint_pass = lint.pass, ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, @@ -238,10 +238,9 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { formatdoc!( r#" - use clippy_utils::msrvs; + use clippy_utils::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; - use rustc_semver::RustcVersion; use rustc_session::{{declare_tool_lint, impl_lint_pass}}; "# @@ -263,12 +262,12 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { formatdoc!( r#" pub struct {name_camel} {{ - msrv: Option, + msrv: Msrv, }} impl {name_camel} {{ #[must_use] - pub fn new(msrv: Option) -> Self {{ + pub fn new(msrv: Msrv) -> Self {{ Self {{ msrv }} }} }} @@ -357,15 +356,14 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let _ = writedoc!( lint_file_contents, r#" - use clippy_utils::{{meets_msrv, msrvs}}; + use clippy_utils::msrvs::{{self, Msrv}}; use rustc_lint::{{{context_import}, LintContext}}; - use rustc_semver::RustcVersion; use super::{name_upper}; // TODO: Adjust the parameters as necessary - pub(super) fn check(cx: &{context_import}, msrv: Option) {{ - if !meets_msrv(msrv, todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ + pub(super) fn check(cx: &{context_import}, msrv: &Msrv) {{ + if !msrv.meets(todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ return; }} todo!(); diff --git a/clippy_lints/src/almost_complete_letter_range.rs b/clippy_lints/src/almost_complete_letter_range.rs index 073e4af1318..3cf8ba0a521 100644 --- a/clippy_lints/src/almost_complete_letter_range.rs +++ b/clippy_lints/src/almost_complete_letter_range.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{trim_span, walk_span_to_context}; -use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; @@ -33,10 +32,10 @@ declare_clippy_lint! { impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]); pub struct AlmostCompleteLetterRange { - msrv: Option, + msrv: Msrv, } impl AlmostCompleteLetterRange { - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -46,7 +45,7 @@ impl EarlyLintPass for AlmostCompleteLetterRange { let ctxt = e.span.ctxt(); let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt) && let Some(end) = walk_span_to_context(end.span, ctxt) - && meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) + && self.msrv.meets(msrvs::RANGE_INCLUSIVE) { Some((trim_span(cx.sess().source_map(), start.between(end)), "..=")) } else { @@ -60,7 +59,7 @@ impl EarlyLintPass for AlmostCompleteLetterRange { if let PatKind::Range(Some(start), Some(end), kind) = &p.kind && matches!(kind.node, RangeEnd::Excluded) { - let sugg = if meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) { + let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) { "..=" } else { "..." diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 724490fb495..ccf82f132f4 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{meets_msrv, msrvs}; +use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -63,12 +63,12 @@ const KNOWN_CONSTS: [(f64, &str, usize, Option); 19] = [ ]; pub struct ApproxConstant { - msrv: Option, + msrv: Msrv, } impl ApproxConstant { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } @@ -87,7 +87,7 @@ impl ApproxConstant { let s = s.as_str(); if s.parse::().is_ok() { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { - if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) { + if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| self.msrv.meets(msrv)) { span_lint_and_help( cx, APPROX_CONSTANT, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index ecf8e83375d..54364f9dab2 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -2,9 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, macro_backtrace}; -use clippy_utils::msrvs; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; -use clippy_utils::{extract_msrv_attr, meets_msrv}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; @@ -14,7 +13,6 @@ use rustc_hir::{ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -599,7 +597,7 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { } pub struct EarlyAttributes { - pub msrv: Option, + pub msrv: Msrv, } impl_lint_pass!(EarlyAttributes => [ @@ -614,7 +612,7 @@ impl EarlyLintPass for EarlyAttributes { } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { - check_deprecated_cfg_attr(cx, attr, self.msrv); + check_deprecated_cfg_attr(cx, attr, &self.msrv); check_mismatched_target_os(cx, attr); } @@ -654,9 +652,9 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It } } -fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option) { +fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) { if_chain! { - if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES); + if msrv.meets(msrvs::TOOL_ATTRIBUTES); // check cfg_attr if attr.has_name(sym::cfg_attr); if let Some(items) = attr.meta_item_list(); diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 3f1edabe6c5..44226298333 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_semver::RustcVersion; use super::CAST_ABS_TO_UNSIGNED; @@ -15,9 +14,9 @@ pub(super) fn check( cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, - msrv: Option, + msrv: &Msrv, ) { - if meets_msrv(msrv, msrvs::UNSIGNED_ABS) + if msrv.meets(msrvs::UNSIGNED_ABS) && let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 13c403234da..cf07e050ccc 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_constant; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; -use clippy_utils::{in_constant, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use rustc_semver::RustcVersion; use super::{utils, CAST_LOSSLESS}; @@ -16,7 +16,7 @@ pub(super) fn check( cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, - msrv: Option, + msrv: &Msrv, ) { if !should_lint(cx, expr, cast_from, cast_to, msrv) { return; @@ -57,13 +57,7 @@ pub(super) fn check( ); } -fn should_lint( - cx: &LateContext<'_>, - expr: &Expr<'_>, - cast_from: Ty<'_>, - cast_to: Ty<'_>, - msrv: Option, -) -> bool { +fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). if in_constant(cx, expr.hir_id) { return false; @@ -89,7 +83,7 @@ fn should_lint( }; !is_isize_or_usize(cast_from) && from_nbits < to_nbits }, - (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true, + (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(msrvs::FROM_BOOL) => true, (_, _) => { matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) }, diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index d31d10d22b9..e862f13e69f 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -1,16 +1,16 @@ -use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source}; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{diagnostics::span_lint_and_then, source}; use if_chain::if_chain; use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut}; -use rustc_semver::RustcVersion; use super::CAST_SLICE_DIFFERENT_SIZES; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv) { // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist - if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) { + if !msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) { return; } diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 284ef165998..627b795d6ed 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_semver::RustcVersion; use super::CAST_SLICE_FROM_RAW_PARTS; @@ -25,15 +25,9 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { } } -pub(super) fn check( - cx: &LateContext<'_>, - expr: &Expr<'_>, - cast_expr: &Expr<'_>, - cast_to: Ty<'_>, - msrv: Option, -) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) { if_chain! { - if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS); + if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS); if let ty::RawPtr(ptrty) = cast_to.kind(); if let ty::Slice(_) = ptrty.ty.kind(); if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind; diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 7148b5e6ebf..c6d505c4a18 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -21,11 +21,11 @@ mod ptr_as_ptr; mod unnecessary_cast; mod utils; -use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs}; +use clippy_utils::is_hir_ty_cfg_dependant; +use clippy_utils::msrvs::{self, Msrv}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -648,12 +648,12 @@ declare_clippy_lint! { } pub struct Casts { - msrv: Option, + msrv: Msrv, } impl Casts { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -686,7 +686,7 @@ impl_lint_pass!(Casts => [ impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !in_external_macro(cx.sess(), expr.span) { - ptr_as_ptr::check(cx, expr, self.msrv); + ptr_as_ptr::check(cx, expr, &self.msrv); } if expr.span.from_expansion() { @@ -705,7 +705,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { return; } - cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv); + cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv); as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to); fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); @@ -717,16 +717,16 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); - cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); + cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); + cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); cast_enum_constructor::check(cx, expr, cast_expr, cast_from); } as_underscore::check(cx, expr, cast_to_hir); - if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { + if self.msrv.meets(msrvs::BORROW_AS_PTR) { borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir); } } @@ -734,8 +734,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_ref_to_mut::check(cx, expr); cast_ptr_alignment::check(cx, expr); char_lit_as_u8::check(cx, expr); - ptr_as_ptr::check(cx, expr, self.msrv); - cast_slice_different_sizes::check(cx, expr, self.msrv); + ptr_as_ptr::check(cx, expr, &self.msrv); + cast_slice_different_sizes::check(cx, expr, &self.msrv); } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index c2b9253ec35..43d75a03235 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,19 +1,18 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, TypeAndMut}; -use rustc_semver::RustcVersion; use super::PTR_AS_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option) { - if !meets_msrv(msrv, msrvs::POINTER_CAST) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { + if !msrv.meets(msrvs::POINTER_CAST) { return; } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 78e9921f036..9102a89e377 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,14 +1,14 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq}; +use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -37,12 +37,12 @@ declare_clippy_lint! { } pub struct CheckedConversions { - msrv: Option, + msrv: Msrv, } impl CheckedConversions { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -51,7 +51,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::TRY_FROM) { + if !self.msrv.meets(msrvs::TRY_FROM) { return; } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 0eee7f23982..faa8467d266 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; use clippy_utils::{ - fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local, - walk_to_expr_usage, + fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage, }; + use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch}; @@ -28,7 +29,6 @@ use rustc_middle::ty::{ self, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, }; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -181,12 +181,12 @@ pub struct Dereferencing<'tcx> { possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, // `IntoIterator` for arrays requires Rust 1.53. - msrv: Option, + msrv: Msrv, } impl<'tcx> Dereferencing<'tcx> { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv, ..Dereferencing::default() @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { match (self.state.take(), kind) { (None, kind) => { let expr_ty = typeck.expr_ty(expr); - let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, self.msrv); + let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv); match kind { RefOp::Deref => { if let Position::FieldAccess { @@ -698,7 +698,7 @@ fn walk_parents<'tcx>( cx: &LateContext<'tcx>, possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, e: &'tcx Expr<'_>, - msrv: Option, + msrv: &Msrv, ) -> (Position, &'tcx [Adjustment<'tcx>]) { let mut adjustments = [].as_slice(); let mut precedence = 0i8; @@ -1082,7 +1082,7 @@ fn needless_borrow_impl_arg_position<'tcx>( param_ty: ParamTy, mut expr: &Expr<'tcx>, precedence: i8, - msrv: Option, + msrv: &Msrv, ) -> Position { let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); @@ -1182,7 +1182,7 @@ fn needless_borrow_impl_arg_position<'tcx>( && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() && ty.is_array() - && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR) + && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) { return false; } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index a73453bf027..ec45be558f1 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::is_diag_trait_item; use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred}; use clippy_utils::macros::{ is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage, }; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs}; use if_chain::if_chain; use itertools::Itertools; use rustc_errors::Applicability; @@ -13,7 +14,6 @@ use rustc_hir::{Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; @@ -158,12 +158,12 @@ impl_lint_pass!(FormatArgs => [ ]); pub struct FormatArgs { - msrv: Option, + msrv: Msrv, } impl FormatArgs { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -188,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); check_to_string_in_format_args(cx, name, arg.param.value); } - if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) { + if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id); } } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 95eda4ea882..7ff4a05fcdd 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::path_def_id; use clippy_utils::source::snippet_opt; -use clippy_utils::{meets_msrv, msrvs, path_def_id}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ @@ -10,7 +11,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{kw, sym}; use rustc_span::{Span, Symbol}; @@ -49,12 +49,12 @@ declare_clippy_lint! { } pub struct FromOverInto { - msrv: Option, + msrv: Msrv, } impl FromOverInto { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { FromOverInto { msrv } } } @@ -63,7 +63,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); impl<'tcx> LateLintPass<'tcx> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) { + if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) { return; } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0d6718c168a..9cadaaa493e 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,14 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{ - contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks, -}; +use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -47,12 +45,12 @@ declare_clippy_lint! { } pub struct IfThenSomeElseNone { - msrv: Option, + msrv: Msrv, } impl IfThenSomeElseNone { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -61,7 +59,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !meets_msrv(self.msrv, msrvs::BOOL_THEN) { + if !self.msrv.meets(msrvs::BOOL_THEN) { return; } @@ -94,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { } else { format!("{{ /* snippet */ {arg_snip} }}") }; - let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { + let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) { "then_some" } else { method_body.insert_str(0, "|| "); diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 0d5099bde6d..ee5f10da5b8 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -1,8 +1,9 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; -use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local}; +use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use if_chain::if_chain; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; @@ -11,7 +12,6 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::Ident, Span}; @@ -51,14 +51,13 @@ declare_clippy_lint! { "avoid indexing on slices which could be destructed" } -#[derive(Copy, Clone)] pub struct IndexRefutableSlice { max_suggested_slice: u64, - msrv: Option, + msrv: Msrv, } impl IndexRefutableSlice { - pub fn new(max_suggested_slice_pattern_length: u64, msrv: Option) -> Self { + pub fn new(max_suggested_slice_pattern_length: u64, msrv: Msrv) -> Self { Self { max_suggested_slice: max_suggested_slice_pattern_length, msrv, @@ -74,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr); if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id); - if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS); + if self.msrv.meets(msrvs::SLICE_PATTERNS); let found_slices = find_slice_values(cx, let_pat); if !found_slices.is_empty(); diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 60754b224fc..dd1b23e7d9d 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,13 +1,11 @@ -use clippy_utils::{ - diagnostics::{self, span_lint_and_sugg}, - meets_msrv, msrvs, source, - sugg::Sugg, - ty, -}; +use clippy_utils::diagnostics::{self, span_lint_and_sugg}; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{source_map::Spanned, sym}; @@ -68,12 +66,12 @@ declare_clippy_lint! { } pub struct InstantSubtraction { - msrv: Option, + msrv: Msrv, } impl InstantSubtraction { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -101,7 +99,7 @@ impl LateLintPass<'_> for InstantSubtraction { } else { if_chain! { if !expr.span.from_expansion(); - if meets_msrv(self.msrv, msrvs::TRY_FROM); + if self.msrv.meets(msrvs::TRY_FROM); if is_an_instant(cx, lhs); if is_a_duration(cx, rhs); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3ab5031696d..46acc9679f5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -52,10 +52,9 @@ extern crate declare_clippy_lint; use std::io; use std::path::PathBuf; -use clippy_utils::parse_msrv; +use clippy_utils::msrvs::Msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; -use rustc_semver::RustcVersion; use rustc_session::Session; #[cfg(feature = "internal")] @@ -322,48 +321,10 @@ pub use crate::utils::conf::{lookup_conf_file, Conf}; /// Used in `./src/driver.rs`. pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. + let msrv = Msrv::read(&conf.msrv, sess); + let msrv = move || msrv.clone(); - let msrv = conf.msrv.as_ref().and_then(|s| { - parse_msrv(s, None, None).or_else(|| { - sess.err(format!( - "error reading Clippy's configuration file. `{s}` is not a valid Rust version" - )); - None - }) - }); - - store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv })); -} - -fn read_msrv(conf: &Conf, sess: &Session) -> Option { - let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") - .ok() - .and_then(|v| parse_msrv(&v, None, None)); - let clippy_msrv = conf.msrv.as_ref().and_then(|s| { - parse_msrv(s, None, None).or_else(|| { - sess.err(format!( - "error reading Clippy's configuration file. `{s}` is not a valid Rust version" - )); - None - }) - }); - - if let Some(cargo_msrv) = cargo_msrv { - if let Some(clippy_msrv) = clippy_msrv { - // if both files have an msrv, let's compare them and emit a warning if they differ - if clippy_msrv != cargo_msrv { - sess.warn(format!( - "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" - )); - } - - Some(clippy_msrv) - } else { - Some(cargo_msrv) - } - } else { - clippy_msrv - } + store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() })); } #[doc(hidden)] @@ -595,43 +556,44 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); - let msrv = read_msrv(conf, sess); + let msrv = Msrv::read(&conf.msrv, sess); + let msrv = move || msrv.clone(); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; - store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv))); + store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv()))); store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, - msrv, + msrv(), allow_expect_in_tests, allow_unwrap_in_tests, )) }); - store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv))); + store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv()))); let matches_for_let_else = conf.matches_for_let_else; - store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv, matches_for_let_else))); - store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv))); - store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); - store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv))); - store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv))); - store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv))); - store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv))); - store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv))); - store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv))); - store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv))); - store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv))); - store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else))); + store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv()))); + store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv()))); + store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv()))); + store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv()))); + store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv()))); + store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv()))); + store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv()))); + store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv()))); + store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv()))); + store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv()))); + store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv()))); store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark)); - store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv))); - store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); + store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv()))); + store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv()))); store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod)); let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; store.register_late_pass(move |_| { Box::new(index_refutable_slice::IndexRefutableSlice::new( max_suggested_slice_pattern_length, - msrv, + msrv(), )) }); store.register_late_pass(|_| Box::::default()); @@ -648,7 +610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef)); store.register_late_pass(|_| Box::new(no_effect::NoEffect)); store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); - store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv))); + store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv()))); let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; store.register_late_pass(move |_| { Box::new(cognitive_complexity::CognitiveComplexity::new( @@ -806,7 +768,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); - store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv))); + store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv()))); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); @@ -840,7 +802,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10)); - store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); + store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv()))); store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_early_pass(move || Box::new(module_style::ModStyle)); store.register_late_pass(|_| Box::new(unused_async::UnusedAsync)); @@ -865,14 +827,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); - store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv))); + store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv()))); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields)); store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); - store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv()))); store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_late_pass(|_| Box::::default()); let allow_dbg_in_tests = conf.allow_dbg_in_tests; @@ -896,20 +858,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::::default()); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); - store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); + store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv()))); store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef)); store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch)); store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec)); store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); - store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); - store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv()))); + store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|_| Box::::default()); - store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv))); + store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv()))); store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); - store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv()))); store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); @@ -920,7 +882,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods)); store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); - store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 6655c92b1da..462d73cf0b9 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{get_parent_expr, meets_msrv, msrvs}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -34,12 +34,12 @@ declare_clippy_lint! { #[derive(Clone)] pub struct ManualBits { - msrv: Option, + msrv: Msrv, } impl ManualBits { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]); impl<'tcx> LateLintPass<'tcx> for ManualBits { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) { + if !self.msrv.meets(msrvs::MANUAL_BITS) { return; } diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 02dc8755dd6..bb6d628af3b 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -1,28 +1,25 @@ +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::higher::If; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::is_const_evaluatable; +use clippy_utils::MaybePath; +use clippy_utils::{ + eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt, +}; use itertools::Itertools; +use rustc_errors::Applicability; use rustc_errors::Diagnostic; use rustc_hir::{ def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span}; use std::ops::Deref; -use clippy_utils::{ - diagnostics::{span_lint_and_then, span_lint_hir_and_then}, - eq_expr_value, - higher::If, - is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks, - peel_blocks_with_stmt, - sugg::Sugg, - ty::implements_trait, - visitors::is_const_evaluatable, - MaybePath, -}; -use rustc_errors::Applicability; - declare_clippy_lint! { /// ### What it does /// Identifies good opportunities for a clamp function from std or core, and suggests using it. @@ -87,11 +84,11 @@ declare_clippy_lint! { impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); pub struct ManualClamp { - msrv: Option, + msrv: Msrv, } impl ManualClamp { - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -114,7 +111,7 @@ struct InputMinMax<'tcx> { impl<'tcx> LateLintPass<'tcx> for ManualClamp { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !meets_msrv(self.msrv, msrvs::CLAMP) { + if !self.msrv.meets(msrvs::CLAMP) { return; } if !expr.span.from_expansion() { @@ -130,7 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { } fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { - if !meets_msrv(self.msrv, msrvs::CLAMP) { + if !self.msrv.meets(msrvs::CLAMP) { return; } for suggestion in is_two_if_pattern(cx, block) { diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index bb8c142f8e4..5ab049d8d13 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,15 +1,12 @@ +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet}; use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{def_id::DefId, sym}; -use clippy_utils::{ - diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, meets_msrv, msrvs, source::snippet, -}; - declare_clippy_lint! { /// ### What it does /// Suggests to use dedicated built-in methods, @@ -45,12 +42,12 @@ declare_clippy_lint! { impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]); pub struct ManualIsAsciiCheck { - msrv: Option, + msrv: Msrv, } impl ManualIsAsciiCheck { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -70,11 +67,11 @@ enum CharRange { impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT) { + if !self.msrv.meets(msrvs::IS_ASCII_DIGIT) { return; } - if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT_CONST) { + if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) { return; } diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 1846596fa4c..20f06830952 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,16 +1,16 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::peel_blocks; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{for_each_expr, Descend}; -use clippy_utils::{meets_msrv, msrvs, peel_blocks}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -50,13 +50,13 @@ declare_clippy_lint! { } pub struct ManualLetElse { - msrv: Option, + msrv: Msrv, matches_behaviour: MatchLintBehaviour, } impl ManualLetElse { #[must_use] - pub fn new(msrv: Option, matches_behaviour: MatchLintBehaviour) -> Self { + pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self { Self { msrv, matches_behaviour, @@ -69,7 +69,7 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]); impl<'tcx> LateLintPass<'tcx> for ManualLetElse { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) { let if_let_or_match = if_chain! { - if meets_msrv(self.msrv, msrvs::LET_ELSE); + if self.msrv.meets(msrvs::LET_ELSE); if !in_external_macro(cx.sess(), stmt.span); if let StmtKind::Local(local) = stmt.kind; if let Some(init) = local.init; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 6a42275322b..d32fa1121f4 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::is_doc_hidden; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; -use clippy_utils::{is_doc_hidden, meets_msrv, msrvs}; use rustc_ast::ast::{self, VisibilityKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -8,7 +9,6 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::ty::DefIdTree; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{sym, Span}; @@ -63,12 +63,12 @@ declare_clippy_lint! { #[expect(clippy::module_name_repetitions)] pub struct ManualNonExhaustiveStruct { - msrv: Option, + msrv: Msrv, } impl ManualNonExhaustiveStruct { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -77,14 +77,14 @@ impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]); #[expect(clippy::module_name_repetitions)] pub struct ManualNonExhaustiveEnum { - msrv: Option, + msrv: Msrv, constructed_enum_variants: FxHashSet<(DefId, DefId)>, potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>, } impl ManualNonExhaustiveEnum { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv, constructed_enum_variants: FxHashSet::default(), @@ -97,7 +97,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustiveStruct { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) { + if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { return; } @@ -149,7 +149,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) { + if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { return; } diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 6f25a2ed8e4..8d447c37150 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,12 +1,12 @@ use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{in_constant, meets_msrv, msrvs, path_to_local}; +use clippy_utils::{in_constant, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -34,12 +34,12 @@ declare_clippy_lint! { } pub struct ManualRemEuclid { - msrv: Option, + msrv: Msrv, } impl ManualRemEuclid { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -48,11 +48,11 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]); impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::REM_EUCLID) { + if !self.msrv.meets(msrvs::REM_EUCLID) { return; } - if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::REM_EUCLID_CONST) { + if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) { return; } diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 3181bc86d17..4907f02b5a3 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; -use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -50,12 +50,12 @@ declare_clippy_lint! { } pub struct ManualRetain { - msrv: Option, + msrv: Msrv, } impl ManualRetain { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -71,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain { && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) { - check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv); - check_iter(cx, parent_expr, left_expr, target_expr, self.msrv); - check_to_owned(cx, parent_expr, left_expr, target_expr, self.msrv); + check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv); + check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv); + check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv); } } @@ -85,7 +85,7 @@ fn check_into_iter( parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>, - msrv: Option, + msrv: &Msrv, ) { if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) @@ -104,7 +104,7 @@ fn check_iter( parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>, - msrv: Option, + msrv: &Msrv, ) { if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) @@ -127,9 +127,9 @@ fn check_to_owned( parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>, - msrv: Option, + msrv: &Msrv, ) { - if meets_msrv(msrv, msrvs::STRING_RETAIN) + if msrv.meets(msrvs::STRING_RETAIN) && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) @@ -215,10 +215,10 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo .any(|&method| match_def_path(cx, collect_def_id, method)) } -fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Option) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| { is_type_diagnostic_item(cx, expr_ty, *ty) - && acceptable_msrv.map_or(true, |acceptable_msrv| meets_msrv(msrv, acceptable_msrv)) + && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv)) }) } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 0976940afac..de166b9765f 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,8 +1,9 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; -use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::{eq_expr_value, higher, match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; @@ -11,7 +12,6 @@ use rustc_hir::BinOpKind; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; @@ -48,12 +48,12 @@ declare_clippy_lint! { } pub struct ManualStrip { - msrv: Option, + msrv: Msrv, } impl ManualStrip { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -68,7 +68,7 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) { + if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) { return; } diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 7d8171ead89..7b15a307fec 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -23,13 +23,13 @@ mod single_match; mod try_err; mod wild_in_or_pats; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs}; +use clippy_utils::{higher, in_constant, is_span_match}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{Span, SpanData, SyntaxContext}; @@ -930,13 +930,13 @@ declare_clippy_lint! { #[derive(Default)] pub struct Matches { - msrv: Option, + msrv: Msrv, infallible_destructuring_match_linted: bool, } impl Matches { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv, ..Matches::default() @@ -1000,9 +1000,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) { if source == MatchSource::Normal { - if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO) - && match_like_matches::check_match(cx, expr, ex, arms)) - { + if !(self.msrv.meets(msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) { match_same_arms::check(cx, arms); } @@ -1034,7 +1032,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else); if !from_expansion { if let Some(else_expr) = if_let.if_else { - if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) { + if self.msrv.meets(msrvs::MATCHES_MACRO) { match_like_matches::check_if_let( cx, expr, diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 0c4d9f100f7..35024ec1224 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,14 +1,14 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; @@ -227,12 +227,12 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< } pub struct MemReplace { - msrv: Option, + msrv: Msrv, } impl MemReplace { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); - if meets_msrv(self.msrv, msrvs::MEM_TAKE) { + if self.msrv.meets(msrvs::MEM_TAKE) { check_replace_with_default(cx, src, dest, expr.span); } } diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index e9aeab2d5b6..4e6ec61f6a8 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,25 +1,25 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; -use clippy_utils::{is_trait_method, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_span::{sym, Span}; use super::CLONED_INSTEAD_OF_COPIED; -pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option) { +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: &Msrv) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && msrv.meets(msrvs::OPTION_COPIED) => { subst.type_at(0) }, - _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => { + _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(msrvs::ITERATOR_COPIED) => { match get_iterator_item_ty(cx, recv_ty) { // ::Item Some(ty) => ty, diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 720d9a68c85..ae03da0d3f9 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -1,27 +1,27 @@ use super::ERR_EXPECT; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::has_debug_impl; -use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item}; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_semver::RustcVersion; use rustc_span::{sym, Span}; pub(super) fn check( cx: &LateContext<'_>, _expr: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>, - msrv: Option, expect_span: Span, err_span: Span, + msrv: &Msrv, ) { if_chain! { if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); // Test the version to make sure the lint can be showed (expect_err has been // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) - if meets_msrv(msrv, msrvs::EXPECT_ERR); + if msrv.meets(msrvs::EXPECT_ERR); // Grabs the `Result` type let result_type = cx.typeck_results().expr_ty(recv); diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index ddf8a1f09b8..175e04f8ac0 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::is_trait_method; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; -use clippy_utils::{is_trait_method, meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_semver::RustcVersion; use rustc_span::sym; use super::FILTER_MAP_NEXT; @@ -14,10 +14,10 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - msrv: Option, + msrv: &Msrv, ) { if is_trait_method(cx, expr, sym::Iterator) { - if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) { + if !msrv.meets(msrvs::ITERATOR_FIND_MAP) { return; } diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index 304024e8066..301aff5ae6a 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,23 +1,22 @@ //! Lint for `c.is_digit(10)` use super::IS_DIGIT_ASCII_RADIX; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::{ - consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, meets_msrv, msrvs, - source::snippet_with_applicability, + consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability, }; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_semver::RustcVersion; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, self_arg: &'tcx Expr<'_>, radix: &'tcx Expr<'_>, - msrv: Option, + msrv: &Msrv, ) { - if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) { + if !msrv.meets(msrvs::IS_ASCII_DIGIT) { return; } diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 6bc783c6d50..52cc1e0464b 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; -use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks}; +use clippy_utils::{is_diag_trait_item, peel_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -9,19 +10,12 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_semver::RustcVersion; use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; use super::MAP_CLONE; -pub(super) fn check( - cx: &LateContext<'_>, - e: &hir::Expr<'_>, - recv: &hir::Expr<'_>, - arg: &hir::Expr<'_>, - msrv: Option, -) { +pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) { if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); if cx.tcx.impl_of_method(method_id) @@ -97,10 +91,10 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { ); } -fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option) { +fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) { let mut applicability = Applicability::MachineApplicable; - let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { + let (message, sugg_method) = if is_copy && msrv.meets(msrvs::ITERATOR_COPIED) { ("you are using an explicit closure for copying elements", "copied") } else { ("you are using an explicit closure for cloning elements", "cloned") diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 74fdead216b..3122f72ee91 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::mutated_variables; -use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_semver::RustcVersion; use rustc_span::symbol::sym; use super::MAP_UNWRAP_OR; @@ -19,13 +18,13 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>, - msrv: Option, + msrv: &Msrv, ) -> bool { // lint if the caller of `map()` is an `Option` let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) { + if is_result && !msrv.meets(msrvs::RESULT_MAP_OR_ELSE) { return false; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index acb3b20a61b..c5451195727 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -104,8 +104,9 @@ 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::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, meets_msrv, msrvs, return_ty}; +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::{Expr, ExprKind, TraitItem, TraitItemKind}; @@ -113,7 +114,6 @@ 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}; @@ -3163,7 +3163,7 @@ declare_clippy_lint! { pub struct Methods { avoid_breaking_exported_api: bool, - msrv: Option, + msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, } @@ -3172,7 +3172,7 @@ impl Methods { #[must_use] pub fn new( avoid_breaking_exported_api: bool, - msrv: Option, + msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, ) -> Self { @@ -3325,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 { @@ -3501,7 +3501,7 @@ 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), + ("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) { @@ -3512,7 +3512,7 @@ impl Methods { map_collect_result_unit::check(cx, expr, m_recv, m_arg); }, Some(("take", take_self_arg, [take_arg], _, _)) => { - if meets_msrv(self.msrv, msrvs::STR_REPEAT) { + if self.msrv.meets(msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, @@ -3539,7 +3539,7 @@ 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(("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), @@ -3578,7 +3578,7 @@ 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", []) => { @@ -3601,7 +3601,7 @@ impl Methods { }, (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { - map_clone::check(cx, expr, recv, m_arg, self.msrv); + 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); } @@ -3610,8 +3610,8 @@ impl Methods { } 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); }, @@ -3632,7 +3632,7 @@ impl Methods { 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), @@ -3680,10 +3680,10 @@ impl Methods { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, ("seek", [arg]) => { - if meets_msrv(self.msrv, msrvs::SEEK_FROM_CURRENT) { + if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) { seek_from_current::check(cx, expr, recv, arg); } - if meets_msrv(self.msrv, msrvs::SEEK_REWIND) { + if self.msrv.meets(msrvs::SEEK_REWIND) { seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } }, @@ -3699,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, _]) => { @@ -3717,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"); @@ -3760,7 +3760,7 @@ impl Methods { }, ("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) => {}, + 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"); diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index e6eb64bcbde..3e33f919337 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks}; +use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_span::sym; use super::OPTION_AS_REF_DEREF; @@ -19,9 +19,9 @@ pub(super) fn check( as_ref_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, is_mut: bool, - msrv: Option, + msrv: &Msrv, ) { - if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) { + if !msrv.meets(msrvs::OPTION_AS_DEREF) { return; } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 1acac59144c..3c01ce1fecd 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -1,9 +1,10 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; -use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths}; +use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; @@ -12,7 +13,6 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_span::{sym, Span, Symbol, SyntaxContext}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; @@ -24,7 +24,7 @@ pub(super) fn check( self_arg: &Expr<'_>, pat_arg: &Expr<'_>, count: u128, - msrv: Option, + msrv: &Msrv, ) { if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { return; @@ -34,7 +34,7 @@ pub(super) fn check( IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::NextTuple => count > 2, }; - let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE); + let manual = count == 2 && msrv.meets(msrvs::STR_SPLIT_ONCE); match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) { Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 4b4f2f47b1d..21d1df4d0c2 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,11 +1,11 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; -use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; use rustc_hir_analysis::check::{FnCtxt, Inherited}; @@ -16,7 +16,6 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::EarlyBinder; use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; -use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; use std::cmp::max; @@ -29,7 +28,7 @@ pub fn check<'tcx>( method_name: Symbol, receiver: &'tcx Expr<'_>, args: &'tcx [Expr<'_>], - msrv: Option, + msrv: &Msrv, ) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); @@ -200,7 +199,7 @@ fn check_into_iter_call_arg( expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>, - msrv: Option, + msrv: &Msrv, ) -> bool { if_chain! { if let Some(parent) = get_parent_expr(cx, expr); @@ -215,7 +214,7 @@ fn check_into_iter_call_arg( if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } - let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { + let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 71cc0d0a81c..5bc04bc17fb 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; -use clippy_utils::{ - fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method, -}; +use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; @@ -11,7 +10,6 @@ use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; @@ -75,12 +73,12 @@ declare_clippy_lint! { impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]); pub struct MissingConstForFn { - msrv: Option, + msrv: Msrv, } impl MissingConstForFn { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -95,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { span: Span, hir_id: HirId, ) { - if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) { + if !self.msrv.meets(msrvs::CONST_IF_MATCH) { return; } @@ -152,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) { + if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { cx.tcx.sess.span_err(span, err.as_ref()); } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index c6fbb5e805a..0a1b9d173cf 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,16 +1,16 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::higher; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, path_to_local}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use std::cmp::Ordering; @@ -161,12 +161,12 @@ declare_clippy_lint! { } pub struct Ranges { - msrv: Option, + msrv: Msrv, } impl Ranges { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -181,7 +181,7 @@ impl_lint_pass!(Ranges => [ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, l, r) = expr.kind { - if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { + if self.msrv.meets(msrvs::RANGE_CONTAINS) { check_possible_range_contains(cx, op.node, l, r, expr, expr.span); } } diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 40b03068f6c..61bff4a0e38 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{meets_msrv, msrvs}; +use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -37,12 +36,12 @@ declare_clippy_lint! { } pub struct RedundantFieldNames { - msrv: Option, + msrv: Msrv, } impl RedundantFieldNames { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -51,7 +50,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) { + if !self.msrv.meets(msrvs::FIELD_INIT_SHORTHAND) { return; } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 60ba62c4a43..3aa2490bc44 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; -use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -34,12 +33,12 @@ declare_clippy_lint! { } pub struct RedundantStaticLifetimes { - msrv: Option, + msrv: Msrv, } impl RedundantStaticLifetimes { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -96,7 +95,7 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) { + if !self.msrv.meets(msrvs::STATIC_IN_CONST) { return; } diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 424a6e9264e..83e651aba8e 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -16,10 +16,10 @@ mod utils; mod wrong_transmute; use clippy_utils::in_constant; +use clippy_utils::msrvs::Msrv; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; @@ -410,7 +410,7 @@ declare_clippy_lint! { } pub struct Transmute { - msrv: Option, + msrv: Msrv, } impl_lint_pass!(Transmute => [ CROSSPOINTER_TRANSMUTE, @@ -431,7 +431,7 @@ impl_lint_pass!(Transmute => [ ]); impl Transmute { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -461,7 +461,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) | transmuting_null::check(cx, e, arg, to_ty) - | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) + | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 12d0b866e1c..3dde4eee671 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,12 +1,12 @@ use super::TRANSMUTE_PTR_TO_REF; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{meets_msrv, msrvs, sugg}; +use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitable}; -use rustc_semver::RustcVersion; /// Checks for `transmute_ptr_to_ref` lint. /// Returns `true` if it's triggered, otherwise returns `false`. @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, path: &'tcx Path<'_>, - msrv: Option, + msrv: &Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => { @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( let sugg = if let Some(ty) = get_explicit_type(path) { let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); - if meets_msrv(msrv, msrvs::POINTER_CAST) { + if msrv.meets(msrvs::POINTER_CAST) { format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par()) } else if from_ptr_ty.has_erased_regions() { sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string() @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( } } else if from_ptr_ty.ty == *to_ref_ty { if from_ptr_ty.has_erased_regions() { - if meets_msrv(msrv, msrvs::POINTER_CAST) { + if msrv.meets(msrvs::POINTER_CAST) { format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) } else { sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))) diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index b305dae7608..2c2730267db 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -2,14 +2,14 @@ use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{meets_msrv, msrvs, over}; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::over; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::DUMMY_SP; @@ -45,14 +45,13 @@ declare_clippy_lint! { "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`" } -#[derive(Clone, Copy)] pub struct UnnestedOrPatterns { - msrv: Option, + msrv: Msrv, } impl UnnestedOrPatterns { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv } } } @@ -61,13 +60,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]); impl EarlyLintPass for UnnestedOrPatterns { fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { - if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { + if self.msrv.meets(msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &a.pat); } } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { + if self.msrv.meets(msrvs::OR_PATTERNS) { if let ast::ExprKind::Let(pat, _, _) = &e.kind { lint_unnested_or_patterns(cx, pat); } @@ -75,13 +74,13 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { - if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { + if self.msrv.meets(msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &p.pat); } } fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { - if meets_msrv(self.msrv, msrvs::OR_PATTERNS) { + if self.msrv.meets(msrvs::OR_PATTERNS) { lint_unnested_or_patterns(cx, &l.pat); } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 464ffdc0a2a..06975443d8f 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::same_type_and_consts; -use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -14,7 +15,6 @@ use rustc_hir::{ }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; @@ -57,13 +57,13 @@ declare_clippy_lint! { #[derive(Default)] pub struct UseSelf { - msrv: Option, + msrv: Msrv, stack: Vec, } impl UseSelf { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Msrv) -> Self { Self { msrv, ..Self::default() @@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { if_chain! { if !hir_ty.span.from_expansion(); - if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); + if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, in_body, @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if !expr.span.from_expansion(); - if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); + if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id); then {} else { return; } @@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { if_chain! { if !pat.span.from_expansion(); - if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS); + if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); // get the path from the pattern if let PatKind::Path(QPath::Resolved(_, path)) diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 1e994e3f2b1..9876a8a765c 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -41,7 +41,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { .type_of(f.did) .walk() .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) - .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION)) + .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV)) }); if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs)); then { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b0063758dce..86ee172cb28 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -105,8 +105,6 @@ use rustc_middle::ty::{ layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture, }; use rustc_middle::ty::{FloatTy, IntTy, UintTy}; -use rustc_semver::RustcVersion; -use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::sym; @@ -118,36 +116,17 @@ use crate::consts::{constant, Constant}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; -pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { - if let Ok(version) = RustcVersion::parse(msrv) { - return Some(version); - } else if let Some(sess) = sess { - if let Some(span) = span { - sess.span_err(span, format!("`{msrv}` is not a valid Rust version")); - } - } - None -} - -pub fn meets_msrv(msrv: Option, lint_msrv: RustcVersion) -> bool { - msrv.map_or(true, |msrv| msrv.meets(lint_msrv)) -} - #[macro_export] macro_rules! extract_msrv_attr { ($context:ident) => { fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { let sess = rustc_lint::LintContext::sess(cx); - match $crate::get_unique_inner_attr(sess, attrs, "msrv") { - Some(msrv_attr) => { - if let Some(msrv) = msrv_attr.value_str() { - self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span)); - } else { - sess.span_err(msrv_attr.span, "bad clippy attribute"); - } - }, - _ => (), - } + self.msrv.enter_lint_attrs(sess, attrs); + } + + fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { + let sess = rustc_lint::LintContext::sess(cx); + self.msrv.exit_lint_attrs(sess, attrs); } }; } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 79b19e6fb3e..2c9f75736e5 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -1,4 +1,11 @@ +use std::sync::OnceLock; + +use rustc_ast::Attribute; use rustc_semver::RustcVersion; +use rustc_session::Session; +use rustc_span::Span; + +use crate::attrs::get_unique_inner_attr; macro_rules! msrv_aliases { ($($major:literal,$minor:literal,$patch:literal { @@ -40,3 +47,97 @@ msrv_aliases! { 1,16,0 { STR_REPEAT } 1,55,0 { SEEK_REWIND } } + +fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { + if let Ok(version) = RustcVersion::parse(msrv) { + return Some(version); + } else if let Some(sess) = sess { + if let Some(span) = span { + sess.span_err(span, format!("`{msrv}` is not a valid Rust version")); + } + } + None +} + +/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` +#[derive(Debug, Clone, Default)] +pub struct Msrv { + stack: Vec, +} + +impl Msrv { + fn new(initial: Option) -> Self { + Self { + stack: Vec::from_iter(initial), + } + } + + fn read_inner(conf_msrv: &Option, sess: &Session) -> Self { + let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") + .ok() + .and_then(|v| parse_msrv(&v, None, None)); + let clippy_msrv = conf_msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(format!( + "error reading Clippy's configuration file. `{s}` is not a valid Rust version" + )); + None + }) + }); + + // if both files have an msrv, let's compare them and emit a warning if they differ + if let Some(cargo_msrv) = cargo_msrv + && let Some(clippy_msrv) = clippy_msrv + && clippy_msrv != cargo_msrv + { + sess.warn(format!( + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" + )); + } + + Self::new(clippy_msrv.or(cargo_msrv)) + } + + /// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version` + /// field in `Cargo.toml` + /// + /// Returns a `&'static Msrv` as `Copy` types are more easily passed to the + /// `register_{late,early}_pass` callbacks + pub fn read(conf_msrv: &Option, sess: &Session) -> &'static Self { + static PARSED: OnceLock = OnceLock::new(); + + PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess)) + } + + pub fn current(&self) -> Option { + self.stack.last().copied() + } + + pub fn meets(&self, required: RustcVersion) -> bool { + self.current().map_or(true, |version| version.meets(required)) + } + + fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option { + if let Some(msrv_attr) = get_unique_inner_attr(sess, attrs, "msrv") { + if let Some(msrv) = msrv_attr.value_str() { + return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span)); + } + + sess.span_err(msrv_attr.span, "bad clippy attribute"); + } + + None + } + + pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { + if let Some(version) = Self::parse_attr(sess, attrs) { + self.stack.push(version); + } + } + + pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { + if Self::parse_attr(sess, attrs).is_some() { + self.stack.pop(); + } + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 6c09c146082..3cf8cb76651 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -60,6 +60,8 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; +#[cfg(feature = "internal")] +pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; @@ -101,8 +103,6 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; -#[cfg(feature = "internal")] -pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 65722f142aa..0def1245615 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -3,6 +3,7 @@ // of terminologies might not be relevant in the context of Clippy. Note that its behavior might // differ from the time of `rustc` even if the name stays the same. +use crate::msrvs::Msrv; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ @@ -18,7 +19,7 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: Option) -> McfResult { +pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -280,7 +281,7 @@ fn check_terminator<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, terminator: &Terminator<'tcx>, - msrv: Option, + msrv: &Msrv, ) -> McfResult { let span = terminator.source_info.span; match &terminator.kind { @@ -364,7 +365,7 @@ fn check_terminator<'tcx>( } } -fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option) -> bool { +fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { tcx.is_const_fn(def_id) && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level { @@ -383,15 +384,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option) -> bo let since = rustc_span::Symbol::intern(short_version); - crate::meets_msrv( - msrv, - RustcVersion::parse(since.as_str()).unwrap_or_else(|err| { - panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}") - }), - ) + msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| { + panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}") + })) } else { // Unstable const fn with the feature enabled. - msrv.is_none() + msrv.current().is_none() } }) } diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 900a8fffd40..08634063a57 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -11,9 +11,9 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_session; use clippy_utils::extract_msrv_attr; +use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; -use rustc_semver::RustcVersion; declare_lint! { pub TEST_LINT, @@ -22,7 +22,7 @@ declare_lint! { } struct Pass { - msrv: Option, + msrv: Msrv, } impl_lint_pass!(Pass => [TEST_LINT]); diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index 4bc8164db67..f8af77e6d39 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -11,9 +11,9 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_session; use clippy_utils::extract_msrv_attr; +use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; -use rustc_semver::RustcVersion; declare_lint! { pub TEST_LINT, @@ -22,7 +22,7 @@ declare_lint! { } struct Pass { - msrv: Option, + msrv: Msrv, } impl_lint_pass!(Pass => [TEST_LINT]); diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index cd148063bf0..28ab132394b 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -27,3 +27,26 @@ fn no_patch_meets() { #![clippy::msrv = "1.43"] let log2_10 = 3.321928094887362; } + +// https://github.com/rust-lang/rust-clippy/issues/6920 +fn scoping() { + mod m { + #![clippy::msrv = "1.42.0"] + } + + // Should warn + let log2_10 = 3.321928094887362; + + mod a { + #![clippy::msrv = "1.42.0"] + + fn should_warn() { + #![clippy::msrv = "1.43.0"] + let log2_10 = 3.321928094887362; + } + + fn should_not_warn() { + let log2_10 = 3.321928094887362; + } + } +} diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr index 68aa5874819..6174443372f 100644 --- a/tests/ui/min_rust_version_attr.stderr +++ b/tests/ui/min_rust_version_attr.stderr @@ -23,5 +23,21 @@ LL | let log2_10 = 3.321928094887362; | = help: consider using the constant directly -error: aborting due to 3 previous errors +error: approximate value of `f{32, 64}::consts::LOG2_10` found + --> $DIR/min_rust_version_attr.rs:38:19 + | +LL | let log2_10 = 3.321928094887362; + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly + +error: approximate value of `f{32, 64}::consts::LOG2_10` found + --> $DIR/min_rust_version_attr.rs:45:27 + | +LL | let log2_10 = 3.321928094887362; + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using the constant directly + +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From ab8c6beb8526f9dbf3934835681e1ff9e951ea5b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 1 Dec 2022 23:05:53 -0500 Subject: Don't lint `implicit_clone` when the type doesn't implement clone --- clippy_lints/src/methods/implicit_clone.rs | 4 +++- tests/ui/implicit_clone.fixed | 10 ++++++++++ tests/ui/implicit_clone.rs | 10 ++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 429cdc1918d..06ecbce4e70 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::peel_mid_ty_refs; +use clippy_utils::ty::{implements_trait, peel_mid_ty_refs}; use clippy_utils::{is_diag_item_method, is_diag_trait_item}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -19,6 +19,8 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv let (input_type, ref_count) = peel_mid_ty_refs(input_type); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())); if return_type == input_type; + if let Some(clone_trait) = cx.tcx.lang_items().clone_trait(); + if implements_trait(cx, return_type, clone_trait, &[]); then { let mut app = Applicability::MachineApplicable; let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed index 33770fc2a2c..51b1afbe5ac 100644 --- a/tests/ui/implicit_clone.fixed +++ b/tests/ui/implicit_clone.fixed @@ -115,4 +115,14 @@ fn main() { let pathbuf_ref = &pathbuf_ref; let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf` let _ = (**pathbuf_ref).clone(); + + struct NoClone; + impl ToOwned for NoClone { + type Owned = Self; + fn to_owned(&self) -> Self { + NoClone + } + } + let no_clone = &NoClone; + let _ = no_clone.to_owned(); } diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index fc896525bd2..8a9027433d9 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -115,4 +115,14 @@ fn main() { let pathbuf_ref = &pathbuf_ref; let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf` let _ = pathbuf_ref.to_path_buf(); + + struct NoClone; + impl ToOwned for NoClone { + type Owned = Self; + fn to_owned(&self) -> Self { + NoClone + } + } + let no_clone = &NoClone; + let _ = no_clone.to_owned(); } -- cgit 1.4.1-3-g733a5 From 2701a4076f3d18edc06781d7a9b3091ee5dbd05f Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Fri, 2 Dec 2022 20:41:29 -0500 Subject: Fix #10021 --- clippy_lints/src/methods/unnecessary_to_owned.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 17b0507682a..9263f051972 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -386,14 +386,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Expr(parent_expr) => { if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr) { - if Some(callee_def_id) == cx.tcx.lang_items().into_future_fn() { - return false; - } - let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) && let Some(param_ty) = fn_sig.inputs().get(arg_index) && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021 + && (*param_index as usize) < call_substs.len() { if fn_sig .inputs() -- cgit 1.4.1-3-g733a5 From 591c18d2f01c140b55eed01ab33b96373a4ab230 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 7 Dec 2022 17:37:08 +0000 Subject: Add 1.58 MSRV for `collapsible_str_replace` --- clippy_lints/src/methods/mod.rs | 5 ++++- clippy_utils/src/msrvs.rs | 2 +- tests/ui/collapsible_str_replace.fixed | 11 +++++++++++ tests/ui/collapsible_str_replace.rs | 11 +++++++++++ tests/ui/collapsible_str_replace.stderr | 34 +++++++++++++++++++-------------- 5 files changed, 47 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d2913680cbb..cb7229ba8a4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3672,7 +3672,10 @@ impl Methods { no_effect_replace::check(cx, expr, arg1, arg2); // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint - if name == "replace" && let Some(("replace", ..)) = method_call(recv) { + if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY) + && name == "replace" + && let Some(("replace", ..)) = method_call(recv) + { collapsible_str_replace::check(cx, expr, arg1, arg2); } }, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 12a512f78a6..ba5bc9c3135 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -21,7 +21,7 @@ macro_rules! msrv_aliases { msrv_aliases! { 1,65,0 { LET_ELSE } 1,62,0 { BOOL_THEN_SOME } - 1,58,0 { FORMAT_ARGS_CAPTURE } + 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed index 49fc9a9629e..9792ae9ed6b 100644 --- a/tests/ui/collapsible_str_replace.fixed +++ b/tests/ui/collapsible_str_replace.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(unused)] #![warn(clippy::collapsible_str_replace)] fn get_filter() -> char { @@ -71,3 +72,13 @@ fn main() { .replace('u', iter.next().unwrap()) .replace('s', iter.next().unwrap()); } + +#[clippy::msrv = "1.57"] +fn msrv_1_57() { + let _ = "".replace('a', "1.57").replace('b', "1.57"); +} + +#[clippy::msrv = "1.58"] +fn msrv_1_58() { + let _ = "".replace(['a', 'b'], "1.58"); +} diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index e3e25c4146f..baee185b79e 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(unused)] #![warn(clippy::collapsible_str_replace)] fn get_filter() -> char { @@ -74,3 +75,13 @@ fn main() { .replace('u', iter.next().unwrap()) .replace('s', iter.next().unwrap()); } + +#[clippy::msrv = "1.57"] +fn msrv_1_57() { + let _ = "".replace('a', "1.57").replace('b', "1.57"); +} + +#[clippy::msrv = "1.58"] +fn msrv_1_58() { + let _ = "".replace('a', "1.58").replace('b', "1.58"); +} diff --git a/tests/ui/collapsible_str_replace.stderr b/tests/ui/collapsible_str_replace.stderr index 8e3daf3b898..223358cf53f 100644 --- a/tests/ui/collapsible_str_replace.stderr +++ b/tests/ui/collapsible_str_replace.stderr @@ -1,5 +1,5 @@ error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:19:27 + --> $DIR/collapsible_str_replace.rs:20:27 | LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")` @@ -7,19 +7,19 @@ LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); = note: `-D clippy::collapsible-str-replace` implied by `-D warnings` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:21:27 + --> $DIR/collapsible_str_replace.rs:22:27 | LL | let _ = "hesuo worpd".replace('s', l).replace('u', l); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:23:27 + --> $DIR/collapsible_str_replace.rs:24:27 | LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:26:10 + --> $DIR/collapsible_str_replace.rs:27:10 | LL | .replace('s', "l") | __________^ @@ -29,58 +29,64 @@ LL | | .replace('d', "l"); | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:31:27 + --> $DIR/collapsible_str_replace.rs:32:27 | LL | let _ = "hesuo world".replace(s, "l").replace('u', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:33:27 + --> $DIR/collapsible_str_replace.rs:34:27 | LL | let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:35:27 + --> $DIR/collapsible_str_replace.rs:36:27 | LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:37:27 + --> $DIR/collapsible_str_replace.rs:38:27 | LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:39:27 + --> $DIR/collapsible_str_replace.rs:40:27 | LL | let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:41:45 + --> $DIR/collapsible_str_replace.rs:42:45 | LL | let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:44:47 + --> $DIR/collapsible_str_replace.rs:45:47 | LL | let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:46:28 + --> $DIR/collapsible_str_replace.rs:47:28 | LL | let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")` error: used consecutive `str::replace` call - --> $DIR/collapsible_str_replace.rs:48:27 + --> $DIR/collapsible_str_replace.rs:49:27 | LL | let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")` -error: aborting due to 13 previous errors +error: used consecutive `str::replace` call + --> $DIR/collapsible_str_replace.rs:86:16 + | +LL | let _ = "".replace('a', "1.58").replace('b', "1.58"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['a', 'b'], "1.58")` + +error: aborting due to 14 previous errors -- cgit 1.4.1-3-g733a5 From 2532c56d8643c9ee343da8dff60828fcfe77d065 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 13 Dec 2022 18:29:22 +0100 Subject: Update version attribute for 1.66 lints --- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/disallowed_macros.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/implicit_saturating_add.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 36daceabe0b..91900542af8 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// ```rust /// let x: Box = Box::default(); /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub BOX_DEFAULT, perf, "Using Box::new(T::default()) instead of Box::default()" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index c6d505c4a18..161e3a698e9 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -641,7 +641,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let _: = 0_u64; /// ``` - #[clippy::version = "1.64.0"] + #[clippy::version = "1.66.0"] pub CAST_NAN_TO_INT, suspicious, "casting a known floating-point NaN into an integer" diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 68122b4cef5..1971cab64ef 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -47,7 +47,7 @@ declare_clippy_lint! { /// value: usize, /// } /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub DISALLOWED_MACROS, style, "use of a disallowed macro" diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index f0995a81329..08976bde882 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -122,7 +122,7 @@ declare_clippy_lint! { /// /// If a format string contains a numbered argument that cannot be inlined /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub UNINLINED_FORMAT_ARGS, style, "using non-inlined variables in `format!` calls" diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index bf1351829c6..6e19343931e 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// /// u = u.saturating_add(1); /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub IMPLICIT_SATURATING_ADD, style, "Perform saturating addition instead of implicitly checking max bound of data type" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d2913680cbb..30883ba8d05 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3059,7 +3059,7 @@ declare_clippy_lint! { /// let map: HashMap = HashMap::new(); /// let values = map.values().collect::>(); /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub ITER_KV_MAP, complexity, "iterating on map using `iter` when `keys` or `values` would do" -- cgit 1.4.1-3-g733a5 From c39849a34dae51d104f197894ed5a9f02dd62d75 Mon Sep 17 00:00:00 2001 From: feniljain Date: Sat, 17 Dec 2022 17:24:03 +0530 Subject: fix: not suggest seek_to_start_instead_of_rewind when expr is used --- clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs | 6 +++++- tests/ui/seek_to_start_instead_of_rewind.fixed | 6 ++++++ tests/ui/seek_to_start_instead_of_rewind.rs | 6 ++++++ tests/ui/seek_to_start_instead_of_rewind.stderr | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7e3bed1e41a..660b7049cce 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -19,6 +19,10 @@ pub(super) fn check<'tcx>( // Get receiver type let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if is_expr_used_or_unified(cx.tcx, expr) { + return; + } + if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && implements_trait(cx, ty, seek_trait_id, &[]) && let ExprKind::Call(func, args1) = arg.kind && diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed index 9d0d1124c46..713cff604a1 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -70,6 +70,12 @@ fn seek_to_end(t: &mut T) { t.seek(SeekFrom::End(0)); } +// This should NOT trigger clippy warning because +// expr is used here +fn seek_to_start_in_let(t: &mut T) { + let a = t.seek(SeekFrom::Start(0)).unwrap(); +} + fn main() { let mut f = OpenOptions::new() .write(true) diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs index c5bc57cc3a7..467003a1a66 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -70,6 +70,12 @@ fn seek_to_end(t: &mut T) { t.seek(SeekFrom::End(0)); } +// This should NOT trigger clippy warning because +// expr is used here +fn seek_to_start_in_let(t: &mut T) { + let a = t.seek(SeekFrom::Start(0)).unwrap(); +} + fn main() { let mut f = OpenOptions::new() .write(true) diff --git a/tests/ui/seek_to_start_instead_of_rewind.stderr b/tests/ui/seek_to_start_instead_of_rewind.stderr index 6cce025359f..342ec00fe72 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.stderr +++ b/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -13,7 +13,7 @@ LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` error: used `seek` to go to the start of the stream - --> $DIR/seek_to_start_instead_of_rewind.rs:128:7 + --> $DIR/seek_to_start_instead_of_rewind.rs:134:7 | LL | f.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` -- cgit 1.4.1-3-g733a5 From 26df55112f754033d18d2157731ae3b4ecd41aa8 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Wed, 12 Oct 2022 04:34:39 -0400 Subject: Fix adjacent code --- clippy_lints/src/casts/cast_slice_different_sizes.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/loops/explicit_counter_loop.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/iter_skip_next.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 2 +- clippy_lints/src/needless_late_init.rs | 6 +++--- clippy_lints/src/octal_escapes.rs | 4 ++-- clippy_lints/src/operators/misrefactored_assign_op.rs | 2 +- clippy_lints/src/same_name_method.rs | 4 ++-- clippy_lints/src/swap.rs | 4 ++-- clippy_lints/src/transmute/transmute_undefined_repr.rs | 14 +++++++------- .../src/transmute/transmutes_expressible_as_ptr_casts.rs | 2 +- clippy_lints/src/transmute/useless_transmute.rs | 2 +- clippy_lints/src/types/redundant_allocation.rs | 8 ++++---- clippy_lints/src/unit_types/unit_arg.rs | 4 ++-- clippy_lints/src/write.rs | 4 ++-- clippy_utils/src/diagnostics.rs | 2 +- tests/ui/manual_retain.fixed | 2 +- tests/ui/manual_retain.rs | 2 +- 27 files changed, 43 insertions(+), 43 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index e862f13e69f..c8e54d7b8e0 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv diag.span_suggestion( expr.span, - &format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"), + format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"), sugg, rustc_errors::Applicability::HasPlaceholders, ); diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 62284235dbf..9891955a4ef 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -377,7 +377,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb call_site, &format!("`format!` in `{name}!` args"), |diag| { - diag.help(&format!( + diag.help(format!( "combine the `format!(..)` arguments with the outer `{name}!(..)` call" )); diag.help("or consider changing `format!` to `format_args!`"); diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index b18456ee523..b8d4abdbb78 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { ); diag.span_label( def.variants[variants_size[1].ind].span, - &if variants_size[1].fields_size.is_empty() { + if variants_size[1].fields_size.is_empty() { "the second-largest variant carries no data at all".to_owned() } else { format!( diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e88d1764a24..9eba4675629 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>( db.span_note(span, "`is_empty` defined here"); } if let Some(self_kind) = self_kind { - db.note(&output.expected_sig(self_kind)); + db.note(output.expected_sig(self_kind)); } }); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7f7d73339e4..f95b9538cef 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -335,7 +335,7 @@ pub fn read_conf(sess: &Session, path: &io::Result>) -> Conf { Ok(Some(path)) => path, Ok(None) => return Conf::default(), Err(error) => { - sess.struct_err(&format!("error finding Clippy's configuration file: {error}")) + sess.struct_err(format!("error finding Clippy's configuration file: {error}")) .emit(); return Conf::default(); }, diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 14f22348132..1953ee8a717 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( applicability, ); - diag.note(&format!( + diag.note(format!( "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" )); }, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 075ecbe7ede..af7c0563555 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, - &help, + help, format!("async {}{ret_snip}", &header_snip[..ret_pos]), Applicability::MachineApplicable ); diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index de166b9765f..c795c1d9a16 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { let test_span = expr.span.until(then.span); span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { - diag.span_note(test_span, &format!("the {kind_word} was tested here")); + diag.span_note(test_span, format!("the {kind_word} was tested here")); multispan_sugg( diag, &format!("try using the `strip_{kind_word}` method"), diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 5c620d02716..122088f4857 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -36,7 +36,7 @@ pub fn check( expr.span, &format!("calling `to_string` on `{arg_ty}`"), |diag| { - diag.help(&format!( + diag.help(format!( "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" )); let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index beb772100af..279175e20c3 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr application = Applicability::Unspecified; diag.span_help( pat.span, - &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), + format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), ); } } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 910ee14855e..4c6328481e4 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -84,7 +84,7 @@ pub(super) fn check<'tcx>( suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); } - diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability); + diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability); }); } } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 3c01ce1fecd..d00708e828e 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -167,7 +167,7 @@ fn check_manual_split_once_indirect( }; diag.span_suggestion_verbose( local.span, - &format!("try `{r}split_once`"), + format!("try `{r}split_once`"), format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"), app, ); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 0e73459ad65..47e2e744112 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( span, - &format!("use `{simplify_using}(..)` instead"), + format!("use `{simplify_using}(..)` instead"), format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), applicability, ); diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 67debe7e08a..5a9387b34cc 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -284,7 +284,7 @@ fn check<'tcx>( diag.span_suggestion( assign.lhs_span, - &format!("declare `{binding_name}` here"), + format!("declare `{binding_name}` here"), let_snippet, Applicability::MachineApplicable, ); @@ -304,7 +304,7 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{binding_name}` here"), + format!("declare `{binding_name}` here"), format!("{let_snippet} = "), applicability, ); @@ -335,7 +335,7 @@ fn check<'tcx>( diag.span_suggestion_verbose( usage.stmt.span.shrink_to_lo(), - &format!("declare `{binding_name}` here"), + format!("declare `{binding_name}` here"), format!("{let_snippet} = "), applicability, ); diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index ae0a41db918..7376ab0c846 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -125,7 +125,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { if is_string { "string" } else { "byte string" } ), |diag| { - diag.help(&format!( + diag.help(format!( "octal escapes are not supported, `\\0` is always a null {}", if is_string { "character" } else { "byte" } )); @@ -139,7 +139,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { // suggestion 2: unambiguous null byte diag.span_suggestion( span, - &format!( + format!( "if the null {} is intended, disambiguate using", if is_string { "character" } else { "byte" } ), diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index ae805147f07..015f6c14e76 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -50,7 +50,7 @@ fn lint_misrefactored_assign_op( let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r)); diag.span_suggestion( expr.span, - &format!( + format!( "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with", op.as_str() ), diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 91326558cd8..f35bfb0b4ed 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { |diag| { diag.span_note( trait_method_span, - &format!("existing `{method_name}` defined here"), + format!("existing `{method_name}` defined here"), ); }, ); @@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { // iterate on trait_spans? diag.span_note( trait_spans[0], - &format!("existing `{method_name}` defined here"), + format!("existing `{method_name}` defined here"), ); }, ); diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index c374529d1ea..17e9cc5f6b7 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -132,7 +132,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa applicability, ); if !is_xor_based { - diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?")); + diag.note(format!("or maybe you should use `{sugg}::mem::replace`?")); } }, ); @@ -214,7 +214,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { Applicability::MaybeIncorrect, ); diag.note( - &format!("or maybe you should use `{sugg}::mem::replace`?") + format!("or maybe you should use `{sugg}::mem::replace`?") ); } }); diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 34642f4b122..af0242348ac 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -77,7 +77,7 @@ pub(super) fn check<'tcx>( &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { - diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); + diag.note(format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -91,7 +91,7 @@ pub(super) fn check<'tcx>( &format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { - diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); + diag.note(format!("the contained type `{to_ty}` has an undefined layout")); } }, ); @@ -119,16 +119,16 @@ pub(super) fn check<'tcx>( ), |diag| { if let Some(same_adt_did) = same_adt_did { - diag.note(&format!( + diag.note(format!( "two instances of the same generic type (`{}`) may have different layouts", cx.tcx.item_name(same_adt_did) )); } else { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); + diag.note(format!("the contained type `{from_ty}` has an undefined layout")); } if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); + diag.note(format!("the contained type `{to_ty}` has an undefined layout")); } } }, @@ -146,7 +146,7 @@ pub(super) fn check<'tcx>( &format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{from_ty}` has an undefined layout")); + diag.note(format!("the contained type `{from_ty}` has an undefined layout")); } }, ); @@ -163,7 +163,7 @@ pub(super) fn check<'tcx>( &format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{to_ty}` has an undefined layout")); + diag.note(format!("the contained type `{to_ty}` has an undefined layout")); } }, ); diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 6b444922a7c..b79d4e915a2 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg = arg.as_ty(&to_ty.to_string()).to_string(); + let sugg = arg.as_ty(to_ty.to_string()).to_string(); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); } }, diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index f919bbd5afc..871c3fadbba 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -61,7 +61,7 @@ pub(super) fn check<'tcx>( "transmute from an integer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified); + diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); } }, ); diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index fae5385ffc8..f9b9a66b5fa 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ &format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); - diag.note(&format!( + diag.note(format!( "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap" )); }, @@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ format!("{outer_sym}<{generic_snippet}>"), applicability, ); - diag.note(&format!( + diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); }, @@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ hir_ty.span, &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { - diag.note(&format!( + diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" )); - diag.help(&format!( + diag.help(format!( "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`" )); }, diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index f6d3fb00f4e..ef9f740f704 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp if arg_snippets_without_empty_blocks.is_empty() { db.multipart_suggestion( - &format!("use {singular}unit literal{plural} instead"), + format!("use {singular}unit literal{plural} instead"), args_to_recover .iter() .map(|arg| (arg.span, "()".to_string())) @@ -142,7 +142,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp let it_or_them = if plural { "them" } else { "it" }; db.span_suggestion( expr.span, - &format!( + format!( "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`" ), sugg, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 6b321765bc0..df335038881 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -377,7 +377,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c // print!("\n"), write!(f, "\n") diag.multipart_suggestion( - &format!("use `{name}ln!` instead"), + format!("use `{name}ln!` instead"), vec![(name_span, format!("{name}ln")), (format_string_span, String::new())], Applicability::MachineApplicable, ); @@ -388,7 +388,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1)); diag.multipart_suggestion( - &format!("use `{name}ln!` instead"), + format!("use `{name}ln!` instead"), vec![(name_span, format!("{name}ln")), (newline_span, String::new())], Applicability::MachineApplicable, ); diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 16b160b6fd2..812f6fe71a0 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -17,7 +17,7 @@ use std::env; fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { - diag.help(&format!( + diag.help(format!( "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| { // extract just major + minor version and ignore patch versions diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index e5ae3cf3e50..8f25fea678f 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_retain)] -#![allow(unused)] +#![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::BinaryHeap; diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index 1021f15edd1..e6b3995a689 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_retain)] -#![allow(unused)] +#![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::BinaryHeap; -- cgit 1.4.1-3-g733a5 From 5b46f2db594fc3f2e8c6d8c7f9274ba77736b67c Mon Sep 17 00:00:00 2001 From: chansuke Date: Thu, 22 Dec 2022 22:59:06 +0900 Subject: chore: fix identation of `if_chain` in `filter_map` --- clippy_lints/src/methods/filter_map.rs | 174 ++++++++++++++++----------------- 1 file changed, 87 insertions(+), 87 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index f888c58a72d..fc80f2eeae0 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if_chain! { - if ident.name == method_name; - if let hir::ExprKind::Path(path) = &receiver.kind; - if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); - then { - return arg_id == *local - } + if ident.name == method_name; + if let hir::ExprKind::Path(path) = &receiver.kind; + if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); + then { + return arg_id == *local + } } false }, @@ -92,92 +92,92 @@ pub(super) fn check( } if_chain! { - if is_trait_method(cx, map_recv, sym::Iterator); - - // filter(|x| ...is_some())... - if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; - let filter_body = cx.tcx.hir().body(filter_body_id); - if let [filter_param] = filter_body.params; - // optional ref pattern: `filter(|&x| ..)` - let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { - (ref_pat, true) - } else { - (filter_param.pat, false) + if is_trait_method(cx, map_recv, sym::Iterator); + + // filter(|x| ...is_some())... + if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; + let filter_body = cx.tcx.hir().body(filter_body_id); + if let [filter_param] = filter_body.params; + // optional ref pattern: `filter(|&x| ..)` + let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + }; + // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; + if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { + Some(false) + } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { + Some(true) + } else { + None + }; + if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + + // ...map(|x| ...unwrap()) + if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; + let map_body = cx.tcx.hir().body(map_body_id); + if let [map_param] = map_body.params; + if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + // closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; + if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + + // .filter(..).map(|y| f(y).copied().unwrap()) + // ~~~~ + let map_arg_peeled = match map_arg.kind { + ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { + original_arg + }, + _ => map_arg, + }; + + // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) + let simple_equal = path_to_local_id(filter_arg, filter_param_id) + && path_to_local_id(map_arg_peeled, map_param_id); + + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; + then { expr_path } else { a } }; - // closure ends with is_some() or is_ok() - if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { - Some(false) - } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { - Some(true) + // let the filter closure arg and the map closure arg be equal + path_to_local_id(a_path, filter_param_id) + && path_to_local_id(b, map_param_id) + && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + }; + + if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); + then { + let span = filter_span.with_hi(expr.span.hi()); + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) } else { - None - }; - if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; - - // ...map(|x| ...unwrap()) - if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; - let map_body = cx.tcx.hir().body(map_body_id); - if let [map_param] = map_body.params; - if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; - // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); - - // .filter(..).map(|y| f(y).copied().unwrap()) - // ~~~~ - let map_arg_peeled = match map_arg.kind { - ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { - original_arg - }, - _ => map_arg, + ("filter", MANUAL_FILTER_MAP) }; + let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); + let (to_opt, deref) = if is_result { + (".ok()", String::new()) + } else { + let derefs = cx.typeck_results() + .expr_adjustments(map_arg) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); - // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) - let simple_equal = path_to_local_id(filter_arg, filter_param_id) - && path_to_local_id(map_arg_peeled, map_param_id); - - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; - // let the filter closure arg and the map closure arg be equal - path_to_local_id(a_path, filter_param_id) - && path_to_local_id(b, map_param_id) - && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + ("", "*".repeat(derefs)) }; - - if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); - then { - let span = filter_span.with_hi(expr.span.hi()); - let (filter_name, lint) = if is_find { - ("find", MANUAL_FIND_MAP) - } else { - ("filter", MANUAL_FILTER_MAP) - }; - let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); - let (to_opt, deref) = if is_result { - (".ok()", String::new()) - } else { - let derefs = cx.typeck_results() - .expr_adjustments(map_arg) - .iter() - .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) - .count(); - - ("", "*".repeat(derefs)) - }; - let sugg = format!( - "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", - snippet(cx, map_arg.span, ".."), - ); - span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); - } + let sugg = format!( + "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", + snippet(cx, map_arg.span, ".."), + ); + span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + } } } -- cgit 1.4.1-3-g733a5 From bd83650e91a751ad352444b458f9f50549fac208 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Wed, 21 Dec 2022 12:47:39 -0700 Subject: Suggest using Path for comparing extensions Signed-off-by: Tyler Weaver --- .../case_sensitive_file_extension_comparisons.rs | 38 ++++++++-- ...case_sensitive_file_extension_comparisons.fixed | 64 +++++++++++++++++ .../case_sensitive_file_extension_comparisons.rs | 8 ++- ...ase_sensitive_file_extension_comparisons.stderr | 82 +++++++++++++++++++--- 4 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 tests/ui/case_sensitive_file_extension_comparisons.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index d226c0bba65..bc9b7a73b5b 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,7 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use rustc_span::{source_map::Spanned, Span}; @@ -28,13 +30,39 @@ pub(super) fn check<'tcx>( let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String); then { - span_lint_and_help( + span_lint_and_then( cx, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - call_span, + recv.span.to(call_span), "case-sensitive file extension comparison", - None, - "consider using a case-insensitive comparison instead", + |diag| { + diag.help("consider using a case-insensitive comparison instead"); + let mut recv_str = Sugg::hir(cx, recv, "").to_string(); + + if is_type_lang_item(cx, recv_ty, LangItem::String) { + recv_str = format!("&{recv_str}"); + } + + if recv_str.contains(".to_lowercase()") { + diag.note("to_lowercase allocates memory, this can be avoided by using Path"); + recv_str = recv_str.replace(".to_lowercase()", ""); + } + + if recv_str.contains(".to_uppercase()") { + diag.note("to_uppercase allocates memory, this can be avoided by using Path"); + recv_str = recv_str.replace(".to_uppercase()", ""); + } + + diag.span_suggestion( + recv.span.to(call_span), + "use std::path::Path", + format!("std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_str, ext_str.strip_prefix('.').unwrap()), + Applicability::MaybeIncorrect, + ); + } ); } } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed new file mode 100644 index 00000000000..a8b5950f208 --- /dev/null +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -0,0 +1,64 @@ +// run-rustfix +#![warn(clippy::case_sensitive_file_extension_comparisons)] + +use std::string::String; + +struct TestStruct; + +impl TestStruct { + fn ends_with(self, _arg: &str) {} +} + +#[allow(dead_code)] +fn is_rust_file(filename: &str) -> bool { + std::path::Path::new(filename) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) +} + +fn main() { + // std::string::String and &str should trigger the lint failure with .ext12 + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + + // The test struct should not trigger the lint failure with .ext12 + TestStruct {}.ends_with(".ext12"); + + // std::string::String and &str should trigger the lint failure with .EXT12 + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + + // This should print a note about how to_lowercase and to_uppercase allocates + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + + // The test struct should not trigger the lint failure with .EXT12 + TestStruct {}.ends_with(".EXT12"); + + // Should not trigger the lint failure with .eXT12 + let _ = String::new().ends_with(".eXT12"); + let _ = "str".ends_with(".eXT12"); + TestStruct {}.ends_with(".eXT12"); + + // Should not trigger the lint failure with .EXT123 (too long) + let _ = String::new().ends_with(".EXT123"); + let _ = "str".ends_with(".EXT123"); + TestStruct {}.ends_with(".EXT123"); + + // Shouldn't fail if it doesn't start with a dot + let _ = String::new().ends_with("a.ext"); + let _ = "str".ends_with("a.extA"); + TestStruct {}.ends_with("a.ext"); +} diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 6f0485b5279..ee9bcd73d52 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; @@ -5,9 +6,10 @@ use std::string::String; struct TestStruct; impl TestStruct { - fn ends_with(self, arg: &str) {} + fn ends_with(self, _arg: &str) {} } +#[allow(dead_code)] fn is_rust_file(filename: &str) -> bool { filename.ends_with(".rs") } @@ -24,6 +26,10 @@ fn main() { let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); + // This should print a note about how to_lowercase and to_uppercase allocates + let _ = String::new().to_lowercase().ends_with(".EXT12"); + let _ = String::new().to_uppercase().ends_with(".EXT12"); + // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index a28dd8bd5ad..33435f086d4 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -1,43 +1,103 @@ error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:12:14 + --> $DIR/case_sensitive_file_extension_comparisons.rs:14:5 | LL | filename.ends_with(".rs") - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings` +help: use std::path::Path + | +LL ~ std::path::Path::new(filename) +LL + .extension() +LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27 + --> $DIR/case_sensitive_file_extension_comparisons.rs:19:13 | LL | let _ = String::new().ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:18:19 + --> $DIR/case_sensitive_file_extension_comparisons.rs:20:13 | LL | let _ = "str".ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27 + --> $DIR/case_sensitive_file_extension_comparisons.rs:26:13 | LL | let _ = String::new().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:25:19 + --> $DIR/case_sensitive_file_extension_comparisons.rs:27:13 | LL | let _ = "str".ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:30:13 + | +LL | let _ = String::new().to_lowercase().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead + = note: to_lowercase allocates memory, this can be avoided by using Path +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 + | +LL | let _ = String::new().to_uppercase().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead + = note: to_uppercase allocates memory, this can be avoided by using Path +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 0aa7d73df37470b9f868873587faf64c3339f964 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Mon, 2 Jan 2023 07:12:43 -0700 Subject: Only remove method from end of recv, indent suggestion source Signed-off-by: Tyler Weaver --- .../case_sensitive_file_extension_comparisons.rs | 28 ++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index bc9b7a73b5b..e34c377f5fc 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{indent_of, reindent_multiline}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; @@ -37,29 +38,36 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - let mut recv_str = Sugg::hir(cx, recv, "").to_string(); + let mut recv_source = Sugg::hir(cx, recv, "").to_string(); if is_type_lang_item(cx, recv_ty, LangItem::String) { - recv_str = format!("&{recv_str}"); + recv_source = format!("&{recv_source}"); } - if recv_str.contains(".to_lowercase()") { + if recv_source.ends_with(".to_lowercase()") { diag.note("to_lowercase allocates memory, this can be avoided by using Path"); - recv_str = recv_str.replace(".to_lowercase()", ""); + recv_source = recv_source.strip_suffix(".to_lowercase()").unwrap().to_string(); } - if recv_str.contains(".to_uppercase()") { + if recv_source.ends_with(".to_uppercase()") { diag.note("to_uppercase allocates memory, this can be avoided by using Path"); - recv_str = recv_str.replace(".to_uppercase()", ""); + recv_source = recv_source.strip_suffix(".to_uppercase()").unwrap().to_string(); } + let suggestion_source = reindent_multiline( + format!( + "std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_source, ext_str.strip_prefix('.').unwrap()).into(), + true, + Some(indent_of(cx, call_span).unwrap_or(0) + 4) + ); + diag.span_suggestion( recv.span.to(call_span), "use std::path::Path", - format!("std::path::Path::new({}) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_str, ext_str.strip_prefix('.').unwrap()), + suggestion_source, Applicability::MaybeIncorrect, ); } -- cgit 1.4.1-3-g733a5 From 0cee2c50952a11099692652af367b4fea3cb09a6 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Mon, 2 Jan 2023 16:42:56 -0700 Subject: Don't trigger lint if last method is to_lower/upper --- .../case_sensitive_file_extension_comparisons.rs | 17 +++++------- ...case_sensitive_file_extension_comparisons.fixed | 10 ++----- .../case_sensitive_file_extension_comparisons.rs | 2 +- ...ase_sensitive_file_extension_comparisons.stderr | 32 +--------------------- 4 files changed, 12 insertions(+), 49 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index e34c377f5fc..b6ec0fba6cf 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -18,6 +18,13 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, ) { + if let ExprKind::MethodCall(path_segment, ..) = recv.kind { + let method_name = path_segment.ident.name.as_str(); + if method_name == "to_lowercase" || method_name == "to_uppercase" { + return; + } + } + if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); @@ -44,16 +51,6 @@ pub(super) fn check<'tcx>( recv_source = format!("&{recv_source}"); } - if recv_source.ends_with(".to_lowercase()") { - diag.note("to_lowercase allocates memory, this can be avoided by using Path"); - recv_source = recv_source.strip_suffix(".to_lowercase()").unwrap().to_string(); - } - - if recv_source.ends_with(".to_uppercase()") { - diag.note("to_uppercase allocates memory, this can be avoided by using Path"); - recv_source = recv_source.strip_suffix(".to_uppercase()").unwrap().to_string(); - } - let suggestion_source = reindent_multiline( format!( "std::path::Path::new({}) diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index a8b5950f208..a19ed1ddcd5 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -36,13 +36,9 @@ fn main() { .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - // This should print a note about how to_lowercase and to_uppercase allocates - let _ = std::path::Path::new(&String::new()) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - let _ = std::path::Path::new(&String::new()) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase + let _ = String::new().to_lowercase().ends_with(".EXT12"); + let _ = String::new().to_uppercase().ends_with(".EXT12"); // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index ee9bcd73d52..ad56b7296f7 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -26,7 +26,7 @@ fn main() { let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); - // This should print a note about how to_lowercase and to_uppercase allocates + // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase let _ = String::new().to_lowercase().ends_with(".EXT12"); let _ = String::new().to_uppercase().ends_with(".EXT12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index 33435f086d4..b5c8e4b4fe6 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -69,35 +69,5 @@ LL + .extension() LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | -error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:30:13 - | -LL | let _ = String::new().to_lowercase().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead - = note: to_lowercase allocates memory, this can be avoided by using Path -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new(&String::new()) -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - | - -error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 - | -LL | let _ = String::new().to_uppercase().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using a case-insensitive comparison instead - = note: to_uppercase allocates memory, this can be avoided by using Path -help: use std::path::Path - | -LL ~ let _ = std::path::Path::new(&String::new()) -LL + .extension() -LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); - | - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From ea6ff7ed04b5785d20af03b1e4ac73b4960fa5d5 Mon Sep 17 00:00:00 2001 From: Tyler Weaver Date: Wed, 4 Jan 2023 07:06:07 -0700 Subject: Apply changes suggested in review --- .../case_sensitive_file_extension_comparisons.rs | 47 ++++++++++++---------- ...case_sensitive_file_extension_comparisons.fixed | 7 ++++ .../case_sensitive_file_extension_comparisons.rs | 5 +++ ...ase_sensitive_file_extension_comparisons.stderr | 20 +++++++-- 4 files changed, 54 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index b6ec0fba6cf..0b3bf22743f 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; @@ -19,8 +19,10 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, ) { if let ExprKind::MethodCall(path_segment, ..) = recv.kind { - let method_name = path_segment.ident.name.as_str(); - if method_name == "to_lowercase" || method_name == "to_uppercase" { + if matches!( + path_segment.ident.name.as_str(), + "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase" + ) { return; } } @@ -45,28 +47,29 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - let mut recv_source = Sugg::hir(cx, recv, "").to_string(); + if let Some(mut recv_source) = snippet_opt(cx, recv.span) { - if is_type_lang_item(cx, recv_ty, LangItem::String) { - recv_source = format!("&{recv_source}"); - } + if !cx.typeck_results().expr_ty(recv).is_ref() { + recv_source = format!("&{recv_source}"); + } - let suggestion_source = reindent_multiline( - format!( - "std::path::Path::new({}) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_source, ext_str.strip_prefix('.').unwrap()).into(), - true, - Some(indent_of(cx, call_span).unwrap_or(0) + 4) - ); + let suggestion_source = reindent_multiline( + format!( + "std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_source, ext_str.strip_prefix('.').unwrap()).into(), + true, + Some(indent_of(cx, call_span).unwrap_or(0) + 4) + ); - diag.span_suggestion( - recv.span.to(call_span), - "use std::path::Path", - suggestion_source, - Applicability::MaybeIncorrect, - ); + diag.span_suggestion( + recv.span.to(call_span), + "use std::path::Path", + suggestion_source, + Applicability::MaybeIncorrect, + ); + } } ); } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index a19ed1ddcd5..5fbaa64db39 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -25,6 +25,13 @@ fn main() { .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + // The fixup should preserve the indentation level + { + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + } + // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index ad56b7296f7..3c0d4821f9f 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -19,6 +19,11 @@ fn main() { let _ = String::new().ends_with(".ext12"); let _ = "str".ends_with(".ext12"); + // The fixup should preserve the indentation level + { + let _ = "str".ends_with(".ext12"); + } + // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index b5c8e4b4fe6..44c8e3fdf74 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -42,7 +42,21 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:26:13 + --> $DIR/case_sensitive_file_extension_comparisons.rs:24:17 + | +LL | let _ = "str".ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 | LL | let _ = String::new().ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +70,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:27:13 + --> $DIR/case_sensitive_file_extension_comparisons.rs:32:13 | LL | let _ = "str".ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,5 +83,5 @@ LL + .extension() LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From d0c1605d5151c86215ad609feadead811e5602c0 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 4 Jan 2023 13:32:34 -0800 Subject: Make the iter_kv_map lint handle ref/mut annotations. For the degenerate (`map(|(k, _)| k)`/`map(|(_, v)| v)`) cases a mut annotation is superfluous and a ref annotation won't compile, so no additional handling is required. For cases where the `map` call must be preserved ref/mut annotations should also be presereved so that the map body continues to work as expected. --- clippy_lints/src/methods/iter_kv_map.rs | 20 ++++-- tests/ui/iter_kv_map.fixed | 35 +++++++++- tests/ui/iter_kv_map.rs | 39 ++++++++++- tests/ui/iter_kv_map.stderr | 114 +++++++++++++++++++++++++------- 4 files changed, 174 insertions(+), 34 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 2244ebfb129..1e5805c5347 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; -use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; +use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::sym; @@ -30,9 +30,9 @@ pub(super) fn check<'tcx>( if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; - let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) { - (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value), - (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key), + let (replacement_kind, annotation, binded_ident) = match (&key_pat.kind, &val_pat.kind) { + (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), + (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, }; @@ -60,13 +60,23 @@ pub(super) fn check<'tcx>( applicability, ); } else { + let ref_annotation = if annotation.0 == ByRef::Yes { + "ref " + } else { + "" + }; + let mut_annotation = if annotation.1 == Mutability::Mut { + "mut " + } else { + "" + }; span_lint_and_sugg( cx, ITER_KV_MAP, expr.span, &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{binded_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index 83fee04080f..f2a4c284cb1 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -1,14 +1,15 @@ // run-rustfix #![warn(clippy::iter_kv_map)] -#![allow(clippy::redundant_clone)] -#![allow(clippy::suspicious_map)] -#![allow(clippy::map_identity)] +#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] use std::collections::{BTreeMap, HashMap}; fn main() { let get_key = |(key, _val)| key; + fn ref_acceptor(v: &u32) -> u32 { + *v + } let map: HashMap = HashMap::new(); @@ -36,6 +37,20 @@ fn main() { let _ = map.keys().map(|key| key * 9).count(); let _ = map.values().map(|value| value * 17).count(); + // Preserve the ref in the fix. + let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone().into_values().map(|mut val| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_values().count(); + let map: BTreeMap = BTreeMap::new(); let _ = map.keys().collect::>(); @@ -61,4 +76,18 @@ fn main() { // Lint let _ = map.keys().map(|key| key * 9).count(); let _ = map.values().map(|value| value * 17).count(); + + // Preserve the ref in the fix. + let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone().into_values().map(|mut val| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_values().count(); } diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index 7a1f1fb0198..ad6564df408 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -1,14 +1,15 @@ // run-rustfix #![warn(clippy::iter_kv_map)] -#![allow(clippy::redundant_clone)] -#![allow(clippy::suspicious_map)] -#![allow(clippy::map_identity)] +#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] use std::collections::{BTreeMap, HashMap}; fn main() { let get_key = |(key, _val)| key; + fn ref_acceptor(v: &u32) -> u32 { + *v + } let map: HashMap = HashMap::new(); @@ -36,6 +37,22 @@ fn main() { let _ = map.iter().map(|(key, _value)| key * 9).count(); let _ = map.iter().map(|(_key, value)| value * 17).count(); + // Preserve the ref in the fix. + let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone() + .into_iter() + .map(|(_, mut val)| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + let map: BTreeMap = BTreeMap::new(); let _ = map.iter().map(|(key, _)| key).collect::>(); @@ -61,4 +78,20 @@ fn main() { // Lint let _ = map.iter().map(|(key, _value)| key * 9).count(); let _ = map.iter().map(|(_key, value)| value * 17).count(); + + // Preserve the ref in the fix. + let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone() + .into_iter() + .map(|(_, mut val)| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); } diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 9b9b04c97d8..e00da223b4d 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -1,5 +1,5 @@ error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:15:13 + --> $DIR/iter_kv_map.rs:16:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` @@ -7,130 +7,198 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::>(); = note: `-D clippy::iter-kv-map` implied by `-D warnings` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:16:13 + --> $DIR/iter_kv_map.rs:17:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:17:13 + --> $DIR/iter_kv_map.rs:18:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:19:13 + --> $DIR/iter_kv_map.rs:20:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:20:13 + --> $DIR/iter_kv_map.rs:21:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:22:13 + --> $DIR/iter_kv_map.rs:23:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:23:13 + --> $DIR/iter_kv_map.rs:24:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:25:13 + --> $DIR/iter_kv_map.rs:26:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:26:13 + --> $DIR/iter_kv_map.rs:27:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:36:13 + --> $DIR/iter_kv_map.rs:37:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:37:13 + --> $DIR/iter_kv_map.rs:38:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` -error: iterating on a map's keys +error: iterating on a map's values --> $DIR/iter_kv_map.rs:41:13 | +LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:44:13 + | +LL | let _ = map + | _____________^ +LL | | .clone() +LL | | .into_iter() +LL | | .map(|(_, mut val)| { +LL | | val += 2; +LL | | val +LL | | }) + | |__________^ + | +help: try + | +LL ~ let _ = map +LL + .clone().into_values().map(|mut val| { +LL + val += 2; +LL + val +LL + }) + | + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:54:13 + | +LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:58:13 + | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:42:13 + --> $DIR/iter_kv_map.rs:59:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:43:13 + --> $DIR/iter_kv_map.rs:60:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:45:13 + --> $DIR/iter_kv_map.rs:62:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:46:13 + --> $DIR/iter_kv_map.rs:63:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:48:13 + --> $DIR/iter_kv_map.rs:65:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:49:13 + --> $DIR/iter_kv_map.rs:66:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:51:13 + --> $DIR/iter_kv_map.rs:68:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:52:13 + --> $DIR/iter_kv_map.rs:69:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:62:13 + --> $DIR/iter_kv_map.rs:79:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:63:13 + --> $DIR/iter_kv_map.rs:80:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` -error: aborting due to 22 previous errors +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:83:13 + | +LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:86:13 + | +LL | let _ = map + | _____________^ +LL | | .clone() +LL | | .into_iter() +LL | | .map(|(_, mut val)| { +LL | | val += 2; +LL | | val +LL | | }) + | |__________^ + | +help: try + | +LL ~ let _ = map +LL + .clone().into_values().map(|mut val| { +LL + val += 2; +LL + val +LL + }) + | + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:96:13 + | +LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: aborting due to 28 previous errors -- cgit 1.4.1-3-g733a5 From 05ba519a3ab8c06ba449d41a14e8584d785c1cb9 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 4 Jan 2023 11:23:35 +0100 Subject: trim paths in `default_trait_access`/`clone_on_copy` suggestions --- clippy_lints/src/default.rs | 5 ++--- clippy_lints/src/methods/clone_on_copy.rs | 14 ++++++++------ tests/ui/clone_on_copy.stderr | 2 +- tests/ui/default_trait_access.fixed | 8 ++++---- tests/ui/default_trait_access.stderr | 16 ++++++++-------- tests/ui/unnecessary_clone.stderr | 10 +++++----- 6 files changed, 28 insertions(+), 27 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 55f6121a09d..a04693f4637 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -11,6 +11,7 @@ use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -98,9 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let ty::Adt(def, ..) = expr_ty.kind(); if !is_from_proc_macro(cx, expr); then { - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did())); + let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did()))); span_lint_and_sugg( cx, DEFAULT_TRAIT_ACCESS, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 7c7938dd2e8..3795c0ec250 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths}; use rustc_span::symbol::{sym, Symbol}; use super::CLONE_DOUBLE_REF; @@ -47,10 +47,10 @@ pub(super) fn check( cx, CLONE_DOUBLE_REF, expr.span, - &format!( + &with_forced_trimmed_paths!(format!( "using `clone` on a double-reference; \ this will copy the reference of type `{ty}` instead of cloning the inner type" - ), + )), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; @@ -61,11 +61,11 @@ pub(super) fn check( } let refs = "&".repeat(n + 1); let derefs = "*".repeat(n); - let explicit = format!("<{refs}{ty}>::clone({snip})"); + let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})")); diag.span_suggestion( expr.span, "try dereferencing it", - format!("{refs}({derefs}{}).clone()", snip.deref()), + with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())), Applicability::MaybeIncorrect, ); diag.span_suggestion( @@ -129,7 +129,9 @@ pub(super) fn check( cx, CLONE_ON_COPY, expr.span, - &format!("using `clone` on type `{ty}` which implements the `Copy` trait"), + &with_forced_trimmed_paths!(format!( + "using `clone` on type `{ty}` which implements the `Copy` trait" + )), help, sugg, app, diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 42ae227777c..862234d204b 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -48,7 +48,7 @@ error: using `clone` on type `i32` which implements the `Copy` trait LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: using `clone` on type `std::option::Option` which implements the `Copy` trait +error: using `clone` on type `Option` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:77:17 | LL | let value = opt.clone()?; // operator precedence needed (*opt)? diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index eedd4361939..5640599d48a 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -12,17 +12,17 @@ use std::default::Default as D2; use std::string; fn main() { - let s1: String = std::string::String::default(); + let s1: String = String::default(); let s2 = String::default(); - let s3: String = std::string::String::default(); + let s3: String = String::default(); - let s4: String = std::string::String::default(); + let s4: String = String::default(); let s5 = string::String::default(); - let s6: String = std::string::String::default(); + let s6: String = String::default(); let s7 = std::string::String::default(); diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index 49b2dde3f1e..e4f73c08d19 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,8 +1,8 @@ -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:15:22 | LL | let s1: String = Default::default(); - | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^ help: try: `String::default()` | note: the lint level is defined here --> $DIR/default_trait_access.rs:3:9 @@ -10,23 +10,23 @@ note: the lint level is defined here LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:19:22 | LL | let s3: String = D2::default(); - | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^ help: try: `String::default()` -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:25:22 | LL | let s6: String = default::Default::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression --> $DIR/default_trait_access.rs:35:46 diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 94cc7777aca..6022d9fa4c5 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -38,13 +38,13 @@ LL | t.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on type `std::option::Option` which implements the `Copy` trait +error: using `clone` on type `Option` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec` instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&Vec` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); @@ -57,10 +57,10 @@ LL | let z: &Vec<_> = &(*y).clone(); | ~~~~~~~~~~~~~ help: or try being explicit if you are sure, that you want to clone a reference | -LL | let z: &Vec<_> = <&std::vec::Vec>::clone(y); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let z: &Vec<_> = <&Vec>::clone(y); + | ~~~~~~~~~~~~~~~~~~~~~ -error: using `clone` on type `many_derefs::E` which implements the `Copy` trait +error: using `clone` on type `E` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); -- cgit 1.4.1-3-g733a5 From 755ae3fa29b0b2c6b11eaecf81b201b0a9a026bf Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 4 Jan 2023 14:58:07 -0800 Subject: Fix spelling while we're in the neighborhood. --- clippy_lints/src/methods/iter_kv_map.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 1e5805c5347..c87f5daab6f 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; - let (replacement_kind, annotation, binded_ident) = match (&key_pat.kind, &val_pat.kind) { + let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( if_chain! { if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind; if let [local_ident] = path.segments; - if local_ident.ident.as_str() == binded_ident.as_str(); + if local_ident.ident.as_str() == bound_ident.as_str(); then { span_lint_and_sugg( @@ -76,7 +76,7 @@ pub(super) fn check<'tcx>( expr.span, &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{binded_ident}| {})", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); -- cgit 1.4.1-3-g733a5 From bd76d9133b62447035741e0f693de9c98893902a Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 8 Jan 2023 16:19:11 +0100 Subject: trim paths in `suspicious_to_owned` --- clippy_lints/src/methods/suspicious_to_owned.rs | 6 ++++-- tests/ui/suspicious_to_owned.stderr | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 15c1c618c51..fe88fa41fd9 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -5,7 +5,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, print::with_forced_trimmed_paths}; use rustc_span::sym; use super::SUSPICIOUS_TO_OWNED; @@ -24,7 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"), + &with_forced_trimmed_paths!(format!( + "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" + )), "consider using, depending on intent", format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), app, diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr index ae1aec34d82..dec3f50d6f1 100644 --- a/tests/ui/suspicious_to_owned.stderr +++ b/tests/ui/suspicious_to_owned.stderr @@ -1,4 +1,4 @@ -error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned +error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); @@ -6,19 +6,19 @@ LL | let _ = cow.to_owned(); | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` -error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned +error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned --> $DIR/suspicious_to_owned.rs:26:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec> contents to become owned +error: this `to_owned` call clones the Cow<'_, Vec> itself and does not cause the Cow<'_, Vec> contents to become owned --> $DIR/suspicious_to_owned.rs:36:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned +error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:46:13 | LL | let _ = cow.to_owned(); -- cgit 1.4.1-3-g733a5 From e3a09eca6d810af2105b4ed3af17048b318d25c4 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 19 Jan 2023 21:57:56 +0100 Subject: Update version attribute for 1.67 lints --- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/from_raw_with_void_ptr.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/suspicious_xor_used_as_pow.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index cdc23a4d227..f7a3d6d53f7 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -251,7 +251,7 @@ declare_clippy_lint! { /// unimplemented!(); /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub UNNECESSARY_SAFETY_DOC, restriction, "`pub fn` or `pub trait` with `# Safety` docs" diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 00f5ba56496..096508dc4f1 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// let _ = unsafe { Box::from_raw(ptr as *mut usize) }; /// ``` /// - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub FROM_RAW_WITH_VOID_PTR, suspicious, "creating a `Box` from a void raw pointer" diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 9f6e8940571..668110c7cc0 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { /// /// [`Duration`]: std::time::Duration /// [`Instant::now()`]: std::time::Instant::now; - #[clippy::version = "1.65.0"] + #[clippy::version = "1.67.0"] pub UNCHECKED_DURATION_SUBTRACTION, pedantic, "finds unchecked subtraction of a 'Duration' from an 'Instant'" diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 61f87b91400..f8e35950980 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -84,7 +84,7 @@ declare_clippy_lint! { /// let _ = foo().await; /// # } /// ``` - #[clippy::version = "1.66"] + #[clippy::version = "1.67.0"] pub LET_UNDERSCORE_FUTURE, suspicious, "non-binding `let` on a future" diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index d9ef7dffa02..2fd32c009ea 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// 'A'.is_ascii_uppercase(); /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub MANUAL_IS_ASCII_CHECK, style, "use dedicated method to check ascii range" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 77be61b4793..42377a3d138 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3102,7 +3102,7 @@ declare_clippy_lint! { /// Ok(()) /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub SEEK_FROM_CURRENT, complexity, "use dedicated method for seek from current position" @@ -3133,7 +3133,7 @@ declare_clippy_lint! { /// t.rewind(); /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub SEEK_TO_START_INSTEAD_OF_REWIND, complexity, "jumping to the start of stream using `seek` method" diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 301aa5798bf..c181919b164 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// ```rust /// let x = 3_i32.pow(4); /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub SUSPICIOUS_XOR_USED_AS_POW, restriction, "XOR (`^`) operator possibly used as exponentiation operator" -- cgit 1.4.1-3-g733a5 From 532841fcae289ff328ddbb10587695b2c6965771 Mon Sep 17 00:00:00 2001 From: koka Date: Sun, 29 Jan 2023 02:02:46 +0900 Subject: add UNNECESSARY_LAZY_EVALUATIONS to msrv UNNECESSARY_LAZY_EVALUATIONS uses msrvs::BOOL_THEN_SOME for `then` to `then_some` --- book/src/lint_configuration.md | 1 + clippy_lints/src/methods/mod.rs | 1 + clippy_lints/src/utils/conf.rs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 4c204d93e0a..d24b5259a0b 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -170,6 +170,7 @@ The minimum rust version that the project supports * [collapsible_str_replace](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) * [seek_from_current](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) * [seek_rewind](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [unnecessary_lazy_evaluations](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) ### cognitive-complexity-threshold diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 42377a3d138..6a1575e182f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1818,6 +1818,7 @@ declare_clippy_lint! { /// - `or_else` to `or` /// - `get_or_insert_with` to `get_or_insert` /// - `ok_or_else` to `ok_or` + /// - `then` to `then_some` (for msrv >= 1.62.0) /// /// ### Why is this bad? /// Using eager evaluation is shorter and simpler in some cases. diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 33ca3c16a24..21301e2e31b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -253,7 +253,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS. /// /// The minimum rust version that the project supports (msrv: Option = None), -- cgit 1.4.1-3-g733a5 From 1fb42daf11e68393f2cf9eb8e67e4b2779a4bf5e Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 5 Feb 2023 01:05:31 +0530 Subject: use span_suggestions to suggest both intents --- clippy_lints/src/methods/suspicious_to_owned.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index fe88fa41fd9..1adc7b7453e 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_diag_trait_item; use clippy_utils::source::snippet_with_context; use if_chain::if_chain; @@ -17,19 +17,25 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - let input_type = cx.typeck_results().expr_ty(expr); if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind(); if cx.tcx.is_diagnostic_item(sym::Cow, adt.did()); + then { let mut app = Applicability::MaybeIncorrect; let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; - span_lint_and_sugg( + span_lint_and_then( cx, SUSPICIOUS_TO_OWNED, expr.span, &with_forced_trimmed_paths!(format!( "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), - "consider using, depending on intent", - format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), - app, + |diag| { + diag.span_suggestions( + expr.span, + "depending on intent, either make the Cow an Owned variant or clone the Cow itself", + [format!("{recv_snip}.into_owned()"), format!("{recv_snip}.clone()")], + Applicability::Unspecified + ); + } ); return true; } -- cgit 1.4.1-3-g733a5 From 63a57ee1c381ec8ee0dec13213619113f030d773 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 5 Feb 2023 01:50:44 +0530 Subject: retain applicability --- clippy_lints/src/methods/suspicious_to_owned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 1adc7b7453e..62eeb3f7a4e 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -33,7 +33,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - expr.span, "depending on intent, either make the Cow an Owned variant or clone the Cow itself", [format!("{recv_snip}.into_owned()"), format!("{recv_snip}.clone()")], - Applicability::Unspecified + app ); } ); -- cgit 1.4.1-3-g733a5 From 2fc1693cd577eb8af48b75518945a71f1652711c Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Mon, 6 Feb 2023 21:34:35 +0530 Subject: split suggestions into two separate suggestions --- clippy_lints/src/methods/suspicious_to_owned.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 62eeb3f7a4e..e818f1892e5 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -29,10 +29,16 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), |diag| { - diag.span_suggestions( + diag.span_suggestion( expr.span, - "depending on intent, either make the Cow an Owned variant or clone the Cow itself", - [format!("{recv_snip}.into_owned()"), format!("{recv_snip}.clone()")], + "depending on intent, either make the Cow an Owned variant", + format!("{recv_snip}.into_owned()"), + app + ); + diag.span_suggestion( + expr.span, + "or clone the Cow itself", + format!("{recv_snip}.clone()"), app ); } -- cgit 1.4.1-3-g733a5 From 145e6a94d6bd9aa360fa7d43e52a2e9aad1752ef Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 16:59:04 +0100 Subject: Add suspicious_command_arg_space lint. --- clippy_lints/src/methods/mod.rs | 30 +++++++++++++++++ .../src/methods/suspicious_command_arg_space.rs | 39 ++++++++++++++++++++++ clippy_utils/src/paths.rs | 1 + 3 files changed, 70 insertions(+) create mode 100644 clippy_lints/src/methods/suspicious_command_arg_space.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f1e8be7f2b8..c97f4661cf1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -80,6 +80,7 @@ mod skip_while_next; mod stable_sort_primitive; mod str_splitn; mod string_extend_chars; +mod suspicious_command_arg_space; mod suspicious_map; mod suspicious_splitn; mod suspicious_to_owned; @@ -3162,6 +3163,32 @@ declare_clippy_lint! { "collecting an iterator when collect is not needed" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for `Command::arg()` invocations that look like they + /// should be multiple arguments instead, such as `arg("-t ext2")`. + /// + /// ### Why is this bad? + /// + /// Arguments are not split by space. An argument like `arg("-t ext2")` + /// will be passed as a single argument to the command, + /// which is likely not what was intended. + /// + /// ### Example + /// ```rust + /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); + /// ``` + /// Use instead: + /// ```rust + /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); + /// ``` + #[clippy::version = "1.67.0"] + pub SUSPICIOUS_COMMAND_ARG_SPACE, + suspicious, + "single command line argument that looks like it should be multiple arguments" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3496,6 +3523,9 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, + ("arg", [arg]) => { + suspicious_command_arg_space::check(cx, recv, arg, span); + } ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs new file mode 100644 index 00000000000..73632c5a357 --- /dev/null +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths; +use clippy_utils::ty::match_type; +use rustc_ast as ast; +use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::SUSPICIOUS_COMMAND_ARG_SPACE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + if match_type(cx, ty, &paths::STD_PROCESS_COMMAND) + && let hir::ExprKind::Lit(lit) = &arg.kind + && let ast::LitKind::Str(s, _) = &lit.node + && let Some((arg1, arg2)) = s.as_str().split_once(' ') + && arg1.starts_with('-') + && arg1.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-') + { + span_lint_and_then( + cx, + SUSPICIOUS_COMMAND_ARG_SPACE, + arg.span, + "single argument that looks like it should be multiple arguments", + |diag: &mut Diagnostic| { + diag.multipart_suggestion_verbose( + "consider splitting the argument", + vec![ + (span, "args".to_string()), + (arg.span, format!("[{arg1:?}, {arg2:?}]")), + ], + Applicability::MaybeIncorrect, + ); + } + ); + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 95eebab7567..4aae0f7284e 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -115,6 +115,7 @@ pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; +pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; -- cgit 1.4.1-3-g733a5 From 984c47b9f4e0341bf4d3ed29007f4a51bf8a146d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 18:59:37 +0100 Subject: Clarify description of suspicious_command_arg_space. Co-authored-by: Manish Goregaokar --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c97f4661cf1..7e34d08ea32 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3171,7 +3171,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// - /// Arguments are not split by space. An argument like `arg("-t ext2")` + /// `Command::arg()` does not split arguments by space. An argument like `arg("-t ext2")` /// will be passed as a single argument to the command, /// which is likely not what was intended. /// -- cgit 1.4.1-3-g733a5 From 1f77866991568557e69e2135369ab2a512052a6b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 12 Feb 2023 22:00:13 +0100 Subject: Add SUSPICIOUS_COMMAND_ARG_SPACE to lint pass. --- clippy_lints/src/methods/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7e34d08ea32..d8c018f7591 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3316,6 +3316,7 @@ impl_lint_pass!(Methods => [ SEEK_FROM_CURRENT, SEEK_TO_START_INSTEAD_OF_REWIND, NEEDLESS_COLLECT, + SUSPICIOUS_COMMAND_ARG_SPACE, ]); /// Extracts a method call name, args, and `Span` of the method name. -- cgit 1.4.1-3-g733a5 From 7e53e27dfdb5ce4cda44912fcc6c288c34ac7d91 Mon Sep 17 00:00:00 2001 From: Krishna Sundarram Date: Thu, 16 Feb 2023 16:41:04 +0000 Subject: Stop bytes_nth from suggesting code that does not compile --- clippy_lints/src/methods/bytes_nth.rs | 42 ++++++++++++++++++++++++----------- tests/ui/bytes_nth.fixed | 6 ++--- tests/ui/bytes_nth.rs | 2 +- tests/ui/bytes_nth.stderr | 10 ++++----- 4 files changed, 38 insertions(+), 22 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index d512cc4eeae..c5fc145b289 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -5,6 +5,8 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; +use crate::methods::method_call; + use super::BYTES_NTH; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) { @@ -16,18 +18,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E } else { return; }; + let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_NTH, - expr.span, - &format!("called `.bytes().nth()` on a `{caller_type}`"), - "try", - format!( - "{}.as_bytes().get({})", - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - snippet_with_applicability(cx, n_arg.span, "..", &mut applicability) - ), - applicability, - ); + let receiver = snippet_with_applicability(cx, recv.span, "..", &mut applicability); + let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability); + + if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) + && let Some((name, _, _, _, _)) = method_call(parent) + && name == "unwrap" { + span_lint_and_sugg( + cx, + BYTES_NTH, + parent.span, + &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), + "try", + format!("{receiver}.as_bytes()[{n}]",), + applicability + ); + } else { + span_lint_and_sugg( + cx, + BYTES_NTH, + expr.span, + &format!("called `.bytes().nth()` on a `{caller_type}`"), + "try", + format!("{receiver}.as_bytes().get({n}).copied()"), + applicability + ); + }; } diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed index b1fb2e16bd5..a35c679afb7 100644 --- a/tests/ui/bytes_nth.fixed +++ b/tests/ui/bytes_nth.fixed @@ -5,7 +5,7 @@ fn main() { let s = String::from("String"); - let _ = s.as_bytes().get(3); - let _ = &s.as_bytes().get(3); - let _ = s[..].as_bytes().get(3); + let _ = s.as_bytes().get(3).copied(); + let _ = &s.as_bytes()[3]; + let _ = s[..].as_bytes().get(3).copied(); } diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs index 034c54e6a42..1ecffea5303 100644 --- a/tests/ui/bytes_nth.rs +++ b/tests/ui/bytes_nth.rs @@ -6,6 +6,6 @@ fn main() { let s = String::from("String"); let _ = s.bytes().nth(3); - let _ = &s.bytes().nth(3); + let _ = &s.bytes().nth(3).unwrap(); let _ = s[..].bytes().nth(3); } diff --git a/tests/ui/bytes_nth.stderr b/tests/ui/bytes_nth.stderr index 9851d4791d8..e8b15027829 100644 --- a/tests/ui/bytes_nth.stderr +++ b/tests/ui/bytes_nth.stderr @@ -2,21 +2,21 @@ error: called `.bytes().nth()` on a `String` --> $DIR/bytes_nth.rs:8:13 | LL | let _ = s.bytes().nth(3); - | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` + | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()` | = note: `-D clippy::bytes-nth` implied by `-D warnings` -error: called `.bytes().nth()` on a `String` +error: called `.bytes().nth().unwrap()` on a `String` --> $DIR/bytes_nth.rs:9:14 | -LL | let _ = &s.bytes().nth(3); - | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` +LL | let _ = &s.bytes().nth(3).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]` error: called `.bytes().nth()` on a `str` --> $DIR/bytes_nth.rs:10:13 | LL | let _ = s[..].bytes().nth(3); - | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 72e773f6a8bca1a4aaec6866ed995eaa0fd05cb2 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:30:42 +0800 Subject: Fix test function checker in [unwrap_used], [expect_used] --- clippy_lints/src/methods/expect_used.rs | 4 ++-- clippy_lints/src/methods/unwrap_used.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index cce8f797e98..9e370de0a05 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_cfg_test; +use clippy_utils::{is_in_cfg_test, is_in_test_function}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; @@ -27,7 +27,7 @@ pub(super) fn check( let method = if is_err { "expect_err" } else { "expect" }; - if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) { + if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { return; } diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 90983f249cd..5e4c3daee64 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_in_cfg_test, is_lint_allowed}; +use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; @@ -27,7 +27,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) { + if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { return; } -- cgit 1.4.1-3-g733a5 From a5acb926c1c7042980b95a4fd75eaed278bb5d14 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:44:56 +0800 Subject: fix fmt --- clippy_lints/src/methods/expect_used.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 9e370de0a05..614610335a1 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; -- cgit 1.4.1-3-g733a5 From 90ba82bd396cf95cb02318e43a66015cc3f65d7b Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Tue, 28 Feb 2023 09:50:07 -0500 Subject: Two small documentation improvements --- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index d2852b4acad..7c5e44bb7dc 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -185,7 +185,7 @@ declare_clippy_lint! { /// ### Examples /// ```rust /// // this could be annotated with `#[must_use]`. - /// fn id(t: T) -> T { t } + /// pub fn id(t: T) -> T { t } /// ``` #[clippy::version = "1.40.0"] pub MUST_USE_CANDIDATE, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 702df4b282b..56e3988bf09 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -340,8 +340,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for methods with certain name prefixes and which - /// doesn't match how self is taken. The actual rules are: + /// Checks for methods with certain name prefixes or suffixes, and which + /// do not adhere to standard conventions regarding how `self` is taken. + /// The actual rules are: /// /// |Prefix |Postfix |`self` taken | `self` type | /// |-------|------------|-------------------------------|--------------| -- cgit 1.4.1-3-g733a5 From 1a81a3e5cfc47908154b13bd921f9c03c5592010 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 2 Mar 2023 00:51:04 -0500 Subject: Remove `snippet_with_macro_callsite` --- clippy_lints/src/default.rs | 9 +++-- clippy_lints/src/if_then_some_else_none.rs | 17 ++++----- clippy_lints/src/loops/same_item_push.rs | 32 ++++++++++------- clippy_lints/src/matches/manual_unwrap_or.rs | 12 ++----- clippy_lints/src/matches/match_bool.rs | 20 ++++++----- clippy_lints/src/matches/match_ref_pats.rs | 28 +++++++++++---- clippy_lints/src/matches/match_single_binding.rs | 41 +++++++++++---------- .../src/matches/redundant_pattern_match.rs | 17 +++++---- clippy_lints/src/matches/single_match.rs | 18 ++++------ clippy_lints/src/methods/bind_instead_of_map.rs | 11 +++--- clippy_lints/src/methods/clone_on_ref_ptr.rs | 8 +++-- clippy_lints/src/methods/or_fun_call.rs | 28 ++++----------- clippy_lints/src/misc.rs | 17 ++++----- clippy_lints/src/needless_bool.rs | 13 ++----- clippy_lints/src/option_if_let_else.rs | 28 +++++++++++---- clippy_lints/src/semicolon_if_nothing_returned.rs | 13 +++---- clippy_lints/src/unit_types/let_unit_value.rs | 7 ++-- clippy_lints/src/useless_conversion.rs | 14 ++++---- clippy_utils/src/source.rs | 42 ++++++++++++---------- clippy_utils/src/sugg.rs | 10 +----- tests/ui/redundant_pattern_matching_result.fixed | 4 +-- tests/ui/redundant_pattern_matching_result.stderr | 4 +-- 22 files changed, 200 insertions(+), 193 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 080d44e6398..80c22742ba4 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; use clippy_utils::{ any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, @@ -160,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for Default { } }; + let init_ctxt = local.span.ctxt(); + // find all "later statement"'s where the fields of the binding set as // Default::default() get reassigned, unless the reassignment refers to the original binding let mut first_assign = None; @@ -169,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs, cx) { + if contains_name(binding_name, assign_rhs, cx) || init_ctxt != consecutive_statement.span.ctxt() { cancel_lint = true; break; } @@ -204,11 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for Default { .iter() .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name)); + let mut app = Applicability::Unspecified; let field_list = assigned_fields .into_iter() .map(|(field, rhs)| { // extract and store the assigned value for help message - let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); + let value_snippet = snippet_with_context(cx, rhs.span, init_ctxt, "..", &mut app).0; format!("{field}: {value_snippet}") }) .collect::>() diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 9cadaaa493e..725bd3d54bc 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; +use clippy_utils::sugg::Sugg; use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -72,21 +74,20 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } + let ctxt = expr.span.ctxt(); + if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && then_expr.span.ctxt() == ctxt && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !stmts_contains_early_return(then_block.stmts) { - let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); - let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({cond_snip})") - } else { - cond_snip.into_owned() - }; - let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let mut app = Applicability::Unspecified; + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 540656a2cd9..9d9341559ac 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -1,15 +1,17 @@ use super::SAME_ITEM_PUSH; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use rustc_span::SyntaxContext; use std::iter::Iterator; /// Detects for loop pushing the same item into a Vec @@ -20,9 +22,10 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) { + let mut app = Applicability::Unspecified; + let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; + let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; span_lint_and_help( cx, @@ -43,7 +46,7 @@ pub(super) fn check<'tcx>( walk_expr(&mut same_item_push_visitor, body); if_chain! { if same_item_push_visitor.should_lint(); - if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push; + if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push; let vec_ty = cx.typeck_results().expr_ty(vec); let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); if cx @@ -69,11 +72,11 @@ pub(super) fn check<'tcx>( then { match init.kind { // immutable bindings that are initialized with literal - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), // immutable bindings that are initialized with constant ExprKind::Path(ref path) => { if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { - emit_lint(cx, vec, pushed_item); + emit_lint(cx, vec, pushed_item, ctxt); } } _ => {}, @@ -82,11 +85,11 @@ pub(super) fn check<'tcx>( } }, // constant - Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } }, - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } } @@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> { non_deterministic_expr: bool, multiple_pushes: bool, // this field holds the last vec push operation visited, which should be the only push seen - vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>, + vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)>, cx: &'a LateContext<'tcx>, used_locals: FxHashSet, } @@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { if_chain! { if !self.non_deterministic_expr; if !self.multiple_pushes; - if let Some((vec, _)) = self.vec_push; + if let Some((vec, _, _)) = self.vec_push; if let Some(hir_id) = path_to_local(vec); then { !self.used_locals.contains(&hir_id) @@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { // Given some statement, determine if that statement is a push on a Vec. If it is, return // the Vec being pushed into and the item being pushed -fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { +fn get_vec_push<'tcx>( + cx: &LateContext<'tcx>, + stmt: &'tcx Stmt<'_>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> { if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; @@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; then { - return Some((self_expr, pushed_item)) + return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) } } None diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 587c926dc01..84ff3c710c2 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -33,14 +33,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); - let suggestion = if scrutinee.span.from_expansion() { - // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)` - sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..") - } - else { - sugg::Sugg::hir(cx, scrutinee, "..").maybe_par() - }; - + let mut app = Applicability::MachineApplicable; + let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, @@ -49,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: format!( "{suggestion}.unwrap_or({reindented_or_body})", ), - Applicability::MachineApplicable, + app, ); } } diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index 1c216e13570..df1e585f10b 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -10,9 +10,9 @@ use rustc_middle::ty; use super::MATCH_BOOL; -pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { +pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool { + if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool { span_lint_and_then( cx, MATCH_BOOL, @@ -36,24 +36,26 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: }; if let Some((true_expr, false_expr)) = exprs { + let mut app = Applicability::HasPlaceholders; + let ctxt = expr.span.ctxt(); let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { (false, false) => Some(format!( "if {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)), - expr_block(cx, false_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )), (false, true) => Some(format!( "if {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) )), (true, false) => { - let test = Sugg::hir(cx, ex, ".."); + let test = Sugg::hir(cx, scrutinee, ".."); Some(format!( "if {} {}", !test, - expr_block(cx, false_expr, None, "..", Some(expr.span)) + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )) }, (true, true) => None, diff --git a/clippy_lints/src/matches/match_ref_pats.rs b/clippy_lints/src/matches/match_ref_pats.rs index 80f964ba1b7..aba4c85c59e 100644 --- a/clippy_lints/src/matches/match_ref_pats.rs +++ b/clippy_lints/src/matches/match_ref_pats.rs @@ -1,13 +1,14 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use core::iter::once; +use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use super::MATCH_REF_PATS; -pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) +pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, scrutinee: &Expr<'_>, pats: I, expr: &Expr<'_>) where 'b: 'a, I: Clone + Iterator>, @@ -17,13 +18,28 @@ where } let (first_sugg, msg, title); - let span = ex.span.source_callsite(); - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string())); + let ctxt = expr.span.ctxt(); + let mut app = Applicability::Unspecified; + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = scrutinee.kind { + if scrutinee.span.ctxt() != ctxt { + return; + } + first_sugg = once(( + scrutinee.span, + Sugg::hir_with_context(cx, inner, ctxt, "..", &mut app).to_string(), + )); msg = "try"; title = "you don't need to add `&` to both the expression and the patterns"; } else { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string())); + let Some(span) = walk_span_to_context(scrutinee.span, ctxt) else { + return; + }; + first_sugg = once(( + span, + Sugg::hir_with_context(cx, scrutinee, ctxt, "..", &mut app) + .deref() + .to_string(), + )); msg = "instead of prefixing all patterns with `&`, you can dereference the expression"; title = "you don't need to add `&` to all patterns"; } diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 065a5c72621..eec5c1143d4 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; -use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability}; -use clippy_utils::sugg::Sugg; +use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability}; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind}; @@ -24,21 +23,25 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e let matched_vars = ex.span; let bind_names = arms[0].pat.span; let match_body = peel_blocks(arms[0].body); - let mut snippet_body = if match_body.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string() - } else { - snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string() - }; + let mut app = Applicability::MaybeIncorrect; + let (snippet_body, from_macro) = snippet_block_with_context( + cx, + match_body.span, + arms[0].span.ctxt(), + "..", + Some(expr.span), + &mut app, + ); + let mut snippet_body = snippet_body.to_string(); // Do we need to add ';' to suggestion ? - if let ExprKind::Block(block, _) = match_body.kind { + if matches!(match_body.kind, ExprKind::Block(..)) { // macro + expr_ty(body) == () - if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { + if from_macro && cx.typeck_results().expr_ty(match_body).is_unit() { snippet_body.push(';'); } } - let mut applicability = Applicability::MaybeIncorrect; match arms[0].pat.kind { PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => { let (target_span, sugg) = match opt_parent_assign_span(cx, ex) { @@ -48,7 +51,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, Some(span), true, ); @@ -60,7 +63,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this assignment could be simplified", "consider removing the `match` expression", sugg, - applicability, + app, ); return; @@ -69,10 +72,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e span, format!( "let {} = {};\n{}let {} = {snippet_body};", - snippet_with_applicability(cx, bind_names, "..", &mut applicability), - snippet_with_applicability(cx, matched_vars, "..", &mut applicability), + snippet_with_applicability(cx, bind_names, "..", &mut app), + snippet_with_applicability(cx, matched_vars, "..", &mut app), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut applicability) + snippet_with_applicability(cx, pat_span, "..", &mut app) ), ), None => { @@ -81,7 +84,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, true, ); @@ -96,7 +99,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be written as a `let` statement", "consider using a `let` statement", sugg, - applicability, + app, ); }, PatKind::Wild => { @@ -106,7 +109,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, false, ); @@ -118,7 +121,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be replaced by its scrutinee and body", "consider using the scrutinee and body instead", sugg, - applicability, + app, ); } else { span_lint_and_sugg( diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 81bebff34c8..e8610670054 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,6 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; @@ -150,22 +150,25 @@ fn find_sugg_for_if_let<'tcx>( // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ let expr_span = expr.span; + let ctxt = expr.span.ctxt(); // if/while let ... = ... { ... } - // ^^^ - let op_span = result_expr.span.source_callsite(); + // ^^^ + let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { + return; + }; // if/while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(op_span.shrink_to_hi()); + // ^^^^^^^^^^^^^^^^^^^^^^ + let span = expr_span.until(res_span.shrink_to_hi()); - let app = if needs_drop { + let mut app = if needs_drop { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable }; - let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_") + let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app) .maybe_par() .to_string(); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 19b49c44d57..ad47c13896c 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -67,8 +67,10 @@ fn report_single_pattern( els: Option<&Expr<'_>>, ) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH }; + let ctxt = expr.span.ctxt(); + let mut app = Applicability::HasPlaceholders; let els_str = els.map_or(String::new(), |els| { - format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span))) + format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); @@ -103,7 +105,7 @@ fn report_single_pattern( // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } else { @@ -112,21 +114,13 @@ fn report_single_pattern( "if let {} = {} {}{els_str}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } }; - span_lint_and_sugg( - cx, - lint, - expr.span, - msg, - "try this", - sugg, - Applicability::HasPlaceholders, - ); + span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app); } fn check_opt_like<'a>( diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 4720a6e6888..8ddb912f90b 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,6 +1,6 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -77,11 +77,8 @@ pub(crate) trait BindInsteadOfMap { if !contains_return(inner_expr); if let Some(msg) = Self::lint_msg(cx); then { - let some_inner_snip = if inner_expr.span.from_expansion() { - snippet_with_macro_callsite(cx, inner_expr.span, "_") - } else { - snippet(cx, inner_expr.span, "_") - }; + let mut app = Applicability::MachineApplicable; + let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); @@ -93,7 +90,7 @@ pub(crate) trait BindInsteadOfMap { &msg, "try this", note, - Applicability::MachineApplicable, + app, ); true } else { diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 355f53532e2..5e8ad0861f3 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -33,7 +33,9 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); + // Sometimes unnecessary ::<_> after Rc/Arc/Weak + let mut app = Applicability::Unspecified; + let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, @@ -42,7 +44,7 @@ pub(super) fn check( "using `.clone()` on a ref-counted pointer", "try this", format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), - Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak + app, ); } } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 4460f38fcc1..7ce28ea93e0 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_trait_item, last_path_segment}; use if_chain::if_chain; @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; -use std::borrow::Cow; use super::OR_FUN_CALL; @@ -111,37 +110,24 @@ pub(super) fn check<'tcx>( if poss.contains(&name); then { + let ctxt = span.ctxt(); + let mut app = Applicability::HasPlaceholders; let sugg = { let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { (false, Some(fun_span)) => (fun_span, false), _ => (arg.span, true), }; - let format_span = |span: Span| { - let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, ".."); - let snip = if not_macro_argument_snippet == "vec![]" { - let macro_expanded_snipped = snippet(cx, snippet_span, ".."); - match macro_expanded_snipped.strip_prefix("$crate::vec::") { - Some(stripped) => Cow::Owned(stripped.to_owned()), - None => macro_expanded_snipped, - } - } else { - not_macro_argument_snippet - }; - - snip.to_string() - }; - - let snip = format_span(snippet_span); + let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0; let snip = if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; format!("|{l_arg}| {snip}") } else { - snip + snip.into_owned() }; if let Some(f) = second_arg { - let f = format_span(f.span); + let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0; format!("{snip}, {f}") } else { snip @@ -155,7 +141,7 @@ pub(super) fn check<'tcx>( &format!("use of `{name}` followed by a function call"), "try this", format!("{name}_{suffix}({sugg})"), - Applicability::HasPlaceholders, + app, ); } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 0705029a613..3752b9a946f 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_context}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -181,20 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; then { - // use the macro callsite when the init span (but not the whole local span) - // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` - let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, init, "..") - } else { - Sugg::hir(cx, init, "..") - }; + let ctxt = local.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); let (mutopt, initref) = if mutabl == Mutability::Mut { ("mut ", sugg_init.mut_addr()) } else { ("", sugg_init.addr()) }; let tyopt = if let Some(ty) = local.ty { - format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, "..")) + let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; + format!(": &{mutopt}{ty_snip}") } else { String::new() }; @@ -212,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { "let {name}{tyopt} = {initref};", name=snippet(cx, name.span, ".."), ), - Applicability::MachineApplicable, + app, ); } ); diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index a4eec95b371..c87059bf61d 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -340,18 +340,11 @@ fn suggest_bool_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, expr: &Expr<'_>, - mut applicability: Applicability, + mut app: Applicability, message: &str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { - let hint = if expr.span.from_expansion() { - if applicability != Applicability::Unspecified { - applicability = Applicability::MaybeIncorrect; - } - Sugg::hir_with_macro_callsite(cx, expr, "..") - } else { - Sugg::hir_with_applicability(cx, expr, "..", &mut applicability) - }; + let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app); span_lint_and_sugg( cx, BOOL_COMPARISON, @@ -359,7 +352,7 @@ fn suggest_bool_comparison<'a, 'tcx>( message, "try simplifying it as shown", conv_hint(hint).to_string(), - applicability, + app, ); } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index c5ea09590d3..bbbcda069c5 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -12,6 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::SyntaxContext; declare_clippy_lint! { /// ### What it does @@ -95,10 +96,10 @@ struct OptionOccurrence { none_expr: String, } -fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { +fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", - Sugg::hir_with_macro_callsite(cx, cond_expr, "..").maybe_par(), + cond_sugg.maybe_par(), if as_mut { ".as_mut()" } else if as_ref { @@ -111,6 +112,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo fn try_get_option_occurrence<'tcx>( cx: &LateContext<'tcx>, + ctxt: SyntaxContext, pat: &Pat<'tcx>, expr: &Expr<'_>, if_then: &'tcx Expr<'_>, @@ -160,11 +162,23 @@ fn try_get_option_occurrence<'tcx>( } } + let mut app = Applicability::Unspecified; return Some(OptionOccurrence { - option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), + option: format_option_in_sugg( + Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), + as_ref, + as_mut, + ), method_sugg: method_sugg.to_string(), - some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), - none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), + some_expr: format!( + "|{capture_mut}{capture_name}| {}", + Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app), + ), + none_expr: format!( + "{}{}", + if method_sugg == "map_or" { "" } else { "|| " }, + Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), + ), }); } } @@ -194,7 +208,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> }) = higher::IfLet::hir(cx, expr) { if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else); } } None @@ -203,7 +217,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else); } } None diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 66638eed998..355f907e257 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::sugg; +use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; @@ -44,7 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); - if let snippet = snippet_with_macro_callsite(cx, expr.span, "}"); + let mut app = Applicability::MaybeIncorrect; + if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0; if !snippet.ends_with('}') && !snippet.ends_with(';'); if cx.sess().source_map().is_multiline(block.span); then { @@ -52,17 +52,14 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let ExprKind::DropTemps(..) = &expr.kind { return; } - - let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); - let suggestion = format!("{sugg};"); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span.source_callsite(), "consider adding a `;` to the last statement for consistent formatting", "add a `;` here", - suggestion, - Applicability::MaybeIncorrect, + format!("{snippet};"), + app, ); } } diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index d6167a62169..a0164fdfc1e 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_node; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -48,12 +48,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { "this let-binding has unit value", |diag| { if let Some(expr) = &local.init { - let snip = snippet_with_macro_callsite(cx, expr.span, "()"); + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; diag.span_suggestion( local.span, "omit the `let` binding", format!("{snip};"), - Applicability::MachineApplicable, // snippet + app, ); } }, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index a95e7b61374..47f19557e58 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; @@ -68,15 +68,16 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, recv.span, "").to_string(); + let mut app = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "", &mut app).0; span_lint_and_sugg( cx, USELESS_CONVERSION, e.span, &format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", - sugg, - Applicability::MachineApplicable, // snippet + sugg.into_owned(), + app, ); } } @@ -165,7 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, arg, "").maybe_par(); + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( @@ -175,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { &format!("useless conversion to the same type: `{b}`"), &sugg_msg, sugg.to_string(), - Applicability::MachineApplicable, // snippet + app, ); } } diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index cd5dcfdaca3..62fa37660fa 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -12,24 +12,21 @@ use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. -/// Also takes an `Option` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>( +pub fn expr_block( cx: &T, expr: &Expr<'_>, - option: Option, - default: &'a str, + outer: SyntaxContext, + default: &str, indent_relative_to: Option, -) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default, indent_relative_to); - let string = option.unwrap_or_default(); - if expr.span.from_expansion() { - Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + app: &mut Applicability, +) -> String { + let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app); + if from_macro { + format!("{{ {code} }}") } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{code}{string}")) - } else if string.is_empty() { - Cow::Owned(format!("{{ {code} }}")) + format!("{code}") } else { - Cow::Owned(format!("{{\n{code};\n{string}\n}}")) + format!("{{ {code} }}") } } @@ -229,12 +226,6 @@ fn snippet_with_applicability_sess<'a>( ) } -/// Same as `snippet`, but should only be used when it's clear that the input span is -/// not a macro argument. -pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet(cx, span.source_callsite(), default) -} - /// Converts a span to a code snippet. Returns `None` if not available. pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option { snippet_opt_sess(cx.sess(), span) @@ -303,6 +294,19 @@ pub fn snippet_block_with_applicability<'a>( reindent_multiline(snip, true, indent) } +pub fn snippet_block_with_context<'a>( + cx: &impl LintContext, + span: Span, + outer: SyntaxContext, + default: &'a str, + indent_relative_to: Option, + app: &mut Applicability, +) -> (Cow<'a, str>, bool) { + let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + (reindent_multiline(snip, true, indent), from_macro) +} + /// Same as `snippet_with_applicability`, but first walks the span up to the given context. This /// will result in the macro call, rather then the expansion, if the span is from a child context. /// If the span is not from a child context, it will be used directly instead. diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 51e270d330c..8e3ee22a765 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -1,9 +1,7 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::source::{ - snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite, -}; +use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context}; use crate::ty::expr_sig; use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; @@ -89,12 +87,6 @@ impl<'a> Sugg<'a> { }) } - /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro. - pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - let get_snippet = |span| snippet_with_macro_callsite(cx, span, default); - Self::hir_from_snippet(expr, get_snippet) - } - /// Same as `hir`, but first walks the span up to the given context. This will result in the /// macro call, rather then the expansion, if the span is from a child context. If the span is /// not from a child context, it will be used directly instead. diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index b88c5d0bec8..42348df4480 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -69,8 +69,8 @@ fn issue5504() { } fn try_result_opt() -> Result { - while (r#try!(result_opt())).is_some() {} - if (r#try!(result_opt())).is_some() {} + while r#try!(result_opt()).is_some() {} + if r#try!(result_opt()).is_some() {} Ok(42) } diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index e6afe9eb78e..d6a46babb77 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -88,13 +88,13 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()` + | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()` + | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:91:12 -- cgit 1.4.1-3-g733a5 From 7f44530f54002401ba771bcc19f56f4950b22bb1 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sat, 18 Mar 2023 10:43:02 +0100 Subject: Create `clear_with_drain` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/clear_with_drain.rs | 8 ++++++++ clippy_lints/src/methods/mod.rs | 21 +++++++++++++++++++++ tests/ui/clear_with_drain.rs | 12 ++++++++++++ 5 files changed, 43 insertions(+) create mode 100644 clippy_lints/src/methods/clear_with_drain.rs create mode 100644 tests/ui/clear_with_drain.rs (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a503510c1..81d0ff80968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4441,6 +4441,7 @@ Released 2018-09-13 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions +[`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2331e857b1f..f7b108c923a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -307,6 +307,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, + crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::CLONE_DOUBLE_REF_INFO, crate::methods::CLONE_ON_COPY_INFO, diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs new file mode 100644 index 00000000000..9e55852ef7a --- /dev/null +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -0,0 +1,8 @@ +use rustc_lint::{LateContext, LintContext}; + +use super::CLEAR_WITH_DRAIN; + +// TODO: Adjust the parameters as necessary +pub(super) fn check(cx: &LateContext) { + todo!(); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 56e3988bf09..859284b6a5c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod chars_last_cmp; mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; +mod clear_with_drain; mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; @@ -3190,6 +3191,25 @@ declare_clippy_lint! { "single command line argument that looks like it should be multiple arguments" } +declare_clippy_lint! { + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "1.69.0"] + pub CLEAR_WITH_DRAIN, + nursery, + "default lint description" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3318,6 +3338,7 @@ impl_lint_pass!(Methods => [ SEEK_TO_START_INSTEAD_OF_REWIND, NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, + CLEAR_WITH_DRAIN, ]); /// Extracts a method call name, args, and `Span` of the method name. diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs new file mode 100644 index 00000000000..bb3a371cc08 --- /dev/null +++ b/tests/ui/clear_with_drain.rs @@ -0,0 +1,12 @@ +#![allow(unused)] +#![warn(clippy::clear_with_drain)] + +fn main() { + let mut vec: Vec = Vec::new(); + //Lint + vec.drain(..); + vec.drain(0..vec.len()); + + // Dont Lint + let iter = vec.drain(..); +} -- cgit 1.4.1-3-g733a5 From 85d428101dc757f7aa41e47696c94683d8398903 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sat, 18 Mar 2023 11:34:30 +0100 Subject: Pull `is_full_range` method from `iter_with_drain` Rename method to `is_range_full` because the type is actually `RangeFull`. Method moved to `clippy_utils` for reuse in `clear_with_drain`. --- clippy_lints/src/methods/iter_with_drain.rs | 23 +++-------------------- clippy_utils/src/lib.rs | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 21 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 3da230e12d7..ea92e3a549f 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::Range; -use clippy_utils::is_integer_const; -use rustc_ast::ast::RangeLimits; +use clippy_utils::is_range_full; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; @@ -16,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) && matches!(ty_name, sym::Vec | sym::VecDeque) && let Some(range) = Range::hir(arg) - && is_full_range(cx, recv, range) + && is_range_full(cx, recv, range) { span_lint_and_sugg( cx, @@ -29,19 +28,3 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span ); }; } - -fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { - range.start.map_or(true, |e| is_integer_const(cx, e, 0)) - && range.end.map_or(true, |e| { - if range.limits == RangeLimits::HalfOpen - && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind - { - container_path.res == path.res - } else { - false - } - }) -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 44b6b9f7b0b..0fdbd7a6341 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; -use rustc_ast::ast::{self, LitKind}; +use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; @@ -115,6 +115,7 @@ use rustc_span::Span; use rustc_target::abi::Integer; use crate::consts::{constant, Constant}; +use crate::higher::Range; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; @@ -1491,6 +1492,24 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } } +/// Checks whether the given `Range` is equivalent to a `RangeFull`. +/// Inclusive ranges are not considered because they already constitute a lint. +pub fn is_range_full(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { + range.start.map_or(true, |e| is_integer_const(cx, e, 0)) + && range.end.map_or(true, |e| { + if range.limits == RangeLimits::HalfOpen + && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind + && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }) +} + /// Checks whether the given expression is a constant integer of the given value. /// unlike `is_integer_literal`, this version does const folding pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool { -- cgit 1.4.1-3-g733a5 From 484c82e0418325df5d25e8d0e11e10a5d1371502 Mon Sep 17 00:00:00 2001 From: bluthej Date: Mon, 20 Mar 2023 18:46:18 +0100 Subject: Update lint declaration --- clippy_lints/src/methods/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 859284b6a5c..4e74ac6af2b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3193,21 +3193,27 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for usage of `.drain(..)` for the sole purpose of clearing a `Vec`. /// /// ### Why is this bad? + /// This creates an unnecessary iterator that is dropped immediately. + /// + /// Calling `.clear()` also makes the intent clearer. /// /// ### Example /// ```rust - /// // example code where clippy issues a warning + /// let mut v = vec![1, 2, 3]; + /// v.drain(..); /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// let mut v = vec![1, 2, 3]; + /// v.clear(); /// ``` #[clippy::version = "1.69.0"] pub CLEAR_WITH_DRAIN, nursery, - "default lint description" + "calling `drain` in order to `clear` a `Vec`" } pub struct Methods { -- cgit 1.4.1-3-g733a5 From c7e3e304d5d2ac82dbebe5f3d3e0611b407d81be Mon Sep 17 00:00:00 2001 From: bluthej Date: Tue, 21 Mar 2023 22:08:37 +0100 Subject: Add the lint logic --- clippy_lints/src/methods/clear_with_drain.rs | 27 ++++++++++++++++++++++++--- clippy_lints/src/methods/mod.rs | 10 ++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 9e55852ef7a..ac6c0e57257 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,8 +1,29 @@ -use rustc_lint::{LateContext, LintContext}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::Range; +use clippy_utils::is_range_full; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use rustc_span::Span; use super::CLEAR_WITH_DRAIN; // TODO: Adjust the parameters as necessary -pub(super) fn check(cx: &LateContext) { - todo!(); +// see clippy_lints/src/methods/mod.rs to add call to this check in `check_methods` +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + if is_type_diagnostic_item(cx, ty, sym::Vec) && let Some(range) = Range::hir(arg) && is_range_full(cx, recv, range) + { + span_lint_and_sugg( + cx, + CLEAR_WITH_DRAIN, + span.with_hi(expr.span.hi()), + "`drain` used to clear a `Vec`", + "try", + "clear()".to_string(), + Applicability::MachineApplicable, + ); + } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4e74ac6af2b..257bc4eccc3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -111,7 +111,7 @@ use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_ 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::{Expr, ExprKind, TraitItem, TraitItemKind}; +use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -3590,7 +3590,13 @@ impl Methods { _ => {}, }, ("drain", [arg]) => { - iter_with_drain::check(cx, expr, recv, span, arg); + if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) + && matches!(kind, StmtKind::Semi(_)) + { + clear_with_drain::check(cx, expr, recv, span, arg); + } else { + iter_with_drain::check(cx, expr, recv, span, arg); + } }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(.., span) = expr.kind { -- cgit 1.4.1-3-g733a5 From e8ec242a61e7fcadf1a8cb3c6f7ec162b5e2726e Mon Sep 17 00:00:00 2001 From: bluthej Date: Tue, 21 Mar 2023 22:46:59 +0100 Subject: Finish tests - add rustfix --- clippy_lints/src/methods/clear_with_drain.rs | 2 -- tests/ui/clear_with_drain.fixed | 40 ++++++++++++++++++++++++++++ tests/ui/clear_with_drain.rs | 1 + tests/ui/clear_with_drain.stderr | 28 +++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 tests/ui/clear_with_drain.fixed create mode 100644 tests/ui/clear_with_drain.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index ac6c0e57257..bf7e7d12405 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -10,8 +10,6 @@ use rustc_span::Span; use super::CLEAR_WITH_DRAIN; -// TODO: Adjust the parameters as necessary -// see clippy_lints/src/methods/mod.rs to add call to this check in `check_methods` pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); if is_type_diagnostic_item(cx, ty, sym::Vec) && let Some(range) = Range::hir(arg) && is_range_full(cx, recv, range) diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed new file mode 100644 index 00000000000..62b0af08eea --- /dev/null +++ b/tests/ui/clear_with_drain.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::clear_with_drain)] + +fn range() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(0..u.len()); // Yay + v.clear(); // Nay +} + +fn range_from() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(0..); // Yay + v.clear(); // Nay +} + +fn range_full() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(..); // Yay + v.clear(); // Nay +} + +fn range_to() { + let (mut u, mut v) = (vec![1, 2, 3], vec![1, 2, 3]); + let iter = u.drain(..u.len()); // Yay + v.clear(); // Nay +} + +fn partial_drains() { + let mut v = vec![1, 2, 3]; + v.drain(1..); // Yay + + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1); // Yay + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); // Yay +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 28119deaebb..721af7d2ea7 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -1,3 +1,4 @@ +// run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr new file mode 100644 index 00000000000..0d6d8263e10 --- /dev/null +++ b/tests/ui/clear_with_drain.stderr @@ -0,0 +1,28 @@ +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:8:7 + | +LL | v.drain(0..v.len()); // Nay + | ^^^^^^^^^^^^^^^^^ help: try: `clear()` + | + = note: `-D clippy::clear-with-drain` implied by `-D warnings` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:14:7 + | +LL | v.drain(0..); // Nay + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:20:7 + | +LL | v.drain(..); // Nay + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:26:7 + | +LL | v.drain(..v.len()); // Nay + | ^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 2493be2196f6ba16eaea25915c25d93f1c2664b5 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 26 Mar 2023 18:25:15 +0200 Subject: Improve `is_range_full` implementation Make this function work with signed integer types by extracting the underlying type and finding the min and max values. Change the signature to make it more consistent: - The range is now given as an `Expr` in order to extract the type - The container's path is now passed, and only as an `Option` so that the function can be called in the general case without a container --- clippy_lints/src/methods/clear_with_drain.rs | 7 +-- clippy_lints/src/methods/iter_with_drain.rs | 7 ++- clippy_utils/src/lib.rs | 71 +++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 20 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index bf7e7d12405..24496bd4689 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::Range; use clippy_utils::is_range_full; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; @@ -12,7 +11,9 @@ use super::CLEAR_WITH_DRAIN; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if is_type_diagnostic_item(cx, ty, sym::Vec) && let Some(range) = Range::hir(arg) && is_range_full(cx, recv, range) + if is_type_diagnostic_item(cx, ty, sym::Vec) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index ea92e3a549f..f6772c5c6b3 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::Range; use clippy_utils::is_range_full; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; @@ -14,8 +13,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) && matches!(ty_name, sym::Vec | sym::VecDeque) - && let Some(range) = Range::hir(arg) - && is_range_full(cx, recv, range) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) { span_lint_and_sugg( cx, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e8225feb33d..2e839fdf472 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -96,6 +96,7 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; +use rustc_middle::mir::ConstantKind; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; @@ -114,7 +115,7 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::Integer; -use crate::consts::{constant, Constant}; +use crate::consts::{constant, miri_to_const, Constant}; use crate::higher::Range; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; @@ -1492,22 +1493,66 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } } -/// Checks whether the given `Range` is equivalent to a `RangeFull`. -/// Inclusive ranges are not considered because they already constitute a lint. -pub fn is_range_full(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { - range.start.map_or(true, |e| is_integer_const(cx, e, 0)) - && range.end.map_or(true, |e| { - if range.limits == RangeLimits::HalfOpen - && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind +/// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. +/// For the lower bound, this means that: +/// - either there is none +/// - or it is the smallest value that can be represented by the range's integer type +/// For the upper bound, this means that: +/// - either there is none +/// - or it is the largest value that can be represented by the range's integer type and is +/// inclusive +/// - or it is a call to some container's `len` method and is exclusive, and the range is passed to +/// a method call on that same container (e.g. `v.drain(..v.len())`) +/// If the given `Expr` is not some kind of range, the function returns `false`. +pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + if let Some(Range { start, end, limits }) = Range::hir(expr) { + let start_is_none_or_min = start.map_or(true, |start| { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) + && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) + && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) + && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start) { - container_path.res == path.res + start_const == min_const } else { false } - }) + }); + let end_is_none_or_max = end.map_or(true, |end| { + match limits { + RangeLimits::Closed => { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) + && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) + && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) + && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end) + { + end_const == max_const + } else { + false + } + }, + RangeLimits::HalfOpen => { + if let Some(container_path) = container_path + && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }, + } + }); + return start_is_none_or_min && end_is_none_or_max; + } + false } /// Checks whether the given expression is a constant integer of the given value. -- cgit 1.4.1-3-g733a5 From 6589d794927451ed5d503b108e0e6900bbf91d3d Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 28 Mar 2023 21:28:57 +0000 Subject: Replace remaining usage of `FormatArgsExpn` --- clippy_lints/src/explicit_write.rs | 29 +- clippy_lints/src/format.rs | 91 ++-- clippy_lints/src/format_impl.rs | 60 ++- clippy_lints/src/methods/expect_fun_call.rs | 27 +- clippy_utils/src/lib.rs | 1 - clippy_utils/src/macros.rs | 727 +--------------------------- 6 files changed, 132 insertions(+), 803 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index c0ea6f338a2..315df6c714f 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::FormatArgsExpn; +use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; @@ -8,7 +8,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; +use rustc_span::{sym, ExpnId}; declare_clippy_lint! { /// ### What it does @@ -43,23 +43,22 @@ declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - // match call to unwrap - if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind; - if unwrap_fun.ident.name == sym::unwrap; + // match call to unwrap + if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind + && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt - if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind); - if write_fun.ident.name == sym!(write_fmt); + && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind) + && write_fun.ident.name == sym!(write_fmt) // match calls to std::io::stdout() / std::io::stderr () - if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { + && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { Some("stdout") } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { Some("stderr") } else { None - }; - if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg); - then { + } + { + find_format_args(cx, write_arg, ExpnId::root(), |format_args| { let calling_macro = // ordering is important here, since `writeln!` uses `write!` internally if is_expn_of(write_call.span, "writeln").is_some() { @@ -92,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { let mut applicability = Applicability::MachineApplicable; let inputs_snippet = snippet_with_applicability( cx, - format_args.inputs_span(), + format_args_inputs_span(format_args), "..", &mut applicability, ); @@ -104,8 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { "try this", format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, - ) - } + ); + }); } } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8040938c626..d34d6e9279e 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node}; +use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::kw; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -44,55 +43,53 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (format_args, call_site) = if_chain! { - if let Some(macro_call) = root_macro_call_first_node(cx, expr); - if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id); - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn); - then { - (format_args, macro_call.span) - } else { - return - } - }; + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { + return; + } + + find_format_args(cx, expr, macro_call.expn, |format_args| { + let mut applicability = Applicability::MachineApplicable; + let call_site = macro_call.span; - let mut applicability = Applicability::MachineApplicable; - if format_args.args.is_empty() { - match *format_args.format_string.parts { - [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), - [_] => { + match (format_args.arguments.all_args(), &format_args.template[..]) { + ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), + ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); }, - [..] => {}, - } - } else if let [arg] = &*format_args.args { - let value = arg.param.value; - if_chain! { - if format_args.format_string.parts == [kw::Empty]; - if arg.format.is_default(); - if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), - ty::Str => true, - _ => false, - }; - then { - let is_new_string = match value.kind { - ExprKind::Binary(..) => true, - ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, - _ => false, - }; - let sugg = if is_new_string { - snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() - } else { - let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); - format!("{}.to_string()", sugg.maybe_par()) - }; - span_useless_format(cx, call_site, sugg, applicability); - } + ([arg], [piece]) => { + if let Ok(value) = find_format_arg_expr(expr, arg) + && let FormatArgsPiece::Placeholder(placeholder) = piece + && placeholder.format_trait == FormatTrait::Display + && placeholder.format_options == FormatOptions::default() + && match cx.typeck_results().expr_ty(value).peel_refs().kind() { + ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), + ty::Str => true, + _ => false, + } + { + let is_new_string = match value.kind { + ExprKind::Binary(..) => true, + ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, + _ => false, + }; + let sugg = if is_new_string { + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + } else { + let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); + format!("{}.to_string()", sugg.maybe_par()) + }; + span_useless_format(cx, call_site, sugg, applicability); + + } + }, + _ => {}, } - }; + }); } } diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index ed1342a5465..e3ddbfb5981 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn}; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; use rustc_span::{sym, symbol::kw, Symbol}; declare_clippy_lint! { @@ -89,7 +91,7 @@ declare_clippy_lint! { } #[derive(Clone, Copy)] -struct FormatTrait { +struct FormatTraitNames { /// e.g. `sym::Display` name: Symbol, /// `f` in `fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {}` @@ -99,7 +101,7 @@ struct FormatTrait { #[derive(Default)] pub struct FormatImpl { // Whether we are inside Display or Debug trait impl - None for neither - format_trait_impl: Option, + format_trait_impl: Option, } impl FormatImpl { @@ -161,43 +163,57 @@ fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { } } -fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTrait) { +fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTraitNames) { // Check each arg in format calls - do we ever use Display on self (directly or via deref)? - if_chain! { - if let Some(outer_macro) = root_macro_call_first_node(cx, expr); - if let macro_def_id = outer_macro.def_id; - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); - if is_format_macro(cx, macro_def_id); - then { - for arg in format_args.args { - if arg.format.r#trait != impl_trait.name { - continue; + if let Some(outer_macro) = root_macro_call_first_node(cx, expr) + && let macro_def_id = outer_macro.def_id + && is_format_macro(cx, macro_def_id) + { + find_format_args(cx, expr, outer_macro.expn, |format_args| { + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let trait_name = match placeholder.format_trait { + FormatTrait::Display => sym::Display, + FormatTrait::Debug => sym::Debug, + FormatTrait::LowerExp => sym!(LowerExp), + FormatTrait::UpperExp => sym!(UpperExp), + FormatTrait::Octal => sym!(Octal), + FormatTrait::Pointer => sym::Pointer, + FormatTrait::Binary => sym!(Binary), + FormatTrait::LowerHex => sym!(LowerHex), + FormatTrait::UpperHex => sym!(UpperHex), + } + && trait_name == impl_trait.name + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + && let Ok(arg_expr) = find_format_arg_expr(expr, arg) + { + check_format_arg_self(cx, expr.span, arg_expr, impl_trait); } - check_format_arg_self(cx, expr, &arg, impl_trait); } - } + }); } } -fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) { +fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_trait: FormatTraitNames) { // Handle multiple dereferencing of references e.g. &&self // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg.param.value); + let reference = peel_ref_operators(cx, arg); let map = cx.tcx.hir(); // Is the reference self? if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { - let FormatTrait { name, .. } = impl_trait; + let FormatTraitNames { name, .. } = impl_trait; span_lint( cx, RECURSIVE_FORMAT_IMPL, - expr.span, + span, &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), ); } } -fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTrait) { +fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) { if_chain! { if let Some(macro_call) = root_macro_call_first_node(cx, expr); if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id); @@ -227,7 +243,7 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: } } -fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { +fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { if_chain! { if impl_item.ident.name == sym::fmt; if let ImplItemKind::Fn(_, body_id) = impl_item.kind; @@ -241,7 +257,7 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio .and_then(|param| param.pat.simple_ident()) .map(|ident| ident.name); - Some(FormatTrait { + Some(FormatTraitNames { name, formatter_name, }) diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index a22285058d4..92d21bb8932 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; +use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; @@ -136,18 +136,19 @@ pub(super) fn check<'tcx>( if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { return; } - let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return }; - let span = format_args.inputs_span(); - let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - &format!("use of `{name}` followed by a function call"), - "try this", - format!("unwrap_or_else({closure_args} panic!({sugg}))"), - applicability, - ); + find_format_args(cx, arg_root, macro_call.expn, |format_args| { + let span = format_args_inputs_span(format_args); + let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + &format!("use of `{name}` followed by a function call"), + "try this", + format!("unwrap_or_else({closure_args} panic!({sugg}))"), + applicability, + ); + }); return; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2e839fdf472..f4af00599cd 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -33,7 +33,6 @@ extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; extern crate rustc_mir_dataflow; -extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index b03e0d4a1ca..62d388a5ece 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,24 +1,16 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; -use itertools::{izip, Either, Itertools}; -use rustc_ast::ast::LitKind; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind}; -use rustc_lexer::unescape::unescape_literal; -use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; +use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; -use rustc_parse_format::{self as rpf, Alignment}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, Symbol}; use std::cell::RefCell; -use std::iter::{once, zip}; use std::ops::ControlFlow; use std::sync::atomic::{AtomicBool, Ordering}; @@ -226,11 +218,11 @@ pub enum PanicExpn<'a> { /// A single argument that implements `Display` - `panic!("{}", object)` Display(&'a Expr<'a>), /// Anything else - `panic!("error {}: {}", a, b)` - Format(FormatArgsExpn<'a>), + Format(&'a Expr<'a>), } impl<'a> PanicExpn<'a> { - pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option { + pub fn parse(expr: &'a Expr<'a>) -> Option { let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else { return None }; let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None }; let result = match path.segments.last().unwrap().ident.as_str() { @@ -240,7 +232,7 @@ impl<'a> PanicExpn<'a> { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None }; Self::Display(e) }, - "panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?), + "panic_fmt" => Self::Format(arg), // Since Rust 1.52, `assert_{eq,ne}` macros expand to use: // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));` "assert_failed" => { @@ -252,7 +244,7 @@ impl<'a> PanicExpn<'a> { // `msg_arg` is either `None` (no custom message) or `Some(format_args!(..))` (custom message) let msg_arg = &rest[2]; match msg_arg.kind { - ExprKind::Call(_, [fmt_arg]) => Self::Format(FormatArgsExpn::parse(cx, fmt_arg)?), + ExprKind::Call(_, [fmt_arg]) => Self::Format(fmt_arg), _ => Self::Empty, } }, @@ -304,7 +296,7 @@ fn find_assert_args_inner<'a, const N: usize>( let mut args = ArrayVec::new(); let panic_expn = for_each_expr(expr, |e| { if args.is_full() { - match PanicExpn::parse(cx, e) { + match PanicExpn::parse(e) { Some(expn) => ControlFlow::Break(expn), None => ControlFlow::Continue(Descend::Yes), } @@ -452,6 +444,21 @@ pub fn format_placeholder_format_span(placeholder: &FormatPlaceholder) -> Option )) } +/// Span covering the format string and values +/// +/// ```ignore +/// format("{}.{}", 10, 11) +/// // ^^^^^^^^^^^^^^^ +/// ``` +pub fn format_args_inputs_span(format_args: &FormatArgs) -> Span { + match format_args.arguments.explicit_args() { + [] => format_args.span, + [.., last] => format_args + .span + .to(hygiene::walk_chain(last.expr.span, format_args.span.ctxt())), + } +} + /// Returns the [`Span`] of the value at `index` extended to the previous comma, e.g. for the value /// `10` /// @@ -473,251 +480,6 @@ pub fn format_arg_removal_span(format_args: &FormatArgs, index: usize) -> Option Some(current.with_lo(prev.hi())) } -/// The format string doesn't exist in the HIR, so we reassemble it from source code -#[derive(Debug)] -pub struct FormatString { - /// Span of the whole format string literal, including `[r#]"`. - pub span: Span, - /// Snippet of the whole format string literal, including `[r#]"`. - pub snippet: String, - /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side. - pub style: Option, - /// The unescaped value of the format string, e.g. `"val – {}"` for the literal - /// `"val \u{2013} {}"`. - pub unescaped: String, - /// The format string split by format args like `{..}`. - pub parts: Vec, -} - -impl FormatString { - fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option { - // format_args!(r"a {} b \", 1); - // - // expands to - // - // ::core::fmt::Arguments::new_v1(&["a ", " b \\"], - // &[::core::fmt::ArgumentV1::new_display(&1)]); - // - // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"` - let span = pieces.span; - let snippet = snippet_opt(cx, span)?; - - let (inner, style) = match tokenize(&snippet).next()?.kind { - TokenKind::Literal { kind, .. } => { - let style = match kind { - LiteralKind::Str { .. } => None, - LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()), - _ => return None, - }; - - let start = style.map_or(1, |n| 2 + n); - let end = snippet.len() - style.map_or(1, |n| 1 + n); - - (&snippet[start..end], style) - }, - _ => return None, - }; - - let mode = if style.is_some() { - unescape::Mode::RawStr - } else { - unescape::Mode::Str - }; - - let mut unescaped = String::with_capacity(inner.len()); - // Sometimes the original string comes from a macro which accepts a malformed string, such as in a - // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the - // string from the span will not be possible, so we will just return None here. - let mut unparsable = false; - unescape_literal(inner, mode, &mut |_, ch| match ch { - Ok(ch) => unescaped.push(ch), - Err(e) if !e.is_fatal() => (), - Err(_) => unparsable = true, - }); - if unparsable { - return None; - } - - let mut parts = Vec::new(); - let _: Option = for_each_expr(pieces, |expr| { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Str(symbol, _) = lit.node - { - parts.push(symbol); - } - ControlFlow::Continue(()) - }); - - Some(Self { - span, - snippet, - style, - unescaped, - parts, - }) - } -} - -struct FormatArgsValues<'tcx> { - /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for - /// `format!("{x} {} {}", 1, z + 2)`. - value_args: Vec<&'tcx Expr<'tcx>>, - /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in - /// `value_args` - pos_to_value_index: Vec, - /// Used to check if a value is declared inline & to resolve `InnerSpan`s. - format_string_span: SpanData, -} - -impl<'tcx> FormatArgsValues<'tcx> { - fn new_empty(format_string_span: SpanData) -> Self { - Self { - value_args: Vec::new(), - pos_to_value_index: Vec::new(), - format_string_span, - } - } - - fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { - let mut pos_to_value_index = Vec::new(); - let mut value_args = Vec::new(); - let _: Option = for_each_expr(args, |expr| { - if expr.span.ctxt() == args.span.ctxt() { - // ArgumentV1::new_() - // ArgumentV1::from_usize() - if let ExprKind::Call(callee, [val]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind - { - let val_idx = if val.span.ctxt() == expr.span.ctxt() - && let ExprKind::Field(_, field) = val.kind - && let Ok(idx) = field.name.as_str().parse() - { - // tuple index - idx - } else { - // assume the value expression is passed directly - pos_to_value_index.len() - }; - - pos_to_value_index.push(val_idx); - } - ControlFlow::Continue(Descend::Yes) - } else { - // assume that any expr with a differing span is a value - value_args.push(expr); - ControlFlow::Continue(Descend::No) - } - }); - - Self { - value_args, - pos_to_value_index, - format_string_span, - } - } -} - -/// The positions of a format argument's value, precision and width -/// -/// A position is an index into the second argument of `Arguments::new_v1[_formatted]` -#[derive(Debug, Default, Copy, Clone)] -struct ParamPosition { - /// The position stored in `rt::v1::Argument::position`. - value: usize, - /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`. - width: Option, - /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`. - precision: Option, -} - -impl<'tcx> Visitor<'tcx> for ParamPosition { - fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { - match field.ident.name { - sym::position => { - if let ExprKind::Lit(lit) = &field.expr.kind - && let LitKind::Int(pos, _) = lit.node - { - self.value = pos as usize; - } - }, - sym::precision => { - self.precision = parse_count(field.expr); - }, - sym::width => { - self.width = parse_count(field.expr); - }, - _ => walk_expr(self, field.expr), - } - } -} - -fn parse_count(expr: &Expr<'_>) -> Option { - // <::core::fmt::rt::v1::Count>::Param(1usize), - if let ExprKind::Call(ctor, [val]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind - && path.ident.name == sym::Param - && let ExprKind::Lit(lit) = &val.kind - && let LitKind::Int(pos, _) = lit.node - { - Some(pos as usize) - } else { - None - } -} - -/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` -fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { - if let ExprKind::AddrOf(.., array) = fmt_arg.kind - && let ExprKind::Array(specs) = array.kind - { - Some(specs.iter().map(|spec| { - if let ExprKind::Call(f, args) = spec.kind - && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind - && f.ident.name == sym::new - && let [position, _fill, _align, _flags, precision, width] = args - && let ExprKind::Lit(position) = &position.kind - && let LitKind::Int(position, _) = position.node { - ParamPosition { - value: position as usize, - width: parse_count(width), - precision: parse_count(precision), - } - } else { - ParamPosition::default() - } - })) - } else { - None - } -} - -/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan` -fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span { - Span::new( - base.lo + BytePos::from_usize(inner.start), - base.lo + BytePos::from_usize(inner.end), - base.ctxt, - base.parent, - ) -} - -/// How a format parameter is used in the format string -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum FormatParamKind { - /// An implicit parameter , such as `{}` or `{:?}`. - Implicit, - /// A parameter with an explicit number, e.g. `{1}`, `{0:?}`, or `{:.0$}` - Numbered, - /// A parameter with an asterisk precision. e.g. `{:.*}`. - Starred, - /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`. - Named(Symbol), - /// An implicit named parameter, such as the `y` in `format!("{y}")`. - NamedInline(Symbol), -} - /// Where a format parameter is being used in the format string #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum FormatParamUsage { @@ -729,451 +491,6 @@ pub enum FormatParamUsage { Precision, } -/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g. -/// -/// ``` -/// let precision = 2; -/// format!("{:.precision$}", 0.1234); -/// ``` -/// -/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234` -/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2` -#[derive(Debug, Copy, Clone)] -pub struct FormatParam<'tcx> { - /// The expression this parameter refers to. - pub value: &'tcx Expr<'tcx>, - /// How this parameter refers to its `value`. - pub kind: FormatParamKind, - /// Where this format param is being used - argument/width/precision - pub usage: FormatParamUsage, - /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters. - /// - /// ```text - /// format!("{}, { }, {0}, {name}", ...); - /// ^ ~~ ~ ~~~~ - /// ``` - pub span: Span, -} - -impl<'tcx> FormatParam<'tcx> { - fn new( - mut kind: FormatParamKind, - usage: FormatParamUsage, - position: usize, - inner: rpf::InnerSpan, - values: &FormatArgsValues<'tcx>, - ) -> Option { - let value_index = *values.pos_to_value_index.get(position)?; - let value = *values.value_args.get(value_index)?; - let span = span_from_inner(values.format_string_span, inner); - - // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points - // into the format string - if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) { - kind = FormatParamKind::NamedInline(name); - } - - Some(Self { - value, - kind, - usage, - span, - }) - } -} - -/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and -/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. -#[derive(Debug, Copy, Clone)] -pub enum Count<'tcx> { - /// Specified with a literal number, stores the value. - Is(usize, Span), - /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be - /// `FormatParamKind::Numbered`. - Param(FormatParam<'tcx>), - /// Not specified. - Implied(Option), -} - -impl<'tcx> Count<'tcx> { - fn new( - usage: FormatParamUsage, - count: rpf::Count<'_>, - position: Option, - inner: Option, - values: &FormatArgsValues<'tcx>, - ) -> Option { - let span = inner.map(|inner| span_from_inner(values.format_string_span, inner)); - - Some(match count { - rpf::Count::CountIs(val) => Self::Is(val, span?), - rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new( - FormatParamKind::Named(Symbol::intern(name)), - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountIsParam(_) => Self::Param(FormatParam::new( - FormatParamKind::Numbered, - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountIsStar(_) => Self::Param(FormatParam::new( - FormatParamKind::Starred, - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountImplied => Self::Implied(span), - }) - } - - pub fn is_implied(self) -> bool { - matches!(self, Count::Implied(_)) - } - - pub fn param(self) -> Option> { - match self { - Count::Param(param) => Some(param), - _ => None, - } - } - - pub fn span(self) -> Option { - match self { - Count::Is(_, span) => Some(span), - Count::Param(param) => Some(param.span), - Count::Implied(span) => span, - } - } -} - -/// Specification for the formatting of an argument in the format string. See -/// for the precise meanings. -#[derive(Debug)] -pub struct FormatSpec<'tcx> { - /// Optionally specified character to fill alignment with. - pub fill: Option, - /// Optionally specified alignment. - pub align: Alignment, - /// Whether all flag options are set to default (no flags specified). - pub no_flags: bool, - /// Represents either the maximum width or the integer precision. - pub precision: Count<'tcx>, - /// The minimum width, will be padded according to `width`/`align` - pub width: Count<'tcx>, - /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for - /// `{:?}`. - pub r#trait: Symbol, - pub trait_span: Option, -} - -impl<'tcx> FormatSpec<'tcx> { - fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option { - Some(Self { - fill: spec.fill, - align: spec.align, - no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(), - precision: Count::new( - FormatParamUsage::Precision, - spec.precision, - positions.precision, - spec.precision_span, - values, - )?, - width: Count::new( - FormatParamUsage::Width, - spec.width, - positions.width, - spec.width_span, - values, - )?, - r#trait: match spec.ty { - "" => sym::Display, - "?" => sym::Debug, - "o" => sym!(Octal), - "x" => sym!(LowerHex), - "X" => sym!(UpperHex), - "p" => sym::Pointer, - "b" => sym!(Binary), - "e" => sym!(LowerExp), - "E" => sym!(UpperExp), - _ => return None, - }, - trait_span: spec - .ty_span - .map(|span| span_from_inner(values.format_string_span, span)), - }) - } - - /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`, - /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}` - pub fn is_default(&self) -> bool { - self.r#trait == sym::Display && self.is_default_for_trait() - } - - /// Has no other formatting specifiers than setting the format trait. returns true for `{}`, - /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}` - pub fn is_default_for_trait(&self) -> bool { - self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags - } -} - -/// A format argument, such as `{}`, `{foo:?}`. -#[derive(Debug)] -pub struct FormatArg<'tcx> { - /// The parameter the argument refers to. - pub param: FormatParam<'tcx>, - /// How to format `param`. - pub format: FormatSpec<'tcx>, - /// span of the whole argument, `{..}`. - pub span: Span, -} - -/// A parsed `format_args!` expansion. -#[derive(Debug)] -pub struct FormatArgsExpn<'tcx> { - /// The format string literal. - pub format_string: FormatString, - /// The format arguments, such as `{:?}`. - pub args: Vec>, - /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will - /// include this added newline. - pub newline: bool, - /// Spans of the commas between the format string and explicit values, excluding any trailing - /// comma - /// - /// ```ignore - /// format!("..", 1, 2, 3,) - /// // ^ ^ ^ - /// ``` - comma_spans: Vec, - /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for - /// `format!("{x} {} {y}", 1, z + 2)`. - explicit_values: Vec<&'tcx Expr<'tcx>>, -} - -impl<'tcx> FormatArgsExpn<'tcx> { - /// Gets the spans of the commas inbetween the format string and explicit args, not including - /// any trailing comma - /// - /// ```ignore - /// format!("{} {}", a, b) - /// // ^ ^ - /// ``` - /// - /// Ensures that the format string and values aren't coming from a proc macro that sets the - /// output span to that of its input - fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option> { - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^^^^ ^^^^^ ^^^^^^^ - let value_spans = explicit_values - .iter() - .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt())); - - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^ ^^ ^^^^^^ - let between_spans = once(fmt_span) - .chain(value_spans) - .tuple_windows() - .map(|(start, end)| start.between(end)); - - let mut comma_spans = Vec::new(); - for between_span in between_spans { - let mut offset = 0; - let mut seen_comma = false; - - for token in tokenize(&snippet_opt(cx, between_span)?) { - match token.kind { - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, - TokenKind::Comma if !seen_comma => { - seen_comma = true; - - let base = between_span.data(); - comma_spans.push(Span::new( - base.lo + BytePos(offset), - base.lo + BytePos(offset + 1), - base.ctxt, - base.parent, - )); - }, - // named arguments, `start_val, name = end_val` - // ^^^^^^^^^ between_span - TokenKind::Ident | TokenKind::Eq if seen_comma => {}, - // An unexpected token usually indicates the format string or a value came from a proc macro output - // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that - // emits a string literal with the span set to that of `"input"` - _ => return None, - } - offset += token.len; - } - - if !seen_comma { - return None; - } - } - - Some(comma_spans) - } - - pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { - let macro_name = macro_backtrace(expr.span) - .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) - .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; - let newline = macro_name == sym::format_args_nl; - - // ::core::fmt::Arguments::new_const(pieces) - // ::core::fmt::Arguments::new_v1(pieces, args) - // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) - if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind - && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted") - { - let format_string = FormatString::new(cx, pieces)?; - - let mut parser = rpf::Parser::new( - &format_string.unescaped, - format_string.style, - Some(format_string.snippet.clone()), - // `format_string.unescaped` does not contain the appended newline - false, - rpf::ParseMode::Format, - ); - - let parsed_args = parser - .by_ref() - .filter_map(|piece| match piece { - rpf::Piece::NextArgument(a) => Some(a), - rpf::Piece::String(_) => None, - }) - .collect_vec(); - if !parser.errors.is_empty() { - return None; - } - - let positions = if let Some(fmt_arg) = rest.get(1) { - // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse - // them. - - Either::Left(parse_rt_fmt(fmt_arg)?) - } else { - // If no format specs are given, the positions are in the given order and there are - // no `precision`/`width`s to consider. - - Either::Right((0..).map(|n| ParamPosition { - value: n, - width: None, - precision: None, - })) - }; - - let values = if let Some(args) = rest.first() { - FormatArgsValues::new(args, format_string.span.data()) - } else { - FormatArgsValues::new_empty(format_string.span.data()) - }; - - let args = izip!(positions, parsed_args, parser.arg_places) - .map(|(position, parsed_arg, arg_span)| { - Some(FormatArg { - param: FormatParam::new( - match parsed_arg.position { - rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit, - rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered, - // NamedInline is handled by `FormatParam::new()` - rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)), - }, - FormatParamUsage::Argument, - position.value, - parsed_arg.position_span, - &values, - )?, - format: FormatSpec::new(parsed_arg.format, position, &values)?, - span: span_from_inner(values.format_string_span, arg_span), - }) - }) - .collect::>>()?; - - let mut explicit_values = values.value_args; - // remove values generated for implicitly captured vars - let len = explicit_values - .iter() - .take_while(|val| !format_string.span.contains(val.span)) - .count(); - explicit_values.truncate(len); - - let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?; - - Some(Self { - format_string, - args, - newline, - comma_spans, - explicit_values, - }) - } else { - None - } - } - - pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { - for_each_expr(expr, |e| { - let e_ctxt = e.span.ctxt(); - if e_ctxt == expr.span.ctxt() { - ControlFlow::Continue(Descend::Yes) - } else if e_ctxt.outer_expn().is_descendant_of(expn_id) { - if let Some(args) = FormatArgsExpn::parse(cx, e) { - ControlFlow::Break(args) - } else { - ControlFlow::Continue(Descend::No) - } - } else { - ControlFlow::Continue(Descend::No) - } - }) - } - - /// Source callsite span of all inputs - pub fn inputs_span(&self) -> Span { - match *self.explicit_values { - [] => self.format_string.span, - [.., last] => self - .format_string - .span - .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())), - } - } - - /// Get the span of a value expanded to the previous comma, e.g. for the value `10` - /// - /// ```ignore - /// format("{}.{}", 10, 11) - /// // ^^^^ - /// ``` - pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option { - for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) { - if value.hir_id == value_id { - return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt()))); - } - } - - None - } - - /// Iterator of all format params, both values and those referenced by `width`/`precision`s. - pub fn params(&'tcx self) -> impl Iterator> { - self.args - .iter() - .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()]) - .flatten() - } -} - /// A node with a `HirId` and a `Span` pub trait HirNode { fn hir_id(&self) -> HirId; -- cgit 1.4.1-3-g733a5 From 9ec542873cde1332baf2a0ed33088ba98eba25cf Mon Sep 17 00:00:00 2001 From: bluthej Date: Thu, 6 Apr 2023 07:49:59 +0200 Subject: Add 5 other container types and start testing --- clippy_lints/src/methods/clear_with_drain.rs | 33 +++++++++++++++++++----- clippy_lints/src/methods/mod.rs | 11 ++++---- tests/ui/clear_with_drain.fixed | 25 +++++++++++++++++- tests/ui/clear_with_drain.rs | 25 +++++++++++++++++- tests/ui/clear_with_drain.stderr | 38 +++++++++++++++++++++++----- 5 files changed, 112 insertions(+), 20 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 24496bd4689..4f5b7762e3c 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_range_full; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; +use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -9,17 +10,37 @@ use rustc_span::Span; use super::CLEAR_WITH_DRAIN; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) { - let ty = cx.typeck_results().expr_ty(recv); - if is_type_diagnostic_item(cx, ty, sym::Vec) - && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind - && is_range_full(cx, arg, Some(container_path)) +const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 3] = [sym::String, sym::Vec, sym::VecDeque]; + +const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, sym::HashMap, sym::HashSet]; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) { + if let Some(arg) = arg { + if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITH_ARG) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) + { + suggest(cx, expr, recv, span); + } + } else if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITHOUT_ARG) { + suggest(cx, expr, recv, span); + } +} + +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); + types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) +} + +fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { + if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) { span_lint_and_sugg( cx, CLEAR_WITH_DRAIN, span.with_hi(expr.span.hi()), - "`drain` used to clear a `Vec`", + &format!("`drain` used to clear a `{}`", ty_name), "try", "clear()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 257bc4eccc3..c25f1b60aa5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3589,12 +3589,13 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, - ("drain", [arg]) => { - if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) - && matches!(kind, StmtKind::Semi(_)) + ("drain", ..) => { + if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) + && matches!(kind, StmtKind::Semi(_)) + && args.len() <= 1 { - clear_with_drain::check(cx, expr, recv, span, arg); - } else { + clear_with_drain::check(cx, expr, recv, span, args.first()); + } else if let [arg] = args { iter_with_drain::check(cx, expr, recv, span, arg); } }, diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 9c4dc010ca7..dd02cc9148f 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -2,6 +2,11 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; + fn range() { let mut v = vec![1, 2, 3]; let iter = v.drain(0..v.len()); // Yay @@ -83,4 +88,22 @@ fn partial_drains() { let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay } -fn main() {} +fn main() { + let mut deque: VecDeque<_> = [1, 2, 3].into(); + deque.clear(); + + let mut set = HashSet::from([1, 2, 3]); + set.clear(); + + let mut a = HashMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.clear(); + + let mut heap = BinaryHeap::from([1, 3]); + heap.clear(); + + // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` + let mut s = String::from("α is alpha, β is beta"); + s.drain(..); +} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index f00dbab234c..af2fe503d9a 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -2,6 +2,11 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; + fn range() { let mut v = vec![1, 2, 3]; let iter = v.drain(0..v.len()); // Yay @@ -83,4 +88,22 @@ fn partial_drains() { let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay } -fn main() {} +fn main() { + let mut deque: VecDeque<_> = [1, 2, 3].into(); + deque.drain(..); + + let mut set = HashSet::from([1, 2, 3]); + set.drain(); + + let mut a = HashMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.drain(); + + let mut heap = BinaryHeap::from([1, 3]); + heap.drain(); + + // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` + let mut s = String::from("α is alpha, β is beta"); + s.drain(..); +} diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index c88aa1a23cb..2c0cc846de2 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,5 +1,5 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:17:7 + --> $DIR/clear_with_drain.rs:22:7 | LL | v.drain(0..v.len()); // Nay | ^^^^^^^^^^^^^^^^^ help: try: `clear()` @@ -7,34 +7,58 @@ LL | v.drain(0..v.len()); // Nay = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:20:7 + --> $DIR/clear_with_drain.rs:25:7 | LL | v.drain(usize::MIN..v.len()); // Nay | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:35:7 + --> $DIR/clear_with_drain.rs:40:7 | LL | v.drain(0..); // Nay | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:38:7 + --> $DIR/clear_with_drain.rs:43:7 | LL | v.drain(usize::MIN..); // Nay | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:52:7 + --> $DIR/clear_with_drain.rs:57:7 | LL | v.drain(..); // Nay | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:66:7 + --> $DIR/clear_with_drain.rs:71:7 | LL | v.drain(..v.len()); // Nay | ^^^^^^^^^^^^^^^^ help: try: `clear()` -error: aborting due to 6 previous errors +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:93:11 + | +LL | deque.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `HashSet` + --> $DIR/clear_with_drain.rs:96:9 + | +LL | set.drain(); + | ^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `HashMap` + --> $DIR/clear_with_drain.rs:101:7 + | +LL | a.drain(); + | ^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `BinaryHeap` + --> $DIR/clear_with_drain.rs:104:10 + | +LL | heap.drain(); + | ^^^^^^^ help: try: `clear()` + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 5b57e5cec84a9c3c2f6240c9f0f4071f391fe6ab Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 12:20:59 +0200 Subject: Fix false negative with `String` and add tests `String` is currently not a diagnostic item so it needs special treatment --- clippy_lints/src/methods/clear_with_drain.rs | 12 +- tests/ui/clear_with_drain.fixed | 333 +++++++++++++++++++++++---- tests/ui/clear_with_drain.rs | 333 +++++++++++++++++++++++---- tests/ui/clear_with_drain.stderr | 104 +++++++-- 4 files changed, 675 insertions(+), 107 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 4f5b7762e3c..6ce3fdae407 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -1,16 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_range_full; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use rustc_span::Span; use super::CLEAR_WITH_DRAIN; -const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 3] = [sym::String, sym::Vec, sym::VecDeque]; +// Add `String` here when it is added to diagnostic items +const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 2] = [sym::Vec, sym::VecDeque]; const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, sym::HashMap, sym::HashSet]; @@ -30,11 +31,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) + // String type is a lang item but not a diagnostic item for now so we need a separate check + || is_type_lang_item(cx, expr_ty, LangItem::String) } fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() - && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) + // Use `opt_item_name` while `String` is not a diagnostic item + && let Some(ty_name) = cx.tcx.opt_item_name(adt.did()) { span_lint_and_sugg( cx, diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index dd02cc9148f..2d9545eeed1 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -2,108 +2,357 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] -use std::collections::BinaryHeap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; -fn range() { +fn vec_range() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..v.len()); // Yay + let iter = v.drain(0..v.len()); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let n = v.drain(0..v.len()).count(); // Yay + let n = v.drain(0..v.len()).count(); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(usize::MIN..v.len()); // Yay + let iter = v.drain(usize::MIN..v.len()); let n = iter.count(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn range_from() { +fn vec_range_from() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..); // Yay + let iter = v.drain(0..); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let mut iter = v.drain(0..); // Yay + let mut iter = v.drain(0..); let next = iter.next(); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let next = v.drain(usize::MIN..).next(); // Yay + let next = v.drain(usize::MIN..).next(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn range_full() { +fn vec_range_full() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..); // Yay + let iter = v.drain(..); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - // Yay for x in v.drain(..) { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn range_to() { +fn vec_range_to() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); for x in iter { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.clear(); // Nay + v.clear(); } -fn partial_drains() { +fn vec_partial_drains() { + // Do not lint any of these because the ranges are not full + let mut v = vec![1, 2, 3]; - v.drain(1..); // Yay + v.drain(1..); let mut v = vec![1, 2, 3]; - v.drain(1..).max(); // Yay + v.drain(1..).max(); let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1); // Yay + v.drain(..v.len() - 1); let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1).min(); // Yay + v.drain(..v.len() - 1).min(); let mut v = vec![1, 2, 3]; - v.drain(1..v.len() - 1); // Yay + v.drain(1..v.len() - 1); let mut v = vec![1, 2, 3]; - let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay + let w: Vec = v.drain(1..v.len() - 1).collect(); +} + +fn vec_deque_range() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..deque.len()); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let n = deque.drain(0..deque.len()).count(); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(usize::MIN..deque.len()); + let n = iter.count(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_from() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let mut iter = deque.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let next = deque.drain(usize::MIN..).next(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_full() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + for x in deque.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); } -fn main() { - let mut deque: VecDeque<_> = [1, 2, 3].into(); +fn vec_deque_range_to() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); +} + +fn vec_deque_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..).max(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1).min(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + let w: Vec = deque.drain(1..deque.len() - 1).collect(); +} + +fn string_range() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..s.len()); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let n = s.drain(0..s.len()).count(); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(usize::MIN..s.len()); + let n = iter.count(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} +fn string_range_from() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let mut iter = s.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let next = s.drain(usize::MIN..).next(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_full() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + for x in s.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_to() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut s = String::from("Hello, world!"); + s.drain(1..); + let mut s = String::from("Hello, world!"); + s.drain(1..).max(); + + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1); + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1).min(); + + let mut s = String::from("Hello, world!"); + s.drain(1..s.len() - 1); + let mut s = String::from("Hello, world!"); + let w: String = s.drain(1..s.len() - 1).collect(); +} + +fn hash_set() { + // Do not lint because iterator is assigned + let mut set = HashSet::from([1, 2, 3]); + let iter = set.drain(); + + // Do not lint because iterator is assigned and used + let mut set = HashSet::from([1, 2, 3]); + let mut iter = set.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut set = HashSet::from([1, 2, 3]); + let next = set.drain().next(); + + // Do lint let mut set = HashSet::from([1, 2, 3]); set.clear(); +} - let mut a = HashMap::new(); - a.insert(1, "a"); - a.insert(2, "b"); - a.clear(); +fn hash_map() { + // Do not lint because iterator is assigned + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let iter = map.drain(); - let mut heap = BinaryHeap::from([1, 3]); - heap.clear(); + // Do not lint because iterator is assigned and used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let mut iter = map.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let next = map.drain().next(); - // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` - let mut s = String::from("α is alpha, β is beta"); - s.drain(..); + // Do lint + let mut map = HashMap::from([(1, "a"), (2, "b")]); + map.clear(); } + +fn binary_heap() { + // Do not lint because iterator is assigned + let mut heap = BinaryHeap::from([1, 2]); + let iter = heap.drain(); + + // Do not lint because iterator is assigned and used + let mut heap = BinaryHeap::from([1, 2]); + let mut iter = heap.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut heap = BinaryHeap::from([1, 2]); + let next = heap.drain().next(); + + // Do lint + let mut heap = BinaryHeap::from([1, 2]); + heap.clear(); +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index af2fe503d9a..4d60ee46e18 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -2,108 +2,357 @@ #![allow(unused)] #![warn(clippy::clear_with_drain)] -use std::collections::BinaryHeap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; -fn range() { +fn vec_range() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..v.len()); // Yay + let iter = v.drain(0..v.len()); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let n = v.drain(0..v.len()).count(); // Yay + let n = v.drain(0..v.len()).count(); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(usize::MIN..v.len()); // Yay + let iter = v.drain(usize::MIN..v.len()); let n = iter.count(); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(0..v.len()); // Nay + v.drain(0..v.len()); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(usize::MIN..v.len()); // Nay + v.drain(usize::MIN..v.len()); } -fn range_from() { +fn vec_range_from() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(0..); // Yay + let iter = v.drain(0..); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let mut iter = v.drain(0..); // Yay + let mut iter = v.drain(0..); let next = iter.next(); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - let next = v.drain(usize::MIN..).next(); // Yay + let next = v.drain(usize::MIN..).next(); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(0..); // Nay + v.drain(0..); + // Do lint let mut v = vec![1, 2, 3]; - v.drain(usize::MIN..); // Nay + v.drain(usize::MIN..); } -fn range_full() { +fn vec_range_full() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..); // Yay + let iter = v.drain(..); + // Do not lint because iterator is used let mut v = vec![1, 2, 3]; - // Yay for x in v.drain(..) { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.drain(..); // Nay + v.drain(..); } -fn range_to() { +fn vec_range_to() { + // Do not lint because iterator is assigned let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); + // Do not lint because iterator is assigned and used let mut v = vec![1, 2, 3]; - let iter = v.drain(..v.len()); // Yay + let iter = v.drain(..v.len()); for x in iter { let y = format!("x = {x}"); } + // Do lint let mut v = vec![1, 2, 3]; - v.drain(..v.len()); // Nay + v.drain(..v.len()); } -fn partial_drains() { +fn vec_partial_drains() { + // Do not lint any of these because the ranges are not full + let mut v = vec![1, 2, 3]; - v.drain(1..); // Yay + v.drain(1..); let mut v = vec![1, 2, 3]; - v.drain(1..).max(); // Yay + v.drain(1..).max(); let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1); // Yay + v.drain(..v.len() - 1); let mut v = vec![1, 2, 3]; - v.drain(..v.len() - 1).min(); // Yay + v.drain(..v.len() - 1).min(); let mut v = vec![1, 2, 3]; - v.drain(1..v.len() - 1); // Yay + v.drain(1..v.len() - 1); let mut v = vec![1, 2, 3]; - let w: Vec = v.drain(1..v.len() - 1).collect(); // Yay + let w: Vec = v.drain(1..v.len() - 1).collect(); +} + +fn vec_deque_range() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..deque.len()); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let n = deque.drain(0..deque.len()).count(); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(usize::MIN..deque.len()); + let n = iter.count(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(0..deque.len()); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(usize::MIN..deque.len()); +} + +fn vec_deque_range_from() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let mut iter = deque.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let next = deque.drain(usize::MIN..).next(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(0..); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(usize::MIN..); } -fn main() { - let mut deque: VecDeque<_> = [1, 2, 3].into(); +fn vec_deque_range_full() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + for x in deque.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); deque.drain(..); +} + +fn vec_deque_range_to() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len()); +} + +fn vec_deque_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..).max(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1).min(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + let w: Vec = deque.drain(1..deque.len() - 1).collect(); +} + +fn string_range() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..s.len()); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let n = s.drain(0..s.len()).count(); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(usize::MIN..s.len()); + let n = iter.count(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(0..s.len()); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(usize::MIN..s.len()); +} + +fn string_range_from() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let mut iter = s.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let next = s.drain(usize::MIN..).next(); + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(0..); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(usize::MIN..); +} + +fn string_range_full() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + for x in s.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(..); +} + +fn string_range_to() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(..s.len()); +} + +fn string_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut s = String::from("Hello, world!"); + s.drain(1..); + let mut s = String::from("Hello, world!"); + s.drain(1..).max(); + + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1); + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1).min(); + + let mut s = String::from("Hello, world!"); + s.drain(1..s.len() - 1); + let mut s = String::from("Hello, world!"); + let w: String = s.drain(1..s.len() - 1).collect(); +} + +fn hash_set() { + // Do not lint because iterator is assigned + let mut set = HashSet::from([1, 2, 3]); + let iter = set.drain(); + + // Do not lint because iterator is assigned and used + let mut set = HashSet::from([1, 2, 3]); + let mut iter = set.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut set = HashSet::from([1, 2, 3]); + let next = set.drain().next(); + + // Do lint let mut set = HashSet::from([1, 2, 3]); set.drain(); +} - let mut a = HashMap::new(); - a.insert(1, "a"); - a.insert(2, "b"); - a.drain(); +fn hash_map() { + // Do not lint because iterator is assigned + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let iter = map.drain(); - let mut heap = BinaryHeap::from([1, 3]); - heap.drain(); + // Do not lint because iterator is assigned and used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let mut iter = map.drain(); + let next = iter.next(); - // Not firing for now because `String` is not reckognized by `is_type_diagnostic_item` - let mut s = String::from("α is alpha, β is beta"); - s.drain(..); + // Do not lint because iterator is used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let next = map.drain().next(); + + // Do lint + let mut map = HashMap::from([(1, "a"), (2, "b")]); + map.drain(); +} + +fn binary_heap() { + // Do not lint because iterator is assigned + let mut heap = BinaryHeap::from([1, 2]); + let iter = heap.drain(); + + // Do not lint because iterator is assigned and used + let mut heap = BinaryHeap::from([1, 2]); + let mut iter = heap.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut heap = BinaryHeap::from([1, 2]); + let next = heap.drain().next(); + + // Do lint + let mut heap = BinaryHeap::from([1, 2]); + heap.drain(); } + +fn main() {} diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr index 2c0cc846de2..20158da1121 100644 --- a/tests/ui/clear_with_drain.stderr +++ b/tests/ui/clear_with_drain.stderr @@ -1,64 +1,130 @@ error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:22:7 + --> $DIR/clear_with_drain.rs:23:7 | -LL | v.drain(0..v.len()); // Nay +LL | v.drain(0..v.len()); | ^^^^^^^^^^^^^^^^^ help: try: `clear()` | = note: `-D clippy::clear-with-drain` implied by `-D warnings` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:25:7 + --> $DIR/clear_with_drain.rs:27:7 | -LL | v.drain(usize::MIN..v.len()); // Nay +LL | v.drain(usize::MIN..v.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:40:7 + --> $DIR/clear_with_drain.rs:46:7 | -LL | v.drain(0..); // Nay +LL | v.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:43:7 + --> $DIR/clear_with_drain.rs:50:7 | -LL | v.drain(usize::MIN..); // Nay +LL | v.drain(usize::MIN..); | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:57:7 + --> $DIR/clear_with_drain.rs:66:7 | -LL | v.drain(..); // Nay +LL | v.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> $DIR/clear_with_drain.rs:71:7 + --> $DIR/clear_with_drain.rs:83:7 | -LL | v.drain(..v.len()); // Nay +LL | v.drain(..v.len()); | ^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> $DIR/clear_with_drain.rs:93:11 + --> $DIR/clear_with_drain.rs:121:11 + | +LL | deque.drain(0..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:125:11 + | +LL | deque.drain(usize::MIN..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:144:11 + | +LL | deque.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:148:11 + | +LL | deque.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:164:11 | LL | deque.drain(..); | ^^^^^^^^^ help: try: `clear()` +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:181:11 + | +LL | deque.drain(..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:219:7 + | +LL | s.drain(0..s.len()); + | ^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:223:7 + | +LL | s.drain(usize::MIN..s.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:242:7 + | +LL | s.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:246:7 + | +LL | s.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:262:7 + | +LL | s.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:279:7 + | +LL | s.drain(..s.len()); + | ^^^^^^^^^^^^^^^^ help: try: `clear()` + error: `drain` used to clear a `HashSet` - --> $DIR/clear_with_drain.rs:96:9 + --> $DIR/clear_with_drain.rs:317:9 | LL | set.drain(); | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `HashMap` - --> $DIR/clear_with_drain.rs:101:7 + --> $DIR/clear_with_drain.rs:336:9 | -LL | a.drain(); - | ^^^^^^^ help: try: `clear()` +LL | map.drain(); + | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `BinaryHeap` - --> $DIR/clear_with_drain.rs:104:10 + --> $DIR/clear_with_drain.rs:355:10 | LL | heap.drain(); | ^^^^^^^ help: try: `clear()` -error: aborting due to 10 previous errors +error: aborting due to 21 previous errors -- cgit 1.4.1-3-g733a5 From 423b54ac121038aefb4b9972dbab9cce13e53086 Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 13:29:27 +0200 Subject: Update documentation for `clear_with_drain` The specific type `Vec` is replaced with the generic term 'container' --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c25f1b60aa5..64bf55ba24c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3193,7 +3193,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `.drain(..)` for the sole purpose of clearing a `Vec`. + /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container. /// /// ### Why is this bad? /// This creates an unnecessary iterator that is dropped immediately. @@ -3213,7 +3213,7 @@ declare_clippy_lint! { #[clippy::version = "1.69.0"] pub CLEAR_WITH_DRAIN, nursery, - "calling `drain` in order to `clear` a `Vec`" + "calling `drain` in order to `clear` a container" } pub struct Methods { -- cgit 1.4.1-3-g733a5 From 7852962820cf2cdbedf6a9a27b4c3795c09a1cff Mon Sep 17 00:00:00 2001 From: bluthej Date: Sun, 9 Apr 2023 13:37:02 +0200 Subject: Change `format!` style to please dogfood test --- clippy_lints/src/methods/clear_with_drain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 6ce3fdae407..67ad58d5a8c 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -44,7 +44,7 @@ fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { cx, CLEAR_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain` used to clear a `{}`", ty_name), + &format!("`drain` used to clear a `{ty_name}`"), "try", "clear()".to_string(), Applicability::MachineApplicable, -- cgit 1.4.1-3-g733a5 From 640955692610120a7ff127d20740f34c46457d38 Mon Sep 17 00:00:00 2001 From: bluthej Date: Wed, 12 Apr 2023 13:48:03 +0200 Subject: Standardize lint formulation --- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/lines_filter_map_ok.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/matches/mod.rs | 6 ++-- clippy_lints/src/methods/mod.rs | 32 +++++++++++----------- clippy_lints/src/mutex_atomic.rs | 6 ++-- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/operators/mod.rs | 2 +- clippy_lints/src/types/mod.rs | 10 +++---- .../utils/internal_lints/unnecessary_def_path.rs | 2 +- clippy_lints/src/write.rs | 2 +- 16 files changed, 39 insertions(+), 39 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 15d46e954a9..b984132acf5 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// Detects uses of the `#[allow]` attribute and suggests replacing it with + /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// /// The expect attribute is still unstable and requires the `lint_reasons` diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 362f70d12d1..37648f7ba0e 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -506,7 +506,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for uses of the `abs()` method that cast the result to unsigned. + /// Checks for usage of the `abs()` method that cast the result to unsigned. /// /// ### Why is this bad? /// The `unsigned_abs()` method avoids panic when called on the MIN value. diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index b2fe0386f94..7436e9ce811 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -9,7 +9,7 @@ use rustc_span::{symbol::sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for use of `crate` as opposed to `$crate` in a macro definition. + /// Checks for usage of `crate` as opposed to `$crate` in a macro definition. /// /// ### Why is this bad? /// `crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 48a54f60253..ee5a875ade7 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -19,7 +19,7 @@ use rustc_span::{Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { /// ### What it does - /// Checks for uses of `contains_key` + `insert` on `HashMap` + /// Checks for usage of `contains_key` + `insert` on `HashMap` /// or `BTreeMap`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index e3ddbfb5981..3ddee1842a3 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -51,7 +51,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `println`, `print`, `eprintln` or `eprint` in an + /// Checks for usage of `println`, `print`, `eprintln` or `eprint` in an /// implementation of a formatting trait. /// /// ### Why is this bad? diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index a866a68987d..4762b354392 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -10,7 +10,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for use of the non-existent `=*`, `=!` and `=-` + /// Checks for usage of the non-existent `=*`, `=!` and `=-` /// operators. /// /// ### Why is this bad? diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index b0f9276475d..bba9bb445a7 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -10,7 +10,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Detect uses of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` + /// Checks for usage of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` /// when `lines` has type `std::io::Lines`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index bc815dc4a26..4629b22d171 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -13,7 +13,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for uses of `std::mem::size_of::() * 8` when + /// Checks for usage of `std::mem::size_of::() * 8` when /// `T::BITS` is available. /// /// ### Why is this bad? diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 97ecca450fa..87b63eead25 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -843,7 +843,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Err(x)?`. + /// Checks for usage of `Err(x)?`. /// /// ### Why is this bad? /// The `?` operator is designed to allow calls that @@ -878,7 +878,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `match` which could be implemented using `map` + /// Checks for usage of `match` which could be implemented using `map` /// /// ### Why is this bad? /// Using the `map` method is clearer and more concise. @@ -902,7 +902,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `match` which could be implemented using `filter` + /// Checks for usage of `match` which could be implemented using `filter` /// /// ### Why is this bad? /// Using the `filter` method is clearer and more concise. diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 64bf55ba24c..c213030f6a8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -121,7 +121,7 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for usages of `cloned()` on an `Iterator` or `Option` where + /// Checks for usage of `cloned()` on an `Iterator` or `Option` where /// `copied()` could be used instead. /// /// ### Why is this bad? @@ -201,7 +201,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be + /// Checks for usage of `Iterator::flat_map()` where `filter_map()` could be /// used instead. /// /// ### Why is this bad? @@ -441,7 +441,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and + /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and /// `Result` values. /// /// ### Why is this bad? @@ -1194,7 +1194,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.iter().nth()` (and the related + /// Checks for usage of `.iter().nth()` (and the related /// `.iter_mut().nth()`) on standard library types with *O*(1) element access. /// /// ### Why is this bad? @@ -1221,7 +1221,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.skip(x).next()` on iterators. + /// Checks for usage of `.skip(x).next()` on iterators. /// /// ### Why is this bad? /// `.nth(x)` is cleaner @@ -1246,7 +1246,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration. + /// Checks for usage of `.drain(..)` on `Vec` and `VecDeque` for iteration. /// /// ### Why is this bad? /// `.into_iter()` is simpler with better performance. @@ -1271,7 +1271,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `x.get(x.len() - 1)` instead of + /// Checks for usage of `x.get(x.len() - 1)` instead of /// `x.last()`. /// /// ### Why is this bad? @@ -1304,7 +1304,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.get().unwrap()` (or + /// Checks for usage of `.get().unwrap()` (or /// `.get_mut().unwrap`) on a standard library type which implements `Index` /// /// ### Why is this bad? @@ -1475,7 +1475,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `fold` when a more succinct alternative exists. + /// Checks for usage of `fold` when a more succinct alternative exists. /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`, /// `sum` or `product`. /// @@ -2161,7 +2161,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `str::splitn(2, _)` + /// Checks for usage of `str::splitn(2, _)` /// /// ### Why is this bad? /// `split_once` is both clearer in intent and slightly more efficient. @@ -2197,7 +2197,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. + /// Checks for usage of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. /// ### Why is this bad? /// The function `split` is simpler and there is no performance difference in these cases, considering /// that both functions return a lazy iterator. @@ -2251,7 +2251,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.collect::>().join("")` on iterators. + /// Checks for usage of `.collect::>().join("")` on iterators. /// /// ### Why is this bad? /// `.collect::()` is more concise and might be more performant @@ -2377,7 +2377,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `.then_some(..).unwrap_or(..)` + /// Checks for usage of `.then_some(..).unwrap_or(..)` /// /// ### Why is this bad? /// This can be written more clearly with `if .. else ..` @@ -2553,7 +2553,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `x.get(0)` instead of + /// Checks for usage of `x.get(0)` instead of /// `x.first()`. /// /// ### Why is this bad? @@ -2957,7 +2957,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Detects uses of `Vec::sort_by` passing in a closure + /// Checks for usage of `Vec::sort_by` passing in a closure /// which compares the two arguments, either directly or indirectly. /// /// ### Why is this bad? @@ -3013,7 +3013,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of File::read_to_end and File::read_to_string. + /// Checks for usage of File::read_to_end and File::read_to_string. /// /// ### Why is this bad? /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index dc866ab6373..99394b9e5fb 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,4 +1,4 @@ -//! Checks for uses of mutex where an atomic value could be used +//! Checks for usage of mutex where an atomic value could be used //! //! This lint is **allow** by default @@ -12,7 +12,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Mutex` where an atomic will do. + /// Checks for usage of `Mutex` where an atomic will do. /// /// ### Why is this bad? /// Using a mutex just to make access to a plain bool or @@ -49,7 +49,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Mutex` where `X` is an integral + /// Checks for usage of `Mutex` where `X` is an integral /// type. /// /// ### Why is this bad? diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 0bedab05eec..9ab6743d369 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,4 +1,4 @@ -//! Checks for uses of const which the type is not `Freeze` (`Cell`-free). +//! Checks for usage of const which the type is not `Freeze` (`Cell`-free). //! //! This lint is **warn** by default. diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index eba230da6c3..19599731bd6 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -685,7 +685,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + /// Checks for usage of bitwise and/or operators between booleans, where performance may be improved by using /// a lazy and. /// /// ### Why is this bad? diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index c1f228d5f90..c6834a8fdaa 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -22,7 +22,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for use of `Box` where T is a collection such as Vec anywhere in the code. + /// Checks for usage of `Box` where T is a collection such as Vec anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -52,7 +52,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Vec>` where T: Sized anywhere in the code. + /// Checks for usage of `Vec>` where T: Sized anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -85,7 +85,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Option>` in function signatures and type + /// Checks for usage of `Option>` in function signatures and type /// definitions /// /// ### Why is this bad? @@ -164,7 +164,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `&Box` anywhere in the code. + /// Checks for usage of `&Box` anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -190,7 +190,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of redundant allocations anywhere in the code. + /// Checks for usage of redundant allocations anywhere in the code. /// /// ### Why is this bad? /// Expressions such as `Rc<&T>`, `Rc>`, `Rc>`, `Rc>`, `Arc<&T>`, `Arc>`, diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 14ed1368e03..00842376628 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -20,7 +20,7 @@ use std::str; declare_clippy_lint! { /// ### What it does - /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used. + /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. /// /// ### Why is this bad? /// The path for an item is subject to change and is less efficient to look up than a diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index d7c94b909bd..f194dc5d4b2 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -104,7 +104,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Debug` formatting. The purpose of this + /// Checks for usage of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. /// /// ### Why is this bad? -- cgit 1.4.1-3-g733a5 From 747ff0656b2f15b13d34161e7652339cd06d80bf Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 19 Apr 2023 14:55:18 +0200 Subject: Update version attribute for 1.69 lints --- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 2 +- clippy_lints/src/question_mark_used.rs | 2 +- clippy_lints/src/significant_drop_tightening.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 7c5e44bb7dc..ac2d253fe83 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -348,7 +348,7 @@ declare_clippy_lint! { /// // [...] /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.69.0"] pub IMPL_TRAIT_IN_PARAMS, restriction, "`impl Trait` is used in the function's parameters" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c213030f6a8..9cafbc2e5f5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3185,7 +3185,7 @@ declare_clippy_lint! { /// ```rust /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); /// ``` - #[clippy::version = "1.67.0"] + #[clippy::version = "1.69.0"] pub SUSPICIOUS_COMMAND_ARG_SPACE, suspicious, "single command line argument that looks like it should be multiple arguments" diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 5418616ded0..2abdfacd276 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { /// unsafe { char::from_u32_unchecked(int_value) } /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.69.0"] pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, restriction, "more than one unsafe operation per `unsafe` block" diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index 9b678e8d753..ff66b8a0095 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ```ignore /// utility_macro!(expr); /// ``` - #[clippy::version = "pre 1.29.0"] + #[clippy::version = "1.69.0"] pub QUESTION_MARK_USED, restriction, "complains if the question mark operator is used" diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 869358fb1ba..003c5e7d151 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { /// do_heavy_computation_that_takes_time(owned_rslt); /// } /// ``` - #[clippy::version = "1.67.0"] + #[clippy::version = "1.69.0"] pub SIGNIFICANT_DROP_TIGHTENING, nursery, "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes" -- cgit 1.4.1-3-g733a5 From def1705a271e317da4ae67d3a92e99fc699c9209 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 20 Apr 2023 14:37:15 +0000 Subject: Update to a compiletest-rs version that requires `//@` for commands --- Cargo.toml | 2 +- book/src/development/adding_lints.md | 2 +- clippy_dev/src/update_lints.rs | 2 +- clippy_lints/src/methods/obfuscated_if_else.rs | 2 - tests/compile-test.rs | 3 +- .../cargo_common_metadata/fail/src/main.rs | 2 +- .../cargo_common_metadata/fail_publish/src/main.rs | 2 +- .../fail_publish_true/src/main.rs | 2 +- .../cargo_common_metadata/pass/src/main.rs | 2 +- .../pass_publish_empty/src/main.rs | 2 +- .../pass_publish_false/src/main.rs | 2 +- tests/ui-cargo/feature_name/fail/src/main.rs | 2 +- tests/ui-cargo/feature_name/pass/src/main.rs | 2 +- .../module_style/fail_mod_remap/src/main.rs | 2 +- .../5041_allow_dev_build/src/main.rs | 2 +- .../multiple_crate_versions/fail/src/main.rs | 2 +- .../multiple_crate_versions/pass/src/main.rs | 2 +- .../wildcard_dependencies/fail/src/main.rs | 2 +- .../wildcard_dependencies/pass/src/main.rs | 2 +- .../ui-internal/collapsible_span_lint_calls.fixed | 2 +- tests/ui-internal/collapsible_span_lint_calls.rs | 2 +- tests/ui-internal/custom_ice_message.rs | 12 +- tests/ui-internal/interning_defined_symbol.fixed | 2 +- tests/ui-internal/interning_defined_symbol.rs | 2 +- tests/ui-internal/invalid_msrv_attr_impl.fixed | 2 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 2 +- tests/ui-internal/outer_expn_data.fixed | 2 +- tests/ui-internal/outer_expn_data.rs | 2 +- tests/ui-internal/unnecessary_def_path.fixed | 4 +- tests/ui-internal/unnecessary_def_path.rs | 4 +- tests/ui-internal/unnecessary_symbol_str.fixed | 2 +- tests/ui-internal/unnecessary_symbol_str.rs | 2 +- .../uninlined_format_args.fixed | 2 +- .../uninlined_format_args.rs | 2 +- tests/ui-toml/dbg_macro/dbg_macro.rs | 2 +- .../ui-toml/disallowed_macros/disallowed_macros.rs | 2 +- tests/ui-toml/expect_used/expect_used.rs | 2 +- tests/ui-toml/mut_key/mut_key.rs | 2 +- .../auxiliary/proc_macro_derive.rs | 4 +- .../conf_nonstandard_macro_braces.fixed | 4 +- .../conf_nonstandard_macro_braces.rs | 4 +- tests/ui-toml/print_macro/print_macro.rs | 2 +- .../conf_disallowed_methods.rs | 2 +- tests/ui-toml/toml_trivially_copy/test.rs | 4 +- tests/ui-toml/toml_unknown_key/conf_unknown_key.rs | 2 + tests/ui-toml/unwrap_used/unwrap_used.rs | 2 +- tests/ui/allow_attributes.fixed | 2 +- tests/ui/allow_attributes.rs | 2 +- tests/ui/almost_complete_range.fixed | 6 +- tests/ui/almost_complete_range.rs | 6 +- tests/ui/arithmetic_side_effects.rs | 2 +- tests/ui/as_conversions.rs | 2 +- tests/ui/as_underscore.fixed | 2 +- tests/ui/as_underscore.rs | 2 +- tests/ui/asm_syntax.rs | 4 +- tests/ui/assertions_on_result_states.fixed | 2 +- tests/ui/assertions_on_result_states.rs | 2 +- tests/ui/assign_ops.fixed | 2 +- tests/ui/assign_ops.rs | 2 +- tests/ui/async_yields_async.fixed | 2 +- tests/ui/async_yields_async.rs | 2 +- tests/ui/author/blocks.rs | 2 +- tests/ui/auxiliary/proc_macro_attr.rs | 4 +- tests/ui/auxiliary/proc_macro_derive.rs | 4 +- .../proc_macro_suspicious_else_formatting.rs | 4 +- tests/ui/auxiliary/proc_macro_unsafe.rs | 4 +- tests/ui/auxiliary/proc_macros.rs | 4 +- tests/ui/bind_instead_of_map.fixed | 2 +- tests/ui/bind_instead_of_map.rs | 2 +- tests/ui/bind_instead_of_map_multipart.fixed | 2 +- tests/ui/bind_instead_of_map_multipart.rs | 2 +- tests/ui/blanket_clippy_restriction_lints.rs | 2 +- tests/ui/blocks_in_if_conditions.fixed | 2 +- tests/ui/blocks_in_if_conditions.rs | 2 +- tests/ui/bool_assert_comparison.fixed | 2 +- tests/ui/bool_assert_comparison.rs | 2 +- tests/ui/bool_comparison.fixed | 2 +- tests/ui/bool_comparison.rs | 2 +- tests/ui/bool_to_int_with_if.fixed | 2 +- tests/ui/bool_to_int_with_if.rs | 2 +- tests/ui/borrow_as_ptr.fixed | 2 +- tests/ui/borrow_as_ptr.rs | 2 +- tests/ui/borrow_as_ptr_no_std.fixed | 2 +- tests/ui/borrow_as_ptr_no_std.rs | 2 +- tests/ui/borrow_deref_ref.fixed | 2 +- tests/ui/borrow_deref_ref.rs | 2 +- tests/ui/borrow_interior_mutable_const/enums.rs | 2 +- tests/ui/box_default.fixed | 2 +- tests/ui/box_default.rs | 2 +- tests/ui/bytes_count_to_len.fixed | 2 +- tests/ui/bytes_count_to_len.rs | 2 +- tests/ui/bytes_nth.fixed | 2 +- tests/ui/bytes_nth.rs | 2 +- ...case_sensitive_file_extension_comparisons.fixed | 2 +- .../case_sensitive_file_extension_comparisons.rs | 2 +- tests/ui/cast_abs_to_unsigned.fixed | 2 +- tests/ui/cast_abs_to_unsigned.rs | 2 +- tests/ui/cast_lossless_bool.fixed | 2 +- tests/ui/cast_lossless_bool.rs | 2 +- tests/ui/cast_lossless_float.fixed | 2 +- tests/ui/cast_lossless_float.rs | 2 +- tests/ui/cast_lossless_integer.fixed | 2 +- tests/ui/cast_lossless_integer.rs | 2 +- tests/ui/cast_raw_slice_pointer_cast.fixed | 2 +- tests/ui/cast_raw_slice_pointer_cast.rs | 2 +- tests/ui/cast_size.rs | 2 +- tests/ui/cast_size_32bit.rs | 2 +- tests/ui/cast_size_32bit.stderr | 53 +++++++++ tests/ui/cfg_attr_rustfmt.fixed | 2 +- tests/ui/cfg_attr_rustfmt.rs | 2 +- tests/ui/char_lit_as_u8_suggestions.fixed | 2 +- tests/ui/char_lit_as_u8_suggestions.rs | 2 +- tests/ui/checked_conversions.fixed | 2 +- tests/ui/checked_conversions.rs | 2 +- tests/ui/clear_with_drain.fixed | 2 +- tests/ui/clear_with_drain.rs | 2 +- tests/ui/clone_on_copy.fixed | 2 +- tests/ui/clone_on_copy.rs | 2 +- tests/ui/cloned_instead_of_copied.fixed | 2 +- tests/ui/cloned_instead_of_copied.rs | 2 +- tests/ui/cmp_owned/asymmetric_partial_eq.fixed | 2 +- tests/ui/cmp_owned/asymmetric_partial_eq.rs | 2 +- tests/ui/cmp_owned/comparison_flip.fixed | 2 +- tests/ui/cmp_owned/comparison_flip.rs | 2 +- tests/ui/cmp_owned/with_suggestion.fixed | 2 +- tests/ui/cmp_owned/with_suggestion.rs | 2 +- tests/ui/collapsible_else_if.fixed | 2 +- tests/ui/collapsible_else_if.rs | 2 +- tests/ui/collapsible_if.fixed | 2 +- tests/ui/collapsible_if.rs | 2 +- tests/ui/collapsible_str_replace.fixed | 2 +- tests/ui/collapsible_str_replace.rs | 2 +- tests/ui/comparison_to_empty.fixed | 2 +- tests/ui/comparison_to_empty.rs | 2 +- tests/ui/crashes/auxiliary/proc_macro_crash.rs | 4 +- tests/ui/crashes/ice-10148.rs | 2 +- tests/ui/crashes/ice-3741.rs | 2 +- tests/ui/crashes/ice-4968.rs | 2 +- tests/ui/crashes/ice-7272.rs | 2 +- tests/ui/crashes/ice-7410.rs | 6 +- tests/ui/crashes/ice-8681.rs | 2 +- tests/ui/crate_in_macro_def.fixed | 2 +- tests/ui/crate_in_macro_def.rs | 2 +- .../ui/crate_level_checks/entrypoint_recursion.rs | 2 +- .../ui/crate_level_checks/no_std_main_recursion.rs | 4 +- tests/ui/create_dir.fixed | 2 +- tests/ui/create_dir.rs | 2 +- tests/ui/dbg_macro.rs | 2 +- tests/ui/decimal_literal_representation.fixed | 2 +- tests/ui/decimal_literal_representation.rs | 2 +- tests/ui/def_id_nocore.rs | 2 +- tests/ui/default_instead_of_iter_empty.fixed | 2 +- tests/ui/default_instead_of_iter_empty.rs | 2 +- tests/ui/default_numeric_fallback_f64.fixed | 4 +- tests/ui/default_numeric_fallback_f64.rs | 4 +- tests/ui/default_numeric_fallback_i32.fixed | 4 +- tests/ui/default_numeric_fallback_i32.rs | 4 +- tests/ui/default_trait_access.fixed | 4 +- tests/ui/default_trait_access.rs | 4 +- tests/ui/deref_addrof.fixed | 4 +- tests/ui/deref_addrof.rs | 4 +- tests/ui/deref_addrof_macro.rs | 2 +- tests/ui/deref_by_slicing.fixed | 2 +- tests/ui/deref_by_slicing.rs | 2 +- tests/ui/derivable_impls.fixed | 2 +- tests/ui/derivable_impls.rs | 2 +- tests/ui/derive_partial_eq_without_eq.fixed | 2 +- tests/ui/derive_partial_eq_without_eq.rs | 2 +- tests/ui/doc/doc-fixable.fixed | 2 +- tests/ui/doc/doc-fixable.rs | 2 +- tests/ui/doc_unsafe.rs | 2 +- tests/ui/double_comparison.fixed | 2 +- tests/ui/double_comparison.rs | 2 +- tests/ui/duration_subsec.fixed | 2 +- tests/ui/duration_subsec.rs | 2 +- tests/ui/empty_drop.fixed | 2 +- tests/ui/empty_drop.rs | 2 +- tests/ui/empty_line_after_outer_attribute.rs | 2 +- tests/ui/empty_loop.rs | 2 +- tests/ui/empty_loop_no_std.rs | 4 +- tests/ui/empty_structs_with_brackets.fixed | 2 +- tests/ui/empty_structs_with_brackets.rs | 2 +- tests/ui/entry.fixed | 4 +- tests/ui/entry.rs | 4 +- tests/ui/entry_btree.fixed | 2 +- tests/ui/entry_btree.rs | 2 +- tests/ui/entry_with_else.fixed | 2 +- tests/ui/entry_with_else.rs | 2 +- tests/ui/enum_clike_unportable_variant.rs | 2 +- tests/ui/enum_glob_use.fixed | 2 +- tests/ui/enum_glob_use.rs | 2 +- tests/ui/eq_op.rs | 2 +- tests/ui/equatable_if_let.fixed | 4 +- tests/ui/equatable_if_let.rs | 4 +- tests/ui/err_expect.fixed | 2 +- tests/ui/err_expect.rs | 2 +- tests/ui/eta.fixed | 2 +- tests/ui/eta.rs | 2 +- tests/ui/excessive_precision.fixed | 2 +- tests/ui/excessive_precision.rs | 2 +- tests/ui/exhaustive_items.fixed | 2 +- tests/ui/exhaustive_items.rs | 2 +- tests/ui/expect_fun_call.fixed | 2 +- tests/ui/expect_fun_call.rs | 2 +- tests/ui/explicit_auto_deref.fixed | 2 +- tests/ui/explicit_auto_deref.rs | 2 +- tests/ui/explicit_deref_methods.fixed | 2 +- tests/ui/explicit_deref_methods.rs | 2 +- tests/ui/explicit_write.fixed | 2 +- tests/ui/explicit_write.rs | 2 +- tests/ui/extend_with_drain.fixed | 2 +- tests/ui/extend_with_drain.rs | 2 +- tests/ui/extra_unused_lifetimes.rs | 2 +- tests/ui/extra_unused_type_parameters.fixed | 2 +- tests/ui/extra_unused_type_parameters.rs | 2 +- tests/ui/field_reassign_with_default.rs | 4 +- tests/ui/filter_map_identity.fixed | 2 +- tests/ui/filter_map_identity.rs | 2 +- tests/ui/filter_map_next_fixable.fixed | 2 +- tests/ui/filter_map_next_fixable.rs | 2 +- tests/ui/flat_map_identity.fixed | 2 +- tests/ui/flat_map_identity.rs | 2 +- tests/ui/flat_map_option.fixed | 2 +- tests/ui/flat_map_option.rs | 2 +- tests/ui/floating_point_abs.fixed | 2 +- tests/ui/floating_point_abs.rs | 2 +- tests/ui/floating_point_exp.fixed | 2 +- tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_hypot.fixed | 2 +- tests/ui/floating_point_hypot.rs | 2 +- tests/ui/floating_point_log.fixed | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_logbase.fixed | 2 +- tests/ui/floating_point_logbase.rs | 2 +- tests/ui/floating_point_mul_add.fixed | 2 +- tests/ui/floating_point_mul_add.rs | 2 +- tests/ui/floating_point_powf.fixed | 2 +- tests/ui/floating_point_powf.rs | 2 +- tests/ui/floating_point_powi.fixed | 2 +- tests/ui/floating_point_powi.rs | 2 +- tests/ui/floating_point_rad.fixed | 2 +- tests/ui/floating_point_rad.rs | 2 +- tests/ui/fn_to_numeric_cast.rs | 2 +- tests/ui/fn_to_numeric_cast_32bit.rs | 2 +- tests/ui/fn_to_numeric_cast_32bit.stderr | 14 +-- tests/ui/for_loop_fixable.fixed | 2 +- tests/ui/for_loop_fixable.rs | 2 +- tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- tests/ui/format_args.fixed | 2 +- tests/ui/format_args.rs | 2 +- tests/ui/from_iter_instead_of_collect.fixed | 2 +- tests/ui/from_iter_instead_of_collect.rs | 2 +- tests/ui/from_over_into.fixed | 2 +- tests/ui/from_over_into.rs | 2 +- tests/ui/get_first.fixed | 2 +- tests/ui/get_first.rs | 2 +- tests/ui/get_last_with_len.fixed | 2 +- tests/ui/get_last_with_len.rs | 2 +- tests/ui/get_unwrap.fixed | 2 +- tests/ui/get_unwrap.rs | 2 +- tests/ui/identity_op.fixed | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/implicit_clone.fixed | 2 +- tests/ui/implicit_clone.rs | 2 +- tests/ui/implicit_hasher.rs | 2 +- tests/ui/implicit_return.fixed | 2 +- tests/ui/implicit_return.rs | 2 +- tests/ui/implicit_saturating_add.fixed | 2 +- tests/ui/implicit_saturating_add.rs | 2 +- tests/ui/implicit_saturating_sub.fixed | 2 +- tests/ui/implicit_saturating_sub.rs | 2 +- tests/ui/inconsistent_digit_grouping.fixed | 2 +- tests/ui/inconsistent_digit_grouping.rs | 2 +- tests/ui/inconsistent_struct_constructor.fixed | 4 +- tests/ui/inconsistent_struct_constructor.rs | 4 +- tests/ui/inefficient_to_string.fixed | 2 +- tests/ui/inefficient_to_string.rs | 2 +- tests/ui/infallible_destructuring_match.fixed | 2 +- tests/ui/infallible_destructuring_match.rs | 2 +- tests/ui/inline_fn_without_body.fixed | 2 +- tests/ui/inline_fn_without_body.rs | 2 +- tests/ui/int_plus_one.fixed | 2 +- tests/ui/int_plus_one.rs | 2 +- tests/ui/integer_arithmetic.rs | 2 +- tests/ui/into_iter_on_ref.fixed | 2 +- tests/ui/into_iter_on_ref.rs | 2 +- tests/ui/invalid_null_ptr_usage.fixed | 2 +- tests/ui/invalid_null_ptr_usage.rs | 2 +- tests/ui/is_digit_ascii_radix.fixed | 2 +- tests/ui/is_digit_ascii_radix.rs | 2 +- tests/ui/issue_2356.fixed | 2 +- tests/ui/issue_2356.rs | 2 +- tests/ui/iter_cloned_collect.fixed | 2 +- tests/ui/iter_cloned_collect.rs | 2 +- tests/ui/iter_count.fixed | 4 +- tests/ui/iter_count.rs | 4 +- tests/ui/iter_kv_map.fixed | 2 +- tests/ui/iter_kv_map.rs | 2 +- tests/ui/iter_next_slice.fixed | 2 +- tests/ui/iter_next_slice.rs | 2 +- tests/ui/iter_nth.rs | 2 +- tests/ui/iter_nth_zero.fixed | 2 +- tests/ui/iter_nth_zero.rs | 2 +- tests/ui/iter_on_empty_collections.fixed | 2 +- tests/ui/iter_on_empty_collections.rs | 2 +- tests/ui/iter_on_single_items.fixed | 2 +- tests/ui/iter_on_single_items.rs | 2 +- tests/ui/iter_overeager_cloned.fixed | 2 +- tests/ui/iter_overeager_cloned.rs | 2 +- tests/ui/iter_skip_next.fixed | 4 +- tests/ui/iter_skip_next.rs | 4 +- tests/ui/iter_with_drain.fixed | 2 +- tests/ui/iter_with_drain.rs | 2 +- tests/ui/large_const_arrays.fixed | 2 +- tests/ui/large_const_arrays.rs | 2 +- tests/ui/large_digit_groups.fixed | 2 +- tests/ui/large_digit_groups.rs | 2 +- tests/ui/large_enum_variant.rs | 2 +- tests/ui/large_types_passed_by_value.rs | 4 +- tests/ui/len_zero.fixed | 2 +- tests/ui/len_zero.rs | 2 +- tests/ui/len_zero_ranges.fixed | 2 +- tests/ui/len_zero_ranges.rs | 2 +- tests/ui/let_unit.fixed | 2 +- tests/ui/let_unit.rs | 2 +- tests/ui/lines_filter_map_ok.fixed | 2 +- tests/ui/lines_filter_map_ok.rs | 2 +- tests/ui/lossy_float_literal.fixed | 2 +- tests/ui/lossy_float_literal.rs | 2 +- tests/ui/macro_use_imports.fixed | 10 +- tests/ui/macro_use_imports.rs | 10 +- tests/ui/macro_use_imports_expect.rs | 8 +- tests/ui/manual_assert.edition2018.fixed | 8 +- tests/ui/manual_assert.edition2021.fixed | 8 +- tests/ui/manual_assert.rs | 8 +- tests/ui/manual_async_fn.fixed | 2 +- tests/ui/manual_async_fn.rs | 2 +- tests/ui/manual_bits.fixed | 2 +- tests/ui/manual_bits.rs | 2 +- tests/ui/manual_filter.fixed | 2 +- tests/ui/manual_filter.rs | 2 +- tests/ui/manual_filter_map.fixed | 2 +- tests/ui/manual_filter_map.rs | 2 +- tests/ui/manual_find_fixable.fixed | 2 +- tests/ui/manual_find_fixable.rs | 2 +- tests/ui/manual_find_map.fixed | 2 +- tests/ui/manual_find_map.rs | 2 +- tests/ui/manual_instant_elapsed.fixed | 2 +- tests/ui/manual_instant_elapsed.rs | 2 +- tests/ui/manual_is_ascii_check.fixed | 2 +- tests/ui/manual_is_ascii_check.rs | 2 +- tests/ui/manual_main_separator_str.fixed | 2 +- tests/ui/manual_main_separator_str.rs | 2 +- tests/ui/manual_map_option.fixed | 2 +- tests/ui/manual_map_option.rs | 2 +- tests/ui/manual_map_option_2.fixed | 2 +- tests/ui/manual_map_option_2.rs | 2 +- tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- tests/ui/manual_rem_euclid.fixed | 4 +- tests/ui/manual_rem_euclid.rs | 4 +- tests/ui/manual_retain.fixed | 2 +- tests/ui/manual_retain.rs | 2 +- tests/ui/manual_saturating_arithmetic.fixed | 2 +- tests/ui/manual_saturating_arithmetic.rs | 2 +- tests/ui/manual_slice_size_calculation.fixed | 4 +- tests/ui/manual_slice_size_calculation.rs | 4 +- tests/ui/manual_split_once.fixed | 2 +- tests/ui/manual_split_once.rs | 2 +- tests/ui/manual_str_repeat.fixed | 2 +- tests/ui/manual_str_repeat.rs | 2 +- tests/ui/manual_string_new.fixed | 2 +- tests/ui/manual_string_new.rs | 2 +- tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.rs | 2 +- tests/ui/map_clone.fixed | 2 +- tests/ui/map_clone.rs | 2 +- tests/ui/map_collect_result_unit.fixed | 2 +- tests/ui/map_collect_result_unit.rs | 2 +- tests/ui/map_flatten_fixable.fixed | 2 +- tests/ui/map_flatten_fixable.rs | 2 +- tests/ui/map_identity.fixed | 2 +- tests/ui/map_identity.rs | 2 +- tests/ui/map_unwrap_or.rs | 2 +- tests/ui/map_unwrap_or_fixable.fixed | 4 +- tests/ui/map_unwrap_or_fixable.rs | 4 +- tests/ui/match_as_ref.fixed | 2 +- tests/ui/match_as_ref.rs | 2 +- tests/ui/match_expr_like_matches_macro.fixed | 2 +- tests/ui/match_expr_like_matches_macro.rs | 2 +- tests/ui/match_ref_pats.fixed | 2 +- tests/ui/match_ref_pats.rs | 2 +- tests/ui/match_result_ok.fixed | 2 +- tests/ui/match_result_ok.rs | 2 +- tests/ui/match_single_binding.fixed | 2 +- tests/ui/match_single_binding.rs | 2 +- tests/ui/match_single_binding2.fixed | 2 +- tests/ui/match_single_binding2.rs | 2 +- tests/ui/match_str_case_mismatch.fixed | 2 +- tests/ui/match_str_case_mismatch.rs | 2 +- tests/ui/match_wildcard_for_single_variants.fixed | 2 +- tests/ui/match_wildcard_for_single_variants.rs | 2 +- tests/ui/mem_replace.fixed | 2 +- tests/ui/mem_replace.rs | 2 +- tests/ui/mem_replace_macro.rs | 2 +- tests/ui/methods.rs | 2 +- tests/ui/methods_fixable.fixed | 2 +- tests/ui/methods_fixable.rs | 2 +- tests/ui/mismatched_target_os_non_unix.fixed | 2 +- tests/ui/mismatched_target_os_non_unix.rs | 2 +- tests/ui/mismatched_target_os_unix.fixed | 2 +- tests/ui/mismatched_target_os_unix.rs | 2 +- tests/ui/missing_const_for_fn/cant_be_const.rs | 4 +- tests/ui/missing_doc.rs | 4 +- tests/ui/missing_doc_impl.rs | 2 +- tests/ui/missing_spin_loop.fixed | 2 +- tests/ui/missing_spin_loop.rs | 2 +- tests/ui/missing_spin_loop_no_std.fixed | 2 +- tests/ui/missing_spin_loop_no_std.rs | 2 +- tests/ui/mistyped_literal_suffix.fixed | 4 +- tests/ui/mistyped_literal_suffix.rs | 4 +- tests/ui/module_name_repetitions.rs | 2 +- tests/ui/multiple_unsafe_ops_per_block.rs | 2 +- tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/must_use_unit.fixed | 4 +- tests/ui/must_use_unit.rs | 4 +- tests/ui/mut_mut.rs | 2 +- tests/ui/mut_mutex_lock.fixed | 2 +- tests/ui/mut_mutex_lock.rs | 2 +- tests/ui/needless_arbitrary_self_type.fixed | 2 +- tests/ui/needless_arbitrary_self_type.rs | 2 +- tests/ui/needless_arbitrary_self_type_unfixable.rs | 2 +- tests/ui/needless_bitwise_bool.fixed | 2 +- tests/ui/needless_bitwise_bool.rs | 2 +- tests/ui/needless_bool/fixable.fixed | 2 +- tests/ui/needless_bool/fixable.rs | 2 +- tests/ui/needless_borrow.fixed | 2 +- tests/ui/needless_borrow.rs | 2 +- tests/ui/needless_borrowed_ref.fixed | 2 +- tests/ui/needless_borrowed_ref.rs | 2 +- tests/ui/needless_collect.fixed | 2 +- tests/ui/needless_collect.rs | 2 +- tests/ui/needless_for_each_fixable.fixed | 2 +- tests/ui/needless_for_each_fixable.rs | 2 +- tests/ui/needless_late_init.fixed | 4 +- tests/ui/needless_late_init.rs | 4 +- tests/ui/needless_lifetimes.fixed | 4 +- tests/ui/needless_lifetimes.rs | 4 +- tests/ui/needless_match.fixed | 2 +- tests/ui/needless_match.rs | 2 +- tests/ui/needless_option_as_deref.fixed | 2 +- tests/ui/needless_option_as_deref.rs | 2 +- tests/ui/needless_option_take.fixed | 2 +- tests/ui/needless_option_take.rs | 2 +- tests/ui/needless_parens_on_range_literals.fixed | 4 +- tests/ui/needless_parens_on_range_literals.rs | 4 +- tests/ui/needless_question_mark.fixed | 2 +- tests/ui/needless_question_mark.rs | 2 +- tests/ui/needless_return.fixed | 2 +- tests/ui/needless_return.rs | 2 +- tests/ui/needless_splitn.fixed | 4 +- tests/ui/needless_splitn.rs | 4 +- tests/ui/neg_multiply.fixed | 2 +- tests/ui/neg_multiply.rs | 2 +- tests/ui/non_octal_unix_permissions.fixed | 4 +- tests/ui/non_octal_unix_permissions.rs | 4 +- tests/ui/nonminimal_bool_methods.fixed | 2 +- tests/ui/nonminimal_bool_methods.rs | 2 +- tests/ui/numbered_fields.fixed | 2 +- tests/ui/numbered_fields.rs | 2 +- tests/ui/obfuscated_if_else.fixed | 2 +- tests/ui/obfuscated_if_else.rs | 2 +- tests/ui/option_as_ref_deref.fixed | 2 +- tests/ui/option_as_ref_deref.rs | 2 +- tests/ui/option_env_unwrap.rs | 2 +- tests/ui/option_filter_map.fixed | 2 +- tests/ui/option_filter_map.rs | 2 +- tests/ui/option_if_let_else.fixed | 2 +- tests/ui/option_if_let_else.rs | 2 +- tests/ui/option_map_or_none.fixed | 2 +- tests/ui/option_map_or_none.rs | 2 +- tests/ui/option_map_unit_fn_fixable.fixed | 2 +- tests/ui/option_map_unit_fn_fixable.rs | 2 +- tests/ui/or_fun_call.fixed | 2 +- tests/ui/or_fun_call.rs | 2 +- tests/ui/or_then_unwrap.fixed | 2 +- tests/ui/or_then_unwrap.rs | 2 +- tests/ui/partialeq_to_none.fixed | 2 +- tests/ui/partialeq_to_none.rs | 2 +- tests/ui/path_buf_push_overwrite.fixed | 2 +- tests/ui/path_buf_push_overwrite.rs | 2 +- tests/ui/patterns.fixed | 2 +- tests/ui/patterns.rs | 2 +- tests/ui/precedence.fixed | 2 +- tests/ui/precedence.rs | 2 +- tests/ui/print_stdout_build_script.rs | 2 +- tests/ui/print_with_newline.rs | 2 +- tests/ui/println_empty_string.fixed | 2 +- tests/ui/println_empty_string.rs | 2 +- tests/ui/ptr_as_ptr.fixed | 4 +- tests/ui/ptr_as_ptr.rs | 4 +- tests/ui/ptr_eq.fixed | 2 +- tests/ui/ptr_eq.rs | 2 +- tests/ui/ptr_offset_with_cast.fixed | 2 +- tests/ui/ptr_offset_with_cast.rs | 2 +- tests/ui/question_mark.fixed | 2 +- tests/ui/question_mark.rs | 2 +- tests/ui/range_contains.fixed | 2 +- tests/ui/range_contains.rs | 2 +- tests/ui/range_plus_minus_one.fixed | 2 +- tests/ui/range_plus_minus_one.rs | 2 +- tests/ui/rc_buffer.fixed | 2 +- tests/ui/rc_buffer.rs | 2 +- tests/ui/rc_buffer_arc.fixed | 2 +- tests/ui/rc_buffer_arc.rs | 2 +- tests/ui/redundant_allocation_fixable.fixed | 2 +- tests/ui/redundant_allocation_fixable.rs | 2 +- tests/ui/redundant_async_block.fixed | 2 +- tests/ui/redundant_async_block.rs | 2 +- tests/ui/redundant_clone.fixed | 2 +- tests/ui/redundant_clone.rs | 2 +- tests/ui/redundant_closure_call_fixable.fixed | 2 +- tests/ui/redundant_closure_call_fixable.rs | 2 +- tests/ui/redundant_field_names.fixed | 2 +- tests/ui/redundant_field_names.rs | 2 +- .../ui/redundant_pattern_matching_drop_order.fixed | 2 +- tests/ui/redundant_pattern_matching_drop_order.rs | 2 +- tests/ui/redundant_pattern_matching_ipaddr.fixed | 2 +- tests/ui/redundant_pattern_matching_ipaddr.rs | 2 +- tests/ui/redundant_pattern_matching_option.fixed | 2 +- tests/ui/redundant_pattern_matching_option.rs | 2 +- tests/ui/redundant_pattern_matching_poll.fixed | 2 +- tests/ui/redundant_pattern_matching_poll.rs | 2 +- tests/ui/redundant_pattern_matching_result.fixed | 2 +- tests/ui/redundant_pattern_matching_result.rs | 2 +- tests/ui/redundant_pub_crate.fixed | 2 +- tests/ui/redundant_pub_crate.rs | 2 +- tests/ui/redundant_slicing.fixed | 2 +- tests/ui/redundant_slicing.rs | 2 +- tests/ui/redundant_static_lifetimes.fixed | 2 +- tests/ui/redundant_static_lifetimes.rs | 2 +- tests/ui/rename.fixed | 2 +- tests/ui/rename.rs | 2 +- tests/ui/renamed_builtin_attr.fixed | 2 +- tests/ui/renamed_builtin_attr.rs | 2 +- tests/ui/repeat_once.fixed | 2 +- tests/ui/repeat_once.rs | 2 +- tests/ui/result_map_or_into_option.fixed | 2 +- tests/ui/result_map_or_into_option.rs | 2 +- tests/ui/result_map_unit_fn_fixable.fixed | 2 +- tests/ui/result_map_unit_fn_fixable.rs | 2 +- tests/ui/reversed_empty_ranges_fixable.fixed | 2 +- tests/ui/reversed_empty_ranges_fixable.rs | 2 +- tests/ui/reversed_empty_ranges_loops_fixable.fixed | 2 +- tests/ui/reversed_empty_ranges_loops_fixable.rs | 2 +- tests/ui/same_functions_in_if_condition.rs | 2 +- tests/ui/same_functions_in_if_condition.stderr | 6 +- tests/ui/search_is_some.rs | 2 +- tests/ui/search_is_some_fixable_none.fixed | 2 +- tests/ui/search_is_some_fixable_none.rs | 2 +- tests/ui/search_is_some_fixable_some.fixed | 2 +- tests/ui/search_is_some_fixable_some.rs | 2 +- tests/ui/seek_from_current.fixed | 2 +- tests/ui/seek_from_current.rs | 2 +- tests/ui/seek_to_start_instead_of_rewind.fixed | 2 +- tests/ui/seek_to_start_instead_of_rewind.rs | 2 +- tests/ui/semicolon_inside_block.fixed | 2 +- tests/ui/semicolon_inside_block.rs | 2 +- tests/ui/semicolon_outside_block.fixed | 2 +- tests/ui/semicolon_outside_block.rs | 2 +- tests/ui/shadow.rs | 2 +- tests/ui/short_circuit_statement.fixed | 2 +- tests/ui/short_circuit_statement.rs | 2 +- tests/ui/significant_drop_in_scrutinee.rs | 2 +- tests/ui/significant_drop_tightening.fixed | 2 +- tests/ui/significant_drop_tightening.rs | 2 +- tests/ui/single_char_add_str.fixed | 2 +- tests/ui/single_char_add_str.rs | 2 +- tests/ui/single_char_pattern.fixed | 2 +- tests/ui/single_char_pattern.rs | 2 +- tests/ui/single_component_path_imports.fixed | 2 +- tests/ui/single_component_path_imports.rs | 2 +- tests/ui/single_element_loop.fixed | 2 +- tests/ui/single_element_loop.rs | 2 +- tests/ui/single_match_else.rs | 2 +- tests/ui/skip_while_next.rs | 2 +- tests/ui/stable_sort_primitive.fixed | 2 +- tests/ui/stable_sort_primitive.rs | 2 +- tests/ui/starts_ends_with.fixed | 2 +- tests/ui/starts_ends_with.rs | 2 +- tests/ui/string_add.rs | 2 +- tests/ui/string_add_assign.fixed | 2 +- tests/ui/string_add_assign.rs | 2 +- tests/ui/string_extend.fixed | 2 +- tests/ui/string_extend.rs | 2 +- tests/ui/string_from_utf8_as_bytes.fixed | 2 +- tests/ui/string_from_utf8_as_bytes.rs | 2 +- tests/ui/string_lit_as_bytes.fixed | 2 +- tests/ui/string_lit_as_bytes.rs | 2 +- tests/ui/strlen_on_c_strings.fixed | 2 +- tests/ui/strlen_on_c_strings.rs | 2 +- tests/ui/suspicious_doc_comments.fixed | 2 +- tests/ui/suspicious_doc_comments.rs | 2 +- tests/ui/suspicious_else_formatting.rs | 2 +- tests/ui/suspicious_operation_groupings.fixed | 2 +- tests/ui/suspicious_operation_groupings.rs | 2 +- tests/ui/swap.fixed | 4 +- tests/ui/swap.rs | 4 +- tests/ui/swap_ptr_to_ref.fixed | 2 +- tests/ui/swap_ptr_to_ref.rs | 2 +- tests/ui/tabs_in_doc_comments.fixed | 2 +- tests/ui/tabs_in_doc_comments.rs | 2 +- tests/ui/tests_outside_test_module.rs | 2 +- tests/ui/to_digit_is_some.fixed | 2 +- tests/ui/to_digit_is_some.rs | 2 +- tests/ui/toplevel_ref_arg.fixed | 4 +- tests/ui/toplevel_ref_arg.rs | 4 +- tests/ui/toplevel_ref_arg_non_rustfix.rs | 2 +- tests/ui/track-diagnostics.rs | 5 +- tests/ui/trait_duplication_in_bounds.fixed | 2 +- tests/ui/trait_duplication_in_bounds.rs | 2 +- tests/ui/transmute_32bit.rs | 2 +- tests/ui/transmute_32bit.stderr | 29 +++-- tests/ui/transmute_64bit.rs | 2 +- tests/ui/transmute_ptr_to_ref.fixed | 2 +- tests/ui/transmute_ptr_to_ref.rs | 2 +- tests/ui/transmutes_expressible_as_ptr_casts.fixed | 2 +- tests/ui/transmutes_expressible_as_ptr_casts.rs | 2 +- tests/ui/trim_split_whitespace.fixed | 2 +- tests/ui/trim_split_whitespace.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 4 +- tests/ui/try_err.fixed | 4 +- tests/ui/try_err.rs | 4 +- tests/ui/types.fixed | 2 +- tests/ui/types.rs | 2 +- tests/ui/unchecked_duration_subtraction.fixed | 2 +- tests/ui/unchecked_duration_subtraction.rs | 2 +- tests/ui/undocumented_unsafe_blocks.rs | 2 +- tests/ui/unicode.fixed | 4 +- tests/ui/unicode.rs | 4 +- tests/ui/uninlined_format_args.fixed | 4 +- tests/ui/uninlined_format_args.rs | 4 +- .../uninlined_format_args_panic.edition2018.fixed | 8 +- .../uninlined_format_args_panic.edition2021.fixed | 8 +- tests/ui/uninlined_format_args_panic.rs | 8 +- tests/ui/unit_arg.rs | 2 +- tests/ui/unit_arg_empty_blocks.fixed | 2 +- tests/ui/unit_arg_empty_blocks.rs | 2 +- tests/ui/unknown_clippy_lints.fixed | 2 +- tests/ui/unknown_clippy_lints.rs | 2 +- tests/ui/unnecessary_cast.fixed | 2 +- tests/ui/unnecessary_cast.rs | 2 +- tests/ui/unnecessary_fold.fixed | 2 +- tests/ui/unnecessary_fold.rs | 2 +- tests/ui/unnecessary_iter_cloned.fixed | 2 +- tests/ui/unnecessary_iter_cloned.rs | 2 +- tests/ui/unnecessary_join.fixed | 2 +- tests/ui/unnecessary_join.rs | 2 +- tests/ui/unnecessary_lazy_eval.fixed | 4 +- tests/ui/unnecessary_lazy_eval.rs | 4 +- tests/ui/unnecessary_operation.fixed | 2 +- tests/ui/unnecessary_operation.rs | 2 +- tests/ui/unnecessary_owned_empty_strings.fixed | 2 +- tests/ui/unnecessary_owned_empty_strings.rs | 2 +- tests/ui/unnecessary_self_imports.fixed | 2 +- tests/ui/unnecessary_self_imports.rs | 2 +- tests/ui/unnecessary_sort_by.fixed | 2 +- tests/ui/unnecessary_sort_by.rs | 2 +- tests/ui/unnecessary_struct_initialization.fixed | 2 +- tests/ui/unnecessary_struct_initialization.rs | 2 +- tests/ui/unnecessary_to_owned.fixed | 2 +- tests/ui/unnecessary_to_owned.rs | 2 +- tests/ui/unnecessary_unsafety_doc.rs | 2 +- tests/ui/unneeded_wildcard_pattern.fixed | 2 +- tests/ui/unneeded_wildcard_pattern.rs | 2 +- tests/ui/unnested_or_patterns.fixed | 2 +- tests/ui/unnested_or_patterns.rs | 2 +- tests/ui/unnested_or_patterns2.fixed | 2 +- tests/ui/unnested_or_patterns2.rs | 2 +- tests/ui/unreadable_literal.fixed | 2 +- tests/ui/unreadable_literal.rs | 2 +- tests/ui/unseparated_prefix_literals.fixed | 4 +- tests/ui/unseparated_prefix_literals.rs | 4 +- tests/ui/unused_rounding.fixed | 2 +- tests/ui/unused_rounding.rs | 2 +- tests/ui/unused_unit.fixed | 2 +- tests/ui/unused_unit.rs | 2 +- tests/ui/unwrap_or_else_default.fixed | 2 +- tests/ui/unwrap_or_else_default.rs | 2 +- tests/ui/use_self.fixed | 4 +- tests/ui/use_self.rs | 4 +- tests/ui/use_self_trait.fixed | 2 +- tests/ui/use_self_trait.rs | 2 +- tests/ui/used_underscore_binding.rs | 2 +- tests/ui/useless_asref.fixed | 2 +- tests/ui/useless_asref.rs | 2 +- tests/ui/useless_attribute.fixed | 4 +- tests/ui/useless_attribute.rs | 4 +- tests/ui/useless_conversion.fixed | 2 +- tests/ui/useless_conversion.rs | 2 +- tests/ui/vec.fixed | 2 +- tests/ui/vec.rs | 2 +- tests/ui/vec_box_sized.fixed | 2 +- tests/ui/vec_box_sized.rs | 2 +- tests/ui/while_let_on_iterator.fixed | 2 +- tests/ui/while_let_on_iterator.rs | 2 +- tests/ui/wildcard_enum_match_arm.fixed | 4 +- tests/ui/wildcard_enum_match_arm.rs | 4 +- tests/ui/wildcard_imports.fixed | 6 +- tests/ui/wildcard_imports.rs | 6 +- tests/ui/wildcard_imports_2021.edition2018.fixed | 10 +- tests/ui/wildcard_imports_2021.edition2021.fixed | 10 +- tests/ui/wildcard_imports_2021.rs | 10 +- tests/ui/wildcard_imports_2021.stderr | 132 --------------------- tests/ui/write_with_newline.rs | 4 +- tests/ui/write_with_newline.stderr | 6 +- tests/ui/writeln_empty_string.fixed | 2 +- tests/ui/writeln_empty_string.rs | 2 +- tests/ui/zero_ptr.fixed | 2 +- tests/ui/zero_ptr.rs | 2 +- tests/ui/zero_ptr_no_std.fixed | 2 +- tests/ui/zero_ptr_no_std.rs | 2 +- 724 files changed, 945 insertions(+), 1009 deletions(-) delete mode 100644 tests/ui/wildcard_imports_2021.stderr (limited to 'clippy_lints/src/methods') diff --git a/Cargo.toml b/Cargo.toml index 5bb9f527081..1ec168737b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true } termize = "0.1" [dev-dependencies] -compiletest_rs = { version = "0.9", features = ["tmp"] } +compiletest_rs = { version = "0.10", features = ["tmp"] } tester = "0.9" regex = "1.5" toml = "0.5" diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 9dacaaaae5c..ccae8d37420 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -164,7 +164,7 @@ The process of generating the `.stderr` file is the same, and prepending the ## Rustfix tests If the lint you are working on is making use of structured suggestions, the test -file should include a `// run-rustfix` comment at the top. This will +file should include a `//@run-rustfix` comment at the top. This will additionally run [rustfix] for that test. Rustfix will apply the suggestions from the lint to the code of the test file and compare that to the contents of a `.fixed` file. diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 95222a9acdf..dd90a38f757 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -741,7 +741,7 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { let mut seen_lints = HashSet::new(); let mut res: String = GENERATED_FILE_COMMENT.into(); - res.push_str("// run-rustfix\n\n"); + res.push_str("//@run-rustfix\n\n"); for lint in lints { if seen_lints.insert(&lint.new_name) { writeln!(res, "#![allow({})]", lint.new_name).unwrap(); diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index 4d7427b2662..eada530d670 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,5 +1,3 @@ -// run-rustfix - use super::OBFUSCATED_IF_ELSE; use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; use rustc_errors::Applicability; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 57890ff3173..35d75cc51c2 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -126,6 +126,7 @@ fn base_config(test_dir: &str) -> compiletest::Config { let mut config = compiletest::Config { edition: Some("2021".into()), mode: TestMode::Ui, + strict_headers: true, ..Default::default() }; @@ -424,7 +425,7 @@ fn check_rustfix_coverage() { .binary_search_by_key(&filename, Path::new) .is_ok(), "`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ - Please either add `// run-rustfix` at the top of the file or add the file to \ + Please either add `//@run-rustfix` at the top of the file or add the file to \ `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.", ); } diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs index 27841e18aa9..1a69bb24101 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs index 27841e18aa9..1a69bb24101 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs index 27841e18aa9..1a69bb24101 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs index 27841e18aa9..1a69bb24101 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs index 27841e18aa9..1a69bb24101 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs index 27841e18aa9..1a69bb24101 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/feature_name/fail/src/main.rs b/tests/ui-cargo/feature_name/fail/src/main.rs index 64f01a98c90..4dd9582aff8 100644 --- a/tests/ui-cargo/feature_name/fail/src/main.rs +++ b/tests/ui-cargo/feature_name/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=feature_name +//@compile-flags: --crate-name=feature_name #![warn(clippy::redundant_feature_names)] #![warn(clippy::negative_feature_names)] diff --git a/tests/ui-cargo/feature_name/pass/src/main.rs b/tests/ui-cargo/feature_name/pass/src/main.rs index 64f01a98c90..4dd9582aff8 100644 --- a/tests/ui-cargo/feature_name/pass/src/main.rs +++ b/tests/ui-cargo/feature_name/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=feature_name +//@compile-flags: --crate-name=feature_name #![warn(clippy::redundant_feature_names)] #![warn(clippy::negative_feature_names)] diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs index ba4c8c873dd..c70d92e359e 100644 --- a/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs +++ b/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --remap-path-prefix {{src-base}}=/remapped +//@compile-flags: --remap-path-prefix {{src-base}}=/remapped #![warn(clippy::self_named_module_files)] diff --git a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs index 1b2d3ec9459..ece260b743d 100644 --- a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs index 1b2d3ec9459..ece260b743d 100644 --- a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs index 1b2d3ec9459..ece260b743d 100644 --- a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs index 581babfeacb..bb3a39d0720 100644 --- a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=wildcard_dependencies +//@compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs index 581babfeacb..bb3a39d0720 100644 --- a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs +++ b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=wildcard_dependencies +//@compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index 9f299d7dec7..72c04bf80b6 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index 2b113f555e4..76f7c3ce94d 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 837811bdf1e..acb98d7ba98 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -1,9 +1,9 @@ -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" -// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" -// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" -// normalize-stderr-test: "'rustc'" -> "''" -// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" +//@rustc-env:RUST_BACKTRACE=0 +//@normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" +//@normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" +//@normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" +//@normalize-stderr-test: "'rustc'" -> "''" +//@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed index eaea218e128..a1a10c0798e 100644 --- a/tests/ui-internal/interning_defined_symbol.fixed +++ b/tests/ui-internal/interning_defined_symbol.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/tests/ui-internal/interning_defined_symbol.rs b/tests/ui-internal/interning_defined_symbol.rs index 7efebb8fae4..32dbfe5dcac 100644 --- a/tests/ui-internal/interning_defined_symbol.rs +++ b/tests/ui-internal/interning_defined_symbol.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 08634063a57..ac0752774f3 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index f8af77e6d39..56f778621a4 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/outer_expn_data.fixed b/tests/ui-internal/outer_expn_data.fixed index bb82faf0c90..d8a08bc9997 100644 --- a/tests/ui-internal/outer_expn_data.fixed +++ b/tests/ui-internal/outer_expn_data.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/outer_expn_data.rs b/tests/ui-internal/outer_expn_data.rs index 187d468b392..f7af0e9d8be 100644 --- a/tests/ui-internal/outer_expn_data.rs +++ b/tests/ui-internal/outer_expn_data.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index e474f370a5d..fce24412f84 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:paths.rs +//@run-rustfix +//@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index f17fed6c653..b10bc9e46e2 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:paths.rs +//@run-rustfix +//@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index 6033d06e4f6..b802de1cbc6 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs index 1bb5d55f0b6..c1bead5bdc9 100644 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ b/tests/ui-internal/unnecessary_symbol_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed index aa8b45b5fe7..23e7bc16d23 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::uninlined_format_args)] fn main() { diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs index ad2e4863ee8..d66b2b8ff6a 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::uninlined_format_args)] fn main() { diff --git a/tests/ui-toml/dbg_macro/dbg_macro.rs b/tests/ui-toml/dbg_macro/dbg_macro.rs index 5d9ce18f631..21e4fce26e4 100644 --- a/tests/ui-toml/dbg_macro/dbg_macro.rs +++ b/tests/ui-toml/dbg_macro/dbg_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/tests/ui-toml/disallowed_macros/disallowed_macros.rs index 2bb5376076e..ba919b48788 100644 --- a/tests/ui-toml/disallowed_macros/disallowed_macros.rs +++ b/tests/ui-toml/disallowed_macros/disallowed_macros.rs @@ -1,4 +1,4 @@ -// aux-build:macros.rs +//@aux-build:macros.rs #![allow(unused)] diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs index 89f142a150d..9e267c89300 100644 --- a/tests/ui-toml/expect_used/expect_used.rs +++ b/tests/ui-toml/expect_used/expect_used.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::expect_used)] fn expect_option() { diff --git a/tests/ui-toml/mut_key/mut_key.rs b/tests/ui-toml/mut_key/mut_key.rs index 667c51cb4a3..095e0d15448 100644 --- a/tests/ui-toml/mut_key/mut_key.rs +++ b/tests/ui-toml/mut_key/mut_key.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name mut_key +//@compile-flags: --crate-name mut_key #![warn(clippy::mutable_key_type)] diff --git a/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs b/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs index 6452189a461..f5761c6afeb 100644 --- a/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs +++ b/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index 01d135764df..e4747bedddb 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// run-rustfix +//@aux-build:proc_macro_derive.rs +//@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index 72883e8270c..54edded99f4 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// run-rustfix +//@aux-build:proc_macro_derive.rs +//@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/print_macro/print_macro.rs b/tests/ui-toml/print_macro/print_macro.rs index 5aefb6a6b4d..3a8b30cca36 100644 --- a/tests/ui-toml/print_macro/print_macro.rs +++ b/tests/ui-toml/print_macro/print_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::print_stdout)] #![warn(clippy::print_stderr)] diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 2f3160c8338..8e1a1710a6c 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name conf_disallowed_methods +//@compile-flags: --crate-name conf_disallowed_methods #![warn(clippy::disallowed_methods)] diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index fb0e226f3aa..179b1266169 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index f328e4d9d04..569fd2c3553 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1 +1,3 @@ +//@error-pattern: unknown field `foobar`, expected one of + fn main() {} diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index 6525ea5bfc3..5d3e800cadd 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![allow(unused_mut, clippy::get_first, clippy::from_iter_instead_of_collect)] #![warn(clippy::unwrap_used)] diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed index b8dd0619e6d..f0936b2608e 100644 --- a/tests/ui/allow_attributes.fixed +++ b/tests/ui/allow_attributes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs index 295f560906a..2fb9e86126e 100644 --- a/tests/ui/allow_attributes.rs +++ b/tests/ui/allow_attributes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] diff --git a/tests/ui/almost_complete_range.fixed b/tests/ui/almost_complete_range.fixed index a4bf7fe18d5..5cd0dcce6f7 100644 --- a/tests/ui/almost_complete_range.fixed +++ b/tests/ui/almost_complete_range.fixed @@ -1,6 +1,6 @@ -// run-rustfix -// edition:2018 -// aux-build:proc_macros.rs +//@run-rustfix +//@edition:2018 +//@aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/almost_complete_range.rs b/tests/ui/almost_complete_range.rs index 8237c3a1361..db0bfc8afc3 100644 --- a/tests/ui/almost_complete_range.rs +++ b/tests/ui/almost_complete_range.rs @@ -1,6 +1,6 @@ -// run-rustfix -// edition:2018 -// aux-build:proc_macros.rs +//@run-rustfix +//@edition:2018 +//@aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index ab7e66a264d..d864fe05800 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![allow( clippy::assign_op_pattern, diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index c50d4088b5e..890bf0b0a7e 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::as_conversions)] #![allow(clippy::borrow_as_ptr)] diff --git a/tests/ui/as_underscore.fixed b/tests/ui/as_underscore.fixed index 948f6d8e6b1..69af84a0eae 100644 --- a/tests/ui/as_underscore.fixed +++ b/tests/ui/as_underscore.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::as_underscore)] diff --git a/tests/ui/as_underscore.rs b/tests/ui/as_underscore.rs index 97785ed08a8..a8cfb81d9a3 100644 --- a/tests/ui/as_underscore.rs +++ b/tests/ui/as_underscore.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::as_underscore)] diff --git a/tests/ui/asm_syntax.rs b/tests/ui/asm_syntax.rs index 0220bf3331f..c93995f939a 100644 --- a/tests/ui/asm_syntax.rs +++ b/tests/ui/asm_syntax.rs @@ -1,5 +1,5 @@ -// only-x86_64 -// ignore-aarch64 +//@only-x86_64 +//@ignore-aarch64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed index 2bb755290c5..ea8b895664c 100644 --- a/tests/ui/assertions_on_result_states.fixed +++ b/tests/ui/assertions_on_result_states.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::assertions_on_result_states)] use std::result::Result; diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs index d8a9bd2f1c4..6fc20f85988 100644 --- a/tests/ui/assertions_on_result_states.rs +++ b/tests/ui/assertions_on_result_states.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::assertions_on_result_states)] use std::result::Result; diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index da034b51cfd..b50682ea00c 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use core::num::Wrapping; diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 337bb02c8a6..780d2d040f1 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use core::num::Wrapping; diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed index 579a63ea477..8d9b023893f 100644 --- a/tests/ui/async_yields_async.fixed +++ b/tests/ui/async_yields_async.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs index 5aec2fb50f6..bed79062f01 100644 --- a/tests/ui/async_yields_async.rs +++ b/tests/ui/async_yields_async.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/tests/ui/author/blocks.rs b/tests/ui/author/blocks.rs index a7335c01baa..164f7d0d9d6 100644 --- a/tests/ui/author/blocks.rs +++ b/tests/ui/author/blocks.rs @@ -1,4 +1,4 @@ -// edition:2018 +//@edition:2018 #![allow(redundant_semicolons, clippy::no_effect)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index b498fece513..92c47b41a38 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 13d93f5c275..5a924ca1830 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_quote)] diff --git a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index a2ef0fe827c..f13b76e44b0 100644 --- a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui/auxiliary/proc_macro_unsafe.rs b/tests/ui/auxiliary/proc_macro_unsafe.rs index 3c40f77469b..c2326678d0d 100644 --- a/tests/ui/auxiliary/proc_macro_unsafe.rs +++ b/tests/ui/auxiliary/proc_macro_unsafe.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 3d5beab1eff..94f075ed09c 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(let_chains)] diff --git a/tests/ui/bind_instead_of_map.fixed b/tests/ui/bind_instead_of_map.fixed index d94e2ac6072..ea2dc2e2293 100644 --- a/tests/ui/bind_instead_of_map.fixed +++ b/tests/ui/bind_instead_of_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/bind_instead_of_map.rs b/tests/ui/bind_instead_of_map.rs index 86f31f58284..1db58dae538 100644 --- a/tests/ui/bind_instead_of_map.rs +++ b/tests/ui/bind_instead_of_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/bind_instead_of_map_multipart.fixed b/tests/ui/bind_instead_of_map_multipart.fixed index e1589843226..63c7aafcddb 100644 --- a/tests/ui/bind_instead_of_map_multipart.fixed +++ b/tests/ui/bind_instead_of_map_multipart.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/tests/ui/bind_instead_of_map_multipart.rs b/tests/ui/bind_instead_of_map_multipart.rs index 49944403f6d..69b982fa8a2 100644 --- a/tests/ui/bind_instead_of_map_multipart.rs +++ b/tests/ui/bind_instead_of_map_multipart.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/tests/ui/blanket_clippy_restriction_lints.rs b/tests/ui/blanket_clippy_restriction_lints.rs index 554745368bc..e1ff25c54cf 100644 --- a/tests/ui/blanket_clippy_restriction_lints.rs +++ b/tests/ui/blanket_clippy_restriction_lints.rs @@ -1,4 +1,4 @@ -// compile-flags: -W clippy::restriction +//@compile-flags: -W clippy::restriction #![warn(clippy::blanket_clippy_restriction_lints)] diff --git a/tests/ui/blocks_in_if_conditions.fixed b/tests/ui/blocks_in_if_conditions.fixed index e6e40a9948c..a9f18782e58 100644 --- a/tests/ui/blocks_in_if_conditions.fixed +++ b/tests/ui/blocks_in_if_conditions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/blocks_in_if_conditions.rs b/tests/ui/blocks_in_if_conditions.rs index 69387ff5782..0a70317c4d4 100644 --- a/tests/ui/blocks_in_if_conditions.rs +++ b/tests/ui/blocks_in_if_conditions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index b8dd92906c8..53f63444aef 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 0a8ad34fda5..151d93a9233 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed index 5a012ff4d27..670eef6a21d 100644 --- a/tests/ui/bool_comparison.fixed +++ b/tests/ui/bool_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bool_comparison)] diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index c534bc25c20..72851be635d 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bool_comparison)] diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 37d3e3286a4..9831c3373d4 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index ebdf86fd185..5e3047bb32c 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] diff --git a/tests/ui/borrow_as_ptr.fixed b/tests/ui/borrow_as_ptr.fixed index ff5c6a8c377..3f440ce0045 100644 --- a/tests/ui/borrow_as_ptr.fixed +++ b/tests/ui/borrow_as_ptr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] fn main() { diff --git a/tests/ui/borrow_as_ptr.rs b/tests/ui/borrow_as_ptr.rs index 0f62ec6ee58..c1ca9180eef 100644 --- a/tests/ui/borrow_as_ptr.rs +++ b/tests/ui/borrow_as_ptr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] fn main() { diff --git a/tests/ui/borrow_as_ptr_no_std.fixed b/tests/ui/borrow_as_ptr_no_std.fixed index eaba3b1c20c..10f2727c793 100644 --- a/tests/ui/borrow_as_ptr_no_std.fixed +++ b/tests/ui/borrow_as_ptr_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/borrow_as_ptr_no_std.rs b/tests/ui/borrow_as_ptr_no_std.rs index d83f9d1f875..311e9341aac 100644 --- a/tests/ui/borrow_as_ptr_no_std.rs +++ b/tests/ui/borrow_as_ptr_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed index bf4691c5bc9..165e4bc8272 100644 --- a/tests/ui/borrow_deref_ref.fixed +++ b/tests/ui/borrow_deref_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs index 28c005fdbef..66c8d69bef9 100644 --- a/tests/ui/borrow_deref_ref.rs +++ b/tests/ui/borrow_deref_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs index 5027db44561..29b08ab3643 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ b/tests/ui/borrow_interior_mutable_const/enums.rs @@ -1,4 +1,4 @@ -// aux-build:helper.rs +//@aux-build:helper.rs #![warn(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const)] diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 59c0baf8718..6afce208769 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::box_default)] #[derive(Default)] diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index f7d832193a3..09365618e63 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::box_default)] #[derive(Default)] diff --git a/tests/ui/bytes_count_to_len.fixed b/tests/ui/bytes_count_to_len.fixed index 860642363b5..fb3d521badd 100644 --- a/tests/ui/bytes_count_to_len.fixed +++ b/tests/ui/bytes_count_to_len.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bytes_count_to_len)] use std::fs::File; use std::io::Read; diff --git a/tests/ui/bytes_count_to_len.rs b/tests/ui/bytes_count_to_len.rs index 162730c2842..8e256b8f0b8 100644 --- a/tests/ui/bytes_count_to_len.rs +++ b/tests/ui/bytes_count_to_len.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bytes_count_to_len)] use std::fs::File; use std::io::Read; diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed index a35c679afb7..d3e0f676b29 100644 --- a/tests/ui/bytes_nth.fixed +++ b/tests/ui/bytes_nth.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs index 1ecffea5303..b7d813fe296 100644 --- a/tests/ui/bytes_nth.rs +++ b/tests/ui/bytes_nth.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index 5fbaa64db39..d5af22aefe5 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 3c0d4821f9f..f5f0a0022a4 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed index 8676b562b4f..ef0a93b01d1 100644 --- a/tests/ui/cast_abs_to_unsigned.fixed +++ b/tests/ui/cast_abs_to_unsigned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_abs_to_unsigned)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs index 5775af874f8..96ced670a05 100644 --- a/tests/ui/cast_abs_to_unsigned.rs +++ b/tests/ui/cast_abs_to_unsigned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_abs_to_unsigned)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/cast_lossless_bool.fixed b/tests/ui/cast_lossless_bool.fixed index 13b3cf838c9..c321cc64437 100644 --- a/tests/ui/cast_lossless_bool.fixed +++ b/tests/ui/cast_lossless_bool.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_bool.rs b/tests/ui/cast_lossless_bool.rs index 3eed2135562..632a718920d 100644 --- a/tests/ui/cast_lossless_bool.rs +++ b/tests/ui/cast_lossless_bool.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.fixed b/tests/ui/cast_lossless_float.fixed index 32a9c1c4ae1..e72a0096acc 100644 --- a/tests/ui/cast_lossless_float.fixed +++ b/tests/ui/cast_lossless_float.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index 6f5ddcfe09c..dbcbaa9b815 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed index 925cbf25368..7dab02084fc 100644 --- a/tests/ui/cast_lossless_integer.fixed +++ b/tests/ui/cast_lossless_integer.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index c82bd9108d2..c24f73960b0 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_raw_slice_pointer_cast.fixed b/tests/ui/cast_raw_slice_pointer_cast.fixed index b70c1912951..9b6fee270ee 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.fixed +++ b/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_slice_from_raw_parts)] #[allow(unused_imports, unused_unsafe)] diff --git a/tests/ui/cast_raw_slice_pointer_cast.rs b/tests/ui/cast_raw_slice_pointer_cast.rs index c1b316765c9..c0bb8137990 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.rs +++ b/tests/ui/cast_raw_slice_pointer_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_slice_from_raw_parts)] #[allow(unused_imports, unused_unsafe)] diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index 595109be46b..cd2184aea38 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/tests/ui/cast_size_32bit.rs b/tests/ui/cast_size_32bit.rs index 99aac6deca3..7ca20d3ca4a 100644 --- a/tests/ui/cast_size_32bit.rs +++ b/tests/ui/cast_size_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/tests/ui/cast_size_32bit.stderr b/tests/ui/cast_size_32bit.stderr index 8990c3ba739..fb51783a487 100644 --- a/tests/ui/cast_size_32bit.stderr +++ b/tests/ui/cast_size_32bit.stderr @@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value LL | 1isize as i8; | ^^^^^^^^^^^^ | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> $DIR/cast_size_32bit.rs:15:5 @@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi | LL | 1isize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:20:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:21:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:22:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:22:5 @@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi | LL | 1i64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:25:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:26:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:26:5 @@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi | LL | 1u64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:28:5 diff --git a/tests/ui/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed index b970b1209b6..13aadb7d330 100644 --- a/tests/ui/cfg_attr_rustfmt.fixed +++ b/tests/ui/cfg_attr_rustfmt.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs index 0a8e6a89d8a..769c5d22b9d 100644 --- a/tests/ui/cfg_attr_rustfmt.rs +++ b/tests/ui/cfg_attr_rustfmt.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/char_lit_as_u8_suggestions.fixed b/tests/ui/char_lit_as_u8_suggestions.fixed index 3dc3cb4e757..ce2f149dc05 100644 --- a/tests/ui/char_lit_as_u8_suggestions.fixed +++ b/tests/ui/char_lit_as_u8_suggestions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::char_lit_as_u8)] diff --git a/tests/ui/char_lit_as_u8_suggestions.rs b/tests/ui/char_lit_as_u8_suggestions.rs index d379a023494..ffad12fc6f9 100644 --- a/tests/ui/char_lit_as_u8_suggestions.rs +++ b/tests/ui/char_lit_as_u8_suggestions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::char_lit_as_u8)] diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index e279ba3147b..188e6d97595 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::cast_lossless, diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 9d7a40995c3..70f0f0975ac 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::cast_lossless, diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 2d9545eeed1..b68c7d867ec 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 4d60ee46e18..0f6562ecad5 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index 72b12227098..a720711585b 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 03e210ebad9..2c5fac8faf5 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, diff --git a/tests/ui/cloned_instead_of_copied.fixed b/tests/ui/cloned_instead_of_copied.fixed index ecbfc1feedf..b6e09ab3190 100644 --- a/tests/ui/cloned_instead_of_copied.fixed +++ b/tests/ui/cloned_instead_of_copied.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] diff --git a/tests/ui/cloned_instead_of_copied.rs b/tests/ui/cloned_instead_of_copied.rs index 163dc3dddce..fa9e1a99613 100644 --- a/tests/ui/cloned_instead_of_copied.rs +++ b/tests/ui/cloned_instead_of_copied.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed index abd059c2308..3bf3deb9b91 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/tests/ui/cmp_owned/asymmetric_partial_eq.rs index 020ef5f840b..10107dc8f86 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.rs +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. diff --git a/tests/ui/cmp_owned/comparison_flip.fixed b/tests/ui/cmp_owned/comparison_flip.fixed index 44e41bdd114..b1133f2a59f 100644 --- a/tests/ui/cmp_owned/comparison_flip.fixed +++ b/tests/ui/cmp_owned/comparison_flip.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::fmt::{self, Display}; diff --git a/tests/ui/cmp_owned/comparison_flip.rs b/tests/ui/cmp_owned/comparison_flip.rs index 662673abb62..091a9aa65c0 100644 --- a/tests/ui/cmp_owned/comparison_flip.rs +++ b/tests/ui/cmp_owned/comparison_flip.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::fmt::{self, Display}; diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index b28c4378e33..76f90ab2a9d 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)] diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index c1089010fe1..f3f663670eb 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)] diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index d6a5a785067..8302cec45e7 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 4399fc8b2bd..5913dcf41ca 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 6bb7682bae9..d2aba2ac59b 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index e216a9ee54c..e0bef7f9c97 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed index 9792ae9ed6b..ba6c1769a9a 100644 --- a/tests/ui/collapsible_str_replace.fixed +++ b/tests/ui/collapsible_str_replace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::collapsible_str_replace)] diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index baee185b79e..f5871be65be 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::collapsible_str_replace)] diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index 261024caca7..dd2615ab25c 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::comparison_to_empty)] diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 98ddd974951..5462784c6ac 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::comparison_to_empty)] diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs index 5ff2af7cd82..66419656a32 100644 --- a/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro // crates. If we don't set this, compiletest will override the `crate_type` attribute below and // compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't diff --git a/tests/ui/crashes/ice-10148.rs b/tests/ui/crashes/ice-10148.rs index 1ab3570c907..c7f0224820e 100644 --- a/tests/ui/crashes/ice-10148.rs +++ b/tests/ui/crashes/ice-10148.rs @@ -1,4 +1,4 @@ -// aux-build:../../auxiliary/proc_macros.rs +//@aux-build:../../auxiliary/proc_macros.rs extern crate proc_macros; diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs index 1253ddcfaeb..3106a2e7216 100644 --- a/tests/ui/crashes/ice-3741.rs +++ b/tests/ui/crashes/ice-3741.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_crash.rs +//@aux-build:proc_macro_crash.rs #![warn(clippy::suspicious_else_formatting)] diff --git a/tests/ui/crashes/ice-4968.rs b/tests/ui/crashes/ice-4968.rs index e0510d942c2..ac724ac93e3 100644 --- a/tests/ui/crashes/ice-4968.rs +++ b/tests/ui/crashes/ice-4968.rs @@ -1,4 +1,4 @@ -// check-pass +//@check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/4968 diff --git a/tests/ui/crashes/ice-7272.rs b/tests/ui/crashes/ice-7272.rs index 57ab6ca14f8..e949038c8d0 100644 --- a/tests/ui/crashes/ice-7272.rs +++ b/tests/ui/crashes/ice-7272.rs @@ -1,4 +1,4 @@ -// aux-build:ice-7272-aux.rs +//@aux-build:ice-7272-aux.rs #![allow(clippy::no_effect)] diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index 85fa4210321..ffe20ab1c31 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,6 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos -// ignore-windows +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos +//@ignore-windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/crashes/ice-8681.rs b/tests/ui/crashes/ice-8681.rs index ee14f011f63..607b9caa324 100644 --- a/tests/ui/crashes/ice-8681.rs +++ b/tests/ui/crashes/ice-8681.rs @@ -1,4 +1,4 @@ -// aux-build: ice-8681-aux.rs +//@aux-build: ice-8681-aux.rs #![warn(clippy::undocumented_unsafe_blocks)] diff --git a/tests/ui/crate_in_macro_def.fixed b/tests/ui/crate_in_macro_def.fixed index 9fc594be311..12a7b9470b3 100644 --- a/tests/ui/crate_in_macro_def.fixed +++ b/tests/ui/crate_in_macro_def.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::crate_in_macro_def)] mod hygienic { diff --git a/tests/ui/crate_in_macro_def.rs b/tests/ui/crate_in_macro_def.rs index ac456108e4a..a1a9eabf639 100644 --- a/tests/ui/crate_in_macro_def.rs +++ b/tests/ui/crate_in_macro_def.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::crate_in_macro_def)] mod hygienic { diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index 1b3bcece6f1..d6cd594d7c9 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -// ignore-macos +//@ignore-macos #![feature(rustc_attrs)] diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs index e1c9fe30a9d..a382135bb69 100644 --- a/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed index 8ed53a56ac0..5de3e9fea0b 100644 --- a/tests/ui/create_dir.fixed +++ b/tests/ui/create_dir.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::create_dir)] diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs index 19c8fc24ba2..d375bfb4a68 100644 --- a/tests/ui/create_dir.rs +++ b/tests/ui/create_dir.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::create_dir)] diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs index 25294e8c766..8701e3cd29f 100644 --- a/tests/ui/dbg_macro.rs +++ b/tests/ui/dbg_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { diff --git a/tests/ui/decimal_literal_representation.fixed b/tests/ui/decimal_literal_representation.fixed index de391465125..a6eb8c21457 100644 --- a/tests/ui/decimal_literal_representation.fixed +++ b/tests/ui/decimal_literal_representation.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] diff --git a/tests/ui/decimal_literal_representation.rs b/tests/ui/decimal_literal_representation.rs index 55d07698e7e..7c666d6d7a6 100644 --- a/tests/ui/decimal_literal_representation.rs +++ b/tests/ui/decimal_literal_representation.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 1af77d1a25b..f7819068ac5 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -// ignore-macos +//@ignore-macos #![feature(no_core, lang_items, start)] #![no_core] diff --git a/tests/ui/default_instead_of_iter_empty.fixed b/tests/ui/default_instead_of_iter_empty.fixed index f1abfdcd6ce..f44d34576f6 100644 --- a/tests/ui/default_instead_of_iter_empty.fixed +++ b/tests/ui/default_instead_of_iter_empty.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::default_instead_of_iter_empty)] #![allow(dead_code)] use std::collections::HashMap; diff --git a/tests/ui/default_instead_of_iter_empty.rs b/tests/ui/default_instead_of_iter_empty.rs index 2630519c46d..1c649df253c 100644 --- a/tests/ui/default_instead_of_iter_empty.rs +++ b/tests/ui/default_instead_of_iter_empty.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::default_instead_of_iter_empty)] #![allow(dead_code)] use std::collections::HashMap; diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index 42c15d6a70b..9520efe6329 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs index 7da7ea254e9..cacbdb4a95b 100644 --- a/tests/ui/default_numeric_fallback_f64.rs +++ b/tests/ui/default_numeric_fallback_f64.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index b7485b73dcd..fbabb8bcf8e 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 7307d31354e..7bfc390e4bf 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 7842ef3ec40..bf5dca97641 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index cbb3e59c970..5e8e9ce85b1 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index ca5c03304c7..b27d3bc1002 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 3db5fafe944..825090c7c12 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] diff --git a/tests/ui/deref_addrof_macro.rs b/tests/ui/deref_addrof_macro.rs index 57c0be3f51e..c7e60f36506 100644 --- a/tests/ui/deref_addrof_macro.rs +++ b/tests/ui/deref_addrof_macro.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::deref_addrof)] diff --git a/tests/ui/deref_by_slicing.fixed b/tests/ui/deref_by_slicing.fixed index 257393e56ff..f91a425c65d 100644 --- a/tests/ui/deref_by_slicing.fixed +++ b/tests/ui/deref_by_slicing.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::deref_by_slicing)] #![allow(clippy::borrow_deref_ref)] diff --git a/tests/ui/deref_by_slicing.rs b/tests/ui/deref_by_slicing.rs index e288046f927..1bfdd0a981b 100644 --- a/tests/ui/deref_by_slicing.rs +++ b/tests/ui/deref_by_slicing.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::deref_by_slicing)] #![allow(clippy::borrow_deref_ref)] diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed index 89ec33a0d8f..aa0efb85c29 100644 --- a/tests/ui/derivable_impls.fixed +++ b/tests/ui/derivable_impls.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index def6e41162f..8dc999ad586 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed index bbbe467590f..a1f29430c30 100644 --- a/tests/ui/derive_partial_eq_without_eq.fixed +++ b/tests/ui/derive_partial_eq_without_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs index 88d6fbd1af7..ff4d888559b 100644 --- a/tests/ui/derive_partial_eq_without_eq.rs +++ b/tests/ui/derive_partial_eq_without_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index ecb0bf3644e..d3aa2816cb6 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 11c48dd103d..d1e7d8017d7 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 30674ce3708..0c8eac5ccff 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] diff --git a/tests/ui/double_comparison.fixed b/tests/ui/double_comparison.fixed index bb6cdaa667d..c80ff671a5d 100644 --- a/tests/ui/double_comparison.fixed +++ b/tests/ui/double_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { let x = 1; diff --git a/tests/ui/double_comparison.rs b/tests/ui/double_comparison.rs index 9a2a9068a28..bc78694aa68 100644 --- a/tests/ui/double_comparison.rs +++ b/tests/ui/double_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { let x = 1; diff --git a/tests/ui/duration_subsec.fixed b/tests/ui/duration_subsec.fixed index d92b8998e88..bfd30f0042d 100644 --- a/tests/ui/duration_subsec.fixed +++ b/tests/ui/duration_subsec.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] diff --git a/tests/ui/duration_subsec.rs b/tests/ui/duration_subsec.rs index 08da804996d..860233f084f 100644 --- a/tests/ui/duration_subsec.rs +++ b/tests/ui/duration_subsec.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] diff --git a/tests/ui/empty_drop.fixed b/tests/ui/empty_drop.fixed index 2e1b768461a..fd0a9a7081e 100644 --- a/tests/ui/empty_drop.fixed +++ b/tests/ui/empty_drop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_drop)] #![allow(unused)] diff --git a/tests/ui/empty_drop.rs b/tests/ui/empty_drop.rs index 75232b0334d..6c15cb93302 100644 --- a/tests/ui/empty_drop.rs +++ b/tests/ui/empty_drop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_drop)] #![allow(unused)] diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 697412c0027..269e66ea0a8 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs index 6a8e6b550c1..54e8fb4907c 100644 --- a/tests/ui/empty_loop.rs +++ b/tests/ui/empty_loop.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::empty_loop)] diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index e742b396fcd..d564b2d24f5 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/empty_structs_with_brackets.fixed b/tests/ui/empty_structs_with_brackets.fixed index 80f07603b8d..6fab3020839 100644 --- a/tests/ui/empty_structs_with_brackets.fixed +++ b/tests/ui/empty_structs_with_brackets.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_structs_with_brackets)] #![allow(dead_code)] diff --git a/tests/ui/empty_structs_with_brackets.rs b/tests/ui/empty_structs_with_brackets.rs index 1d1ed4c7690..0caa3c49cd6 100644 --- a/tests/ui/empty_structs_with_brackets.rs +++ b/tests/ui/empty_structs_with_brackets.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_structs_with_brackets)] #![allow(dead_code)] diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index dbe09e0ff3c..7e82390605c 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -1,5 +1,5 @@ -// needs-asm-support -// run-rustfix +//@needs-asm-support +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 30fed34fc5d..742c9322535 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -1,5 +1,5 @@ -// needs-asm-support -// run-rustfix +//@needs-asm-support +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry_btree.fixed b/tests/ui/entry_btree.fixed index 94979104556..3baaacffd20 100644 --- a/tests/ui/entry_btree.fixed +++ b/tests/ui/entry_btree.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_entry)] #![allow(dead_code)] diff --git a/tests/ui/entry_btree.rs b/tests/ui/entry_btree.rs index 080c1d959e8..770e8e91da2 100644 --- a/tests/ui/entry_btree.rs +++ b/tests/ui/entry_btree.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_entry)] #![allow(dead_code)] diff --git a/tests/ui/entry_with_else.fixed b/tests/ui/entry_with_else.fixed index 2332fa6313f..71fe04fd648 100644 --- a/tests/ui/entry_with_else.fixed +++ b/tests/ui/entry_with_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry_with_else.rs b/tests/ui/entry_with_else.rs index 2ff0c038efe..80f74649a60 100644 --- a/tests/ui/entry_with_else.rs +++ b/tests/ui/entry_with_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/enum_clike_unportable_variant.rs b/tests/ui/enum_clike_unportable_variant.rs index 7d6842f5b54..f17556ea907 100644 --- a/tests/ui/enum_clike_unportable_variant.rs +++ b/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -// ignore-x86 +//@ignore-x86 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/tests/ui/enum_glob_use.fixed b/tests/ui/enum_glob_use.fixed index a98216758bb..419370ffb1d 100644 --- a/tests/ui/enum_glob_use.fixed +++ b/tests/ui/enum_glob_use.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::enum_glob_use)] #![allow(unused)] diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index 5d929c9731d..645ed98325c 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::enum_glob_use)] #![allow(unused)] diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index e7379550265..cdd33ebe582 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::eq_op)] #![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)] diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 007702ab550..53e62760bef 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 3bda7977645..55918a5bb11 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] diff --git a/tests/ui/err_expect.fixed b/tests/ui/err_expect.fixed index b63cbd8a8e6..6ade6f54689 100644 --- a/tests/ui/err_expect.fixed +++ b/tests/ui/err_expect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/err_expect.rs b/tests/ui/err_expect.rs index c081a745fb4..a93fb59493f 100644 --- a/tests/ui/err_expect.rs +++ b/tests/ui/err_expect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index dc129591eac..b1baf462c0f 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 025fd6a0b7a..e113c3d6cd6 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index b74bda182be..0a07957386c 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::excessive_precision)] #![allow(dead_code, unused_variables, clippy::print_literal)] diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index 6e84a71f24c..62a832caa67 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::excessive_precision)] #![allow(dead_code, unused_variables, clippy::print_literal)] diff --git a/tests/ui/exhaustive_items.fixed b/tests/ui/exhaustive_items.fixed index c209f5b4b72..6c7b1cab6f2 100644 --- a/tests/ui/exhaustive_items.fixed +++ b/tests/ui/exhaustive_items.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] diff --git a/tests/ui/exhaustive_items.rs b/tests/ui/exhaustive_items.rs index 6f59dbf2da5..d205bac2d2a 100644 --- a/tests/ui/exhaustive_items.rs +++ b/tests/ui/exhaustive_items.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 15172ae345c..8e97054fb6b 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::expect_fun_call)] #![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 0f448d00417..31e6bcc7ff6 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::expect_fun_call)] #![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 5d40c850424..71a5ed96d5c 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 79e03f4d76c..9d0cafa150f 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 6d32bbece1e..77e9f5fc1fd 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_deref_methods)] #![allow(unused_variables)] #![allow( diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index 779909e4238..0c2cc7c2c3a 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_deref_methods)] #![allow(unused_variables)] #![allow( diff --git a/tests/ui/explicit_write.fixed b/tests/ui/explicit_write.fixed index 862c3fea9ee..213485bc221 100644 --- a/tests/ui/explicit_write.fixed +++ b/tests/ui/explicit_write.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_write)] #![allow(unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index 41d7c225573..64acd7108bf 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_write)] #![allow(unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/extend_with_drain.fixed b/tests/ui/extend_with_drain.fixed index 71ebad24c16..594f2f6d413 100644 --- a/tests/ui/extend_with_drain.fixed +++ b/tests/ui/extend_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::extend_with_drain)] #![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; diff --git a/tests/ui/extend_with_drain.rs b/tests/ui/extend_with_drain.rs index e9f011abb0e..3e2ad02052d 100644 --- a/tests/ui/extend_with_drain.rs +++ b/tests/ui/extend_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::extend_with_drain)] #![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index d6631e01290..cdfaf8d3afe 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![allow( unused, diff --git a/tests/ui/extra_unused_type_parameters.fixed b/tests/ui/extra_unused_type_parameters.fixed index 19e71862558..adcd1f6d407 100644 --- a/tests/ui/extra_unused_type_parameters.fixed +++ b/tests/ui/extra_unused_type_parameters.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index e53bb587e89..c4c5227ac91 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 0e208b3ed0e..2045b1eebcd 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// aux-build:proc_macros.rs +//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed index a5860aa49b3..44665b451ad 100644 --- a/tests/ui/filter_map_identity.fixed +++ b/tests/ui/filter_map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs index 7e998b9cdf7..9832acb013f 100644 --- a/tests/ui/filter_map_identity.rs +++ b/tests/ui/filter_map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] diff --git a/tests/ui/filter_map_next_fixable.fixed b/tests/ui/filter_map_next_fixable.fixed index 462d46169fc..efb37f8b1b7 100644 --- a/tests/ui/filter_map_next_fixable.fixed +++ b/tests/ui/filter_map_next_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(unused)] diff --git a/tests/ui/filter_map_next_fixable.rs b/tests/ui/filter_map_next_fixable.rs index 2ea00cf7307..b10e20d359e 100644 --- a/tests/ui/filter_map_next_fixable.rs +++ b/tests/ui/filter_map_next_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(unused)] diff --git a/tests/ui/flat_map_identity.fixed b/tests/ui/flat_map_identity.fixed index 1f4b880ef5b..97091d6f1a5 100644 --- a/tests/ui/flat_map_identity.fixed +++ b/tests/ui/flat_map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] diff --git a/tests/ui/flat_map_identity.rs b/tests/ui/flat_map_identity.rs index de14a06d4e6..5607683a5d0 100644 --- a/tests/ui/flat_map_identity.rs +++ b/tests/ui/flat_map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] diff --git a/tests/ui/flat_map_option.fixed b/tests/ui/flat_map_option.fixed index 6a34f008995..eeab864c42f 100644 --- a/tests/ui/flat_map_option.fixed +++ b/tests/ui/flat_map_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::flat_map_option)] #![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] diff --git a/tests/ui/flat_map_option.rs b/tests/ui/flat_map_option.rs index 2479abddbf0..ebc389f7f02 100644 --- a/tests/ui/flat_map_option.rs +++ b/tests/ui/flat_map_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::flat_map_option)] #![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] diff --git a/tests/ui/floating_point_abs.fixed b/tests/ui/floating_point_abs.fixed index ca747fefc64..0cc572822e7 100644 --- a/tests/ui/floating_point_abs.fixed +++ b/tests/ui/floating_point_abs.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_abs.rs b/tests/ui/floating_point_abs.rs index e4b60657497..6c732d398f0 100644 --- a/tests/ui/floating_point_abs.rs +++ b/tests/ui/floating_point_abs.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed index b9e3d89c2b2..1a33b8153ec 100644 --- a/tests/ui/floating_point_exp.fixed +++ b/tests/ui/floating_point_exp.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index ef008dd9be0..4f4a5ec81ac 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_hypot.fixed b/tests/ui/floating_point_hypot.fixed index bbe411b3f48..431cb270978 100644 --- a/tests/ui/floating_point_hypot.fixed +++ b/tests/ui/floating_point_hypot.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] fn main() { diff --git a/tests/ui/floating_point_hypot.rs b/tests/ui/floating_point_hypot.rs index 586fd170ea1..e5506ed391c 100644 --- a/tests/ui/floating_point_hypot.rs +++ b/tests/ui/floating_point_hypot.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] fn main() { diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index ee540646160..6582c0a0f6c 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 0590670a50b..854d269fff5 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] diff --git a/tests/ui/floating_point_logbase.fixed b/tests/ui/floating_point_logbase.fixed index 7347bf72cbe..0783ecee1ee 100644 --- a/tests/ui/floating_point_logbase.fixed +++ b/tests/ui/floating_point_logbase.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_logbase.rs b/tests/ui/floating_point_logbase.rs index ba5b8d40692..80fcfab6825 100644 --- a/tests/ui/floating_point_logbase.rs +++ b/tests/ui/floating_point_logbase.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_mul_add.fixed b/tests/ui/floating_point_mul_add.fixed index d3e536ba350..8848981a11d 100644 --- a/tests/ui/floating_point_mul_add.fixed +++ b/tests/ui/floating_point_mul_add.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_mul_add.rs b/tests/ui/floating_point_mul_add.rs index 5d4a9e35cfc..b0edf5cb210 100644 --- a/tests/ui/floating_point_mul_add.rs +++ b/tests/ui/floating_point_mul_add.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index f7f93de2957..1e660b140c5 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 499fc0e15e4..71c2f529205 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed index 8ffd4cc5137..41d5288d6e0 100644 --- a/tests/ui/floating_point_powi.fixed +++ b/tests/ui/floating_point_powi.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs index 9ae3455a134..7951aab31be 100644 --- a/tests/ui/floating_point_powi.rs +++ b/tests/ui/floating_point_powi.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_rad.fixed b/tests/ui/floating_point_rad.fixed index 27674b8a455..af236452712 100644 --- a/tests/ui/floating_point_rad.fixed +++ b/tests/ui/floating_point_rad.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_rad.rs b/tests/ui/floating_point_rad.rs index f1ea73df398..d7612c56a3e 100644 --- a/tests/ui/floating_point_rad.rs +++ b/tests/ui/floating_point_rad.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/fn_to_numeric_cast.rs b/tests/ui/fn_to_numeric_cast.rs index a456c085c87..4f6af870889 100644 --- a/tests/ui/fn_to_numeric_cast.rs +++ b/tests/ui/fn_to_numeric_cast.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/tests/ui/fn_to_numeric_cast_32bit.rs b/tests/ui/fn_to_numeric_cast_32bit.rs index 04ee985c086..62ce97f098d 100644 --- a/tests/ui/fn_to_numeric_cast_32bit.rs +++ b/tests/ui/fn_to_numeric_cast_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/tests/ui/fn_to_numeric_cast_32bit.stderr b/tests/ui/fn_to_numeric_cast_32bit.stderr index 08dd611d675..671347d2bcd 100644 --- a/tests/ui/fn_to_numeric_cast_32bit.stderr +++ b/tests/ui/fn_to_numeric_cast_32bit.stderr @@ -12,19 +12,19 @@ error: casting function pointer `foo` to `i16`, which truncates the value LL | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` -error: casting function pointer `foo` to `i32` +error: casting function pointer `foo` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:12:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` - | - = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i64` --> $DIR/fn_to_numeric_cast_32bit.rs:13:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` + | + = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i128` --> $DIR/fn_to_numeric_cast_32bit.rs:14:13 @@ -50,7 +50,7 @@ error: casting function pointer `foo` to `u16`, which truncates the value LL | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` -error: casting function pointer `foo` to `u32` +error: casting function pointer `foo` to `u32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:19:13 | LL | let _ = foo as u32; @@ -80,7 +80,7 @@ error: casting function pointer `abc` to `i16`, which truncates the value LL | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `abc` to `i32` +error: casting function pointer `abc` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:36:13 | LL | let _ = abc as i32; @@ -116,7 +116,7 @@ error: casting function pointer `abc` to `u16`, which truncates the value LL | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `abc` to `u32` +error: casting function pointer `abc` to `u32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:43:13 | LL | let _ = abc as u32; @@ -134,7 +134,7 @@ error: casting function pointer `abc` to `u128` LL | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `f` to `i32` +error: casting function pointer `f` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:52:5 | LL | f as i32 diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index e9dd38fe40e..f578c98da15 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 534fb4dd4ef..42bc6de0c7d 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index beedf2c1db2..9288956f513 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/format.rs b/tests/ui/format.rs index e805f181889..b2b817e0f4c 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 825e122be5a..ea383686135 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::to_string_in_format_args)] #![allow(unused)] #![allow( diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index a41e53389e5..bfb32449246 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::to_string_in_format_args)] #![allow(unused)] #![allow( diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 48f8093311c..915ff4fb079 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index ebe0ad278be..e926f8c529d 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed index 72d635c2ccd..fc6d937060d 100644 --- a/tests/ui/from_over_into.fixed +++ b/tests/ui/from_over_into.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs index 965f4d5d785..fe1ebee35f1 100644 --- a/tests/ui/from_over_into.rs +++ b/tests/ui/from_over_into.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index def58afa4fb..ef132b79611 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_first)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index 85a381854cd..4d872235614 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_first)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/get_last_with_len.fixed b/tests/ui/get_last_with_len.fixed index 1e90b37687a..a58dfda7988 100644 --- a/tests/ui/get_last_with_len.fixed +++ b/tests/ui/get_last_with_len.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_last_with_len)] #![allow(unused)] diff --git a/tests/ui/get_last_with_len.rs b/tests/ui/get_last_with_len.rs index d63a731bd52..d626656c78f 100644 --- a/tests/ui/get_last_with_len.rs +++ b/tests/ui/get_last_with_len.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_last_with_len)] #![allow(unused)] diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 5827fc7d76e..4950c47ddeb 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] #![warn(clippy::unwrap_used)] diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index a2a323c14fb..6b1e8edb7bd 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] #![warn(clippy::unwrap_used)] diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index cac69ef42c4..beb16000eca 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::identity_op)] #![allow(unused)] #![allow( diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index 33201aad4f6..072e00c00f0 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::identity_op)] #![allow(unused)] #![allow( diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed index 8ccc3da7b47..e62db8b40be 100644 --- a/tests/ui/implicit_clone.fixed +++ b/tests/ui/implicit_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::implicit_clone)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index 59333312607..88352b06af3 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::implicit_clone)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index 35d08a07bc3..ca7c1221372 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed index 5e55b8b6739..64813eafda6 100644 --- a/tests/ui/implicit_return.fixed +++ b/tests/ui/implicit_return.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 76f0a980352..39d47b110db 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] diff --git a/tests/ui/implicit_saturating_add.fixed b/tests/ui/implicit_saturating_add.fixed index 7d363d59a6f..7fc510d6b41 100644 --- a/tests/ui/implicit_saturating_add.fixed +++ b/tests/ui/implicit_saturating_add.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::implicit_saturating_add)] diff --git a/tests/ui/implicit_saturating_add.rs b/tests/ui/implicit_saturating_add.rs index 31a5916277f..3dcd91f42fe 100644 --- a/tests/ui/implicit_saturating_add.rs +++ b/tests/ui/implicit_saturating_add.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::implicit_saturating_add)] diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 93df81b1a7f..1a11db0982f 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)] #![warn(clippy::implicit_saturating_sub)] diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 8340bc8264d..9369df67430 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)] #![warn(clippy::implicit_saturating_sub)] diff --git a/tests/ui/inconsistent_digit_grouping.fixed b/tests/ui/inconsistent_digit_grouping.fixed index dd683e7f746..06919809ee9 100644 --- a/tests/ui/inconsistent_digit_grouping.fixed +++ b/tests/ui/inconsistent_digit_grouping.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::inconsistent_digit_grouping)] #[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index d5d27c853c2..04d9125f2bf 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::inconsistent_digit_grouping)] #[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 5aaa00f8517..620d45e6828 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index 2b2dd7f59a4..10ffadcb2ba 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/tests/ui/inefficient_to_string.fixed b/tests/ui/inefficient_to_string.fixed index c972b9419ef..557f7fb7358 100644 --- a/tests/ui/inefficient_to_string.fixed +++ b/tests/ui/inefficient_to_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; diff --git a/tests/ui/inefficient_to_string.rs b/tests/ui/inefficient_to_string.rs index acdc55aa0d6..6503001e345 100644 --- a/tests/ui/inefficient_to_string.rs +++ b/tests/ui/inefficient_to_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; diff --git a/tests/ui/infallible_destructuring_match.fixed b/tests/ui/infallible_destructuring_match.fixed index 61985e56b76..e396ae94aaa 100644 --- a/tests/ui/infallible_destructuring_match.fixed +++ b/tests/ui/infallible_destructuring_match.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/tests/ui/infallible_destructuring_match.rs b/tests/ui/infallible_destructuring_match.rs index f2768245bbc..3fce7bbb6c7 100644 --- a/tests/ui/infallible_destructuring_match.rs +++ b/tests/ui/infallible_destructuring_match.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/tests/ui/inline_fn_without_body.fixed b/tests/ui/inline_fn_without_body.fixed index fe21a71a42c..9c5819558fe 100644 --- a/tests/ui/inline_fn_without_body.fixed +++ b/tests/ui/inline_fn_without_body.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/tests/ui/inline_fn_without_body.rs b/tests/ui/inline_fn_without_body.rs index 50746989466..43ffaf8122b 100644 --- a/tests/ui/inline_fn_without_body.rs +++ b/tests/ui/inline_fn_without_body.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/tests/ui/int_plus_one.fixed b/tests/ui/int_plus_one.fixed index 642830f24f5..5a36ec462d4 100644 --- a/tests/ui/int_plus_one.fixed +++ b/tests/ui/int_plus_one.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index 0755a0c79d2..bffa4afd6b0 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index d253d103127..ab9b6094c2c 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index b77f17944d8..9f550acb157 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 3854bb05af8..3381ae04dce 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] diff --git a/tests/ui/invalid_null_ptr_usage.fixed b/tests/ui/invalid_null_ptr_usage.fixed index 4f5322ebf20..9264fb7e9e7 100644 --- a/tests/ui/invalid_null_ptr_usage.fixed +++ b/tests/ui/invalid_null_ptr_usage.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { unsafe { diff --git a/tests/ui/invalid_null_ptr_usage.rs b/tests/ui/invalid_null_ptr_usage.rs index ae51c52d8af..80c942d7757 100644 --- a/tests/ui/invalid_null_ptr_usage.rs +++ b/tests/ui/invalid_null_ptr_usage.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { unsafe { diff --git a/tests/ui/is_digit_ascii_radix.fixed b/tests/ui/is_digit_ascii_radix.fixed index c0ba647d707..bc43303a680 100644 --- a/tests/ui/is_digit_ascii_radix.fixed +++ b/tests/ui/is_digit_ascii_radix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::is_digit_ascii_radix)] diff --git a/tests/ui/is_digit_ascii_radix.rs b/tests/ui/is_digit_ascii_radix.rs index 68e3f3243d9..93cba5c8e4e 100644 --- a/tests/ui/is_digit_ascii_radix.rs +++ b/tests/ui/is_digit_ascii_radix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::is_digit_ascii_radix)] diff --git a/tests/ui/issue_2356.fixed b/tests/ui/issue_2356.fixed index a73ee0fb2e5..a69f5ebdc08 100644 --- a/tests/ui/issue_2356.fixed +++ b/tests/ui/issue_2356.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index 9dd9069609b..50e1bce1f8c 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 9b862133580..88f08bb991b 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index 639f50665f2..d3438b7f51a 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed index 90a6eef7526..4367a12f820 100644 --- a/tests/ui/iter_count.fixed +++ b/tests/ui/iter_count.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_count)] #![allow( diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs index 6681a480a28..8c7543cf03b 100644 --- a/tests/ui/iter_count.rs +++ b/tests/ui/iter_count.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_count)] #![allow( diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index f2a4c284cb1..64201b553fd 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_kv_map)] #![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index ad6564df408..ec0231ba572 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_kv_map)] #![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed index f612d26aaab..d862abc34e0 100644 --- a/tests/ui/iter_next_slice.fixed +++ b/tests/ui/iter_next_slice.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_next_slice)] fn main() { diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs index 5195f1c8667..da6fc46e428 100644 --- a/tests/ui/iter_next_slice.rs +++ b/tests/ui/iter_next_slice.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_next_slice)] fn main() { diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs index 9c21dd82ee4..e7fb97d4fbc 100644 --- a/tests/ui/iter_nth.rs +++ b/tests/ui/iter_nth.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::iter_nth)] diff --git a/tests/ui/iter_nth_zero.fixed b/tests/ui/iter_nth_zero.fixed index f23671c26e4..587b0d1d366 100644 --- a/tests/ui/iter_nth_zero.fixed +++ b/tests/ui/iter_nth_zero.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_nth_zero)] use std::collections::HashSet; diff --git a/tests/ui/iter_nth_zero.rs b/tests/ui/iter_nth_zero.rs index 7c968d49845..93b576ec56f 100644 --- a/tests/ui/iter_nth_zero.rs +++ b/tests/ui/iter_nth_zero.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_nth_zero)] use std::collections::HashSet; diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed index bd9b07aefbf..4616f0cdc45 100644 --- a/tests/ui/iter_on_empty_collections.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs index e15ba94bd46..81cc7265e11 100644 --- a/tests/ui/iter_on_empty_collections.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_on_single_items.fixed b/tests/ui/iter_on_single_items.fixed index 1fa4b03641b..80dbe454b47 100644 --- a/tests/ui/iter_on_single_items.fixed +++ b/tests/ui/iter_on_single_items.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_on_single_items.rs b/tests/ui/iter_on_single_items.rs index ea96d8066c5..71c8c7a3f94 100644 --- a/tests/ui/iter_on_single_items.rs +++ b/tests/ui/iter_on_single_items.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index c100705d017..bf576e9cbfb 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] #![allow(dead_code, clippy::let_unit_value)] diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 2caa8802066..df42d88eff0 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] #![allow(dead_code, clippy::let_unit_value)] diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index d56d623b526..8f2cefc4304 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 3ec5d1b8214..71d83384f3a 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/iter_with_drain.fixed b/tests/ui/iter_with_drain.fixed index 0330d554926..24a95c4d0fe 100644 --- a/tests/ui/iter_with_drain.fixed +++ b/tests/ui/iter_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing diff --git a/tests/ui/iter_with_drain.rs b/tests/ui/iter_with_drain.rs index 993936fb8de..a118c981ee3 100644 --- a/tests/ui/iter_with_drain.rs +++ b/tests/ui/iter_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing diff --git a/tests/ui/large_const_arrays.fixed b/tests/ui/large_const_arrays.fixed index c5af07c8a17..f7ce6fbe6bb 100644 --- a/tests/ui/large_const_arrays.fixed +++ b/tests/ui/large_const_arrays.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_const_arrays)] #![allow(dead_code)] diff --git a/tests/ui/large_const_arrays.rs b/tests/ui/large_const_arrays.rs index a160b9f8ad5..002ac77ddda 100644 --- a/tests/ui/large_const_arrays.rs +++ b/tests/ui/large_const_arrays.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_const_arrays)] #![allow(dead_code)] diff --git a/tests/ui/large_digit_groups.fixed b/tests/ui/large_digit_groups.fixed index ea18dac0683..f42fcd96d79 100644 --- a/tests/ui/large_digit_groups.fixed +++ b/tests/ui/large_digit_groups.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_digit_groups)] fn main() { diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index ac116d5dbda..3db9da6a3a5 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_digit_groups)] fn main() { diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index f09f8ae0ccc..ea8bc5b4aca 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/large_types_passed_by_value.rs b/tests/ui/large_types_passed_by_value.rs index 7601b5c66fa..f9e3c7192ad 100644 --- a/tests/ui/large_types_passed_by_value.rs +++ b/tests/ui/large_types_passed_by_value.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![warn(clippy::large_types_passed_by_value)] diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index c1c0b5ae40f..34b2021df45 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(dead_code, unused, clippy::len_without_is_empty)] diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index cc2eb05b6bf..c83ae2ac553 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(dead_code, unused, clippy::len_without_is_empty)] diff --git a/tests/ui/len_zero_ranges.fixed b/tests/ui/len_zero_ranges.fixed index 79781766242..4b1241ec86b 100644 --- a/tests/ui/len_zero_ranges.fixed +++ b/tests/ui/len_zero_ranges.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(unused)] diff --git a/tests/ui/len_zero_ranges.rs b/tests/ui/len_zero_ranges.rs index a0eb51cc976..4b47132c766 100644 --- a/tests/ui/len_zero_ranges.rs +++ b/tests/ui/len_zero_ranges.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(unused)] diff --git a/tests/ui/let_unit.fixed b/tests/ui/let_unit.fixed index 76ff0645f41..8ba89ec78bb 100644 --- a/tests/ui/let_unit.fixed +++ b/tests/ui/let_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::let_unit_value)] diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index 895ccfe366a..7e8764a482a 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::let_unit_value)] diff --git a/tests/ui/lines_filter_map_ok.fixed b/tests/ui/lines_filter_map_ok.fixed index f4033cd8ed8..64114f6585d 100644 --- a/tests/ui/lines_filter_map_ok.fixed +++ b/tests/ui/lines_filter_map_ok.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::map_identity)] #![warn(clippy::lines_filter_map_ok)] diff --git a/tests/ui/lines_filter_map_ok.rs b/tests/ui/lines_filter_map_ok.rs index 7e11816b2ac..5aedc686336 100644 --- a/tests/ui/lines_filter_map_ok.rs +++ b/tests/ui/lines_filter_map_ok.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::map_identity)] #![warn(clippy::lines_filter_map_ok)] diff --git a/tests/ui/lossy_float_literal.fixed b/tests/ui/lossy_float_literal.fixed index 24e372354fc..a2088575610 100644 --- a/tests/ui/lossy_float_literal.fixed +++ b/tests/ui/lossy_float_literal.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::lossy_float_literal)] fn main() { diff --git a/tests/ui/lossy_float_literal.rs b/tests/ui/lossy_float_literal.rs index 3dcf98fa0bd..1a75f214c85 100644 --- a/tests/ui/lossy_float_literal.rs +++ b/tests/ui/lossy_float_literal.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::lossy_float_literal)] fn main() { diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index 15f7a099a7d..9208fbcb783 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -1,8 +1,8 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// run-rustfix -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@run-rustfix +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index b1a28733294..925a2c61f8d 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -1,8 +1,8 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// run-rustfix -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@run-rustfix +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index 5aac5af26db..b9677851b92 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -1,7 +1,7 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 8c7e919bf62..ab9b375dc03 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 8c7e919bf62..ab9b375dc03 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index f037c5b8405..eac52d1b5de 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index 5cc4a43af7e..e458f0d254f 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index ba504b8a823..dd5ca1c9b5b 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/tests/ui/manual_bits.fixed b/tests/ui/manual_bits.fixed index e7f8cd878ca..037de0262e2 100644 --- a/tests/ui/manual_bits.fixed +++ b/tests/ui/manual_bits.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_bits)] #![allow( diff --git a/tests/ui/manual_bits.rs b/tests/ui/manual_bits.rs index 7b1d1549528..b15a531ec17 100644 --- a/tests/ui/manual_bits.rs +++ b/tests/ui/manual_bits.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_bits)] #![allow( diff --git a/tests/ui/manual_filter.fixed b/tests/ui/manual_filter.fixed index ef6780dc96d..755caa664d5 100644 --- a/tests/ui/manual_filter.fixed +++ b/tests/ui/manual_filter.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_filter)] #![allow(unused_variables, dead_code)] diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs index ea0ce83172b..faccfe9db12 100644 --- a/tests/ui/manual_filter.rs +++ b/tests/ui/manual_filter.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_filter)] #![allow(unused_variables, dead_code)] diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index 4936dc9b2e0..831323089e7 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 8c67e827b4c..2692303d313 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_find_fixable.fixed b/tests/ui/manual_find_fixable.fixed index 2bce6e624c9..9c5eb20c81c 100644 --- a/tests/ui/manual_find_fixable.fixed +++ b/tests/ui/manual_find_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_find)] #![allow(unused)] #![allow(clippy::needless_return, clippy::uninlined_format_args)] diff --git a/tests/ui/manual_find_fixable.rs b/tests/ui/manual_find_fixable.rs index f5c6de37a25..7b670320ee3 100644 --- a/tests/ui/manual_find_fixable.rs +++ b/tests/ui/manual_find_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_find)] #![allow(unused)] #![allow(clippy::needless_return, clippy::uninlined_format_args)] diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index 54302beceff..554613a30a9 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index afcc1825a9a..d6245758f9d 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed index 85a91543c89..55073c3b57c 100644 --- a/tests/ui/manual_instant_elapsed.fixed +++ b/tests/ui/manual_instant_elapsed.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::unchecked_duration_subtraction)] diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs index c98cb15b916..c9029a04940 100644 --- a/tests/ui/manual_instant_elapsed.rs +++ b/tests/ui/manual_instant_elapsed.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::unchecked_duration_subtraction)] diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index 5b2b44c2fdb..87e86658668 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, dead_code)] #![warn(clippy::manual_is_ascii_check)] diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index c9433f33a1b..931f0f20276 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, dead_code)] #![warn(clippy::manual_is_ascii_check)] diff --git a/tests/ui/manual_main_separator_str.fixed b/tests/ui/manual_main_separator_str.fixed index 50f46d6b355..7e7da8f20bb 100644 --- a/tests/ui/manual_main_separator_str.fixed +++ b/tests/ui/manual_main_separator_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_main_separator_str)] diff --git a/tests/ui/manual_main_separator_str.rs b/tests/ui/manual_main_separator_str.rs index 2dbb9e66151..cf90e12efc3 100644 --- a/tests/ui/manual_main_separator_str.rs +++ b/tests/ui/manual_main_separator_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_main_separator_str)] diff --git a/tests/ui/manual_map_option.fixed b/tests/ui/manual_map_option.fixed index e12ea7ec145..e8ff65cad6a 100644 --- a/tests/ui/manual_map_option.fixed +++ b/tests/ui/manual_map_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow( diff --git a/tests/ui/manual_map_option.rs b/tests/ui/manual_map_option.rs index 325a6db06c4..b06a96451ce 100644 --- a/tests/ui/manual_map_option.rs +++ b/tests/ui/manual_map_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow( diff --git a/tests/ui/manual_map_option_2.fixed b/tests/ui/manual_map_option_2.fixed index ebf3f8cabd4..dc722878248 100644 --- a/tests/ui/manual_map_option_2.fixed +++ b/tests/ui/manual_map_option_2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow(clippy::toplevel_ref_arg)] diff --git a/tests/ui/manual_map_option_2.rs b/tests/ui/manual_map_option_2.rs index 1382d9af0aa..c495ab0fa6e 100644 --- a/tests/ui/manual_map_option_2.rs +++ b/tests/ui/manual_map_option_2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow(clippy::toplevel_ref_arg)] diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index fc8511626b3..d8901dc3b03 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_ok_or)] #![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index b5303d33f5f..7188a521357 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_ok_or)] #![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/manual_rem_euclid.fixed b/tests/ui/manual_rem_euclid.fixed index 1f6df1b0a86..f2e44e56f02 100644 --- a/tests/ui/manual_rem_euclid.fixed +++ b/tests/ui/manual_rem_euclid.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/tests/ui/manual_rem_euclid.rs b/tests/ui/manual_rem_euclid.rs index b275e8a38d2..b2329c33a47 100644 --- a/tests/ui/manual_rem_euclid.rs +++ b/tests/ui/manual_rem_euclid.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index 8f25fea678f..d3cac666763 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index e6b3995a689..34f0c4d5029 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index c4f53c446c9..7dd4521fa78 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports)] diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index cd83cf6e65e..463ee069289 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports)] diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 71368a25e22..ac85bd8d3ac 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused)] #![warn(clippy::manual_slice_size_calculation)] diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index 5dd14aaede0..1f824b12bc2 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused)] #![warn(clippy::manual_slice_size_calculation)] diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed index 50b02019cc2..e317c597109 100644 --- a/tests/ui/manual_split_once.fixed +++ b/tests/ui/manual_split_once.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index e1e8b71a9de..7e2dc22bc46 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] diff --git a/tests/ui/manual_str_repeat.fixed b/tests/ui/manual_str_repeat.fixed index 3d56f2a0ded..9468c3df904 100644 --- a/tests/ui/manual_str_repeat.fixed +++ b/tests/ui/manual_str_repeat.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_str_repeat)] diff --git a/tests/ui/manual_str_repeat.rs b/tests/ui/manual_str_repeat.rs index e8240a949db..baa0a10260d 100644 --- a/tests/ui/manual_str_repeat.rs +++ b/tests/ui/manual_str_repeat.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_str_repeat)] diff --git a/tests/ui/manual_string_new.fixed b/tests/ui/manual_string_new.fixed index a376411bfbc..0d1bab23304 100644 --- a/tests/ui/manual_string_new.fixed +++ b/tests/ui/manual_string_new.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_string_new)] diff --git a/tests/ui/manual_string_new.rs b/tests/ui/manual_string_new.rs index 6bfc52fb1bc..2392ebfc322 100644 --- a/tests/ui/manual_string_new.rs +++ b/tests/ui/manual_string_new.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_string_new)] diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 7d68978216c..c17634bffe3 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![allow(unused_variables, clippy::unnecessary_wraps)] diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index b937fe6f977..6d49a6949fa 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![allow(unused_variables, clippy::unnecessary_wraps)] diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 0860dcf8e0d..d7474f35719 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_clone)] #![allow( clippy::clone_on_copy, diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index b6987336834..74978ae8006 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_clone)] #![allow( clippy::clone_on_copy, diff --git a/tests/ui/map_collect_result_unit.fixed b/tests/ui/map_collect_result_unit.fixed index e66c9cc2420..b00c2cf284e 100644 --- a/tests/ui/map_collect_result_unit.fixed +++ b/tests/ui/map_collect_result_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_collect_result_unit)] fn main() { diff --git a/tests/ui/map_collect_result_unit.rs b/tests/ui/map_collect_result_unit.rs index 6f08f4c3c53..ad2198ec1fe 100644 --- a/tests/ui/map_collect_result_unit.rs +++ b/tests/ui/map_collect_result_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_collect_result_unit)] fn main() { diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed index 8e2f11389f8..14816de1a63 100644 --- a/tests/ui/map_flatten_fixable.fixed +++ b/tests/ui/map_flatten_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::let_underscore_untyped)] diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs index a783a99c4ff..f38a00a59fa 100644 --- a/tests/ui/map_flatten_fixable.rs +++ b/tests/ui/map_flatten_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::let_underscore_untyped)] diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed index 2256e51f2d0..7fb7d8c1218 100644 --- a/tests/ui/map_identity.fixed +++ b/tests/ui/map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_identity)] #![allow(clippy::needless_return)] diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs index ccfdc9ea76d..7891c242628 100644 --- a/tests/ui/map_identity.rs +++ b/tests/ui/map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_identity)] #![allow(clippy::needless_return)] diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 32631024ca5..cb25d8567aa 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_lazy_evaluations)] diff --git a/tests/ui/map_unwrap_or_fixable.fixed b/tests/ui/map_unwrap_or_fixable.fixed index bd5b4f7165a..ea5b6a6691e 100644 --- a/tests/ui/map_unwrap_or_fixable.fixed +++ b/tests/ui/map_unwrap_or_fixable.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] diff --git a/tests/ui/map_unwrap_or_fixable.rs b/tests/ui/map_unwrap_or_fixable.rs index 0b892caf20e..f8bb9d8ca6a 100644 --- a/tests/ui/map_unwrap_or_fixable.rs +++ b/tests/ui/map_unwrap_or_fixable.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index ddfa1e741ad..8fa3f532587 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::match_as_ref)] diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 025d475ae13..02a17791426 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::match_as_ref)] diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed index 55cd15bd5c3..7215660da67 100644 --- a/tests/ui/match_expr_like_matches_macro.fixed +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_like_matches_macro)] #![allow( diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs index 5d645e108e5..afdf1069f5e 100644 --- a/tests/ui/match_expr_like_matches_macro.rs +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_like_matches_macro)] #![allow( diff --git a/tests/ui/match_ref_pats.fixed b/tests/ui/match_ref_pats.fixed index cf37fc6dc90..50c3dcc1e0a 100644 --- a/tests/ui/match_ref_pats.fixed +++ b/tests/ui/match_ref_pats.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] #![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 3220b97d1b5..d29ddacc04a 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] #![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index 10ae1ee5245..fe67b225fa1 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_result_ok)] #![allow(dead_code)] #![allow(clippy::boxed_local, clippy::uninlined_format_args)] diff --git a/tests/ui/match_result_ok.rs b/tests/ui/match_result_ok.rs index bc2c4b50e27..eac382e1f62 100644 --- a/tests/ui/match_result_ok.rs +++ b/tests/ui/match_result_ok.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_result_ok)] #![allow(dead_code)] #![allow(clippy::boxed_local, clippy::uninlined_format_args)] diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 201301cc9b7..7c29bb08e64 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow( unused, diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index 8b047b19ce9..c068d5e17c3 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow( unused, diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index e3cf56a4293..adfb4ba91f7 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/match_single_binding2.rs b/tests/ui/match_single_binding2.rs index 5a4bb8441ff..b5cfe3654a5 100644 --- a/tests/ui/match_single_binding2.rs +++ b/tests/ui/match_single_binding2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/match_str_case_mismatch.fixed b/tests/ui/match_str_case_mismatch.fixed index e436bcf495f..cd53b1f06fa 100644 --- a/tests/ui/match_str_case_mismatch.fixed +++ b/tests/ui/match_str_case_mismatch.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_str_case_mismatch)] #![allow(dead_code)] diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs index 92e2a000ade..6885305662a 100644 --- a/tests/ui/match_str_case_mismatch.rs +++ b/tests/ui/match_str_case_mismatch.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_str_case_mismatch)] #![allow(dead_code)] diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed index 9fd3739b69c..d2e6fef0759 100644 --- a/tests/ui/match_wildcard_for_single_variants.fixed +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_wildcard_for_single_variants)] #![allow(dead_code)] diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs index 9a5c849e6ec..cff0c896065 100644 --- a/tests/ui/match_wildcard_for_single_variants.rs +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_wildcard_for_single_variants)] #![allow(dead_code)] diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed index 7fd340173af..d37e97b0a06 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn( diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index fa2903addbc..34e37f3dbbb 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn( diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs index 3932e7d00c1..132873858b7 100644 --- a/tests/ui/mem_replace_macro.rs +++ b/tests/ui/mem_replace_macro.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::mem_replace_with_default)] extern crate proc_macros; diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 1519e4da934..e0e2cac30a2 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::all, clippy::pedantic)] #![allow( diff --git a/tests/ui/methods_fixable.fixed b/tests/ui/methods_fixable.fixed index ee7c1b0da6d..dcbed5a4d99 100644 --- a/tests/ui/methods_fixable.fixed +++ b/tests/ui/methods_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::filter_next)] diff --git a/tests/ui/methods_fixable.rs b/tests/ui/methods_fixable.rs index 6d0f1b7bd51..3a976d23527 100644 --- a/tests/ui/methods_fixable.rs +++ b/tests/ui/methods_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::filter_next)] diff --git a/tests/ui/mismatched_target_os_non_unix.fixed b/tests/ui/mismatched_target_os_non_unix.fixed index f219a570e7f..f58e9a429b6 100644 --- a/tests/ui/mismatched_target_os_non_unix.fixed +++ b/tests/ui/mismatched_target_os_non_unix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/mismatched_target_os_non_unix.rs b/tests/ui/mismatched_target_os_non_unix.rs index 8a8ae756a4f..e00224f5ceb 100644 --- a/tests/ui/mismatched_target_os_non_unix.rs +++ b/tests/ui/mismatched_target_os_non_unix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/mismatched_target_os_unix.fixed b/tests/ui/mismatched_target_os_unix.fixed index 7d9d406d99d..330587a3c4c 100644 --- a/tests/ui/mismatched_target_os_unix.fixed +++ b/tests/ui/mismatched_target_os_unix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/mismatched_target_os_unix.rs b/tests/ui/mismatched_target_os_unix.rs index c1177f1eedc..5a90019a2e4 100644 --- a/tests/ui/mismatched_target_os_unix.rs +++ b/tests/ui/mismatched_target_os_unix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index e6f88c6e622..5db73a7b8ea 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -2,8 +2,8 @@ //! compilation error. //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. -// aux-build:helper.rs -// aux-build:../../auxiliary/proc_macros.rs +//@aux-build:helper.rs +//@aux-build:../../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index 5752048949c..bf587e774f7 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ -// needs-asm-support -// aux-build: proc_macros.rs +//@needs-asm-support +//@aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs index e2d49b0907d..520ddbe16b8 100644 --- a/tests/ui/missing_doc_impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] diff --git a/tests/ui/missing_spin_loop.fixed b/tests/ui/missing_spin_loop.fixed index aa89e04d26e..a15298dc37b 100644 --- a/tests/ui/missing_spin_loop.fixed +++ b/tests/ui/missing_spin_loop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![allow(clippy::bool_comparison)] #![allow(unused_braces)] diff --git a/tests/ui/missing_spin_loop.rs b/tests/ui/missing_spin_loop.rs index 88745e47732..be74581ecd0 100644 --- a/tests/ui/missing_spin_loop.rs +++ b/tests/ui/missing_spin_loop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![allow(clippy::bool_comparison)] #![allow(unused_braces)] diff --git a/tests/ui/missing_spin_loop_no_std.fixed b/tests/ui/missing_spin_loop_no_std.fixed index bb4b4795516..960e5c05fb6 100644 --- a/tests/ui/missing_spin_loop_no_std.fixed +++ b/tests/ui/missing_spin_loop_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/missing_spin_loop_no_std.rs b/tests/ui/missing_spin_loop_no_std.rs index a19bc72baf8..e532ca62dc5 100644 --- a/tests/ui/missing_spin_loop_no_std.rs +++ b/tests/ui/missing_spin_loop_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index 9a47d7c56ed..62cfeafdc49 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![allow( dead_code, diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index 04261cba55a..f83b7c3dbda 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![allow( dead_code, diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index ebaa77cc283..fb2c7612343 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 9082f1675a8..73ef35c8c36 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index bbbb3cf621e..0c275504d36 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(never_type)] #![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 94d3c83bdb9..d1c9267732f 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(never_type)] #![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index b7d375ff80e..4f7cf4e56d1 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -1,5 +1,5 @@ -//run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index 74d6b4ca865..3a814ce1685 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -1,5 +1,5 @@ -//run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 06bb085442a..d838098de11 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index ecad10a8290..433817a4e03 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index f2b1d6fbfbc..567a0b59e70 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] diff --git a/tests/ui/needless_arbitrary_self_type.fixed b/tests/ui/needless_arbitrary_self_type.fixed index 9da21eb6b29..d7eb1a047ed 100644 --- a/tests/ui/needless_arbitrary_self_type.fixed +++ b/tests/ui/needless_arbitrary_self_type.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] diff --git a/tests/ui/needless_arbitrary_self_type.rs b/tests/ui/needless_arbitrary_self_type.rs index 17aeaaf97ac..85a2a957f29 100644 --- a/tests/ui/needless_arbitrary_self_type.rs +++ b/tests/ui/needless_arbitrary_self_type.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.rs b/tests/ui/needless_arbitrary_self_type_unfixable.rs index 02b43cce2bd..00871f9f450 100644 --- a/tests/ui/needless_arbitrary_self_type_unfixable.rs +++ b/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs #![warn(clippy::needless_arbitrary_self_type)] diff --git a/tests/ui/needless_bitwise_bool.fixed b/tests/ui/needless_bitwise_bool.fixed index 5e1ea663a10..7543ab72ca2 100644 --- a/tests/ui/needless_bitwise_bool.fixed +++ b/tests/ui/needless_bitwise_bool.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bitwise_bool)] diff --git a/tests/ui/needless_bitwise_bool.rs b/tests/ui/needless_bitwise_bool.rs index f3075fba0a2..2cea701dce6 100644 --- a/tests/ui/needless_bitwise_bool.rs +++ b/tests/ui/needless_bitwise_bool.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bitwise_bool)] diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 89dc13fd5b1..f860852e7b7 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bool)] #![allow( diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index c11d9472e8d..6680dab5b6d 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bool)] #![allow( diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 4cb7f6b687f..425e6eb6200 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![allow( unused, diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 9a01190ed8d..3f7fa4a9d7d 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![allow( unused, diff --git a/tests/ui/needless_borrowed_ref.fixed b/tests/ui/needless_borrowed_ref.fixed index 0c47ceb7b67..6663520da8a 100644 --- a/tests/ui/needless_borrowed_ref.fixed +++ b/tests/ui/needless_borrowed_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_borrowed_reference)] #![allow( diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index f883bb0c889..6c8efd2ce18 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_borrowed_reference)] #![allow( diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index 2659ad38488..024c22de225 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::suspicious_map, clippy::iter_count)] diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 535ec82982b..7ed7babec30 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::suspicious_map, clippy::iter_count)] diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index 09e671b88e1..a04f9ec651e 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_for_each)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index abb4045b919..4975c705081 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_for_each)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 86d899bb46c..92f7b3f777a 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 969afb38edf..be378c42f95 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index e6ead69d148..7b99042f744 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 06eb430506f..6fcf1efc2ee 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed index 7e47406798c..d8a0400a4f0 100644 --- a/tests/ui/needless_match.fixed +++ b/tests/ui/needless_match.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_match)] #![allow(clippy::manual_map)] #![allow(dead_code)] diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs index 809c694bf40..3de9bd6d7a1 100644 --- a/tests/ui/needless_match.rs +++ b/tests/ui/needless_match.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_match)] #![allow(clippy::manual_map)] #![allow(dead_code)] diff --git a/tests/ui/needless_option_as_deref.fixed b/tests/ui/needless_option_as_deref.fixed index acd22c6bb43..70015fccf9e 100644 --- a/tests/ui/needless_option_as_deref.fixed +++ b/tests/ui/needless_option_as_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::needless_option_as_deref)] diff --git a/tests/ui/needless_option_as_deref.rs b/tests/ui/needless_option_as_deref.rs index 61eda5052a2..e2e35360cb3 100644 --- a/tests/ui/needless_option_as_deref.rs +++ b/tests/ui/needless_option_as_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::needless_option_as_deref)] diff --git a/tests/ui/needless_option_take.fixed b/tests/ui/needless_option_take.fixed index 29691e81666..bfc6d20d5a3 100644 --- a/tests/ui/needless_option_take.fixed +++ b/tests/ui/needless_option_take.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { println!("Testing non erroneous option_take_on_temporary"); diff --git a/tests/ui/needless_option_take.rs b/tests/ui/needless_option_take.rs index 9f4109eb463..697eeab4207 100644 --- a/tests/ui/needless_option_take.rs +++ b/tests/ui/needless_option_take.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { println!("Testing non erroneous option_take_on_temporary"); diff --git a/tests/ui/needless_parens_on_range_literals.fixed b/tests/ui/needless_parens_on_range_literals.fixed index f11330a8916..9b98f6ea7f7 100644 --- a/tests/ui/needless_parens_on_range_literals.fixed +++ b/tests/ui/needless_parens_on_range_literals.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_parens_on_range_literals)] #![allow(clippy::almost_complete_range)] diff --git a/tests/ui/needless_parens_on_range_literals.rs b/tests/ui/needless_parens_on_range_literals.rs index 671c0009e23..088e7b2b98f 100644 --- a/tests/ui/needless_parens_on_range_literals.rs +++ b/tests/ui/needless_parens_on_range_literals.rs @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_parens_on_range_literals)] #![allow(clippy::almost_complete_range)] diff --git a/tests/ui/needless_question_mark.fixed b/tests/ui/needless_question_mark.fixed index 7eaca571992..679b73d404a 100644 --- a/tests/ui/needless_question_mark.fixed +++ b/tests/ui/needless_question_mark.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_question_mark)] #![allow( diff --git a/tests/ui/needless_question_mark.rs b/tests/ui/needless_question_mark.rs index 960bc7b7898..a993d3ec35d 100644 --- a/tests/ui/needless_question_mark.rs +++ b/tests/ui/needless_question_mark.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_question_mark)] #![allow( diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 57c08996ce2..ee4e5007dc5 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(yeet_expr)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 7c1feefbe32..cd999db4f40 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(yeet_expr)] diff --git a/tests/ui/needless_splitn.fixed b/tests/ui/needless_splitn.fixed index 5496031fefa..30a038312c8 100644 --- a/tests/ui/needless_splitn.fixed +++ b/tests/ui/needless_splitn.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_splitn)] #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] diff --git a/tests/ui/needless_splitn.rs b/tests/ui/needless_splitn.rs index 35c2465bae1..1b0b9a5981a 100644 --- a/tests/ui/needless_splitn.rs +++ b/tests/ui/needless_splitn.rs @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_splitn)] #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] diff --git a/tests/ui/neg_multiply.fixed b/tests/ui/neg_multiply.fixed index 58ab9e85678..e07e7c88d68 100644 --- a/tests/ui/neg_multiply.fixed +++ b/tests/ui/neg_multiply.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] #![allow(unused)] diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index 581290dc72e..2887af7b421 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] #![allow(unused)] diff --git a/tests/ui/non_octal_unix_permissions.fixed b/tests/ui/non_octal_unix_permissions.fixed index a9b2dcfb085..89d12752834 100644 --- a/tests/ui/non_octal_unix_permissions.fixed +++ b/tests/ui/non_octal_unix_permissions.fixed @@ -1,5 +1,5 @@ -// ignore-windows -// run-rustfix +//@ignore-windows +//@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; diff --git a/tests/ui/non_octal_unix_permissions.rs b/tests/ui/non_octal_unix_permissions.rs index 7d2922f494e..1b3a322d726 100644 --- a/tests/ui/non_octal_unix_permissions.rs +++ b/tests/ui/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ -// ignore-windows -// run-rustfix +//@ignore-windows +//@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index aad44089de4..05802a2c865 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index b9074da8427..cd5b576fa07 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/numbered_fields.fixed index 68c987eb4c6..a52845e53a4 100644 --- a/tests/ui/numbered_fields.fixed +++ b/tests/ui/numbered_fields.fixed @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::init_numbered_fields)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/numbered_fields.rs b/tests/ui/numbered_fields.rs index 2ef4fb4de53..ca93f7dce59 100644 --- a/tests/ui/numbered_fields.rs +++ b/tests/ui/numbered_fields.rs @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::init_numbered_fields)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed index 62d932c2c6b..9e4f97253f8 100644 --- a/tests/ui/obfuscated_if_else.fixed +++ b/tests/ui/obfuscated_if_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::obfuscated_if_else)] diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs index 273be9092a7..c2351d64c1c 100644 --- a/tests/ui/obfuscated_if_else.rs +++ b/tests/ui/obfuscated_if_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::obfuscated_if_else)] diff --git a/tests/ui/option_as_ref_deref.fixed b/tests/ui/option_as_ref_deref.fixed index d124d133faa..e1c0fa3f7fd 100644 --- a/tests/ui/option_as_ref_deref.fixed +++ b/tests/ui/option_as_ref_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone)] #![warn(clippy::option_as_ref_deref)] diff --git a/tests/ui/option_as_ref_deref.rs b/tests/ui/option_as_ref_deref.rs index 86e354c6716..6f4917fd149 100644 --- a/tests/ui/option_as_ref_deref.rs +++ b/tests/ui/option_as_ref_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone)] #![warn(clippy::option_as_ref_deref)] diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs index 9a56cf40d8a..ee1fe3f1fc0 100644 --- a/tests/ui/option_env_unwrap.rs +++ b/tests/ui/option_env_unwrap.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_filter_map.fixed b/tests/ui/option_filter_map.fixed index b20f73f3110..93c250cfa73 100644 --- a/tests/ui/option_filter_map.fixed +++ b/tests/ui/option_filter_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_filter_map)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_filter_map.rs b/tests/ui/option_filter_map.rs index 7abaaa0fb83..2c5f03250b9 100644 --- a/tests/ui/option_filter_map.rs +++ b/tests/ui/option_filter_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_filter_map)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 0456005dce4..f7d2cf2c7d8 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 23b148752cb..1534572f6a2 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index 04bfac7735f..501757647bf 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/option_map_or_none.rs b/tests/ui/option_map_or_none.rs index bb84f8a48f4..4d8704e737d 100644 --- a/tests/ui/option_map_or_none.rs +++ b/tests/ui/option_map_or_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 00264dcceaa..8f64451edf3 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index f3363ebce54..2bf7a8e0f7d 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index be9a65506e1..f723a55f77f 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] #![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 628c9704638..61ef6e27f32 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] #![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/or_then_unwrap.fixed b/tests/ui/or_then_unwrap.fixed index 844cc4b7a09..40badac4424 100644 --- a/tests/ui/or_then_unwrap.fixed +++ b/tests/ui/or_then_unwrap.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity, clippy::let_unit_value)] diff --git a/tests/ui/or_then_unwrap.rs b/tests/ui/or_then_unwrap.rs index 1528ef9be96..76c9942fe6c 100644 --- a/tests/ui/or_then_unwrap.rs +++ b/tests/ui/or_then_unwrap.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity, clippy::let_unit_value)] diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed index 4644ea8f51d..81a716bd276 100644 --- a/tests/ui/partialeq_to_none.fixed +++ b/tests/ui/partialeq_to_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::partialeq_to_none)] struct Foobar; diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs index 61011b3a8c5..f454715fa30 100644 --- a/tests/ui/partialeq_to_none.rs +++ b/tests/ui/partialeq_to_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::partialeq_to_none)] struct Foobar; diff --git a/tests/ui/path_buf_push_overwrite.fixed b/tests/ui/path_buf_push_overwrite.fixed index ef8856830fc..393fc6e1c69 100644 --- a/tests/ui/path_buf_push_overwrite.fixed +++ b/tests/ui/path_buf_push_overwrite.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::path::PathBuf; #[warn(clippy::all, clippy::path_buf_push_overwrite)] diff --git a/tests/ui/path_buf_push_overwrite.rs b/tests/ui/path_buf_push_overwrite.rs index 6e2d483f454..18de6e06412 100644 --- a/tests/ui/path_buf_push_overwrite.rs +++ b/tests/ui/path_buf_push_overwrite.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::path::PathBuf; #[warn(clippy::all, clippy::path_buf_push_overwrite)] diff --git a/tests/ui/patterns.fixed b/tests/ui/patterns.fixed index cd69014326e..a1da47d84fd 100644 --- a/tests/ui/patterns.fixed +++ b/tests/ui/patterns.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 9128da420c0..399066b813e 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed index 163bd044c17..af4d5636b61 100644 --- a/tests/ui/precedence.fixed +++ b/tests/ui/precedence.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::precedence)] #![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)] #![allow(clippy::identity_op)] diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 8c849e3209b..e23ae912786 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::precedence)] #![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)] #![allow(clippy::identity_op)] diff --git a/tests/ui/print_stdout_build_script.rs b/tests/ui/print_stdout_build_script.rs index 997ebef8a69..91448cb0faf 100644 --- a/tests/ui/print_stdout_build_script.rs +++ b/tests/ui/print_stdout_build_script.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=build_script_build +//@compile-flags: --crate-name=build_script_build #![warn(clippy::print_stdout)] diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index b8c29d207ad..ff79ca75ffa 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![allow(clippy::print_literal)] #![warn(clippy::print_with_newline)] diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 9760680927a..abf951ae22d 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::match_single_binding)] fn main() { diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 80fdb3e6e21..fd86e2543cc 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::match_single_binding)] fn main() { diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index ee7b998a0b2..2c2567d67cd 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index c88329ce4ec..6000e5c08ac 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_eq.fixed b/tests/ui/ptr_eq.fixed index 209081e6e80..d5fa273d41f 100644 --- a/tests/ui/ptr_eq.fixed +++ b/tests/ui/ptr_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::ptr_eq)] macro_rules! mac { diff --git a/tests/ui/ptr_eq.rs b/tests/ui/ptr_eq.rs index 69162870807..e033366a4aa 100644 --- a/tests/ui/ptr_eq.rs +++ b/tests/ui/ptr_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::ptr_eq)] macro_rules! mac { diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index c57e2990fb9..f69bc131898 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_cast)] fn main() { diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index 3de7997acdd..eae36c27729 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_cast)] fn main() { diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 5c49d46da72..7f1660f31fa 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index d057df6a9b3..a90eae50ed4 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed index 4923731fe45..0a92ee7c8dd 100644 --- a/tests/ui/range_contains.fixed +++ b/tests/ui/range_contains.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_range_contains)] #![allow(unused)] diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs index d623ccb5da6..7a83be60957 100644 --- a/tests/ui/range_contains.rs +++ b/tests/ui/range_contains.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_range_contains)] #![allow(unused)] diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index a16a3e54d45..79c133cb5e3 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index bd6cb4d21be..689a6b7a17c 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] diff --git a/tests/ui/rc_buffer.fixed b/tests/ui/rc_buffer.fixed index 8910c01b1fc..4cba292c1b7 100644 --- a/tests/ui/rc_buffer.fixed +++ b/tests/ui/rc_buffer.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs index 1e63a43262e..d8a9aa2786d 100644 --- a/tests/ui/rc_buffer.rs +++ b/tests/ui/rc_buffer.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/rc_buffer_arc.fixed b/tests/ui/rc_buffer_arc.fixed index 13dd6f5fcd1..ac51ac9e467 100644 --- a/tests/ui/rc_buffer_arc.fixed +++ b/tests/ui/rc_buffer_arc.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs index 1a521bfeb7c..21dc27bc5fa 100644 --- a/tests/ui/rc_buffer_arc.rs +++ b/tests/ui/rc_buffer_arc.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index 6db02718c70..edb7715f42c 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::disallowed_names, unused_variables, dead_code)] diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index c15806f30c0..c59422dd966 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::disallowed_names, unused_variables, dead_code)] diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed index ad96993c4a7..328958491ee 100644 --- a/tests/ui/redundant_async_block.fixed +++ b/tests/ui/redundant_async_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs index 7ae23558369..cd189b31555 100644 --- a/tests/ui/redundant_async_block.rs +++ b/tests/ui/redundant_async_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 00b42745093..8bebb5183bc 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] #![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index f899127db8d..b4bd5d16b1a 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] #![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index b987fd2ce6f..61aed2733fe 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index 633a2979d5d..56b28663539 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] diff --git a/tests/ui/redundant_field_names.fixed b/tests/ui/redundant_field_names.fixed index 276266a2dd8..d2a65399da6 100644 --- a/tests/ui/redundant_field_names.fixed +++ b/tests/ui/redundant_field_names.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_field_names)] #![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index f674141c138..605ffd21e2f 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_field_names)] #![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] diff --git a/tests/ui/redundant_pattern_matching_drop_order.fixed b/tests/ui/redundant_pattern_matching_drop_order.fixed index ce3229f1759..bebdf89716f 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Issue #5746 #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_drop_order.rs b/tests/ui/redundant_pattern_matching_drop_order.rs index 29b8543cf47..8fb6ed5f7ec 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/tests/ui/redundant_pattern_matching_drop_order.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Issue #5746 #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed index 21bae909555..a9faf12cd5a 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::redundant_pattern_matching)] #![allow(unused_must_use)] #![allow( diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs index 4dd9171677e..574671d03d1 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::redundant_pattern_matching)] #![allow(unused_must_use)] #![allow( diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index a89845c1dd3..87100b97288 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index d6f44403487..0b69e13f655 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index 3645f2c4bfd..bf3e692202c 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index 866c71b7cfa..892a21d9d29 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 42348df4480..c48d1522935 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow(deprecated, unused_must_use)] diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index 5949cb2271c..26f37d169fa 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow(deprecated, unused_must_use)] diff --git a/tests/ui/redundant_pub_crate.fixed b/tests/ui/redundant_pub_crate.fixed index 106947de68c..f65c0fdd35d 100644 --- a/tests/ui/redundant_pub_crate.fixed +++ b/tests/ui/redundant_pub_crate.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] diff --git a/tests/ui/redundant_pub_crate.rs b/tests/ui/redundant_pub_crate.rs index f96cfd31843..fb07fed98be 100644 --- a/tests/ui/redundant_pub_crate.rs +++ b/tests/ui/redundant_pub_crate.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] diff --git a/tests/ui/redundant_slicing.fixed b/tests/ui/redundant_slicing.fixed index 8dd8d309237..56ddca71903 100644 --- a/tests/ui/redundant_slicing.fixed +++ b/tests/ui/redundant_slicing.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] diff --git a/tests/ui/redundant_slicing.rs b/tests/ui/redundant_slicing.rs index 51c16dd8d65..d67b6665e26 100644 --- a/tests/ui/redundant_slicing.rs +++ b/tests/ui/redundant_slicing.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] diff --git a/tests/ui/redundant_static_lifetimes.fixed b/tests/ui/redundant_static_lifetimes.fixed index bca777a890c..2651735d103 100644 --- a/tests/ui/redundant_static_lifetimes.fixed +++ b/tests/ui/redundant_static_lifetimes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/redundant_static_lifetimes.rs b/tests/ui/redundant_static_lifetimes.rs index afe7644816d..7286652899d 100644 --- a/tests/ui/redundant_static_lifetimes.rs +++ b/tests/ui/redundant_static_lifetimes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 5076f61334d..e8a00a9e7f7 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -// run-rustfix +//@run-rustfix #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 64bc1ca7116..c8ea70c2bcb 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -// run-rustfix +//@run-rustfix #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/renamed_builtin_attr.fixed b/tests/ui/renamed_builtin_attr.fixed index cb91b841d2c..0334c1e1a29 100644 --- a/tests/ui/renamed_builtin_attr.fixed +++ b/tests/ui/renamed_builtin_attr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[clippy::cognitive_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs index b3ce2758067..d350370c244 100644 --- a/tests/ui/renamed_builtin_attr.rs +++ b/tests/ui/renamed_builtin_attr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[clippy::cyclomatic_complexity = "1"] fn main() {} diff --git a/tests/ui/repeat_once.fixed b/tests/ui/repeat_once.fixed index dc197e50300..c517bfcc6aa 100644 --- a/tests/ui/repeat_once.fixed +++ b/tests/ui/repeat_once.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::repeat_once)] #[allow(unused, clippy::redundant_clone)] fn main() { diff --git a/tests/ui/repeat_once.rs b/tests/ui/repeat_once.rs index 0ec5127117c..9a30b47418f 100644 --- a/tests/ui/repeat_once.rs +++ b/tests/ui/repeat_once.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::repeat_once)] #[allow(unused, clippy::redundant_clone)] fn main() { diff --git a/tests/ui/result_map_or_into_option.fixed b/tests/ui/result_map_or_into_option.fixed index 331531b5165..119ff25918a 100644 --- a/tests/ui/result_map_or_into_option.fixed +++ b/tests/ui/result_map_or_into_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_or_into_option)] diff --git a/tests/ui/result_map_or_into_option.rs b/tests/ui/result_map_or_into_option.rs index 3058480e2ad..eeeef830af0 100644 --- a/tests/ui/result_map_or_into_option.rs +++ b/tests/ui/result_map_or_into_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_or_into_option)] diff --git a/tests/ui/result_map_unit_fn_fixable.fixed b/tests/ui/result_map_unit_fn_fixable.fixed index d8b56237e98..0583d29277b 100644 --- a/tests/ui/result_map_unit_fn_fixable.fixed +++ b/tests/ui/result_map_unit_fn_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/result_map_unit_fn_fixable.rs b/tests/ui/result_map_unit_fn_fixable.rs index 44f50d21109..7ad3bdd04bd 100644 --- a/tests/ui/result_map_unit_fn_fixable.rs +++ b/tests/ui/result_map_unit_fn_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_fixable.fixed b/tests/ui/reversed_empty_ranges_fixable.fixed index c67edb36c67..30dfc977681 100644 --- a/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_fixable.rs b/tests/ui/reversed_empty_ranges_fixable.rs index 0a4fef5bfe8..1837249eae1 100644 --- a/tests/ui/reversed_empty_ranges_fixable.rs +++ b/tests/ui/reversed_empty_ranges_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/tests/ui/reversed_empty_ranges_loops_fixable.fixed index 78401e463d5..a74569599c7 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.rs b/tests/ui/reversed_empty_ranges_loops_fixable.rs index f9e0f7fcd6d..42f9957dfbd 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.rs +++ b/tests/ui/reversed_empty_ranges_loops_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index e6198a1bc9a..aea1507cc5b 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -1,5 +1,5 @@ #![feature(adt_const_params)] -#![warn(clippy::same_functions_in_if_condition)] +#![deny(clippy::same_functions_in_if_condition)] // ifs_same_cond warning is different from `ifs_same_cond`. // clippy::if_same_then_else, clippy::comparison_chain -- all empty blocks #![allow(incomplete_features)] diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index f352ade150e..aade3b1fa45 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -9,7 +9,11 @@ note: same as this | LL | if function() { | ^^^^^^^^^^ - = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/same_functions_in_if_condition.rs:2:9 + | +LL | #![deny(clippy::same_functions_in_if_condition)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:42:15 diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index 72f335153c1..670599b0dcf 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] #![allow(dead_code)] extern crate option_helpers; diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 5190c5304c7..9386618c123 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 310d87333a9..6b2537a96c2 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 385a9986aba..e9116fc59f1 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index 67e190ee378..b1528399457 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/seek_from_current.fixed b/tests/ui/seek_from_current.fixed index 1309c91b81c..34c33baf686 100644 --- a/tests/ui/seek_from_current.fixed +++ b/tests/ui/seek_from_current.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::seek_from_current)] use std::fs::File; diff --git a/tests/ui/seek_from_current.rs b/tests/ui/seek_from_current.rs index 5d9b1424cf6..22bcff1bc40 100644 --- a/tests/ui/seek_from_current.rs +++ b/tests/ui/seek_from_current.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::seek_from_current)] use std::fs::File; diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed index dc24d447c60..d8a6e6985d4 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::seek_to_start_instead_of_rewind)] diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs index 4adde2c4018..fc6a6433c2b 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::seek_to_start_instead_of_rewind)] diff --git a/tests/ui/semicolon_inside_block.fixed b/tests/ui/semicolon_inside_block.fixed index 42e97e1ca35..ee359f60cbd 100644 --- a/tests/ui/semicolon_inside_block.fixed +++ b/tests/ui/semicolon_inside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/semicolon_inside_block.rs b/tests/ui/semicolon_inside_block.rs index f40848f702e..e8516f79b20 100644 --- a/tests/ui/semicolon_inside_block.rs +++ b/tests/ui/semicolon_inside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/semicolon_outside_block.fixed b/tests/ui/semicolon_outside_block.fixed index 091eaa7518e..034c7f8c7c1 100644 --- a/tests/ui/semicolon_outside_block.fixed +++ b/tests/ui/semicolon_outside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/semicolon_outside_block.rs b/tests/ui/semicolon_outside_block.rs index 7ce46431fac..4dc956d8a4b 100644 --- a/tests/ui/semicolon_outside_block.rs +++ b/tests/ui/semicolon_outside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index ab7800a2110..03337ec3564 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] #![allow(clippy::let_unit_value)] diff --git a/tests/ui/short_circuit_statement.fixed b/tests/ui/short_circuit_statement.fixed index dd22ecab0b5..1737d501441 100644 --- a/tests/ui/short_circuit_statement.fixed +++ b/tests/ui/short_circuit_statement.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::short_circuit_statement)] #![allow(clippy::nonminimal_bool)] diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index 73a55bf1f5e..ab93aa1ca5c 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::short_circuit_statement)] #![allow(clippy::nonminimal_bool)] diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index c65df9ece38..8c48b21f188 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![warn(clippy::significant_drop_in_scrutinee)] #![allow(dead_code, unused_assignments)] #![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index da998c610bd..ee7f2b0631a 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::significant_drop_tightening)] diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index 83823f95f68..9c139deb95f 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::significant_drop_tightening)] diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed index 63a6d37a9cc..cbcf1ab21c9 100644 --- a/tests/ui/single_char_add_str.fixed +++ b/tests/ui/single_char_add_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_char_add_str)] macro_rules! get_string { diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs index a799ea7d885..a1f005cc833 100644 --- a/tests/ui/single_char_add_str.rs +++ b/tests/ui/single_char_add_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_char_add_str)] macro_rules! get_string { diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 68e26726724..dba89872070 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 186202d78ec..6a145a14bfd 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index 8c96c4715d3..d4d2cbbe57a 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 8434bf7eaf1..80d72115f43 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index a0dcc0172e8..1697a0cf29b 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Tests from for_loop.rs that don't have suggestions #[warn(clippy::single_element_loop)] diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs index bc014035c98..860424f42dd 100644 --- a/tests/ui/single_element_loop.rs +++ b/tests/ui/single_element_loop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Tests from for_loop.rs that don't have suggestions #[warn(clippy::single_element_loop)] diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 3c86f41f3a6..c8ac768b60f 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::single_match_else)] #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs index a551c19d98b..62574e2c8ce 100644 --- a/tests/ui/skip_while_next.rs +++ b/tests/ui/skip_while_next.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/stable_sort_primitive.fixed b/tests/ui/stable_sort_primitive.fixed index f5f18169df2..1370dd2df4d 100644 --- a/tests/ui/stable_sort_primitive.fixed +++ b/tests/ui/stable_sort_primitive.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::stable_sort_primitive)] fn main() { diff --git a/tests/ui/stable_sort_primitive.rs b/tests/ui/stable_sort_primitive.rs index 8149c5638e0..cd344dd1238 100644 --- a/tests/ui/stable_sort_primitive.rs +++ b/tests/ui/stable_sort_primitive.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::stable_sort_primitive)] fn main() { diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed index 983fac7afe6..29d56f852ed 100644 --- a/tests/ui/starts_ends_with.fixed +++ b/tests/ui/starts_ends_with.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_must_use)] fn main() {} diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index e3335dd2e2e..56bbe2574d4 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_must_use)] fn main() {} diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index 20edbe31fa9..de78dfe4d69 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs extern crate proc_macros; use proc_macros::external; diff --git a/tests/ui/string_add_assign.fixed b/tests/ui/string_add_assign.fixed index b687f43b254..616c6daaf66 100644 --- a/tests/ui/string_add_assign.fixed +++ b/tests/ui/string_add_assign.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::string_add, unused)] #[warn(clippy::string_add_assign)] diff --git a/tests/ui/string_add_assign.rs b/tests/ui/string_add_assign.rs index e5dbde108fb..e1f8859757c 100644 --- a/tests/ui/string_add_assign.rs +++ b/tests/ui/string_add_assign.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::string_add, unused)] #[warn(clippy::string_add_assign)] diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed index d200d7310fc..65c9abff3d4 100644 --- a/tests/ui/string_extend.fixed +++ b/tests/ui/string_extend.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[derive(Copy, Clone)] struct HasChars; diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index 0dd96a3b210..5f72ffe2fda 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[derive(Copy, Clone)] struct HasChars; diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed index 6e665cdd563..9b315ae2b55 100644 --- a/tests/ui/string_from_utf8_as_bytes.fixed +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::string_from_utf8_as_bytes)] fn main() { diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs index 670d206d367..043dd235082 100644 --- a/tests/ui/string_from_utf8_as_bytes.rs +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::string_from_utf8_as_bytes)] fn main() { diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 506187fc125..058f2aa54da 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index 2c339f1ddb8..b550bea001f 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] diff --git a/tests/ui/strlen_on_c_strings.fixed b/tests/ui/strlen_on_c_strings.fixed index 947a59bcc02..ef207e28cca 100644 --- a/tests/ui/strlen_on_c_strings.fixed +++ b/tests/ui/strlen_on_c_strings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::strlen_on_c_strings)] #![allow(dead_code)] diff --git a/tests/ui/strlen_on_c_strings.rs b/tests/ui/strlen_on_c_strings.rs index 1237f1ab03a..03ec5f79d09 100644 --- a/tests/ui/strlen_on_c_strings.rs +++ b/tests/ui/strlen_on_c_strings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::strlen_on_c_strings)] #![allow(dead_code)] diff --git a/tests/ui/suspicious_doc_comments.fixed b/tests/ui/suspicious_doc_comments.fixed index b404df94d3c..bffda1cc412 100644 --- a/tests/ui/suspicious_doc_comments.fixed +++ b/tests/ui/suspicious_doc_comments.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::suspicious_doc_comments)] diff --git a/tests/ui/suspicious_doc_comments.rs b/tests/ui/suspicious_doc_comments.rs index 46eff51e220..cdd972ee30f 100644 --- a/tests/ui/suspicious_doc_comments.rs +++ b/tests/ui/suspicious_doc_comments.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::suspicious_doc_comments)] diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/suspicious_else_formatting.rs index 21753e5dc6a..e0153cdd8cd 100644 --- a/tests/ui/suspicious_else_formatting.rs +++ b/tests/ui/suspicious_else_formatting.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_suspicious_else_formatting.rs +//@aux-build:proc_macro_suspicious_else_formatting.rs #![warn(clippy::suspicious_else_formatting)] #![allow(clippy::if_same_then_else, clippy::let_unit_value)] diff --git a/tests/ui/suspicious_operation_groupings.fixed b/tests/ui/suspicious_operation_groupings.fixed index ede8a39fed7..0e37701ec48 100644 --- a/tests/ui/suspicious_operation_groupings.fixed +++ b/tests/ui/suspicious_operation_groupings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/tests/ui/suspicious_operation_groupings.rs b/tests/ui/suspicious_operation_groupings.rs index 26ce97bb37f..dd4f3b71c37 100644 --- a/tests/ui/suspicious_operation_groupings.rs +++ b/tests/ui/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 9703674d1a4..fd3569cf362 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: macro_rules.rs +//@run-rustfix +//@aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index a0228065e46..34fbce0524b 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: macro_rules.rs +//@run-rustfix +//@aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( diff --git a/tests/ui/swap_ptr_to_ref.fixed b/tests/ui/swap_ptr_to_ref.fixed index 596b6ee919b..3bede3017a1 100644 --- a/tests/ui/swap_ptr_to_ref.fixed +++ b/tests/ui/swap_ptr_to_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::swap_ptr_to_ref)] diff --git a/tests/ui/swap_ptr_to_ref.rs b/tests/ui/swap_ptr_to_ref.rs index 282f571211d..726b09d3764 100644 --- a/tests/ui/swap_ptr_to_ref.rs +++ b/tests/ui/swap_ptr_to_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::swap_ptr_to_ref)] diff --git a/tests/ui/tabs_in_doc_comments.fixed b/tests/ui/tabs_in_doc_comments.fixed index 4bc4bc86c76..21020182c24 100644 --- a/tests/ui/tabs_in_doc_comments.fixed +++ b/tests/ui/tabs_in_doc_comments.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::tabs_in_doc_comments)] #[allow(dead_code)] diff --git a/tests/ui/tabs_in_doc_comments.rs b/tests/ui/tabs_in_doc_comments.rs index 9db3416e659..df704267dd2 100644 --- a/tests/ui/tabs_in_doc_comments.rs +++ b/tests/ui/tabs_in_doc_comments.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::tabs_in_doc_comments)] #[allow(dead_code)] diff --git a/tests/ui/tests_outside_test_module.rs b/tests/ui/tests_outside_test_module.rs index 1982b1d0107..21fdfdf9005 100644 --- a/tests/ui/tests_outside_test_module.rs +++ b/tests/ui/tests_outside_test_module.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![allow(unused)] #![warn(clippy::tests_outside_test_module)] diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed index 3c5e9642714..dc9be66d48a 100644 --- a/tests/ui/to_digit_is_some.fixed +++ b/tests/ui/to_digit_is_some.fixed @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::to_digit_is_some)] diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs index 4f247c06cee..d2a09ac30de 100644 --- a/tests/ui/to_digit_is_some.rs +++ b/tests/ui/to_digit_is_some.rs @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::to_digit_is_some)] diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index 174c858a47d..ea30c1fda6f 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 4b81a06112f..7a3d33e5be5 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs index 2047593e7e4..8aaf47b1bd0 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] diff --git a/tests/ui/track-diagnostics.rs b/tests/ui/track-diagnostics.rs index fa9221ed02d..6ab0bce770e 100644 --- a/tests/ui/track-diagnostics.rs +++ b/tests/ui/track-diagnostics.rs @@ -1,9 +1,8 @@ -// compile-flags: -Z track-diagnostics -// error-pattern: created at +//@compile-flags: -Z track-diagnostics // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. -// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC" +//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" struct A; struct B; diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index 4ce5d421782..eef8024b131 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index 7f2e96a22e6..a7a1caf2880 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index ffe22b12f55..8e1316ca39d 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_32bit.stderr b/tests/ui/transmute_32bit.stderr index 040519564b9..75ddca60d2a 100644 --- a/tests/ui/transmute_32bit.stderr +++ b/tests/ui/transmute_32bit.stderr @@ -1,28 +1,39 @@ -error: transmute from a `f32` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:6:31 | LL | let _: *const usize = std::mem::transmute(6.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::wrong-transmute` implied by `-D warnings` + = note: source type: `f32` (32 bits) + = note: target type: `*const usize` (64 bits) -error: transmute from a `f32` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:8:29 | LL | let _: *mut usize = std::mem::transmute(6.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `f32` (32 bits) + = note: target type: `*mut usize` (64 bits) -error: transmute from a `char` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:10:31 | LL | let _: *const usize = std::mem::transmute('x'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `char` (32 bits) + = note: target type: `*const usize` (64 bits) -error: transmute from a `char` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:12:29 | LL | let _: *mut usize = std::mem::transmute('x'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `char` (32 bits) + = note: target type: `*mut usize` (64 bits) error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 00dc0b2c360..ceecf9b279f 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed index 074dae5fb28..575dadde906 100644 --- a/tests/ui/transmute_ptr_to_ref.fixed +++ b/tests/ui/transmute_ptr_to_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs index 2edc122cf47..4238ff80478 100644 --- a/tests/ui/transmute_ptr_to_ref.rs +++ b/tests/ui/transmute_ptr_to_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index cc84ba25bd0..05aa86c479a 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmutes_expressible_as_ptr_casts)] // These two warnings currently cover the cases transmutes_expressible_as_ptr_casts // would otherwise be responsible for diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index aa65ab4dd24..29fa6914cfd 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmutes_expressible_as_ptr_casts)] // These two warnings currently cover the cases transmutes_expressible_as_ptr_casts // would otherwise be responsible for diff --git a/tests/ui/trim_split_whitespace.fixed b/tests/ui/trim_split_whitespace.fixed index e4d352f7367..7909b319ddd 100644 --- a/tests/ui/trim_split_whitespace.fixed +++ b/tests/ui/trim_split_whitespace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::trim_split_whitespace)] #![allow(clippy::let_unit_value)] diff --git a/tests/ui/trim_split_whitespace.rs b/tests/ui/trim_split_whitespace.rs index f98451a9837..0cf58979fb2 100644 --- a/tests/ui/trim_split_whitespace.rs +++ b/tests/ui/trim_split_whitespace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::trim_split_whitespace)] #![allow(clippy::let_unit_value)] diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index c0af011d33d..48615583156 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] #![allow( clippy::disallowed_names, diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index dc497b1690f..dc773ad4bad 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 86aeb75cd96..7a7433a7ec2 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed index 417da42edf1..4a2616a7a22 100644 --- a/tests/ui/types.fixed +++ b/tests/ui/types.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/types.rs b/tests/ui/types.rs index b16e9e538b1..5e0917907db 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/unchecked_duration_subtraction.fixed b/tests/ui/unchecked_duration_subtraction.fixed index a0e49a8beb1..757d1592184 100644 --- a/tests/ui/unchecked_duration_subtraction.fixed +++ b/tests/ui/unchecked_duration_subtraction.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/tests/ui/unchecked_duration_subtraction.rs b/tests/ui/unchecked_duration_subtraction.rs index a14a7ea57cc..da7faab6753 100644 --- a/tests/ui/unchecked_duration_subtraction.rs +++ b/tests/ui/unchecked_duration_subtraction.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/tests/ui/undocumented_unsafe_blocks.rs b/tests/ui/undocumented_unsafe_blocks.rs index c05eb447b2e..229d150851a 100644 --- a/tests/ui/undocumented_unsafe_blocks.rs +++ b/tests/ui/undocumented_unsafe_blocks.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_unsafe.rs +//@aux-build:proc_macro_unsafe.rs #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] #![allow(clippy::let_unit_value, clippy::missing_safety_doc)] diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed index 94b4723452f..910968afa7f 100644 --- a/tests/ui/unicode.fixed +++ b/tests/ui/unicode.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// compile-flags: --test +//@run-rustfix +//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 6ad0b255b94..bc4b84d3435 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,5 +1,5 @@ -// run-rustfix -// compile-flags: --test +//@run-rustfix +//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 3122081a44f..e25d123dd51 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,5 +1,5 @@ -// aux-build:proc_macros.rs -// run-rustfix +//@aux-build:proc_macros.rs +//@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index b153ef256e0..6793ec24441 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macros.rs -// run-rustfix +//@aux-build:proc_macros.rs +//@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed index 52b5343c351..559050b3df6 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed index ee72065e28a..3a753b49caf 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs index b4a0a0f496e..83fbb9afd2a 100644 --- a/tests/ui/uninlined_format_args_panic.rs +++ b/tests/ui/uninlined_format_args_panic.rs @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 674ae4f1df9..d082063c8e8 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( diff --git a/tests/ui/unit_arg_empty_blocks.fixed b/tests/ui/unit_arg_empty_blocks.fixed index 5787471a32c..8c065115a74 100644 --- a/tests/ui/unit_arg_empty_blocks.fixed +++ b/tests/ui/unit_arg_empty_blocks.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow(clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs index 6a42c2ccf42..af166b56ff4 100644 --- a/tests/ui/unit_arg_empty_blocks.rs +++ b/tests/ui/unit_arg_empty_blocks.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow(clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/unknown_clippy_lints.fixed b/tests/ui/unknown_clippy_lints.fixed index 4249ff8a958..0c269d650c8 100644 --- a/tests/ui/unknown_clippy_lints.fixed +++ b/tests/ui/unknown_clippy_lints.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::pedantic)] // Should suggest lowercase diff --git a/tests/ui/unknown_clippy_lints.rs b/tests/ui/unknown_clippy_lints.rs index 5db345f5444..b60042923ea 100644 --- a/tests/ui/unknown_clippy_lints.rs +++ b/tests/ui/unknown_clippy_lints.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::pedantic)] // Should suggest lowercase diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 2f7e2997e73..bcc231ea7bc 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_cast)] #![allow( unused_must_use, diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 54dd46ba59f..282b2f1283e 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_cast)] #![allow( unused_must_use, diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index 52300a3b640..2bed14973ca 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 4028d80c0a3..a3cec8ea3d5 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed index e01e9f07baf..a0f8dd1a200 100644 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index 6ef2966c8b7..98f2dfe7549 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_join.fixed b/tests/ui/unnecessary_join.fixed index 34795396025..e102df62599 100644 --- a/tests/ui/unnecessary_join.fixed +++ b/tests/ui/unnecessary_join.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_join)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/unnecessary_join.rs b/tests/ui/unnecessary_join.rs index 344918cd2a2..b87c15bc126 100644 --- a/tests/ui/unnecessary_join.rs +++ b/tests/ui/unnecessary_join.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_join)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 3b93800f8b7..c3728886ec9 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 2851c0c5190..76e50fa5b03 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index b046694f8c6..fbd2d34591f 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::deref_addrof, diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 9ed9679e938..b45298a6dc4 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::deref_addrof, diff --git a/tests/ui/unnecessary_owned_empty_strings.fixed b/tests/ui/unnecessary_owned_empty_strings.fixed index 40052c41039..af12fd1d63d 100644 --- a/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/tests/ui/unnecessary_owned_empty_strings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_owned_empty_strings)] diff --git a/tests/ui/unnecessary_owned_empty_strings.rs b/tests/ui/unnecessary_owned_empty_strings.rs index 2304dff5192..a460b21af8c 100644 --- a/tests/ui/unnecessary_owned_empty_strings.rs +++ b/tests/ui/unnecessary_owned_empty_strings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_owned_empty_strings)] diff --git a/tests/ui/unnecessary_self_imports.fixed b/tests/ui/unnecessary_self_imports.fixed index 1185eaa1d55..7fc978d3ef7 100644 --- a/tests/ui/unnecessary_self_imports.fixed +++ b/tests/ui/unnecessary_self_imports.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_self_imports)] #![allow(unused_imports, dead_code)] diff --git a/tests/ui/unnecessary_self_imports.rs b/tests/ui/unnecessary_self_imports.rs index 56bfbc09402..02424bc12b0 100644 --- a/tests/ui/unnecessary_self_imports.rs +++ b/tests/ui/unnecessary_self_imports.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_self_imports)] #![allow(unused_imports, dead_code)] diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 21e2da474a8..165cabd8298 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::stable_sort_primitive)] diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 3365bf6e119..8a2158d5a84 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::stable_sort_primitive)] diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed index b47129e4a36..bdf746cf2c4 100644 --- a/tests/ui/unnecessary_struct_initialization.fixed +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::unnecessary_struct_initialization)] diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs index 63b11c626e5..7271e2f957a 100644 --- a/tests/ui/unnecessary_struct_initialization.rs +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::unnecessary_struct_initialization)] diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 345f6d604c4..c879fdc3b6a 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7eb53df39e5..10588beb263 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_unsafety_doc.rs b/tests/ui/unnecessary_unsafety_doc.rs index 431093ab369..373b18470f6 100644 --- a/tests/ui/unnecessary_unsafety_doc.rs +++ b/tests/ui/unnecessary_unsafety_doc.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] diff --git a/tests/ui/unneeded_wildcard_pattern.fixed b/tests/ui/unneeded_wildcard_pattern.fixed index 12c3461c955..16c2de760e5 100644 --- a/tests/ui/unneeded_wildcard_pattern.fixed +++ b/tests/ui/unneeded_wildcard_pattern.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] diff --git a/tests/ui/unneeded_wildcard_pattern.rs b/tests/ui/unneeded_wildcard_pattern.rs index 4ac01d5d23b..9d9eae1d903 100644 --- a/tests/ui/unneeded_wildcard_pattern.rs +++ b/tests/ui/unneeded_wildcard_pattern.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] diff --git a/tests/ui/unnested_or_patterns.fixed b/tests/ui/unnested_or_patterns.fixed index 0a8e7b34dfa..8ec35ba4eea 100644 --- a/tests/ui/unnested_or_patterns.fixed +++ b/tests/ui/unnested_or_patterns.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unnested_or_patterns.rs b/tests/ui/unnested_or_patterns.rs index 2c454adfe89..efdb91b2402 100644 --- a/tests/ui/unnested_or_patterns.rs +++ b/tests/ui/unnested_or_patterns.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unnested_or_patterns2.fixed b/tests/ui/unnested_or_patterns2.fixed index d3539d79815..de40e936747 100644 --- a/tests/ui/unnested_or_patterns2.fixed +++ b/tests/ui/unnested_or_patterns2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unnested_or_patterns2.rs b/tests/ui/unnested_or_patterns2.rs index 9cea5cdea69..87f66d26c46 100644 --- a/tests/ui/unnested_or_patterns2.rs +++ b/tests/ui/unnested_or_patterns2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index 13e5feb1926..f5e87648a23 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unreadable_literal)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 82f04e7ced5..426bdf7d732 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unreadable_literal)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/unseparated_prefix_literals.fixed b/tests/ui/unseparated_prefix_literals.fixed index f0c2ba7ccdf..b6241612d9d 100644 --- a/tests/ui/unseparated_prefix_literals.fixed +++ b/tests/ui/unseparated_prefix_literals.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/tests/ui/unseparated_prefix_literals.rs b/tests/ui/unseparated_prefix_literals.rs index f44880b4147..ae583f4bde3 100644 --- a/tests/ui/unseparated_prefix_literals.rs +++ b/tests/ui/unseparated_prefix_literals.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/tests/ui/unused_rounding.fixed b/tests/ui/unused_rounding.fixed index f6f734c05ed..f02b55502a0 100644 --- a/tests/ui/unused_rounding.fixed +++ b/tests/ui/unused_rounding.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unused_rounding)] fn main() { diff --git a/tests/ui/unused_rounding.rs b/tests/ui/unused_rounding.rs index a0267d8144a..c7bd4906d0b 100644 --- a/tests/ui/unused_rounding.rs +++ b/tests/ui/unused_rounding.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unused_rounding)] fn main() { diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index 3dd640b86f0..7b8f7847dbf 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index bddecf06fb7..fdde1ecadf0 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 84f779569ff..59a0ca3f192 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index 1735bd5808e..97cafa336ed 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 3ac6217312a..89ea14759b7 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 9dc5d1e3f9b..49e5bcb7ed9 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/use_self_trait.fixed b/tests/ui/use_self_trait.fixed index 4e779308d02..4623aeeb0eb 100644 --- a/tests/ui/use_self_trait.fixed +++ b/tests/ui/use_self_trait.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::use_self)] #![allow(dead_code)] diff --git a/tests/ui/use_self_trait.rs b/tests/ui/use_self_trait.rs index 325dc73b21e..d7d76dd9623 100644 --- a/tests/ui/use_self_trait.rs +++ b/tests/ui/use_self_trait.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::use_self)] #![allow(dead_code)] diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 8c29e15b145..c672eff1c27 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![feature(rustc_private)] #![warn(clippy::all)] #![warn(clippy::used_underscore_binding)] diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 38e4b9201e6..490d36ae6d6 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_asref)] #![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index f1e83f9d396..f2681af924d 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_asref)] #![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index 871e4fb5c3a..de6660c95e6 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index cb50736ba39..8de4331e8a6 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 94b206d8e58..01eb6c5b080 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_conversion)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index c7ae927941b..34b43a6299b 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_conversion)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index 2518d804915..d77a4dd8e0b 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_vec)] #![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index e1492e2f3ae..dfed3a29a03 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_vec)] #![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] diff --git a/tests/ui/vec_box_sized.fixed b/tests/ui/vec_box_sized.fixed index a40d91fdb18..0d0f710b558 100644 --- a/tests/ui/vec_box_sized.fixed +++ b/tests/ui/vec_box_sized.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/vec_box_sized.rs b/tests/ui/vec_box_sized.rs index 843bbb64e71..fd3a7543ee1 100644 --- a/tests/ui/vec_box_sized.rs +++ b/tests/ui/vec_box_sized.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index 5afa0a89f82..c2f216a8911 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::while_let_on_iterator)] #![allow(dead_code, unreachable_code, unused_mut)] #![allow( diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 3de586c9d8f..971bd5f0c4a 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::while_let_on_iterator)] #![allow(dead_code, unreachable_code, unused_mut)] #![allow( diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index 293bf75a717..ccb40acfbe1 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:non-exhaustive-enum.rs +//@run-rustfix +//@aux-build:non-exhaustive-enum.rs #![deny(clippy::wildcard_enum_match_arm)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow( diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index decd86165f3..3ce00b021a5 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:non-exhaustive-enum.rs +//@run-rustfix +//@aux-build:non-exhaustive-enum.rs #![deny(clippy::wildcard_enum_match_arm)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow( diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 0baec6f0b64..bd845361fa8 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -1,6 +1,6 @@ -// edition:2015 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@edition:2015 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index db591d56ab4..fb51f7bdfcc 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -1,6 +1,6 @@ -// edition:2015 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@edition:2015 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index 6d534a10edc..3aea013fb3a 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index 6d534a10edc..3aea013fb3a 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index b5ed58e6813..40c2d07527d 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports_2021.stderr b/tests/ui/wildcard_imports_2021.stderr deleted file mode 100644 index 92f6d31530f..00000000000 --- a/tests/ui/wildcard_imports_2021.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:9:5 - | -LL | use crate::fn_mod::*; - | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` - | - = note: `-D clippy::wildcard-imports` implied by `-D warnings` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:10:5 - | -LL | use crate::mod_mod::*; - | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:11:5 - | -LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:12:5 - | -LL | use crate::struct_mod::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:15:5 - | -LL | use wildcard_imports_helper::inner::inner_for_self_import::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:17:5 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:87:13 - | -LL | use crate::fn_mod::*; - | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:93:75 - | -LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; - | ^ help: try: `inner_extern_foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:94:13 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:105:20 - | -LL | use self::{inner::*, inner2::*}; - | ^^^^^^^^ help: try: `inner::inner_foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:105:30 - | -LL | use self::{inner::*, inner2::*}; - | ^^^^^^^^^ help: try: `inner2::inner_bar` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:112:13 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:141:9 - | -LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:150:9 - | -LL | use crate:: in_fn_test:: * ; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:151:9 - | -LL | use crate:: fn_mod:: - | _________^ -LL | | *; - | |_________^ help: try: `crate:: fn_mod::foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:162:13 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:197:17 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::insidefoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:205:13 - | -LL | use crate::super_imports::*; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:214:17 - | -LL | use super::super::*; - | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:223:13 - | -LL | use super::super::super_imports::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:231:13 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::foofoo` - -error: aborting due to 21 previous errors - diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index b79364c8758..35bd9e7f3a0 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![allow(clippy::write_literal)] #![warn(clippy::write_with_newline)] @@ -54,7 +54,7 @@ fn main() { // Don't warn on CRLF (#4208) write!(v, "\r\n"); write!(v, "foo\r\n"); - write!(v, "\\r\n"); //~ ERROR + write!(v, "\\r\n"); write!(v, "foo\rbar\n"); // Ignore expanded format strings diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 2baaea166d8..9035275b29d 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -106,13 +106,13 @@ LL ~ v error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:57:5 | -LL | write!(v, "/r/n"); //~ ERROR +LL | write!(v, "/r/n"); | ^^^^^^^^^^^^^^^^^^ | help: use `writeln!` instead | -LL - write!(v, "/r/n"); //~ ERROR -LL + writeln!(v, "/r"); //~ ERROR +LL - write!(v, "/r/n"); +LL + writeln!(v, "/r"); | error: aborting due to 9 previous errors diff --git a/tests/ui/writeln_empty_string.fixed b/tests/ui/writeln_empty_string.fixed index e7d94acd130..45dedd9ead6 100644 --- a/tests/ui/writeln_empty_string.fixed +++ b/tests/ui/writeln_empty_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/tests/ui/writeln_empty_string.rs b/tests/ui/writeln_empty_string.rs index 662c62f0211..3b9f51a15d2 100644 --- a/tests/ui/writeln_empty_string.rs +++ b/tests/ui/writeln_empty_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/tests/ui/zero_ptr.fixed b/tests/ui/zero_ptr.fixed index 489aa4121a3..bed38ecafc7 100644 --- a/tests/ui/zero_ptr.fixed +++ b/tests/ui/zero_ptr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs index c3b55ef9ebd..b7b778915a8 100644 --- a/tests/ui/zero_ptr.rs +++ b/tests/ui/zero_ptr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { diff --git a/tests/ui/zero_ptr_no_std.fixed b/tests/ui/zero_ptr_no_std.fixed index 8906c776977..7afd80ccaca 100644 --- a/tests/ui/zero_ptr_no_std.fixed +++ b/tests/ui/zero_ptr_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/zero_ptr_no_std.rs b/tests/ui/zero_ptr_no_std.rs index 379c1b18d29..05a0587d22b 100644 --- a/tests/ui/zero_ptr_no_std.rs +++ b/tests/ui/zero_ptr_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lang_items, start, libc)] #![no_std] -- cgit 1.4.1-3-g733a5 From a8834bc46ab948c8978b5fcbe0a7aa4760783338 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Thu, 4 May 2023 22:44:35 +0200 Subject: add lint `manual_next_back` checks for manual reverse iteration (`.rev().next()`) of a `DoubleEndedIterator` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/manual_next_back.rs | 38 ++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 26 +++++++++++++++++++ tests/ui/manual_next_back.fixed | 36 ++++++++++++++++++++++++++ tests/ui/manual_next_back.rs | 36 ++++++++++++++++++++++++++ tests/ui/manual_next_back.stderr | 16 ++++++++++++ 7 files changed, 154 insertions(+) create mode 100644 clippy_lints/src/methods/manual_next_back.rs create mode 100644 tests/ui/manual_next_back.fixed create mode 100644 tests/ui/manual_next_back.rs create mode 100644 tests/ui/manual_next_back.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 85d451a87d0..4cb937e8766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4785,6 +4785,7 @@ Released 2018-09-13 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 6614b99713a..982d5a802f5 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -351,6 +351,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_WITH_DRAIN_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, diff --git a/clippy_lints/src/methods/manual_next_back.rs b/clippy_lints/src/methods/manual_next_back.rs new file mode 100644 index 00000000000..5f3fec53827 --- /dev/null +++ b/clippy_lints/src/methods/manual_next_back.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + rev_call: &'tcx Expr<'_>, + rev_recv: &'tcx Expr<'_>, +) { + let rev_recv_ty = cx.typeck_results().expr_ty(rev_recv); + + // check that the receiver of `rev` implements `DoubleEndedIterator` and + // that `rev` and `next` come from `Iterator` + if cx + .tcx + .get_diagnostic_item(sym::DoubleEndedIterator) + .map_or(false, |double_ended_iterator| { + implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]) + }) + && is_trait_method(cx, rev_call, sym::Iterator) + && is_trait_method(cx, expr, sym::Iterator) + { + span_lint_and_sugg( + cx, + super::MANUAL_NEXT_BACK, + expr.span.with_lo(rev_recv.span.hi()), + "manual backwards iteration", + "use", + String::from(".next_back()"), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 06b88e34d24..cb86917464b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; @@ -3193,6 +3194,29 @@ declare_clippy_lint! { "calling `drain` in order to `clear` a container" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.rev().next()` on a `DoubleEndedIterator` + /// + /// ### Why is this bad? + /// `.next_back()` is cleaner. + /// + /// ### Example + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().rev().next(); + /// ``` + /// Use instead: + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().next_back(); + /// ``` + #[clippy::version = "1.71.0"] + pub MANUAL_NEXT_BACK, + style, + "manual reverse iteration of `DoubleEndedIterator`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3321,6 +3345,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, + MANUAL_NEXT_BACK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3677,6 +3702,7 @@ impl Methods { ("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), + ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } diff --git a/tests/ui/manual_next_back.fixed b/tests/ui/manual_next_back.fixed new file mode 100644 index 00000000000..e8a47063ad6 --- /dev/null +++ b/tests/ui/manual_next_back.fixed @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).next_back().unwrap(); + let _ = "something".bytes().next_back(); +} diff --git a/tests/ui/manual_next_back.rs b/tests/ui/manual_next_back.rs new file mode 100644 index 00000000000..9ec89242241 --- /dev/null +++ b/tests/ui/manual_next_back.rs @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).rev().next().unwrap(); + let _ = "something".bytes().rev().next(); +} diff --git a/tests/ui/manual_next_back.stderr b/tests/ui/manual_next_back.stderr new file mode 100644 index 00000000000..94ccaa9e4cc --- /dev/null +++ b/tests/ui/manual_next_back.stderr @@ -0,0 +1,16 @@ +error: manual backwards iteration + --> $DIR/manual_next_back.rs:34:20 + | +LL | let _ = (0..10).rev().next().unwrap(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + | + = note: `-D clippy::manual-next-back` implied by `-D warnings` + +error: manual backwards iteration + --> $DIR/manual_next_back.rs:35:32 + | +LL | let _ = "something".bytes().rev().next(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 84f89f30ebda5485badac09b34d666fbab243a19 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Sat, 13 May 2023 11:47:05 +0200 Subject: enhance `needless_collect` Updates `needless_collect` to lint for collecting into a method or function argument thats taking an `IntoIterator` (for example `extend`). Every `Iterator` trivially implements `IntoIterator` and colleting it only causes an unnecessary allocation. --- clippy_lints/src/methods/needless_collect.rs | 68 +++++++++++++++++++++++++++- tests/ui/needless_collect.fixed | 12 +++++ tests/ui/needless_collect.rs | 12 +++++ tests/ui/needless_collect.stderr | 26 ++++++++++- 4 files changed, 115 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 0b0c6adc504..6841aaf626c 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -1,6 +1,5 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; @@ -8,6 +7,7 @@ use clippy_utils::{ can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, CaptureKind, }; +use clippy_utils::{fn_def_id, higher}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol}; @@ -32,6 +32,8 @@ pub(super) fn check<'tcx>( if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) { match parent { Node::Expr(parent) => { + check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr); + if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; let name = name.ident.as_str(); @@ -134,6 +136,68 @@ pub(super) fn check<'tcx>( } } +/// checks for for collecting into a (generic) method or function argument +/// taking an `IntoIterator` +fn check_collect_into_intoiterator<'tcx>( + cx: &LateContext<'tcx>, + parent: &'tcx Expr<'tcx>, + collect_expr: &'tcx Expr<'tcx>, + call_span: Span, + iter_expr: &'tcx Expr<'tcx>, +) { + if let Some(id) = fn_def_id(cx, parent) { + let args = match parent.kind { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => args, + _ => &[], + }; + // find the argument index of the `collect_expr` in the + // function / method call + if let Some(arg_idx) = args.iter().position(|e| e.hir_id == collect_expr.hir_id).map(|i| { + if matches!(parent.kind, ExprKind::MethodCall(_, _, _, _)) { + i + 1 + } else { + i + } + }) { + // extract the input types of the function/method call + // that contains `collect_expr` + let inputs = cx + .tcx + .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity()) + .inputs(); + + // map IntoIterator generic bounds to their signature + // types and check whether the argument type is an + // `IntoIterator` + if cx + .tcx + .param_env(id) + .caller_bounds() + .into_iter() + .filter_map(|p| { + if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { + Some(t.self_ty()) + } else { + None + } + }) + .any(|ty| ty == inputs[arg_idx]) + { + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + call_span.with_lo(iter_expr.span.hi()), + NEEDLESS_COLLECT_MSG, + "remove this call", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } +} + /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index 024c22de225..b7e80af5015 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().next().is_none(); let _ = sample.iter().any(|x| x == &0); + + #[allow(clippy::double_parens)] + { + Vec::::new().extend((0..10)); + foo((0..10)); + bar((0..10).collect::>(), (0..10)); + baz((0..10), (), ('a'..='z')) + } } + +fn foo(_: impl IntoIterator) {} +fn bar>(_: Vec, _: I) {} +fn baz>(_: I, _: (), _: impl IntoIterator) {} diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 7ed7babec30..680b6fa5b55 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().collect::>().is_empty(); let _ = sample.iter().collect::>().contains(&&0); + + #[allow(clippy::double_parens)] + { + Vec::::new().extend((0..10).collect::>()); + foo((0..10).collect::>()); + bar((0..10).collect::>(), (0..10).collect::>()); + baz((0..10), (), ('a'..='z').collect::>()) + } } + +fn foo(_: impl IntoIterator) {} +fn bar>(_: Vec, _: I) {} +fn baz>(_: I, _: (), _: impl IntoIterator) {} diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 584d2a1d835..ad22a7b057e 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -90,5 +90,29 @@ error: avoid using `collect()` when not needed LL | let _ = sample.iter().collect::>().contains(&&0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` -error: aborting due to 15 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:68:40 + | +LL | Vec::::new().extend((0..10).collect::>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:69:20 + | +LL | foo((0..10).collect::>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:70:49 + | +LL | bar((0..10).collect::>(), (0..10).collect::>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:71:37 + | +LL | baz((0..10), (), ('a'..='z').collect::>()) + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: aborting due to 19 previous errors -- cgit 1.4.1-3-g733a5 From 79eb06c6ec8838f6929ee54681de346f1b6bbde4 Mon Sep 17 00:00:00 2001 From: Mick van Gelderen Date: Mon, 15 May 2023 22:24:37 +0200 Subject: Remove unnecessary from example --- clippy_lints/src/methods/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cb86917464b..02d4a9aa08f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3133,8 +3133,11 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let iterator = vec![1].into_iter(); - /// let len = iterator.clone().collect::>().len(); - /// // should be + /// let len = iterator.collect::>().len(); + /// ``` + /// Use instead: + /// ```rust + /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` #[clippy::version = "1.30.0"] -- cgit 1.4.1-3-g733a5 From 5351170744bdc6dfca0f57908cd072cfa84a3f30 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 9 Mar 2023 15:46:46 -0500 Subject: Slightly refactor constant evaluation and add detection for empty macro expansion and `cfg`ed statements. --- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/casts/cast_nan_to_int.rs | 4 +- clippy_lints/src/casts/cast_possible_truncation.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 22 ++--- clippy_lints/src/fn_null_check.rs | 6 +- clippy_lints/src/implicit_saturating_add.rs | 4 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 8 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 4 +- clippy_lints/src/methods/iter_nth_zero.rs | 2 +- clippy_lints/src/methods/iterator_step_by_zero.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 +- clippy_lints/src/methods/repeat_once.rs | 4 +- clippy_lints/src/methods/str_splitn.rs | 2 +- .../src/operators/absurd_extreme_comparisons.rs | 2 +- .../src/operators/arithmetic_side_effects.rs | 2 +- clippy_lints/src/operators/bit_mask.rs | 2 +- clippy_lints/src/operators/cmp_nan.rs | 2 +- clippy_lints/src/operators/duration_subsec.rs | 2 +- clippy_lints/src/operators/float_cmp.rs | 57 +++++------ clippy_lints/src/operators/modulo_arithmetic.rs | 6 +- clippy_lints/src/ranges.rs | 8 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/transmute/transmute_null_to_fn.rs | 4 +- clippy_lints/src/transmute/transmuting_null.rs | 5 +- clippy_lints/src/vec.rs | 2 +- clippy_utils/src/consts.rs | 107 ++++++++++++++------- clippy_utils/src/hir_utils.rs | 2 + clippy_utils/src/lib.rs | 2 +- tests/ui/match_same_arms.rs | 12 +++ 32 files changed, 163 insertions(+), 126 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index a36df55d0bd..a8dc0cb3b58 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, }; let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return }; - let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return }; + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return }; if val { span_lint_and_help( cx, diff --git a/clippy_lints/src/casts/cast_nan_to_int.rs b/clippy_lints/src/casts/cast_nan_to_int.rs index 322dc41b3a1..da756129db3 100644 --- a/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/clippy_lints/src/casts/cast_nan_to_int.rs @@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match constant(cx, cx.typeck_results(), e) { - Some((Constant::F64(n), _)) => n.is_nan(), - Some((Constant::F32(n), _)) => n.is_nan(), + Some(Constant::F64(n)) => n.is_nan(), + Some(Constant::F32(n)) => n.is_nan(), _ => false, } } diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 95c2ecbf791..84b99ad5c24 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType; use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) { Some(c) } else { None diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index a20a97d4e56..a83dfd94dc2 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -29,7 +29,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast // Don't lint for positive constants. let const_val = constant(cx, cx.typeck_results(), cast_op); if_chain! { - if let Some((Constant::Int(n), _)) = const_val; + if let Some(Constant::Int(n)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index a1a2c398a8a..3c55a563af4 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -114,7 +114,7 @@ declare_lint_pass!(FloatingPointArithmetic => [ // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> { - if let Some((value, _)) = constant(cx, cx.typeck_results(), base) { + if let Some(value) = constant(cx, cx.typeck_results(), base) { if F32(2.0) == value || F64(2.0) == value { return Some("log2"); } else if F32(10.0) == value || F64(10.0) == value { @@ -193,8 +193,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { constant(cx, cx.typeck_results(), lhs), constant(cx, cx.typeck_results(), rhs), ) { - (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, - (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, + (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs, _ => return, }; @@ -237,7 +237,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { + if let Some(value) = constant(cx, cx.typeck_results(), receiver) { if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { Some("exp") } else if F32(2.0) == value || F64(2.0) == value { @@ -258,7 +258,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } // Check argument - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, @@ -298,7 +298,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { @@ -384,8 +384,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { _ ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1); - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); + if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1); + if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); @@ -416,7 +416,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind; if cx.typeck_results().expr_ty(lhs).is_floating_point(); - if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); + if let Some(value) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; if cx.typeck_results().expr_ty(self_arg).is_floating_point(); @@ -669,8 +669,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { mul_lhs, mul_rhs, ) = &div_lhs.kind; - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs); - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs); + if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs); + if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs); then { // TODO: also check for constant values near PI/180 or 180/PI if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && diff --git a/clippy_lints/src/fn_null_check.rs b/clippy_lints/src/fn_null_check.rs index d8f4a5fe221..521045a9fed 100644 --- a/clippy_lints/src/fn_null_check.rs +++ b/clippy_lints/src/fn_null_check.rs @@ -89,11 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for FnNullCheck { // Catching: // (fn_ptr as * ) == - _ if matches!( - constant(cx, cx.typeck_results(), to_check), - Some((Constant::RawPtr(0), _)) - ) => - { + _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); }, diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index 012aa5a1d1d..ee7973b82ab 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -101,10 +101,10 @@ fn get_int_max(ty: Ty<'_>) -> Option { fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> { if let ExprKind::Binary(op, l, r) = expr.kind { let tr = cx.typeck_results(); - if let Some((Constant::Int(c), _)) = constant(cx, tr, r) { + if let Some(Constant::Int(c)) = constant(cx, tr, r) { return Some((c, op.node, l)); }; - if let Some((Constant::Int(c), _)) = constant(cx, tr, l) { + if let Some(Constant::Int(c)) = constant(cx, tr, l) { return Some((c, invert_op(op.node)?, r)); } } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index bdeddf44df7..7a269e98ff1 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { let parent_id = map.parent_id(expr.hir_id); if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind; - if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr); + if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr); if let Ok(index_value) = index_value.try_into(); if index_value < max_suggested_slice; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 924a361c0f6..22c14d9b04d 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -191,18 +191,14 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { /// Returns a tuple of options with the start and end (exclusive) values of /// the range. If the start or end is not constant, None is returned. fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option, Option) { - let s = range - .start - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr)); let start = match s { Some(Some(Constant::Int(x))) => Some(x), Some(_) => None, None => Some(0), }; - let e = range - .end - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr)); let end = match e { Some(Some(Constant::Int(x))) => { if range.limits == RangeLimits::Closed { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 7d28c111624..93d977a5c96 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -144,7 +144,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E // Returns the length of the `expr` if it's a constant string or char. fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - let (value, _) = constant(cx, cx.typeck_results(), expr)?; + let value = constant(cx, cx.typeck_results(), expr)?; match value { Constant::Str(value) => Some(value.len() as u128), Constant::Char(value) => Some(value.len_utf8() as u128), diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index ae69ca8a339..abf2525a61c 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -34,7 +34,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs_const = match lhs { - Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, + Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; let min_constant = mir::ConstantKind::from_value( @@ -45,7 +45,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) }, }; let rhs_const = match rhs { - Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, + Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; let max_constant = mir::ConstantKind::from_value( diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index c830958d5c8..d1609eebfdc 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -13,7 +13,7 @@ use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, expr, sym::Iterator); - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg); + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs index 64c09214a76..b631cd00cda 100644 --- a/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { if is_trait_method(cx, expr, sym::Iterator) { - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) { + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) { span_lint( cx, ITERATOR_STEP_BY_ZERO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 02d4a9aa08f..9a594d964ab 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3770,13 +3770,13 @@ impl Methods { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_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); } }, ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); } }, diff --git a/clippy_lints/src/methods/repeat_once.rs b/clippy_lints/src/methods/repeat_once.rs index a345ec813ff..bb4cdd2a6fa 100644 --- a/clippy_lints/src/methods/repeat_once.rs +++ b/clippy_lints/src/methods/repeat_once.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_lang_item; @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, repeat_arg: &'tcx Expr<'_>, ) { - if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); if ty.is_str() { span_lint_and_sugg( diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 91f7ce1dbe5..5ea12c44184 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -316,7 +316,7 @@ fn parse_iter_usage<'tcx>( }; }, ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) { let span = if name.ident.as_str() == "nth" { e.span } else { diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index d29ca37eaeb..f4863600ccc 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>( fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { let ty = cx.typeck_results().expr_ty(expr); - let cv = constant(cx, cx.typeck_results(), expr)?.0; + let cv = constant(cx, cx.typeck_results(), expr)?; let which = match (ty.kind(), cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum, diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index c80e2ff7057..5c240276b76 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -113,7 +113,7 @@ impl ArithmeticSideEffects { if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { return Some(n) } - if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); } None diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs index 1369b3e7462..1fddf0f50e3 100644 --- a/clippy_lints/src/operators/bit_mask.rs +++ b/clippy_lints/src/operators/bit_mask.rs @@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: } fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option { - match constant(cx, cx.typeck_results(), lit)?.0 { + match constant(cx, cx.typeck_results(), lit)? { Constant::Int(n) => Some(n), _ => None, } diff --git a/clippy_lints/src/operators/cmp_nan.rs b/clippy_lints/src/operators/cmp_nan.rs index 786ae1552ad..e18064b7061 100644 --- a/clippy_lints/src/operators/cmp_nan.rs +++ b/clippy_lints/src/operators/cmp_nan.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp } fn is_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - if let Some((value, _)) = constant(cx, cx.typeck_results(), e) { + if let Some(value) = constant(cx, cx.typeck_results(), e) { match value { Constant::F32(num) => num.is_nan(), Constant::F64(num) => num.is_nan(), diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index 49e662cacb0..f120be13836 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>( if op == BinOpKind::Div && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) - && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) + && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right) { let suggested_fn = match (method_path.ident.as_str(), divisor) { ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index 97ddcdb2479..15dff126be7 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, Constant}; +use clippy_utils::consts::{constant_with_source, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; @@ -18,9 +18,16 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } + let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; + let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; // Allow comparing the results of signum() if is_signum(cx, left) && is_signum(cx, right) { @@ -34,10 +41,7 @@ pub(crate) fn check<'tcx>( } } let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); + let (lint, msg) = get_lint_and_message(left_is_local && right_is_local, is_comparing_arrays); span_lint_and_then(cx, lint, expr.span, msg, |diag| { let lhs = Sugg::hir(cx, left, ".."); let rhs = Sugg::hir(cx, right, ".."); @@ -59,44 +63,33 @@ pub(crate) fn check<'tcx>( } } -fn get_lint_and_message( - is_comparing_constants: bool, - is_comparing_arrays: bool, -) -> (&'static rustc_lint::Lint, &'static str) { - if is_comparing_constants { +fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static rustc_lint::Lint, &'static str) { + if is_local { ( - FLOAT_CMP_CONST, + FLOAT_CMP, if is_comparing_arrays { - "strict comparison of `f32` or `f64` constant arrays" + "strict comparison of `f32` or `f64` arrays" } else { - "strict comparison of `f32` or `f64` constant" + "strict comparison of `f32` or `f64`" }, ) } else { ( - FLOAT_CMP, + FLOAT_CMP_CONST, if is_comparing_arrays { - "strict comparison of `f32` or `f64` arrays" + "strict comparison of `f32` or `f64` constant arrays" } else { - "strict comparison of `f32` or `f64`" + "strict comparison of `f32` or `f64` constant" }, ) } } -fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { - res - } else { - false - } -} - -fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - match constant(cx, cx.typeck_results(), expr) { - Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f { +fn is_allowed(val: &Constant) -> bool { + match val { + &Constant::F32(f) => f == 0.0 || f.is_infinite(), + &Constant::F64(f) => f == 0.0 || f.is_infinite(), + Constant::Vec(vec) => vec.iter().all(|f| match f { Constant::F32(f) => *f == 0.0 || (*f).is_infinite(), Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), _ => false, diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index af4e74947f4..a2c3a4d8ba7 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -40,7 +40,7 @@ struct OperandInfo { fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { match constant(cx, cx.typeck_results(), operand) { - Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() { + Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); return Some(OperandInfo { @@ -58,10 +58,10 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> }, _ => {}, }, - Some((Constant::F32(f), _)) => { + Some(Constant::F32(f)) => { return Some(floating_point_operand_info(&f)); }, - Some((Constant::F64(f), _)) => { + Some(Constant::F64(f)) => { return Some(floating_point_operand_info(&f)); }, _ => {}, diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index fc655fe2d0b..dd7ded491e7 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -319,7 +319,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option return None, }; if let Some(id) = path_to_local(l) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { + if let Some(c) = constant(cx, cx.typeck_results(), r) { return Some(RangeBounds { val: c, expr: r, @@ -331,7 +331,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option, expr: &Expr<'_>) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr); let ty = cx.typeck_results().expr_ty(start); if let ty::Int(_) | ty::Uint(_) = ty.kind(); - if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start); - if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end); + if let Some(start_idx) = constant(cx, cx.typeck_results(), start); + if let Some(end_idx) = constant(cx, cx.typeck_results(), end); if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index fe5be248700..ef19c6f4617 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -122,7 +122,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option { - constant(cx, cx.typeck_results(), e).and_then(|(c, _)| match c { + constant(cx, cx.typeck_results(), e).and_then(|c| match c { Constant::Str(s) => Some(s), _ => None, }) diff --git a/clippy_lints/src/transmute/transmute_null_to_fn.rs b/clippy_lints/src/transmute/transmute_null_to_fn.rs index e75d7f6bf1d..4944381da24 100644 --- a/clippy_lints/src/transmute/transmute_null_to_fn.rs +++ b/clippy_lints/src/transmute/transmute_null_to_fn.rs @@ -31,9 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t match arg.kind { // Catching: // transmute over constants that resolve to `null`. - ExprKind::Path(ref _qpath) - if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) => - { + ExprKind::Path(ref _qpath) if matches!(constant(cx, cx.typeck_results(), arg), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); true }, diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 1e407fc4138..770914e99e1 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; @@ -16,9 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - let mut const_eval_context = constant_context(cx, cx.typeck_results()); if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg) + let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 297a80e5767..7329e508106 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -84,7 +84,7 @@ impl UselessVec { let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { - if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) { + if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) { #[expect(clippy::cast_possible_truncation)] if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack { return; diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index b52caf6e405..34ca9b2d67e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1,18 +1,21 @@ #![allow(clippy::float_cmp)] +use crate::source::{span_source_range, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{List, SubstsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; +use rustc_span::SyntaxContext; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; use std::iter; @@ -227,27 +230,46 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option>) -> Constant { } } +/// The source of a constant value. +pub enum ConstantSource { + /// The value is determined solely from the expression. + Local, + /// The value is dependent on a defined constant. + Constant, +} +impl ConstantSource { + pub fn is_local(&self) -> bool { + matches!(self, Self::Local) + } +} + +/// Attempts to evaluate the expression as a constant. pub fn constant<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option<(Constant, bool)> { - let mut cx = ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - }; - cx.expr(e).map(|cst| (cst, cx.needed_resolution)) +) -> Option { + ConstEvalLateContext::new(lcx, typeck_results).expr(e) +} + +/// Attempts to evaluate the expression as a constant. +pub fn constant_with_source<'tcx>( + lcx: &LateContext<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + e: &Expr<'_>, +) -> Option<(Constant, ConstantSource)> { + let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); + let res = ctxt.expr(e); + res.map(|x| (x, ctxt.source)) } +/// Attempts to evaluate an expression only if it's value is not dependent on other items. pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option { - constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) + constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c)) } pub fn constant_full_int<'tcx>( @@ -296,29 +318,25 @@ impl Ord for FullInt { } } -/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. -pub fn constant_context<'a, 'tcx>( - lcx: &'a LateContext<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, -) -> ConstEvalLateContext<'a, 'tcx> { - ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - } -} - pub struct ConstEvalLateContext<'a, 'tcx> { lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - needed_resolution: bool, + source: ConstantSource, substs: SubstsRef<'tcx>, } impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { + fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self { + Self { + lcx, + typeck_results, + param_env: lcx.param_env, + source: ConstantSource::Local, + substs: List::empty(), + } + } + /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option { match e.kind { @@ -453,11 +471,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; - let result = miri_to_const(self.lcx.tcx, result); - if result.is_some() { - self.needed_resolution = true; - } - result + let result = miri_to_const(self.lcx.tcx, result)?; + self.source = ConstantSource::Constant; + Some(result) }, // FIXME: cover all usable cases. _ => None, @@ -491,8 +507,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// A block can only yield a constant if it only has one constant expression. fn block(&mut self, block: &Block<'_>) -> Option { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|b| self.expr(b)) + if block.stmts.is_empty() + && let Some(expr) = block.expr + { + // Try to detect any `cfg`ed statements or empty macro expansions. + let span = block.span.data(); + if span.ctxt == SyntaxContext::root() { + if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) + && let expr_lo = expr_span.lo() + && expr_lo >= span.lo + && let Some(src) = span_source_range(self.lcx, span.lo..expr_lo) + && let Some(src) = src.as_str() + { + use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace}; + if !tokenize(src) + .map(|t| t.kind) + .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) + .eq([OpenBrace]) + { + self.source = ConstantSource::Constant; + } + } else { + // Unable to access the source. Assume a non-local dependency. + self.source = ConstantSource::Constant; + } + } + + self.expr(expr) } else { None } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 3561e760ac9..2aec5a10e5d 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -151,6 +151,8 @@ impl HirEqInterExpr<'_, '_, '_> { if !self.eq_stmt(left, right) { return false; } + + // Try to detect any `cfg`ed statements or empty macro expansions. let Some(lstmt_span) = walk_span_to_context(left.span, lspan.ctxt) else { return false; }; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2ddd2ade6ae..c857595b844 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1547,7 +1547,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool return true; } let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); - if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { + if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { return value == v; } false diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs index 15410734dec..26e2ca86758 100644 --- a/tests/ui/match_same_arms.rs +++ b/tests/ui/match_same_arms.rs @@ -72,6 +72,18 @@ fn main() { _ => 1, }; + let _ = match 0 { + 0 => { + m!(foo); + 0 + }, + 1 => { + m!(bar); + 0 + }, + _ => 1, + }; + let _ = match 0 { 0 => { let mut x = 0; -- cgit 1.4.1-3-g733a5 From c5b974b55da246ee0850f5b38084f93cf5e0b913 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 29 May 2023 00:46:15 +0200 Subject: Update version attribute for 1.70 lints --- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/collection_is_never_read.rs | 2 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/missing_assert_message.rs | 2 +- clippy_lints/src/redundant_async_block.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index add73d0aeee..554efdc58e1 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// a.len() /// } /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.70.0"] pub ALLOW_ATTRIBUTES, restriction, "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 5e2eb5789f6..ac5ac542cf9 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// println!("{sample}"); /// } /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.70.0"] pub COLLECTION_IS_NEVER_READ, nursery, "a collection is never queried" diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 0ca31033b16..087c4a65250 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// wait(fut).await; /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.70.0"] pub LARGE_FUTURES, pedantic, "large future may lead to unexpected stack overflows" diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index c01e3882d52..2f10e3d2581 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// ```rust,ignore /// let my_number = 1; /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.70.0"] pub LET_WITH_TYPE_UNDERSCORE, complexity, "unneeded underscore type (`_`) in a variable declaration" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9a594d964ab..88cbefbb5d3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3191,7 +3191,7 @@ declare_clippy_lint! { /// let mut v = vec![1, 2, 3]; /// v.clear(); /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.70.0"] pub CLEAR_WITH_DRAIN, nursery, "calling `drain` in order to `clear` a container" diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 2214a568d9c..4dbb79334ca 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests"); /// } /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.70.0"] pub MISSING_ASSERT_MESSAGE, restriction, "checks assertions without a custom panic message" diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index a0f831764d0..05e52e6b38b 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// }; /// let fut = f; /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.70.0"] pub REDUNDANT_ASYNC_BLOCK, complexity, "`async { future.await }` can be replaced by `future`" -- cgit 1.4.1-3-g733a5 From dd084940de3947b7d095fcbd6d3381f98470c58b Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 9 Jun 2023 04:13:00 +0200 Subject: check that the adjusted receiver type matches target --- clippy_lints/src/methods/unnecessary_to_owned.rs | 5 ++++ tests/ui/unnecessary_to_owned.fixed | 33 ++++++++++++++++++++++++ tests/ui/unnecessary_to_owned.rs | 33 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 309d2157b76..da7196ed0a8 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -144,6 +144,11 @@ fn check_addr_of_expr( if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); if implements_trait(cx, receiver_ty, deref_trait_id, &[]); if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty); + // Make sure that it's actually calling the right `.to_string()`, (#10033) + // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) + // but that's ok for Cow::into_owned specifically) + if cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty + || is_cow_into_owned(cx, method_name, method_def_id); then { if n_receiver_refs > 0 { span_lint_and_sugg( diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 08733906b0e..592a53f3a81 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -474,3 +474,36 @@ mod issue_10021 { Ok(()) } } + +mod issue_10033 { + #![allow(dead_code)] + use std::{fmt::Display, ops::Deref}; + + fn _main() { + let f = Foo; + + // Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does + // deref to `str`) + foo(&f.to_string()); + } + + fn foo(s: &str) { + println!("{}", s); + } + + struct Foo; + + impl Deref for Foo { + type Target = str; + + fn deref(&self) -> &Self::Target { + "str" + } + } + + impl Display for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Foo") + } + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index e3589ea0d65..f2e48b1c4a6 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -474,3 +474,36 @@ mod issue_10021 { Ok(()) } } + +mod issue_10033 { + #![allow(dead_code)] + use std::{fmt::Display, ops::Deref}; + + fn _main() { + let f = Foo; + + // Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does + // deref to `str`) + foo(&f.to_string()); + } + + fn foo(s: &str) { + println!("{}", s); + } + + struct Foo; + + impl Deref for Foo { + type Target = str; + + fn deref(&self) -> &Self::Target { + "str" + } + } + + impl Display for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Foo") + } + } +} -- cgit 1.4.1-3-g733a5 From 9d58a426230b5b4200791b9bedee1b14cb971197 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 10 Jun 2023 01:38:04 +0200 Subject: [`map_unwrap_or`]: don't lint when referenced variable is moved --- clippy_lints/src/methods/option_map_unwrap_or.rs | 87 ++++++++++++++++-------- tests/ui/map_unwrap_or.rs | 29 ++++++++ 2 files changed, 88 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 4c6328481e4..e931c6277f4 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -4,12 +4,17 @@ use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::ExprKind; +use rustc_hir::Node; +use rustc_hir::PatKind; +use rustc_hir::QPath; use rustc_hir::{self, HirId, Path}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_span::source_map::Span; -use rustc_span::{sym, Symbol}; +use rustc_span::sym; use super::MAP_UNWRAP_OR; @@ -26,8 +31,22 @@ pub(super) fn check<'tcx>( // lint if the caller of `map()` is an `Option` if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { - // Do not lint if the `map` argument uses identifiers in the `map` - // argument that are also used in the `unwrap_or` argument + // Replacing `.map().unwrap_or()` with `.map_or(, )` can sometimes lead to + // borrowck errors, see #10579 for one such instance. + // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x); + // ``` + // This compiles, but changing it to `map_or` will produce a compile error: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map_or(x, |s| s.to_vec()) + // ^ moving `x` here + // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure) + // ``` + // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!) + // before the call to `unwrap_or`. let mut unwrap_visitor = UnwrapVisitor { cx, @@ -35,14 +54,18 @@ pub(super) fn check<'tcx>( }; unwrap_visitor.visit_expr(unwrap_arg); - let mut map_expr_visitor = MapExprVisitor { + let mut reference_visitor = ReferenceVisitor { cx, identifiers: unwrap_visitor.identifiers, - found_identifier: false, + found_reference: false, + unwrap_or_span: unwrap_arg.span, }; - map_expr_visitor.visit_expr(map_arg); - if map_expr_visitor.found_identifier { + let map = cx.tcx.hir(); + let body = map.body(map.body_owned_by(map.enclosing_body_owner(expr.hir_id))); + reference_visitor.visit_body(body); + + if reference_visitor.found_reference { return; } } @@ -91,14 +114,19 @@ pub(super) fn check<'tcx>( struct UnwrapVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - identifiers: FxHashSet, + identifiers: FxHashSet, } impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { - self.identifiers.insert(ident(path)); + fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { + if let Res::Local(local_id) = path.res + && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id) + && let PatKind::Binding(_, local_id, ..) = pat.kind + { + self.identifiers.insert(local_id); + } walk_path(self, path); } @@ -107,32 +135,35 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { } } -struct MapExprVisitor<'a, 'tcx> { +struct ReferenceVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - identifiers: FxHashSet, - found_identifier: bool, + identifiers: FxHashSet, + found_reference: bool, + unwrap_or_span: Span, } -impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; - - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { - if self.identifiers.contains(&ident(path)) { - self.found_identifier = true; - return; + fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) { + // If we haven't found a reference yet, check if this references + // one of the locals that was moved in the `unwrap_or` argument. + // We are only interested in exprs that appear before the `unwrap_or` call. + if !self.found_reference { + if expr.span < self.unwrap_or_span + && let ExprKind::Path(ref path) = expr.kind + && let QPath::Resolved(_, path) = path + && let Res::Local(local_id) = path.res + && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id) + && let PatKind::Binding(_, local_id, ..) = pat.kind + && self.identifiers.contains(&local_id) + { + self.found_reference = true; + } + rustc_hir::intravisit::walk_expr(self, expr); } - walk_path(self, path); } fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } } - -fn ident(path: &Path<'_>) -> Symbol { - path.segments - .last() - .expect("segments should be composed of at least 1 element") - .ident - .name -} diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index cb25d8567aa..0cd49dd7760 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -94,3 +94,32 @@ fn msrv_1_41() { let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); } + +mod issue_10579 { + // Different variations of the same issue. + fn v1() { + let x = vec![1, 2, 3, 0]; + let y = x.strip_suffix(&[0]).map(|s| s.to_vec()).unwrap_or(x); + println!("{y:?}"); + } + fn v2() { + let x = vec![1, 2, 3, 0]; + let y = Some(()).map(|_| x.to_vec()).unwrap_or(x); + println!("{y:?}"); + } + fn v3() { + let x = vec![1, 2, 3, 0]; + let xref = &x; + let y = Some(()).map(|_| xref.to_vec()).unwrap_or(x); + println!("{y:?}"); + } + fn v4() { + struct VecInStruct { + v: Vec, + } + let s = VecInStruct { v: vec![1, 2, 3, 0] }; + + let y = Some(()).map(|_| s.v.clone()).unwrap_or(s.v); + println!("{y:?}"); + } +} -- cgit 1.4.1-3-g733a5 From c9daec2585c464f2e7d37756c341b217ca795bde Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 12 Jun 2023 02:43:23 +0200 Subject: [`unnecessary_fold`]: suggest turbofish if necessary --- clippy_lints/src/methods/unnecessary_fold.rs | 124 ++++++++++++++++++++++++--- tests/ui/unnecessary_fold.fixed | 24 ++++++ tests/ui/unnecessary_fold.rs | 24 ++++++ tests/ui/unnecessary_fold.stderr | 56 +++++++++++- 4 files changed, 217 insertions(+), 11 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 5a3d12fd790..de29d99cf8d 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -7,10 +7,74 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; +use rustc_middle::ty; use rustc_span::{source_map::Span, sym}; use super::UNNECESSARY_FOLD; +/// No turbofish needed in any case. +fn no_turbofish(_: &LateContext<'_>, _: &hir::Expr<'_>) -> bool { + false +} + +/// Turbofish (`::`) may be needed, but can be omitted if we are certain +/// that the type can be inferred from usage. +fn turbofish_if_not_inferred(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + let parent = cx.tcx.hir().get_parent(expr.hir_id); + + // some common cases where turbofish isn't needed: + // - assigned to a local variable with a type annotation + if let hir::Node::Local(local) = parent + && local.ty.is_some() + { + return false; + } + + // - part of a function call argument, can be inferred from the function signature (provided that + // the parameter is not a generic type parameter) + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(recv, args) = parent_expr.kind + && let hir::ExprKind::Path(ref qpath) = recv.kind + && let Some(fn_def_id) = cx.qpath_res(qpath, recv.hir_id).opt_def_id() + && let fn_sig = cx.tcx.fn_sig(fn_def_id).skip_binder().skip_binder() + && let Some(arg_pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(ty) = fn_sig.inputs().get(arg_pos) + && !matches!(ty.kind(), ty::Param(_)) + { + return false; + } + + // if it's neither of those, stay on the safe side and suggest turbofish, + // even if it could work! + true +} + +#[derive(Copy, Clone)] +struct Replacement { + method_name: &'static str, + has_args: bool, + requires_turbofish: fn(&LateContext<'_>, &hir::Expr<'_>) -> bool, +} +impl Replacement { + /// `any(f)`, `all(f)` + pub fn non_generic(method_name: &'static str) -> Self { + Self { + method_name, + has_args: true, + requires_turbofish: no_turbofish, + } + } + + /// `sum::()`, `product::()` + pub fn generic(method_name: &'static str) -> Self { + Self { + method_name, + has_args: false, + requires_turbofish: turbofish_if_not_inferred, + } + } +} + pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -24,8 +88,7 @@ pub(super) fn check( acc: &hir::Expr<'_>, fold_span: Span, op: hir::BinOpKind, - replacement_method_name: &str, - replacement_has_args: bool, + replacement: Replacement, ) { if_chain! { // Extract the body of the closure passed to fold @@ -43,18 +106,27 @@ pub(super) fn check( if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; if path_to_local_id(left_expr, first_arg_id); - if replacement_has_args || path_to_local_id(right_expr, second_arg_id); + if replacement.has_args || path_to_local_id(right_expr, second_arg_id); then { let mut applicability = Applicability::MachineApplicable; - let sugg = if replacement_has_args { + + let turbofish = if (replacement.requires_turbofish)(cx, expr) { + format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) + } else { + String::new() + }; + + let sugg = if replacement.has_args { format!( - "{replacement_method_name}(|{second_arg_ident}| {r})", + "{method}{turbofish}(|{second_arg_ident}| {r})", + method = replacement.method_name, r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { format!( - "{replacement_method_name}()", + "{method}{turbofish}()", + method = replacement.method_name, ) }; @@ -80,11 +152,43 @@ pub(super) fn check( // Check if the first argument to .fold is a suitable literal if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { - ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true), - ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true), - ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false), + ast::LitKind::Bool(false) => { + check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::Or, + Replacement::non_generic("any"), + ); + }, + ast::LitKind::Bool(true) => { + check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::And, + Replacement::non_generic("all"), + ); + }, + ast::LitKind::Int(0, _) => check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::Add, + Replacement::generic("sum"), + ), ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false); + check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::Mul, + Replacement::generic("product"), + ); }, _ => (), } diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index 2bed14973ca..bd1d4a152ae 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -49,4 +49,28 @@ fn unnecessary_fold_over_multiple_lines() { .any(|x| x > 2); } +fn issue10000() { + use std::collections::HashMap; + use std::hash::BuildHasher; + + fn anything(_: T) {} + fn num(_: i32) {} + fn smoketest_map(mut map: HashMap) { + map.insert(0, 0); + assert_eq!(map.values().sum::(), 0); + + // more cases: + let _ = map.values().sum::(); + let _ = map.values().product::(); + let _: i32 = map.values().sum(); + let _: i32 = map.values().product(); + anything(map.values().sum::()); + anything(map.values().product::()); + num(map.values().sum()); + num(map.values().product()); + } + + smoketest_map(HashMap::new()); +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index a3cec8ea3d5..d27cc460c44 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -49,4 +49,28 @@ fn unnecessary_fold_over_multiple_lines() { .fold(false, |acc, x| acc || x > 2); } +fn issue10000() { + use std::collections::HashMap; + use std::hash::BuildHasher; + + fn anything(_: T) {} + fn num(_: i32) {} + fn smoketest_map(mut map: HashMap) { + map.insert(0, 0); + assert_eq!(map.values().fold(0, |x, y| x + y), 0); + + // more cases: + let _ = map.values().fold(0, |x, y| x + y); + let _ = map.values().fold(1, |x, y| x * y); + let _: i32 = map.values().fold(0, |x, y| x + y); + let _: i32 = map.values().fold(1, |x, y| x * y); + anything(map.values().fold(0, |x, y| x + y)); + anything(map.values().fold(1, |x, y| x * y)); + num(map.values().fold(0, |x, y| x + y)); + num(map.values().fold(1, |x, y| x * y)); + } + + smoketest_map(HashMap::new()); +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index 22c44588ab7..98979f7477f 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -36,5 +36,59 @@ error: this `.fold` can be written more succinctly using another method LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` -error: aborting due to 6 previous errors +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:60:33 + | +LL | assert_eq!(map.values().fold(0, |x, y| x + y), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:63:30 + | +LL | let _ = map.values().fold(0, |x, y| x + y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:64:30 + | +LL | let _ = map.values().fold(1, |x, y| x * y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:65:35 + | +LL | let _: i32 = map.values().fold(0, |x, y| x + y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:66:35 + | +LL | let _: i32 = map.values().fold(1, |x, y| x * y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:67:31 + | +LL | anything(map.values().fold(0, |x, y| x + y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:68:31 + | +LL | anything(map.values().fold(1, |x, y| x * y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:69:26 + | +LL | num(map.values().fold(0, |x, y| x + y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:70:26 + | +LL | num(map.values().fold(1, |x, y| x * y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From e707447a861739fa3e12e9c05c039c8c9c6b0544 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 11:32:12 +0000 Subject: Boilerplate for the new lint --- clippy_lints/src/methods/mod.rs | 52 ++++++++++++++++++++++ .../src/methods/unnecessary_literal_unwrap.rs | 30 +++++++++++++ tests/ui/unnecessary_literal_unwrap.rs | 10 +++++ tests/ui/unwrap_literal.rs | 17 ------- 4 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_literal_unwrap.rs create mode 100644 tests/ui/unnecessary_literal_unwrap.rs delete mode 100644 tests/ui/unwrap_literal.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 88cbefbb5d3..f24f00ef6a7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -93,6 +93,7 @@ mod unnecessary_fold; mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; +mod unnecessary_literal_unwrap; mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_or_else_default; @@ -273,6 +274,56 @@ declare_clippy_lint! { "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. + /// + /// ### Why is this bad? + /// It is better to handle the `None` or `Err` case, + /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of + /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is + /// `Allow` by default. + /// + /// `result.unwrap()` will let the thread panic on `Err` values. + /// Normally, you want to implement more sophisticated error handling, + /// and propagate errors upwards with `?` operator. + /// + /// Even if you want to panic on errors, not all `Error`s implement good + /// messages on display. Therefore, it may be beneficial to look at the places + /// where they may get displayed. Activate this lint to do just that. + /// + /// ### Examples + /// ```rust + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.unwrap(); + /// result.unwrap(); + /// ``` + /// + /// Use instead: + /// ```rust + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.expect("more helpful message"); + /// result.expect("more helpful message"); + /// ``` + /// + /// If [expect_used](#expect_used) is enabled, instead: + /// ```rust,ignore + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option?; + /// + /// // or + /// + /// result?; + /// ``` + #[clippy::version = "1.69.0"] + pub UNNECESSARY_LITERAL_UNWRAP, + complexity, + "checks for calls of `unwrap()` or `expect()` on `Some()` that cannot fail" +} + declare_clippy_lint! { /// ### What it does /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. @@ -3814,6 +3865,7 @@ impl Methods { Some(("or", recv, [or_arg], or_span, _)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, + // unnecessary_literal_unwrap::check(cx, expr, recv); _ => {}, } unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs new file mode 100644 index 00000000000..39b30b7769d --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -0,0 +1,30 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNNECESSARY_LITERAL_UNWRAP; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { + let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + Some((UNNECESSARY_LITERAL_UNWRAP, "an `Option`", "None", "")) + } else { + None + }; + + if let Some((lint, kind, none_value, none_prefix)) = mess { + let help = format!("if this value is {none_prefix}`{none_value}`, it will panic"); + + span_lint_and_help( + cx, + lint, + expr.span, + &format!("used `unwrap()` on {kind} value"), + None, + &help, + ); + } +} diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs new file mode 100644 index 00000000000..9ae50517a3e --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -0,0 +1,10 @@ +#![warn(clippy::unnecessary_literal_unwrap)] + +fn unwrap_option() { + let val = Some(1).unwrap(); + let val = Some(1).expect("this never happens"); +} + +fn main() { + unwrap_option(); +} diff --git a/tests/ui/unwrap_literal.rs b/tests/ui/unwrap_literal.rs deleted file mode 100644 index 917ef2126f5..00000000000 --- a/tests/ui/unwrap_literal.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![warn(clippy::unnecessary_unwrap)] - -fn unwrap_option() { - let val = Some(1).unwrap(); - let val = Some(1).expect("this never happens"); -} - -fn unwrap_result() { - let val = Ok(1).unwrap(); - let val = Err(1).unwrap_err(); - let val = Ok(1).expect("this never happens"); -} - -fn main() { - unwrap_option(); - unwrap_result(); -} -- cgit 1.4.1-3-g733a5 From 5bb768177ee83065191b1f47111ecf63de347cff Mon Sep 17 00:00:00 2001 From: rsdy Date: Thu, 16 Feb 2023 11:49:19 +0000 Subject: Add hook --- clippy_lints/src/methods/mod.rs | 4 +++- clippy_lints/src/methods/unnecessary_literal_unwrap.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f24f00ef6a7..9d7b607ec7b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3865,7 +3865,9 @@ impl Methods { Some(("or", recv, [or_arg], or_span, _)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, - // unnecessary_literal_unwrap::check(cx, expr, recv); + Some((constructor @ "Some", _, _, _, _)) => { + unnecessary_literal_unwrap::check(cx, expr, recv, constructor); + } _ => {}, } unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 39b30b7769d..3572f4965ef 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -6,7 +6,7 @@ use rustc_span::sym; use super::UNNECESSARY_LITERAL_UNWRAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, constructor: &str) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { -- cgit 1.4.1-3-g733a5 From 2902359b3c922910b5b5bc1c2fa73c3e8bf2fcfb Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 11:32:12 +0000 Subject: Add the lint to the lib --- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 523faa302dc..62317dc60eb 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -408,6 +408,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_FOLD_INFO, crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, + crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9d7b607ec7b..6eb97227e0a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3400,6 +3400,7 @@ impl_lint_pass!(Methods => [ SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, MANUAL_NEXT_BACK, + UNNECESSARY_LITERAL_UNWRAP, ]); /// Extracts a method call name, args, and `Span` of the method name. -- cgit 1.4.1-3-g733a5 From 0b1bb5fbf3a4d3e73192f95490ce7246f9fd1914 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 13:36:51 +0000 Subject: Implement the lint --- clippy_lints/src/methods/mod.rs | 6 +++--- .../src/methods/unnecessary_literal_unwrap.rs | 19 +++++++------------ tests/ui/unnecessary_literal_unwrap.stderr | 11 +++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 tests/ui/unnecessary_literal_unwrap.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6eb97227e0a..7a7d5a588b0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3866,11 +3866,11 @@ impl Methods { Some(("or", recv, [or_arg], or_span, _)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, - Some((constructor @ "Some", _, _, _, _)) => { - unnecessary_literal_unwrap::check(cx, expr, recv, constructor); - } _ => {}, } + if let ExprKind::Call(recv, _) = recv.kind { + unnecessary_literal_unwrap::check(cx, expr, recv, name); + } unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 3572f4965ef..181e4a06664 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,28 +1,23 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{diagnostics::span_lint_and_help, is_res_lang_ctor, path_res}; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; use super::UNNECESSARY_LITERAL_UNWRAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, constructor: &str) { - let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((UNNECESSARY_LITERAL_UNWRAP, "an `Option`", "None", "")) +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, name: &str) { + let mess = if is_res_lang_ctor(cx, path_res(cx, recv), hir::LangItem::OptionSome) { + Some((UNNECESSARY_LITERAL_UNWRAP, "Some")) } else { None }; - if let Some((lint, kind, none_value, none_prefix)) = mess { - let help = format!("if this value is {none_prefix}`{none_value}`, it will panic"); - + if let Some((lint, constructor)) = mess { + let help = String::new(); span_lint_and_help( cx, lint, expr.span, - &format!("used `unwrap()` on {kind} value"), + &format!("used `{name}()` on `{constructor}` value"), None, &help, ); diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr new file mode 100644 index 00000000000..5f9881b2ae3 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -0,0 +1,11 @@ +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:4:15 + | +LL | let val = Some(1).unwrap(); + | ^^^^^^^^^^^^^^^^ + | + = help: + = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 21b88ce290ee90259fdd35b33923ee330acb0991 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 13:44:11 +0000 Subject: Implement the lint for expect --- clippy_lints/src/methods/mod.rs | 13 +++++++++---- tests/ui/unnecessary_literal_unwrap.stderr | 10 +++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7a7d5a588b0..cb82aef1ef0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3658,10 +3658,15 @@ impl Methods { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); } }, - ("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, span, err_span, &self.msrv), - _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), + ("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, span, err_span, &self.msrv), + _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), + } + if let ExprKind::Call(recv, _) = recv.kind { + unnecessary_literal_unwrap::check(cx, expr, recv, name); + } }, ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), ("extend", [arg]) => { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 5f9881b2ae3..414d4445cae 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -7,5 +7,13 @@ LL | let val = Some(1).unwrap(); = help: = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` -error: aborting due to previous error +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:5:15 + | +LL | let val = Some(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: + +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From daf61974813ba6f9e7513068bc8cce2839fb8939 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 14:21:43 +0000 Subject: Implement the suggestion --- clippy_lints/src/methods/mod.rs | 8 ++++---- .../src/methods/unnecessary_literal_unwrap.rs | 22 ++++++++++++++++------ tests/ui/unnecessary_literal_unwrap.fixed | 11 +++++++++++ tests/ui/unnecessary_literal_unwrap.rs | 1 + tests/ui/unnecessary_literal_unwrap.stderr | 16 ++++++++++++---- 5 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 tests/ui/unnecessary_literal_unwrap.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cb82aef1ef0..a5c55a42ea5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3664,8 +3664,8 @@ impl Methods { 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), } - if let ExprKind::Call(recv, _) = recv.kind { - unnecessary_literal_unwrap::check(cx, expr, recv, name); + if let ExprKind::Call(recv, [arg]) = recv.kind { + unnecessary_literal_unwrap::check(cx, expr, recv, arg, name); } }, ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), @@ -3873,8 +3873,8 @@ impl Methods { }, _ => {}, } - if let ExprKind::Call(recv, _) = recv.kind { - unnecessary_literal_unwrap::check(cx, expr, recv, name); + if let ExprKind::Call(recv, [arg]) = recv.kind { + unnecessary_literal_unwrap::check(cx, expr, recv, arg, name); } unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 181e4a06664..9a82d7e58ea 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,10 +1,11 @@ -use clippy_utils::{diagnostics::span_lint_and_help, is_res_lang_ctor, path_res}; +use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, path_res}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use super::UNNECESSARY_LITERAL_UNWRAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, name: &str) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, name: &str) { let mess = if is_res_lang_ctor(cx, path_res(cx, recv), hir::LangItem::OptionSome) { Some((UNNECESSARY_LITERAL_UNWRAP, "Some")) } else { @@ -12,14 +13,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr }; if let Some((lint, constructor)) = mess { - let help = String::new(); - span_lint_and_help( + span_lint_and_then( cx, lint, expr.span, &format!("used `{name}()` on `{constructor}` value"), - None, - &help, + |diag| { + let suggestions = vec![ + (recv.span.with_hi(arg.span.lo()), String::new()), + (expr.span.with_lo(arg.span.hi()), String::new()), + ]; + + diag.multipart_suggestion( + format!("remove the `{constructor}` and `{name}()`"), + suggestions, + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed new file mode 100644 index 00000000000..8696048d332 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -0,0 +1,11 @@ +//run-rustfix +#![warn(clippy::unnecessary_literal_unwrap)] + +fn unwrap_option() { + let val = 1; + let val = 1; +} + +fn main() { + unwrap_option(); +} diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 9ae50517a3e..ae41634495b 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -1,3 +1,4 @@ +//run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] fn unwrap_option() { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 414d4445cae..00d7f186fc4 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -1,19 +1,27 @@ error: used `unwrap()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:4:15 + --> $DIR/unnecessary_literal_unwrap.rs:5:15 | LL | let val = Some(1).unwrap(); | ^^^^^^^^^^^^^^^^ | - = help: = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` +help: remove the `Some` and `unwrap()` + | +LL - let val = Some(1).unwrap(); +LL + let val = 1; + | error: used `expect()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:5:15 + --> $DIR/unnecessary_literal_unwrap.rs:6:15 | LL | let val = Some(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: +help: remove the `Some` and `expect()` + | +LL - let val = Some(1).expect("this never happens"); +LL + let val = 1; + | error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 1d159e7d11d86d030c030ec0ec23a88871289d1b Mon Sep 17 00:00:00 2001 From: rsdy Date: Thu, 16 Feb 2023 14:37:18 +0000 Subject: Recognize `Ok` --- .../src/methods/unnecessary_literal_unwrap.rs | 8 ++-- tests/ui/unnecessary_literal_unwrap.fixed | 11 +++++- tests/ui/unnecessary_literal_unwrap.rs | 11 +++++- tests/ui/unnecessary_literal_unwrap.stderr | 46 ++++++++++++++++------ 4 files changed, 58 insertions(+), 18 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 9a82d7e58ea..0c8a70fedb9 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -7,15 +7,17 @@ use super::UNNECESSARY_LITERAL_UNWRAP; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, name: &str) { let mess = if is_res_lang_ctor(cx, path_res(cx, recv), hir::LangItem::OptionSome) { - Some((UNNECESSARY_LITERAL_UNWRAP, "Some")) + Some("Some") + } else if is_res_lang_ctor(cx, path_res(cx, recv), hir::LangItem::ResultOk) { + Some("Ok") } else { None }; - if let Some((lint, constructor)) = mess { + if let Some(constructor) = mess { span_lint_and_then( cx, - lint, + UNNECESSARY_LITERAL_UNWRAP, expr.span, &format!("used `{name}()` on `{constructor}` value"), |diag| { diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 8696048d332..b59dec7d48a 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -2,10 +2,17 @@ #![warn(clippy::unnecessary_literal_unwrap)] fn unwrap_option() { - let val = 1; - let val = 1; + let _val = 1; + let _val = 1; +} + +fn unwrap_result() { + let _val = 1; + let _val = 1; + // let val = Err(1).unwrap_err(); } fn main() { unwrap_option(); + unwrap_result(); } diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index ae41634495b..c46204f7a99 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -2,10 +2,17 @@ #![warn(clippy::unnecessary_literal_unwrap)] fn unwrap_option() { - let val = Some(1).unwrap(); - let val = Some(1).expect("this never happens"); + let _val = Some(1).unwrap(); + let _val = Some(1).expect("this never happens"); +} + +fn unwrap_result() { + let _val = Ok::(1).unwrap(); + let _val = Ok::(1).expect("this never happens"); + // let val = Err(1).unwrap_err(); } fn main() { unwrap_option(); + unwrap_result(); } diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 00d7f186fc4..c5e3cd1657b 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -1,27 +1,51 @@ error: used `unwrap()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:5:15 + --> $DIR/unnecessary_literal_unwrap.rs:5:16 | -LL | let val = Some(1).unwrap(); - | ^^^^^^^^^^^^^^^^ +LL | let _val = Some(1).unwrap(); + | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` help: remove the `Some` and `unwrap()` | -LL - let val = Some(1).unwrap(); -LL + let val = 1; +LL - let _val = Some(1).unwrap(); +LL + let _val = 1; | error: used `expect()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:6:15 + --> $DIR/unnecessary_literal_unwrap.rs:6:16 | -LL | let val = Some(1).expect("this never happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Some(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `expect()` | -LL - let val = Some(1).expect("this never happens"); -LL + let val = 1; +LL - let _val = Some(1).expect("this never happens"); +LL + let _val = 1; | -error: aborting due to 2 previous errors +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:10:16 + | +LL | let _val = Ok::(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + | +LL - let _val = Ok::(1).unwrap(); +LL + let _val = 1; + | + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:11:16 + | +LL | let _val = Ok::(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + | +LL - let _val = Ok::(1).expect("this never happens"); +LL + let _val = 1; + | + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 8f83502989f8723377082c52c3aa5c086d5fd3f2 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 14:43:41 +0000 Subject: Recognize `unwrap_or` methods --- clippy_lints/src/methods/mod.rs | 36 ++++++++------- .../src/methods/unnecessary_literal_unwrap.rs | 54 +++++++++++----------- tests/ui/unnecessary_literal_unwrap.fixed | 12 +++++ tests/ui/unnecessary_literal_unwrap.rs | 12 +++++ tests/ui/unnecessary_literal_unwrap.stderr | 50 +++++++++++++++++++- 5 files changed, 120 insertions(+), 44 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a5c55a42ea5..5e42123a8da 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3664,9 +3664,7 @@ impl Methods { 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), } - if let ExprKind::Call(recv, [arg]) = recv.kind { - unnecessary_literal_unwrap::check(cx, expr, recv, arg, name); - } + unnecessary_literal_unwrap::check(cx, expr, recv, name); }, ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), ("extend", [arg]) => { @@ -3873,24 +3871,28 @@ impl Methods { }, _ => {}, } - if let ExprKind::Call(recv, [arg]) = recv.kind { - unnecessary_literal_unwrap::check(cx, expr, recv, arg, name); - } + unnecessary_literal_unwrap::check(cx, expr, recv, name); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, ("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], _, _)) => { - manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); - }, - 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], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); - }, - _ => {}, + ("unwrap_or", [u_arg]) => { + match method_call(recv) { + 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, _)) => { + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); + }, + Some(("then_some", t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); + }, + _ => {}, + } + unnecessary_literal_unwrap::check(cx, expr, recv, name); }, + ("unwrap_or_default", []) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name); + } ("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) => {}, diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 0c8a70fedb9..9a9c659b232 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -5,33 +5,35 @@ use rustc_lint::LateContext; use super::UNNECESSARY_LITERAL_UNWRAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, name: &str) { - let mess = if is_res_lang_ctor(cx, path_res(cx, recv), hir::LangItem::OptionSome) { - Some("Some") - } else if is_res_lang_ctor(cx, path_res(cx, recv), hir::LangItem::ResultOk) { - Some("Ok") - } else { - None - }; +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, name: &str) { + if let hir::ExprKind::Call(call, [arg]) = recv.kind { + let mess = if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { + Some("Some") + } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) { + Some("Ok") + } else { + None + }; - if let Some(constructor) = mess { - span_lint_and_then( - cx, - UNNECESSARY_LITERAL_UNWRAP, - expr.span, - &format!("used `{name}()` on `{constructor}` value"), - |diag| { - let suggestions = vec![ - (recv.span.with_hi(arg.span.lo()), String::new()), - (expr.span.with_lo(arg.span.hi()), String::new()), - ]; + if let Some(constructor) = mess { + span_lint_and_then( + cx, + UNNECESSARY_LITERAL_UNWRAP, + expr.span, + &format!("used `{name}()` on `{constructor}` value"), + |diag| { + let suggestions = vec![ + (call.span.with_hi(arg.span.lo()), String::new()), + (expr.span.with_lo(arg.span.hi()), String::new()), + ]; - diag.multipart_suggestion( - format!("remove the `{constructor}` and `{name}()`"), - suggestions, - Applicability::MachineApplicable, - ); - }, - ); + diag.multipart_suggestion( + format!("remove the `{constructor}` and `{name}()`"), + suggestions, + Applicability::MachineApplicable, + ); + }, + ); + } } } diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index b59dec7d48a..55a210bdb98 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -12,7 +12,19 @@ fn unwrap_result() { // let val = Err(1).unwrap_err(); } +fn unwrap_methods_option() { + let _val = 1; + let _val = 1; +} + +fn unwrap_methods_result() { + let _val = 1; + let _val = 1; +} + fn main() { unwrap_option(); unwrap_result(); + unwrap_methods_option(); + unwrap_methods_result(); } diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index c46204f7a99..80f72ce3cf2 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -12,7 +12,19 @@ fn unwrap_result() { // let val = Err(1).unwrap_err(); } +fn unwrap_methods_option() { + let _val = Some(1).unwrap_or(2); + let _val = Some(1).unwrap_or_default(); +} + +fn unwrap_methods_result() { + let _val = Ok::(1).unwrap_or(2); + let _val = Ok::(1).unwrap_or_default(); +} + fn main() { unwrap_option(); unwrap_result(); + unwrap_methods_option(); + unwrap_methods_result(); } diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index c5e3cd1657b..b8b5a612da1 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -47,5 +47,53 @@ LL - let _val = Ok::(1).expect("this never happens"); LL + let _val = 1; | -error: aborting due to 4 previous errors +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:16:16 + | +LL | let _val = Some(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + | +LL - let _val = Some(1).unwrap_or(2); +LL + let _val = 1; + | + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:17:16 + | +LL | let _val = Some(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + | +LL - let _val = Some(1).unwrap_or_default(); +LL + let _val = 1; + | + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:21:16 + | +LL | let _val = Ok::(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + | +LL - let _val = Ok::(1).unwrap_or(2); +LL + let _val = 1; + | + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:22:16 + | +LL | let _val = Ok::(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + | +LL - let _val = Ok::(1).unwrap_or_default(); +LL + let _val = 1; + | + +error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 7ed7283e0f9de697f8d5c8c2118c4b0b8bc7d6b0 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 15:05:56 +0000 Subject: Recognize `unwrap_or_else` method --- CHANGELOG.md | 1 + clippy_lints/src/methods/mod.rs | 17 +++++++----- tests/ui/unnecessary_literal_unwrap.fixed | 3 +++ tests/ui/unnecessary_literal_unwrap.rs | 3 +++ tests/ui/unnecessary_literal_unwrap.stderr | 42 +++++++++++++++++++++++------- 5 files changed, 50 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 85fddc97047..abc35e8546f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5248,6 +5248,7 @@ Released 2018-09-13 [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations +[`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5e42123a8da..4686adda683 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3893,13 +3893,16 @@ impl Methods { ("unwrap_or_default", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name); } - ("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) => {}, - _ => { - unwrap_or_else_default::check(cx, expr, recv, u_arg); - unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); - }, + ("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) => {}, + _ => { + unwrap_or_else_default::check(cx, expr, recv, u_arg); + unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); + }, + } + unnecessary_literal_unwrap::check(cx, expr, recv, name); }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 55a210bdb98..a388a7f83d2 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -1,5 +1,6 @@ //run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unnecessary_lazy_evaluations)] fn unwrap_option() { let _val = 1; @@ -15,11 +16,13 @@ fn unwrap_result() { fn unwrap_methods_option() { let _val = 1; let _val = 1; + let _val = 1; } fn unwrap_methods_result() { let _val = 1; let _val = 1; + let _val = 1; } fn main() { diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 80f72ce3cf2..fe557957dd9 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -1,5 +1,6 @@ //run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unnecessary_lazy_evaluations)] fn unwrap_option() { let _val = Some(1).unwrap(); @@ -15,11 +16,13 @@ fn unwrap_result() { fn unwrap_methods_option() { let _val = Some(1).unwrap_or(2); let _val = Some(1).unwrap_or_default(); + let _val = Some(1).unwrap_or_else(|| _val); } fn unwrap_methods_result() { let _val = Ok::(1).unwrap_or(2); let _val = Ok::(1).unwrap_or_default(); + let _val = Ok::(1).unwrap_or_else(|()| _val); } fn main() { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index b8b5a612da1..60499fe700b 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:5:16 + --> $DIR/unnecessary_literal_unwrap.rs:6:16 | LL | let _val = Some(1).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + let _val = 1; | error: used `expect()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:6:16 + --> $DIR/unnecessary_literal_unwrap.rs:7:16 | LL | let _val = Some(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + let _val = 1; | error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:10:16 + --> $DIR/unnecessary_literal_unwrap.rs:11:16 | LL | let _val = Ok::(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + let _val = 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:11:16 + --> $DIR/unnecessary_literal_unwrap.rs:12:16 | LL | let _val = Ok::(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:16:16 + --> $DIR/unnecessary_literal_unwrap.rs:17:16 | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:17:16 + --> $DIR/unnecessary_literal_unwrap.rs:18:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,8 +71,20 @@ LL - let _val = Some(1).unwrap_or_default(); LL + let _val = 1; | +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:19:16 + | +LL | let _val = Some(1).unwrap_or_else(|| _val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + | +LL - let _val = Some(1).unwrap_or_else(|| _val); +LL + let _val = 1; + | + error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:21:16 + --> $DIR/unnecessary_literal_unwrap.rs:23:16 | LL | let _val = Ok::(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +96,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:22:16 + --> $DIR/unnecessary_literal_unwrap.rs:24:16 | LL | let _val = Ok::(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,5 +107,17 @@ LL - let _val = Ok::(1).unwrap_or_default(); LL + let _val = 1; | -error: aborting due to 8 previous errors +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:25:16 + | +LL | let _val = Ok::(1).unwrap_or_else(|()| _val); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + | +LL - let _val = Ok::(1).unwrap_or_else(|()| _val); +LL + let _val = 1; + | + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 6e0e09c8f7622caa6ea6536f2bbc5c033a9cffa2 Mon Sep 17 00:00:00 2001 From: rsdy Date: Thu, 16 Feb 2023 15:30:09 +0000 Subject: Track init and unwrap of expr --- .../src/methods/unnecessary_literal_unwrap.rs | 22 +++++++++++++++++++--- tests/ui/unnecessary_literal_unwrap_unfixable.rs | 6 ++++++ .../ui/unnecessary_literal_unwrap_unfixable.stderr | 15 +++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 tests/ui/unnecessary_literal_unwrap_unfixable.rs create mode 100644 tests/ui/unnecessary_literal_unwrap_unfixable.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 9a9c659b232..54160a27cb2 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -6,7 +6,9 @@ use rustc_lint::LateContext; use super::UNNECESSARY_LITERAL_UNWRAP; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, name: &str) { - if let hir::ExprKind::Call(call, [arg]) = recv.kind { + let init = clippy_utils::expr_or_init(cx, recv); + + if let hir::ExprKind::Call(call, [arg]) = init.kind { let mess = if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { Some("Some") } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) { @@ -15,7 +17,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr None }; - if let Some(constructor) = mess { + let Some(constructor) = mess else { + return; + }; + + if init.span == recv.span { span_lint_and_then( cx, UNNECESSARY_LITERAL_UNWRAP, @@ -23,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr &format!("used `{name}()` on `{constructor}` value"), |diag| { let suggestions = vec![ - (call.span.with_hi(arg.span.lo()), String::new()), + (recv.span.with_hi(arg.span.lo()), String::new()), (expr.span.with_lo(arg.span.hi()), String::new()), ]; @@ -34,6 +40,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr ); }, ); + } else { + span_lint_and_then( + cx, + UNNECESSARY_LITERAL_UNWRAP, + expr.span, + &format!("used `{name}()` on `{constructor}` value"), + |diag| { + diag.span_help(init.span, format!("remove the `{constructor}` and `{name}()`")); + }, + ); } } } diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/tests/ui/unnecessary_literal_unwrap_unfixable.rs new file mode 100644 index 00000000000..ac3a84934af --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.rs @@ -0,0 +1,6 @@ +#![warn(clippy::unnecessary_literal_unwrap)] + +fn main() { + let val = Some(1); + let _val2 = val.unwrap(); +} diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr new file mode 100644 index 00000000000..abc789ccda4 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr @@ -0,0 +1,15 @@ +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:5:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:4:15 + | +LL | let val = Some(1); + | ^^^^^^^ + = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 69af0e13b2662807ba51ffc3a9fe4a9576e100e2 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 17:15:19 +0000 Subject: Recognize `Err` --- clippy_lints/src/methods/mod.rs | 10 ++++-- .../src/methods/unnecessary_literal_unwrap.rs | 14 ++++---- tests/ui/unnecessary_literal_unwrap.fixed | 11 +++++-- tests/ui/unnecessary_literal_unwrap.rs | 11 +++++-- tests/ui/unnecessary_literal_unwrap.stderr | 38 ++++++++++++++++++---- 5 files changed, 61 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4686adda683..66789e6137a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3666,7 +3666,10 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name); }, - ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), + ("expect_err", [_]) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name); + expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests); + }, ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); @@ -3874,7 +3877,10 @@ impl Methods { unnecessary_literal_unwrap::check(cx, expr, recv, name); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, - ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), + ("unwrap_err", []) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name); + 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], _, _)) => { diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 54160a27cb2..56d3c16a5d2 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -9,18 +9,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let init = clippy_utils::expr_or_init(cx, recv); if let hir::ExprKind::Call(call, [arg]) = init.kind { - let mess = if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { - Some("Some") + let constructor = if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { + "Some" } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) { - Some("Ok") + "Ok" + } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultErr) { + "Err" } else { - None + return; }; - let Some(constructor) = mess else { - return; - }; - if init.span == recv.span { span_lint_and_then( cx, diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index a388a7f83d2..9733993d619 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -7,10 +7,14 @@ fn unwrap_option() { let _val = 1; } -fn unwrap_result() { +fn unwrap_result_ok() { + let _val = 1; + let _val = 1; +} + +fn unwrap_result_err() { let _val = 1; let _val = 1; - // let val = Err(1).unwrap_err(); } fn unwrap_methods_option() { @@ -27,7 +31,8 @@ fn unwrap_methods_result() { fn main() { unwrap_option(); - unwrap_result(); + unwrap_result_ok(); + unwrap_result_err(); unwrap_methods_option(); unwrap_methods_result(); } diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index fe557957dd9..775d744c13e 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -7,10 +7,14 @@ fn unwrap_option() { let _val = Some(1).expect("this never happens"); } -fn unwrap_result() { +fn unwrap_result_ok() { let _val = Ok::(1).unwrap(); let _val = Ok::(1).expect("this never happens"); - // let val = Err(1).unwrap_err(); +} + +fn unwrap_result_err() { + let _val = Err::<(), usize>(1).unwrap_err(); + let _val = Err::<(), usize>(1).expect_err("this never happens"); } fn unwrap_methods_option() { @@ -27,7 +31,8 @@ fn unwrap_methods_result() { fn main() { unwrap_option(); - unwrap_result(); + unwrap_result_ok(); + unwrap_result_err(); unwrap_methods_option(); unwrap_methods_result(); } diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 60499fe700b..622743f8c85 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -47,9 +47,33 @@ LL - let _val = Ok::(1).expect("this never happens"); LL + let _val = 1; | -error: used `unwrap_or()` on `Some` value +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:16:16 + | +LL | let _val = Err::<(), usize>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + | +LL - let _val = Err::<(), usize>(1).unwrap_err(); +LL + let _val = 1; + | + +error: used `expect_err()` on `Err` value --> $DIR/unnecessary_literal_unwrap.rs:17:16 | +LL | let _val = Err::<(), usize>(1).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + | +LL - let _val = Err::<(), usize>(1).expect_err("this never happens"); +LL + let _val = 1; + | + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:21:16 + | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ | @@ -60,7 +84,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:18:16 + --> $DIR/unnecessary_literal_unwrap.rs:22:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +96,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:19:16 + --> $DIR/unnecessary_literal_unwrap.rs:23:16 | LL | let _val = Some(1).unwrap_or_else(|| _val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +108,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:23:16 + --> $DIR/unnecessary_literal_unwrap.rs:27:16 | LL | let _val = Ok::(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +120,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:24:16 + --> $DIR/unnecessary_literal_unwrap.rs:28:16 | LL | let _val = Ok::(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +132,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:25:16 + --> $DIR/unnecessary_literal_unwrap.rs:29:16 | LL | let _val = Ok::(1).unwrap_or_else(|()| _val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,5 +143,5 @@ LL - let _val = Ok::(1).unwrap_or_else(|()| _val); LL + let _val = 1; | -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors -- cgit 1.4.1-3-g733a5 From 6e4dc93e24866018f2567a7a0baa1955a4c7d868 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 16 Feb 2023 22:31:52 +0000 Subject: Support suggesting panics --- clippy_lints/src/methods/mod.rs | 16 ++-- .../src/methods/unnecessary_literal_unwrap.rs | 91 +++++++++++++--------- tests/ui/unnecessary_literal_unwrap.fixed | 15 +++- tests/ui/unnecessary_literal_unwrap.rs | 15 +++- tests/ui/unnecessary_literal_unwrap.stderr | 87 +++++++++++++++++---- 5 files changed, 163 insertions(+), 61 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 66789e6137a..912cce39e2e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3664,10 +3664,10 @@ impl Methods { 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), } - unnecessary_literal_unwrap::check(cx, expr, recv, name); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("expect_err", [_]) => { - unnecessary_literal_unwrap::check(cx, expr, recv, name); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests); }, ("extend", [arg]) => { @@ -3874,12 +3874,12 @@ impl Methods { }, _ => {}, } - unnecessary_literal_unwrap::check(cx, expr, recv, name); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, ("unwrap_err", []) => { - unnecessary_literal_unwrap::check(cx, expr, recv, name); - unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests) + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests); }, ("unwrap_or", [u_arg]) => { match method_call(recv) { @@ -3894,10 +3894,10 @@ impl Methods { }, _ => {}, } - unnecessary_literal_unwrap::check(cx, expr, recv, name); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("unwrap_or_default", []) => { - unnecessary_literal_unwrap::check(cx, expr, recv, name); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); } ("unwrap_or_else", [u_arg]) => { match method_call(recv) { @@ -3908,7 +3908,7 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); }, } - unnecessary_literal_unwrap::check(cx, expr, recv, name); + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 56d3c16a5d2..fe6b86b34f5 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -5,49 +5,68 @@ use rustc_lint::LateContext; use super::UNNECESSARY_LITERAL_UNWRAP; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, name: &str) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + method: &str, + args: &[hir::Expr<'_>], +) { let init = clippy_utils::expr_or_init(cx, recv); - if let hir::ExprKind::Call(call, [arg]) = init.kind { - let constructor = if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { - "Some" + let (constructor, call_args) = if let hir::ExprKind::Call(call, call_args) = init.kind { + if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { + ("Some", call_args) } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) { - "Ok" + ("Ok", call_args) } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultErr) { - "Err" + ("Err", call_args) } else { return; - }; + } + } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) { + let call_args: &[hir::Expr<'_>] = &[]; + ("None", call_args) + } else { + return; + }; - if init.span == recv.span { - span_lint_and_then( - cx, - UNNECESSARY_LITERAL_UNWRAP, - expr.span, - &format!("used `{name}()` on `{constructor}` value"), - |diag| { - let suggestions = vec![ - (recv.span.with_hi(arg.span.lo()), String::new()), - (expr.span.with_lo(arg.span.hi()), String::new()), - ]; + let help_message = format!("used `{method}()` on `{constructor}` value"); + let suggestion_message = format!("remove the `{constructor}` and `{method}()`"); - diag.multipart_suggestion( - format!("remove the `{constructor}` and `{name}()`"), - suggestions, - Applicability::MachineApplicable, - ); - }, - ); - } else { - span_lint_and_then( - cx, - UNNECESSARY_LITERAL_UNWRAP, - expr.span, - &format!("used `{name}()` on `{constructor}` value"), - |diag| { - diag.span_help(init.span, format!("remove the `{constructor}` and `{name}()`")); - }, - ); - } + if init.span == recv.span { + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + let suggestions = match (constructor, method) { + ("None", "unwrap") => vec![(expr.span, "panic!()".to_string())], + ("None", "expect") => vec![ + (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), + (expr.span.with_lo(args[0].span.hi()), ")".to_string()), + ], + ("Ok", "unwrap_err") | ("Err", "unwrap") => vec![ + ( + recv.span.with_hi(call_args[0].span.lo()), + "panic!(\"{:?}\", ".to_string(), + ), + (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), + ], + ("Ok", "expect_err") | ("Err", "expect") => vec![ + ( + recv.span.with_hi(call_args[0].span.lo()), + "panic!(\"{1}: {:?}\", ".to_string(), + ), + (call_args[0].span.with_lo(args[0].span.lo()), ", ".to_string()), + ], + _ => vec![ + (recv.span.with_hi(call_args[0].span.lo()), String::new()), + (expr.span.with_lo(call_args[0].span.hi()), String::new()), + ], + }; + + diag.multipart_suggestion(suggestion_message, suggestions, Applicability::MachineApplicable); + }); + } else { + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + diag.span_help(init.span, suggestion_message); + }); } } diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 9733993d619..d622c984c52 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -1,20 +1,30 @@ //run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] #![allow(clippy::unnecessary_lazy_evaluations)] +#![allow(unreachable_code)] -fn unwrap_option() { +fn unwrap_option_some() { let _val = 1; let _val = 1; } +fn unwrap_option_none() { + panic!(); + panic!("this always happens"); +} + fn unwrap_result_ok() { let _val = 1; let _val = 1; + panic!("{:?}", 1); + panic!("{1}: {:?}", 1, "this always happens"); } fn unwrap_result_err() { let _val = 1; let _val = 1; + panic!("{:?}", 1); + panic!("{1}: {:?}", 1, "this always happens"); } fn unwrap_methods_option() { @@ -30,7 +40,8 @@ fn unwrap_methods_result() { } fn main() { - unwrap_option(); + unwrap_option_some(); + unwrap_option_none(); unwrap_result_ok(); unwrap_result_err(); unwrap_methods_option(); diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 775d744c13e..926265a3471 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -1,20 +1,30 @@ //run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] #![allow(clippy::unnecessary_lazy_evaluations)] +#![allow(unreachable_code)] -fn unwrap_option() { +fn unwrap_option_some() { let _val = Some(1).unwrap(); let _val = Some(1).expect("this never happens"); } +fn unwrap_option_none() { + None::.unwrap(); + None::.expect("this always happens"); +} + fn unwrap_result_ok() { let _val = Ok::(1).unwrap(); let _val = Ok::(1).expect("this never happens"); + Ok::(1).unwrap_err(); + Ok::(1).expect_err("this always happens"); } fn unwrap_result_err() { let _val = Err::<(), usize>(1).unwrap_err(); let _val = Err::<(), usize>(1).expect_err("this never happens"); + Err::<(), usize>(1).unwrap(); + Err::<(), usize>(1).expect("this always happens"); } fn unwrap_methods_option() { @@ -30,7 +40,8 @@ fn unwrap_methods_result() { } fn main() { - unwrap_option(); + unwrap_option_some(); + unwrap_option_none(); unwrap_result_ok(); unwrap_result_err(); unwrap_methods_option(); diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 622743f8c85..1d23bb22bdd 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:6:16 + --> $DIR/unnecessary_literal_unwrap.rs:7:16 | LL | let _val = Some(1).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + let _val = 1; | error: used `expect()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:7:16 + --> $DIR/unnecessary_literal_unwrap.rs:8:16 | LL | let _val = Some(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,8 +23,25 @@ LL - let _val = Some(1).expect("this never happens"); LL + let _val = 1; | +error: used `unwrap()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:12:5 + | +LL | None::.unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` + +error: used `expect()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:13:5 + | +LL | None::.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `expect()` + | +LL | panic!("this always happens"); + | ~~~~~~~ ~ + error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:11:16 + --> $DIR/unnecessary_literal_unwrap.rs:17:16 | LL | let _val = Ok::(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +53,7 @@ LL + let _val = 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:12:16 + --> $DIR/unnecessary_literal_unwrap.rs:18:16 | LL | let _val = Ok::(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,8 +64,30 @@ LL - let _val = Ok::(1).expect("this never happens"); LL + let _val = 1; | +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:19:5 + | +LL | Ok::(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + | +LL | panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:20:5 + | +LL | Ok::(1).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + | +LL | panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:16:16 + --> $DIR/unnecessary_literal_unwrap.rs:24:16 | LL | let _val = Err::<(), usize>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +99,7 @@ LL + let _val = 1; | error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:17:16 + --> $DIR/unnecessary_literal_unwrap.rs:25:16 | LL | let _val = Err::<(), usize>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,8 +110,30 @@ LL - let _val = Err::<(), usize>(1).expect_err("this never happens"); LL + let _val = 1; | +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:26:5 + | +LL | Err::<(), usize>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + | +LL | panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:27:5 + | +LL | Err::<(), usize>(1).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + | +LL | panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:21:16 + --> $DIR/unnecessary_literal_unwrap.rs:31:16 | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +145,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:22:16 + --> $DIR/unnecessary_literal_unwrap.rs:32:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +157,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:23:16 + --> $DIR/unnecessary_literal_unwrap.rs:33:16 | LL | let _val = Some(1).unwrap_or_else(|| _val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +169,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:27:16 + --> $DIR/unnecessary_literal_unwrap.rs:37:16 | LL | let _val = Ok::(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +181,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:28:16 + --> $DIR/unnecessary_literal_unwrap.rs:38:16 | LL | let _val = Ok::(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +193,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:29:16 + --> $DIR/unnecessary_literal_unwrap.rs:39:16 | LL | let _val = Ok::(1).unwrap_or_else(|()| _val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,5 +204,5 @@ LL - let _val = Ok::(1).unwrap_or_else(|()| _val); LL + let _val = 1; | -error: aborting due to 12 previous errors +error: aborting due to 18 previous errors -- cgit 1.4.1-3-g733a5 From 6e4c5561be566c164c7519e6e3c6772f2da17cb4 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Wed, 31 May 2023 20:09:12 +0100 Subject: Preserve type annotations when present --- clippy_lints/src/methods/mod.rs | 42 +- .../src/methods/unnecessary_literal_unwrap.rs | 109 +++-- tests/ui/unnecessary_literal_unwrap.fixed | 31 +- tests/ui/unnecessary_literal_unwrap.rs | 57 ++- tests/ui/unnecessary_literal_unwrap.stderr | 307 ++++++++++-- tests/ui/unnecessary_literal_unwrap_unfixable.rs | 84 +++- .../ui/unnecessary_literal_unwrap_unfixable.stderr | 526 ++++++++++++++++++--- 7 files changed, 932 insertions(+), 224 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 912cce39e2e..183bd582a48 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -276,52 +276,28 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. + /// Checks for `.unwrap()` related calls on `Result`s and `Option`s that are constructed. /// /// ### Why is this bad? - /// It is better to handle the `None` or `Err` case, - /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of - /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is - /// `Allow` by default. - /// - /// `result.unwrap()` will let the thread panic on `Err` values. - /// Normally, you want to implement more sophisticated error handling, - /// and propagate errors upwards with `?` operator. - /// - /// Even if you want to panic on errors, not all `Error`s implement good - /// messages on display. Therefore, it may be beneficial to look at the places - /// where they may get displayed. Activate this lint to do just that. + /// It is better to write the value directly without the indirection. /// /// ### Examples /// ```rust - /// # let option = Some(1); - /// # let result: Result = Ok(1); - /// option.unwrap(); - /// result.unwrap(); + /// let val1 = Some(1).unwrap(); + /// let val2 = Ok::<_, ()>(1).unwrap(); + /// let val3 = Err::<(), _>(1).unwrap_err(); /// ``` /// /// Use instead: /// ```rust - /// # let option = Some(1); - /// # let result: Result = Ok(1); - /// option.expect("more helpful message"); - /// result.expect("more helpful message"); - /// ``` - /// - /// If [expect_used](#expect_used) is enabled, instead: - /// ```rust,ignore - /// # let option = Some(1); - /// # let result: Result = Ok(1); - /// option?; - /// - /// // or - /// - /// result?; + /// let val1 = 1; + /// let val2 = 1; + /// let val3 = 1; /// ``` #[clippy::version = "1.69.0"] pub UNNECESSARY_LITERAL_UNWRAP, complexity, - "checks for calls of `unwrap()` or `expect()` on `Some()` that cannot fail" + "using `unwrap()` related calls on `Result` and `Option` constructors" } declare_clippy_lint! { diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index fe6b86b34f5..7877f6a386c 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,10 +1,26 @@ -use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, path_res}; +use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_segment, path_res, MaybePath}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use super::UNNECESSARY_LITERAL_UNWRAP; +fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a>> { + let args = args?; + + if args.len() <= index { + return None; + } + + match args[index] { + hir::GenericArg::Type(ty) => match ty.kind { + hir::TyKind::Infer => None, + _ => Some(ty), + }, + _ => None, + } +} + pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -14,19 +30,24 @@ pub(super) fn check( ) { let init = clippy_utils::expr_or_init(cx, recv); - let (constructor, call_args) = if let hir::ExprKind::Call(call, call_args) = init.kind { - if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { - ("Some", call_args) - } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) { - ("Ok", call_args) - } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultErr) { - ("Err", call_args) + let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind { + let Some(qpath) = call.qpath_opt() else { return }; + + let args = last_path_segment(qpath).args.map(|args| args.args); + let res = cx.qpath_res(qpath, call.hir_id()); + + if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) { + ("Some", call_args, get_ty_from_args(args, 0)) + } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) { + ("Ok", call_args, get_ty_from_args(args, 0)) + } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) { + ("Err", call_args, get_ty_from_args(args, 1)) } else { return; } } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) { let call_args: &[hir::Expr<'_>] = &[]; - ("None", call_args) + ("None", call_args, None) } else { return; }; @@ -34,39 +55,41 @@ pub(super) fn check( let help_message = format!("used `{method}()` on `{constructor}` value"); let suggestion_message = format!("remove the `{constructor}` and `{method}()`"); - if init.span == recv.span { - span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { - let suggestions = match (constructor, method) { - ("None", "unwrap") => vec![(expr.span, "panic!()".to_string())], - ("None", "expect") => vec![ - (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), - (expr.span.with_lo(args[0].span.hi()), ")".to_string()), - ], - ("Ok", "unwrap_err") | ("Err", "unwrap") => vec![ - ( - recv.span.with_hi(call_args[0].span.lo()), - "panic!(\"{:?}\", ".to_string(), - ), - (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), - ], - ("Ok", "expect_err") | ("Err", "expect") => vec![ - ( - recv.span.with_hi(call_args[0].span.lo()), - "panic!(\"{1}: {:?}\", ".to_string(), - ), - (call_args[0].span.with_lo(args[0].span.lo()), ", ".to_string()), - ], - _ => vec![ - (recv.span.with_hi(call_args[0].span.lo()), String::new()), - (expr.span.with_lo(call_args[0].span.hi()), String::new()), - ], - }; + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + let suggestions = match (constructor, method, ty) { + ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), + ("None", "expect", _) => Some(vec![ + (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), + (expr.span.with_lo(args[0].span.hi()), ")".to_string()), + ]), + (_, _, Some(_)) => None, + ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ + ( + recv.span.with_hi(call_args[0].span.lo()), + "panic!(\"{:?}\", ".to_string(), + ), + (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), + ]), + ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![ + ( + recv.span.with_hi(call_args[0].span.lo()), + "panic!(\"{1}: {:?}\", ".to_string(), + ), + (call_args[0].span.with_lo(args[0].span.lo()), ", ".to_string()), + ]), + (_, _, None) => Some(vec![ + (recv.span.with_hi(call_args[0].span.lo()), String::new()), + (expr.span.with_lo(call_args[0].span.hi()), String::new()), + ]), + }; - diag.multipart_suggestion(suggestion_message, suggestions, Applicability::MachineApplicable); - }); - } else { - span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { - diag.span_help(init.span, suggestion_message); - }); - } + match (init.span == recv.span, suggestions) { + (true, Some(suggestions)) => { + diag.multipart_suggestion(suggestion_message, suggestions, Applicability::MachineApplicable); + }, + _ => { + diag.span_help(init.span, suggestion_message); + }, + } + }); } diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 41c4dfda47f..630a1bea3c8 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -1,14 +1,25 @@ //@run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] #![allow(unreachable_code)] -#![allow(clippy::unnecessary_lazy_evaluations)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::diverging_sub_expression, + clippy::let_unit_value, + clippy::no_effect +)] fn unwrap_option_some() { let _val = 1; let _val = 1; + + 1; + 1; } fn unwrap_option_none() { + let _val = panic!(); + let _val = panic!("this always happens"); + panic!(); panic!("this always happens"); } @@ -16,6 +27,11 @@ fn unwrap_option_none() { fn unwrap_result_ok() { let _val = 1; let _val = 1; + let _val = panic!("{:?}", 1); + let _val = panic!("{1}: {:?}", 1, "this always happens"); + + 1; + 1; panic!("{:?}", 1); panic!("{1}: {:?}", 1, "this always happens"); } @@ -23,6 +39,11 @@ fn unwrap_result_ok() { fn unwrap_result_err() { let _val = 1; let _val = 1; + let _val = panic!("{:?}", 1); + let _val = panic!("{1}: {:?}", 1, "this always happens"); + + 1; + 1; panic!("{:?}", 1); panic!("{1}: {:?}", 1, "this always happens"); } @@ -31,12 +52,20 @@ fn unwrap_methods_option() { let _val = 1; let _val = 1; let _val = 1; + + 1; + 1; + 1; } fn unwrap_methods_result() { let _val = 1; let _val = 1; let _val = 1; + + 1; + 1; + 1; } fn main() { diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index f15c063fe54..14f92cb370f 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -1,42 +1,71 @@ //@run-rustfix #![warn(clippy::unnecessary_literal_unwrap)] #![allow(unreachable_code)] -#![allow(clippy::unnecessary_lazy_evaluations)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::diverging_sub_expression, + clippy::let_unit_value, + clippy::no_effect +)] fn unwrap_option_some() { let _val = Some(1).unwrap(); let _val = Some(1).expect("this never happens"); + + Some(1).unwrap(); + Some(1).expect("this never happens"); } fn unwrap_option_none() { - None::.unwrap(); - None::.expect("this always happens"); + let _val = None::<()>.unwrap(); + let _val = None::<()>.expect("this always happens"); + + None::<()>.unwrap(); + None::<()>.expect("this always happens"); } fn unwrap_result_ok() { - let _val = Ok::(1).unwrap(); - let _val = Ok::(1).expect("this never happens"); - Ok::(1).unwrap_err(); - Ok::(1).expect_err("this always happens"); + let _val = Ok::<_, ()>(1).unwrap(); + let _val = Ok::<_, ()>(1).expect("this never happens"); + let _val = Ok::<_, ()>(1).unwrap_err(); + let _val = Ok::<_, ()>(1).expect_err("this always happens"); + + Ok::<_, ()>(1).unwrap(); + Ok::<_, ()>(1).expect("this never happens"); + Ok::<_, ()>(1).unwrap_err(); + Ok::<_, ()>(1).expect_err("this always happens"); } fn unwrap_result_err() { - let _val = Err::<(), usize>(1).unwrap_err(); - let _val = Err::<(), usize>(1).expect_err("this never happens"); - Err::<(), usize>(1).unwrap(); - Err::<(), usize>(1).expect("this always happens"); + let _val = Err::<(), _>(1).unwrap_err(); + let _val = Err::<(), _>(1).expect_err("this never happens"); + let _val = Err::<(), _>(1).unwrap(); + let _val = Err::<(), _>(1).expect("this always happens"); + + Err::<(), _>(1).unwrap_err(); + Err::<(), _>(1).expect_err("this never happens"); + Err::<(), _>(1).unwrap(); + Err::<(), _>(1).expect("this always happens"); } fn unwrap_methods_option() { let _val = Some(1).unwrap_or(2); let _val = Some(1).unwrap_or_default(); let _val = Some(1).unwrap_or_else(|| 2); + + Some(1).unwrap_or(2); + Some(1).unwrap_or_default(); + Some(1).unwrap_or_else(|| 2); } fn unwrap_methods_result() { - let _val = Ok::(1).unwrap_or(2); - let _val = Ok::(1).unwrap_or_default(); - let _val = Ok::(1).unwrap_or_else(|_| 2); + let _val = Ok::<_, ()>(1).unwrap_or(2); + let _val = Ok::<_, ()>(1).unwrap_or_default(); + let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); + + Ok::<_, ()>(1).unwrap_or(2); + Ok::<_, ()>(1).unwrap_or_default(); + Ok::<_, ()>(1).unwrap_or_else(|_| 2); } fn main() { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index cf057d7fe5a..0c71ee05323 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:7:16 + --> $DIR/unnecessary_literal_unwrap.rs:12:16 | LL | let _val = Some(1).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + let _val = 1; | error: used `expect()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:8:16 + --> $DIR/unnecessary_literal_unwrap.rs:13:16 | LL | let _val = Some(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,17 +23,58 @@ LL - let _val = Some(1).expect("this never happens"); LL + let _val = 1; | +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:15:5 + | +LL | Some(1).unwrap(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + | +LL - Some(1).unwrap(); +LL + 1; + | + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:16:5 + | +LL | Some(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + | +LL - Some(1).expect("this never happens"); +LL + 1; + | + error: used `unwrap()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:12:5 + --> $DIR/unnecessary_literal_unwrap.rs:20:16 | -LL | None::.unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` +LL | let _val = None::<()>.unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` error: used `expect()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:13:5 + --> $DIR/unnecessary_literal_unwrap.rs:21:16 | -LL | None::.expect("this always happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = None::<()>.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `expect()` + | +LL | let _val = panic!("this always happens"); + | ~~~~~~~ ~ + +error: used `unwrap()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:23:5 + | +LL | None::<()>.unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` + +error: used `expect()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:24:5 + | +LL | None::<()>.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `None` and `expect()` | @@ -41,34 +82,80 @@ LL | panic!("this always happens"); | ~~~~~~~ ~ error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:17:16 + --> $DIR/unnecessary_literal_unwrap.rs:28:16 | -LL | let _val = Ok::(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::<_, ()>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` | -LL - let _val = Ok::(1).unwrap(); +LL - let _val = Ok::<_, ()>(1).unwrap(); LL + let _val = 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:18:16 + --> $DIR/unnecessary_literal_unwrap.rs:29:16 | -LL | let _val = Ok::(1).expect("this never happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::<_, ()>(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` | -LL - let _val = Ok::(1).expect("this never happens"); +LL - let _val = Ok::<_, ()>(1).expect("this never happens"); LL + let _val = 1; | error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:19:5 + --> $DIR/unnecessary_literal_unwrap.rs:30:16 | -LL | Ok::(1).unwrap_err(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::<_, ()>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + | +LL | let _val = panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:31:16 + | +LL | let _val = Ok::<_, ()>(1).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + | +LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:33:5 + | +LL | Ok::<_, ()>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + | +LL - Ok::<_, ()>(1).unwrap(); +LL + 1; + | + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:34:5 + | +LL | Ok::<_, ()>(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + | +LL - Ok::<_, ()>(1).expect("this never happens"); +LL + 1; + | + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:35:5 + | +LL | Ok::<_, ()>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` | @@ -76,10 +163,10 @@ LL | panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:20:5 + --> $DIR/unnecessary_literal_unwrap.rs:36:5 | -LL | Ok::(1).expect_err("this always happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Ok::<_, ()>(1).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` | @@ -87,45 +174,91 @@ LL | panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:24:16 + --> $DIR/unnecessary_literal_unwrap.rs:40:16 | -LL | let _val = Err::<(), usize>(1).unwrap_err(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Err::<(), _>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` | -LL - let _val = Err::<(), usize>(1).unwrap_err(); +LL - let _val = Err::<(), _>(1).unwrap_err(); LL + let _val = 1; | error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:25:16 + --> $DIR/unnecessary_literal_unwrap.rs:41:16 | -LL | let _val = Err::<(), usize>(1).expect_err("this never happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Err::<(), _>(1).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` | -LL - let _val = Err::<(), usize>(1).expect_err("this never happens"); +LL - let _val = Err::<(), _>(1).expect_err("this never happens"); LL + let _val = 1; | error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:26:5 + --> $DIR/unnecessary_literal_unwrap.rs:42:16 + | +LL | let _val = Err::<(), _>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + | +LL | let _val = panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:43:16 + | +LL | let _val = Err::<(), _>(1).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` | -LL | Err::<(), usize>(1).unwrap(); +LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:45:5 + | +LL | Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +help: remove the `Err` and `unwrap_err()` + | +LL - Err::<(), _>(1).unwrap_err(); +LL + 1; + | + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:46:5 + | +LL | Err::<(), _>(1).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + | +LL - Err::<(), _>(1).expect_err("this never happens"); +LL + 1; + | + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:47:5 + | +LL | Err::<(), _>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | help: remove the `Err` and `unwrap()` | LL | panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:27:5 + --> $DIR/unnecessary_literal_unwrap.rs:48:5 | -LL | Err::<(), usize>(1).expect("this always happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Err::<(), _>(1).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` | @@ -133,7 +266,7 @@ LL | panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:31:16 + --> $DIR/unnecessary_literal_unwrap.rs:52:16 | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +278,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:32:16 + --> $DIR/unnecessary_literal_unwrap.rs:53:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +290,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:33:16 + --> $DIR/unnecessary_literal_unwrap.rs:54:16 | LL | let _val = Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,41 +301,113 @@ LL - let _val = Some(1).unwrap_or_else(|| 2); LL + let _val = 1; | +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:56:5 + | +LL | Some(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + | +LL - Some(1).unwrap_or(2); +LL + 1; + | + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:57:5 + | +LL | Some(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + | +LL - Some(1).unwrap_or_default(); +LL + 1; + | + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:58:5 + | +LL | Some(1).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + | +LL - Some(1).unwrap_or_else(|| 2); +LL + 1; + | + error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:37:16 + --> $DIR/unnecessary_literal_unwrap.rs:62:16 | -LL | let _val = Ok::(1).unwrap_or(2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::<_, ()>(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` | -LL - let _val = Ok::(1).unwrap_or(2); +LL - let _val = Ok::<_, ()>(1).unwrap_or(2); LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:38:16 + --> $DIR/unnecessary_literal_unwrap.rs:63:16 | -LL | let _val = Ok::(1).unwrap_or_default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::<_, ()>(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` | -LL - let _val = Ok::(1).unwrap_or_default(); +LL - let _val = Ok::<_, ()>(1).unwrap_or_default(); LL + let _val = 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:39:16 + --> $DIR/unnecessary_literal_unwrap.rs:64:16 | -LL | let _val = Ok::(1).unwrap_or_else(|_| 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` | -LL - let _val = Ok::(1).unwrap_or_else(|_| 2); +LL - let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); LL + let _val = 1; | -error: aborting due to 18 previous errors +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:66:5 + | +LL | Ok::<_, ()>(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + | +LL - Ok::<_, ()>(1).unwrap_or(2); +LL + 1; + | + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:67:5 + | +LL | Ok::<_, ()>(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + | +LL - Ok::<_, ()>(1).unwrap_or_default(); +LL + 1; + | + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:68:5 + | +LL | Ok::<_, ()>(1).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + | +LL - Ok::<_, ()>(1).unwrap_or_else(|_| 2); +LL + 1; + | + +error: aborting due to 36 previous errors diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/tests/ui/unnecessary_literal_unwrap_unfixable.rs index 9ccf6b21447..711fdce3962 100644 --- a/tests/ui/unnecessary_literal_unwrap_unfixable.rs +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.rs @@ -1,6 +1,6 @@ #![warn(clippy::unnecessary_literal_unwrap)] -#![allow(clippy::unnecessary_lazy_evaluations)] #![allow(unreachable_code)] +#![allow(clippy::unnecessary_lazy_evaluations, clippy::let_unit_value)] fn unwrap_option_some() { let val = Some(1); @@ -8,26 +8,61 @@ fn unwrap_option_some() { let _val2 = val.expect("this never happens"); } +fn unwrap_option_some_context() { + let _val = Some::([1, 2, 3].iter().sum()).unwrap(); + let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); + + let val = Some::([1, 2, 3].iter().sum()); + let _val2 = val.unwrap(); + let _val2 = val.expect("this never happens"); +} + fn unwrap_option_none() { - let val = None::; - val.unwrap(); - val.expect("this always happens"); + let val = None::<()>; + let _val2 = val.unwrap(); + let _val2 = val.expect("this always happens"); } fn unwrap_result_ok() { - let val = Ok::(1); + let val = Ok::<_, ()>(1); + let _val2 = val.unwrap(); + let _val2 = val.expect("this never happens"); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this always happens"); +} + +fn unwrap_result_ok_context() { + let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); + let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); + let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); + + let val = Ok::([1, 2, 3].iter().sum()); let _val2 = val.unwrap(); let _val2 = val.expect("this never happens"); - val.unwrap_err(); - val.expect_err("this always happens"); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this always happens"); } fn unwrap_result_err() { - let val = Err::<(), usize>(1); + let val = Err::<(), _>(1); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this never happens"); + let _val2 = val.unwrap(); + let _val2 = val.expect("this always happens"); +} + +fn unwrap_result_err_context() { + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); + + let val = Err::<(), usize>([1, 2, 3].iter().sum()); let _val2 = val.unwrap_err(); let _val2 = val.expect_err("this never happens"); - val.unwrap(); - val.expect("this always happens"); + let _val2 = val.unwrap(); + let _val2 = val.expect("this always happens"); } fn unwrap_methods_option() { @@ -37,8 +72,30 @@ fn unwrap_methods_option() { let _val2 = val.unwrap_or_else(|| 2); } +fn unwrap_methods_option_context() { + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); + + let val = Some::([1, 2, 3].iter().sum()); + let _val2 = val.unwrap_or(2); + let _val2 = val.unwrap_or_default(); + let _val2 = val.unwrap_or_else(|| 2); +} + fn unwrap_methods_result() { - let val = Ok::(1); + let val = Ok::<_, ()>(1); + let _val2 = val.unwrap_or(2); + let _val2 = val.unwrap_or_default(); + let _val2 = val.unwrap_or_else(|_| 2); +} + +fn unwrap_methods_result_context() { + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); + + let val = Ok::([1, 2, 3].iter().sum()); let _val2 = val.unwrap_or(2); let _val2 = val.unwrap_or_default(); let _val2 = val.unwrap_or_else(|_| 2); @@ -46,9 +103,14 @@ fn unwrap_methods_result() { fn main() { unwrap_option_some(); + unwrap_option_some_context(); unwrap_option_none(); unwrap_result_ok(); + unwrap_result_ok_context(); unwrap_result_err(); + unwrap_result_err_context(); unwrap_methods_option(); + unwrap_methods_option_context(); unwrap_methods_result(); + unwrap_methods_result_context(); } diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr index 7931deeca7f..feb9325b77a 100644 --- a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr @@ -23,197 +23,581 @@ help: remove the `Some` and `expect()` LL | let val = Some(1); | ^^^^^^^ +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:12:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:12:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:13:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:13:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:16:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:15:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:17:17 + | +LL | let _val2 = val.expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:15:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: used `unwrap()` on `None` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:13:5 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:22:17 | -LL | val.unwrap(); - | ^^^^^^^^^^^^ +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ | help: remove the `None` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:12:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:21:15 | -LL | let val = None::; - | ^^^^^^^^^^^^^ +LL | let val = None::<()>; + | ^^^^^^^^^^ error: used `expect()` on `None` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:14:5 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:23:17 | -LL | val.expect("this always happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val2 = val.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `None` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:12:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:21:15 | -LL | let val = None::; - | ^^^^^^^^^^^^^ +LL | let val = None::<()>; + | ^^^^^^^^^^ error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:19:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:18:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:20:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:18:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:21:5 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17 | -LL | val.unwrap_err(); - | ^^^^^^^^^^^^^^^^ +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:18:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:22:5 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17 | -LL | val.expect_err("this always happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val2 = val.expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:18:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17 + | +LL | let _val2 = val.expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17 + | +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17 + | +LL | let _val2 = val.expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:49:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:26:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 | -LL | let val = Err::<(), usize>(1); - | ^^^^^^^^^^^^^^^^^^^ +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:17 + | +LL | let _val2 = val.expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17 + | +LL | let _val2 = val.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:62:17 + | +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + | +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:17 | LL | let _val2 = val.expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:26:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 | -LL | let val = Err::<(), usize>(1); - | ^^^^^^^^^^^^^^^^^^^ +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:5 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17 | -LL | val.unwrap(); - | ^^^^^^^^^^^^ +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:26:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 | -LL | let val = Err::<(), usize>(1); - | ^^^^^^^^^^^^^^^^^^^ +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:5 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17 | -LL | val.expect("this always happens"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _val2 = val.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:26:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 | -LL | let val = Err::<(), usize>(1); - | ^^^^^^^^^^^^^^^^^^^ +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:70:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:34:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:34:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17 | LL | let _val2 = val.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:34:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 | LL | let val = Some(1); | ^^^^^^^ +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:81:17 + | +LL | let _val2 = val.unwrap_or(2); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:17 + | +LL | let _val2 = val.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17 + | +LL | let _val2 = val.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:88:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17 + | +LL | let _val2 = val.unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:99:17 + | +LL | let _val2 = val.unwrap_or(2); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:17 + | +LL | let _val2 = val.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17 | LL | let _val2 = val.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 | -LL | let val = Ok::(1); - | ^^^^^^^^^^^^^^^^^^ +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: aborting due to 50 previous errors -- cgit 1.4.1-3-g733a5 From 69e892e3a182bedb22e20399d6ba862572be46b2 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 14 Jun 2023 22:29:57 +0200 Subject: get rid of unnecessary function pointer --- clippy_lints/src/methods/unnecessary_fold.rs | 59 ++++++++++++---------------- 1 file changed, 26 insertions(+), 33 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index de29d99cf8d..e545abd8ba8 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -12,14 +12,10 @@ use rustc_span::{source_map::Span, sym}; use super::UNNECESSARY_FOLD; -/// No turbofish needed in any case. -fn no_turbofish(_: &LateContext<'_>, _: &hir::Expr<'_>) -> bool { - false -} - -/// Turbofish (`::`) may be needed, but can be omitted if we are certain -/// that the type can be inferred from usage. -fn turbofish_if_not_inferred(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { +/// Do we need to suggest turbofish when suggesting a replacement method? +/// Changing `fold` to `sum` needs it sometimes when the return type can't be +/// inferred. This checks for some common cases where it can be safely omitted +fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { let parent = cx.tcx.hir().get_parent(expr.hir_id); // some common cases where turbofish isn't needed: @@ -53,26 +49,7 @@ fn turbofish_if_not_inferred(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool struct Replacement { method_name: &'static str, has_args: bool, - requires_turbofish: fn(&LateContext<'_>, &hir::Expr<'_>) -> bool, -} -impl Replacement { - /// `any(f)`, `all(f)` - pub fn non_generic(method_name: &'static str) -> Self { - Self { - method_name, - has_args: true, - requires_turbofish: no_turbofish, - } - } - - /// `sum::()`, `product::()` - pub fn generic(method_name: &'static str) -> Self { - Self { - method_name, - has_args: false, - requires_turbofish: turbofish_if_not_inferred, - } - } + has_generic_return: bool, } pub(super) fn check( @@ -111,7 +88,7 @@ pub(super) fn check( then { let mut applicability = Applicability::MachineApplicable; - let turbofish = if (replacement.requires_turbofish)(cx, expr) { + let turbofish = if replacement.has_generic_return { format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) } else { String::new() @@ -159,7 +136,11 @@ pub(super) fn check( acc, fold_span, hir::BinOpKind::Or, - Replacement::non_generic("any"), + Replacement { + has_args: true, + has_generic_return: false, + method_name: "any", + }, ); }, ast::LitKind::Bool(true) => { @@ -169,7 +150,11 @@ pub(super) fn check( acc, fold_span, hir::BinOpKind::And, - Replacement::non_generic("all"), + Replacement { + has_args: true, + has_generic_return: false, + method_name: "all", + }, ); }, ast::LitKind::Int(0, _) => check_fold_with_op( @@ -178,7 +163,11 @@ pub(super) fn check( acc, fold_span, hir::BinOpKind::Add, - Replacement::generic("sum"), + Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "sum", + }, ), ast::LitKind::Int(1, _) => { check_fold_with_op( @@ -187,7 +176,11 @@ pub(super) fn check( acc, fold_span, hir::BinOpKind::Mul, - Replacement::generic("product"), + Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "product", + }, ); }, _ => (), -- cgit 1.4.1-3-g733a5 From d102e2296c2a507c32f3882b296ee65926dfc32f Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 14 Jun 2023 22:38:06 +0200 Subject: move check_fold_with_op function out --- clippy_lints/src/methods/unnecessary_fold.rs | 122 +++++++++++++-------------- 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index e545abd8ba8..8ec15a1c1b7 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -52,75 +52,75 @@ struct Replacement { has_generic_return: bool, } -pub(super) fn check( +fn check_fold_with_op( cx: &LateContext<'_>, expr: &hir::Expr<'_>, - init: &hir::Expr<'_>, acc: &hir::Expr<'_>, fold_span: Span, + op: hir::BinOpKind, + replacement: Replacement, ) { - fn check_fold_with_op( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - acc: &hir::Expr<'_>, - fold_span: Span, - op: hir::BinOpKind, - replacement: Replacement, - ) { - if_chain! { - // Extract the body of the closure passed to fold - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(closure_body.value); - - // Check if the closure body is of the form `acc some_expr(x)` - if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; - if bin_op.node == op; - - // Extract the names of the two arguments to the closure - if let [param_a, param_b] = closure_body.params; - if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind; - if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; - - if path_to_local_id(left_expr, first_arg_id); - if replacement.has_args || path_to_local_id(right_expr, second_arg_id); - - then { - let mut applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) - } else { - String::new() - }; - - let sugg = if replacement.has_args { - format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", - method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!( - "{method}{turbofish}()", - method = replacement.method_name, - ) - }; - - span_lint_and_sugg( - cx, - UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), - // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) - "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, - ); - } + if_chain! { + // Extract the body of the closure passed to fold + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(closure_body.value); + + // Check if the closure body is of the form `acc some_expr(x)` + if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; + if bin_op.node == op; + + // Extract the names of the two arguments to the closure + if let [param_a, param_b] = closure_body.params; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; + + if path_to_local_id(left_expr, first_arg_id); + if replacement.has_args || path_to_local_id(right_expr, second_arg_id); + + then { + let mut applicability = Applicability::MachineApplicable; + + let turbofish = if replacement.has_generic_return { + format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) + } else { + String::new() + }; + + let sugg = if replacement.has_args { + format!( + "{method}{turbofish}(|{second_arg_ident}| {r})", + method = replacement.method_name, + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), + ) + } else { + format!( + "{method}{turbofish}()", + method = replacement.method_name, + ) + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FOLD, + fold_span.with_hi(expr.span.hi()), + // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) + "this `.fold` can be written more succinctly using another method", + "try", + sugg, + applicability, + ); } } +} +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + init: &hir::Expr<'_>, + acc: &hir::Expr<'_>, + fold_span: Span, +) { // Check that this is a call to Iterator::fold rather than just some function called fold if !is_trait_method(cx, expr, sym::Iterator) { return; -- cgit 1.4.1-3-g733a5 From 2748ab9565100dedfe170c899fe1f7f0791677d2 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 27 May 2023 00:58:44 +0200 Subject: new lint: `drain_collect` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/drain_collect.rs | 77 +++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 41 ++++++++++++++++ tests/ui/drain_collect.rs | 65 ++++++++++++++++++++++++++ tests/ui/drain_collect.stderr | 62 +++++++++++++++++++++++++ tests/ui/iter_with_drain.fixed | 2 +- tests/ui/iter_with_drain.rs | 2 +- 8 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/drain_collect.rs create mode 100644 tests/ui/drain_collect.rs create mode 100644 tests/ui/drain_collect.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 218bca40cb0..ad7a101d38a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4737,6 +4737,7 @@ Released 2018-09-13 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens +[`drain_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#drain_collect [`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds [`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy [`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 9509e6d016a..b726f343ffe 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -324,6 +324,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, + crate::methods::DRAIN_COLLECT_INFO, crate::methods::ERR_EXPECT_INFO, crate::methods::EXPECT_FUN_CALL_INFO, crate::methods::EXPECT_USED_INFO, diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs new file mode 100644 index 00000000000..6d9df587518 --- /dev/null +++ b/clippy_lints/src/methods/drain_collect.rs @@ -0,0 +1,77 @@ +use crate::methods::DRAIN_COLLECT; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_range_full; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_lang_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_hir::ExprKind; +use rustc_hir::LangItem; +use rustc_hir::Path; +use rustc_hir::QPath; +use rustc_lint::LateContext; +use rustc_middle::query::Key; +use rustc_middle::ty::Ty; +use rustc_span::sym; +use rustc_span::Symbol; + +/// Checks if both types match the given diagnostic item, e.g.: +/// +/// `vec![1,2].drain(..).collect::>()` +/// ^^^^^^^^^ ^^^^^^ true +/// `vec![1,2].drain(..).collect::>()` +/// ^^^^^^^^^ ^^^^^^^^^^ false +fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { + if let Some(expr_adt_did) = expr.ty_adt_id() + && let Some(recv_adt_did) = recv.ty_adt_id() + { + cx.tcx.is_diagnostic_item(sym, expr_adt_did) && cx.tcx.is_diagnostic_item(sym, recv_adt_did) + } else { + false + } +} + +/// Checks `std::{vec::Vec, collections::VecDeque}`. +fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { + (types_match_diagnostic_item(cx, expr, recv, sym::Vec) + || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque)) + && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) +} + +/// Checks `std::string::String` +fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { + is_type_lang_item(cx, expr, LangItem::String) + && is_type_lang_item(cx, recv, LangItem::String) + && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) +} + +/// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`. +fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> { + types_match_diagnostic_item(cx, expr, recv, sym::HashSet) + .then_some("HashSet") + .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap")) + .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::BinaryHeap).then_some("BinaryHeap")) +} + +pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, recv: &Expr<'_>) { + let expr_ty = cx.typeck_results().expr_ty(expr); + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + if let ExprKind::Path(QPath::Resolved(_, recv_path)) = recv.kind + && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty, recv_path) + .then_some("Vec") + .or_else(|| check_string(cx, args, expr_ty, recv_ty, recv_path).then_some("String")) + .or_else(|| check_collections(cx, expr_ty, recv_ty)) + { + let recv = snippet(cx, recv.span, ""); + span_lint_and_sugg( + cx, + DRAIN_COLLECT, + expr.span, + &format!("you seem to be trying to move all elements into a new `{typename}`"), + "consider using `mem::take`", + format!("std::mem::take(&mut {recv})"), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 183bd582a48..faddb036eaa 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -14,6 +14,7 @@ mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; mod collapsible_str_replace; +mod drain_collect; mod err_expect; mod expect_fun_call; mod expect_used; @@ -3247,6 +3248,42 @@ declare_clippy_lint! { "manual reverse iteration of `DoubleEndedIterator`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `.drain()` that clear the collection, immediately followed by a call to `.collect()`. + /// + /// > "Collection" in this context refers to any type with a `drain` method: + /// > `Vec`, `VecDeque`, `BinaryHeap`, `HashSet`,`HashMap`, `String` + /// + /// ### Why is this bad? + /// Using `mem::take` is faster as it avoids the allocation. + /// When using `mem::take`, the old collection is replaced with an empty one and ownership of + /// the old collection is returned. + /// + /// ### Drawback + /// `mem::take(&mut vec)` is almost equivalent to `vec.drain(..).collect()`, except that + /// it also moves the **capacity**. The user might have explicitly written it this way + /// to keep the capacity on the original `Vec`. + /// + /// ### Example + /// ```rust + /// fn remove_all(v: &mut Vec) -> Vec { + /// v.drain(..).collect() + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::mem; + /// fn remove_all(v: &mut Vec) -> Vec { + /// mem::take(v) + /// } + /// ``` + #[clippy::version = "1.71.0"] + pub DRAIN_COLLECT, + perf, + "description" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3377,6 +3414,7 @@ impl_lint_pass!(Methods => [ CLEAR_WITH_DRAIN, MANUAL_NEXT_BACK, UNNECESSARY_LITERAL_UNWRAP, + DRAIN_COLLECT ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3606,6 +3644,9 @@ impl Methods { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, + Some(("drain", recv, args, ..)) => { + drain_collect::check(cx, args, expr, recv); + } _ => {}, } }, diff --git a/tests/ui/drain_collect.rs b/tests/ui/drain_collect.rs new file mode 100644 index 00000000000..1bedab75c03 --- /dev/null +++ b/tests/ui/drain_collect.rs @@ -0,0 +1,65 @@ +#![deny(clippy::drain_collect)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn binaryheap(b: &mut BinaryHeap) -> BinaryHeap { + b.drain().collect() +} + +fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { + b.drain().collect() +} + +fn hashmap(b: &mut HashMap) -> HashMap { + b.drain().collect() +} + +fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { + b.drain().collect() +} + +fn hashset(b: &mut HashSet) -> HashSet { + b.drain().collect() +} + +fn hashset_dont_lint(b: &mut HashSet) -> Vec { + b.drain().collect() +} + +fn vecdeque(b: &mut VecDeque) -> VecDeque { + b.drain(..).collect() +} + +fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { + b.drain(..).collect() +} + +fn vec(b: &mut Vec) -> Vec { + b.drain(..).collect() +} + +fn vec2(b: &mut Vec) -> Vec { + b.drain(0..).collect() +} + +fn vec3(b: &mut Vec) -> Vec { + b.drain(..b.len()).collect() +} + +fn vec4(b: &mut Vec) -> Vec { + b.drain(0..b.len()).collect() +} + +fn vec_dont_lint(b: &mut Vec) -> HashSet { + b.drain(..).collect() +} + +fn string(b: &mut String) -> String { + b.drain(..).collect() +} + +fn string_dont_lint(b: &mut String) -> HashSet { + b.drain(..).collect() +} + +fn main() {} diff --git a/tests/ui/drain_collect.stderr b/tests/ui/drain_collect.stderr new file mode 100644 index 00000000000..d4e2b4a6fa2 --- /dev/null +++ b/tests/ui/drain_collect.stderr @@ -0,0 +1,62 @@ +error: you seem to be trying to move all elements into a new `BinaryHeap` + --> $DIR/drain_collect.rs:6:5 + | +LL | b.drain().collect() + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | +note: the lint level is defined here + --> $DIR/drain_collect.rs:1:9 + | +LL | #![deny(clippy::drain_collect)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: you seem to be trying to move all elements into a new `HashMap` + --> $DIR/drain_collect.rs:14:5 + | +LL | b.drain().collect() + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `HashSet` + --> $DIR/drain_collect.rs:22:5 + | +LL | b.drain().collect() + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:30:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:38:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:42:5 + | +LL | b.drain(0..).collect() + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:46:5 + | +LL | b.drain(..b.len()).collect() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:50:5 + | +LL | b.drain(0..b.len()).collect() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `String` + --> $DIR/drain_collect.rs:58:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/iter_with_drain.fixed b/tests/ui/iter_with_drain.fixed index 24a95c4d0fe..7a8c6770101 100644 --- a/tests/ui/iter_with_drain.fixed +++ b/tests/ui/iter_with_drain.fixed @@ -2,7 +2,7 @@ // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing -#![allow(clippy::needless_collect)] +#![allow(clippy::needless_collect, clippy::drain_collect)] #![warn(clippy::iter_with_drain)] use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/iter_with_drain.rs b/tests/ui/iter_with_drain.rs index a118c981ee3..cf3a935c349 100644 --- a/tests/ui/iter_with_drain.rs +++ b/tests/ui/iter_with_drain.rs @@ -2,7 +2,7 @@ // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing -#![allow(clippy::needless_collect)] +#![allow(clippy::needless_collect, clippy::drain_collect)] #![warn(clippy::iter_with_drain)] use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; -- cgit 1.4.1-3-g733a5 From d2a6ec2d4d7930401d2600edfdac1cd964ebe55c Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 27 May 2023 01:31:55 +0200 Subject: take into account reborrowing when inserting `&mut` in sugg --- clippy_lints/src/methods/drain_collect.rs | 36 ++++++++++----- tests/ui/drain_collect.fixed | 73 +++++++++++++++++++++++++++++++ tests/ui/drain_collect.rs | 8 ++++ tests/ui/drain_collect.stderr | 44 +++++++++++-------- 4 files changed, 132 insertions(+), 29 deletions(-) create mode 100644 tests/ui/drain_collect.fixed (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 6d9df587518..53f63266073 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -11,7 +11,7 @@ use rustc_hir::Path; use rustc_hir::QPath; use rustc_lint::LateContext; use rustc_middle::query::Key; -use rustc_middle::ty::Ty; +use rustc_middle::ty; use rustc_span::sym; use rustc_span::Symbol; @@ -21,7 +21,7 @@ use rustc_span::Symbol; /// ^^^^^^^^^ ^^^^^^ true /// `vec![1,2].drain(..).collect::>()` /// ^^^^^^^^^ ^^^^^^^^^^ false -fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { +fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: ty::Ty<'_>, recv: ty::Ty<'_>, sym: Symbol) -> bool { if let Some(expr_adt_did) = expr.ty_adt_id() && let Some(recv_adt_did) = recv.ty_adt_id() { @@ -32,21 +32,33 @@ fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, } /// Checks `std::{vec::Vec, collections::VecDeque}`. -fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { +fn check_vec( + cx: &LateContext<'_>, + args: &[Expr<'_>], + expr: ty::Ty<'_>, + recv: ty::Ty<'_>, + recv_path: &Path<'_>, +) -> bool { (types_match_diagnostic_item(cx, expr, recv, sym::Vec) || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque)) && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) } /// Checks `std::string::String` -fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { +fn check_string( + cx: &LateContext<'_>, + args: &[Expr<'_>], + expr: ty::Ty<'_>, + recv: ty::Ty<'_>, + recv_path: &Path<'_>, +) -> bool { is_type_lang_item(cx, expr, LangItem::String) && is_type_lang_item(cx, recv, LangItem::String) && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) } /// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`. -fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> { +fn check_collections(cx: &LateContext<'_>, expr: ty::Ty<'_>, recv: ty::Ty<'_>) -> Option<&'static str> { types_match_diagnostic_item(cx, expr, recv, sym::HashSet) .then_some("HashSet") .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap")) @@ -55,13 +67,14 @@ fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, recv: &Expr<'_>) { let expr_ty = cx.typeck_results().expr_ty(expr); - let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + let recv_ty = cx.typeck_results().expr_ty(recv); + let recv_ty_no_refs = recv_ty.peel_refs(); if let ExprKind::Path(QPath::Resolved(_, recv_path)) = recv.kind - && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty, recv_path) + && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty_no_refs, recv_path) .then_some("Vec") - .or_else(|| check_string(cx, args, expr_ty, recv_ty, recv_path).then_some("String")) - .or_else(|| check_collections(cx, expr_ty, recv_ty)) + .or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String")) + .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs)) { let recv = snippet(cx, recv.span, ""); span_lint_and_sugg( @@ -70,7 +83,10 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re expr.span, &format!("you seem to be trying to move all elements into a new `{typename}`"), "consider using `mem::take`", - format!("std::mem::take(&mut {recv})"), + match recv_ty.kind() { + ty::Ref(..) => format!("std::mem::take({recv})"), + _ => format!("std::mem::take(&mut {recv})"), + }, Applicability::MachineApplicable, ); } diff --git a/tests/ui/drain_collect.fixed b/tests/ui/drain_collect.fixed new file mode 100644 index 00000000000..0d40a648378 --- /dev/null +++ b/tests/ui/drain_collect.fixed @@ -0,0 +1,73 @@ +//@run-rustfix + +#![deny(clippy::drain_collect)] +#![allow(dead_code)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn binaryheap(b: &mut BinaryHeap) -> BinaryHeap { + std::mem::take(b) +} + +fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { + b.drain().collect() +} + +fn hashmap(b: &mut HashMap) -> HashMap { + std::mem::take(b) +} + +fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { + b.drain().collect() +} + +fn hashset(b: &mut HashSet) -> HashSet { + std::mem::take(b) +} + +fn hashset_dont_lint(b: &mut HashSet) -> Vec { + b.drain().collect() +} + +fn vecdeque(b: &mut VecDeque) -> VecDeque { + std::mem::take(b) +} + +fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { + b.drain(..).collect() +} + +fn vec(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec2(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec3(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec4(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec_no_reborrow() -> Vec { + let mut b = vec![1, 2, 3]; + std::mem::take(&mut b) +} + +fn vec_dont_lint(b: &mut Vec) -> HashSet { + b.drain(..).collect() +} + +fn string(b: &mut String) -> String { + std::mem::take(b) +} + +fn string_dont_lint(b: &mut String) -> HashSet { + b.drain(..).collect() +} + +fn main() {} diff --git a/tests/ui/drain_collect.rs b/tests/ui/drain_collect.rs index 1bedab75c03..7144a1847ca 100644 --- a/tests/ui/drain_collect.rs +++ b/tests/ui/drain_collect.rs @@ -1,4 +1,7 @@ +//@run-rustfix + #![deny(clippy::drain_collect)] +#![allow(dead_code)] use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; @@ -50,6 +53,11 @@ fn vec4(b: &mut Vec) -> Vec { b.drain(0..b.len()).collect() } +fn vec_no_reborrow() -> Vec { + let mut b = vec![1, 2, 3]; + b.drain(..).collect() +} + fn vec_dont_lint(b: &mut Vec) -> HashSet { b.drain(..).collect() } diff --git a/tests/ui/drain_collect.stderr b/tests/ui/drain_collect.stderr index d4e2b4a6fa2..0792f0254cb 100644 --- a/tests/ui/drain_collect.stderr +++ b/tests/ui/drain_collect.stderr @@ -1,62 +1,68 @@ error: you seem to be trying to move all elements into a new `BinaryHeap` - --> $DIR/drain_collect.rs:6:5 + --> $DIR/drain_collect.rs:9:5 | LL | b.drain().collect() - | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | note: the lint level is defined here - --> $DIR/drain_collect.rs:1:9 + --> $DIR/drain_collect.rs:3:9 | LL | #![deny(clippy::drain_collect)] | ^^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to move all elements into a new `HashMap` - --> $DIR/drain_collect.rs:14:5 + --> $DIR/drain_collect.rs:17:5 | LL | b.drain().collect() - | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `HashSet` - --> $DIR/drain_collect.rs:22:5 + --> $DIR/drain_collect.rs:25:5 | LL | b.drain().collect() - | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> $DIR/drain_collect.rs:30:5 + --> $DIR/drain_collect.rs:33:5 | LL | b.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> $DIR/drain_collect.rs:38:5 + --> $DIR/drain_collect.rs:41:5 | LL | b.drain(..).collect() - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> $DIR/drain_collect.rs:42:5 + --> $DIR/drain_collect.rs:45:5 | LL | b.drain(0..).collect() - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> $DIR/drain_collect.rs:46:5 + --> $DIR/drain_collect.rs:49:5 | LL | b.drain(..b.len()).collect() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> $DIR/drain_collect.rs:50:5 + --> $DIR/drain_collect.rs:53:5 | LL | b.drain(0..b.len()).collect() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` -error: you seem to be trying to move all elements into a new `String` +error: you seem to be trying to move all elements into a new `Vec` --> $DIR/drain_collect.rs:58:5 | LL | b.drain(..).collect() | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` -error: aborting due to 9 previous errors +error: you seem to be trying to move all elements into a new `String` + --> $DIR/drain_collect.rs:66:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 3f3657a3e4ae745339e42e377bef57f2f56ed5ff Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 27 May 2023 01:50:36 +0200 Subject: make clippy happy --- clippy_lints/src/methods/drain_collect.rs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 53f63266073..8bd8f88a214 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -12,6 +12,7 @@ use rustc_hir::QPath; use rustc_lint::LateContext; use rustc_middle::query::Key; use rustc_middle::ty; +use rustc_middle::ty::Ty; use rustc_span::sym; use rustc_span::Symbol; @@ -21,7 +22,7 @@ use rustc_span::Symbol; /// ^^^^^^^^^ ^^^^^^ true /// `vec![1,2].drain(..).collect::>()` /// ^^^^^^^^^ ^^^^^^^^^^ false -fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: ty::Ty<'_>, recv: ty::Ty<'_>, sym: Symbol) -> bool { +fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { if let Some(expr_adt_did) = expr.ty_adt_id() && let Some(recv_adt_did) = recv.ty_adt_id() { @@ -32,33 +33,21 @@ fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: ty::Ty<'_>, recv: ty: } /// Checks `std::{vec::Vec, collections::VecDeque}`. -fn check_vec( - cx: &LateContext<'_>, - args: &[Expr<'_>], - expr: ty::Ty<'_>, - recv: ty::Ty<'_>, - recv_path: &Path<'_>, -) -> bool { +fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { (types_match_diagnostic_item(cx, expr, recv, sym::Vec) || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque)) && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) } /// Checks `std::string::String` -fn check_string( - cx: &LateContext<'_>, - args: &[Expr<'_>], - expr: ty::Ty<'_>, - recv: ty::Ty<'_>, - recv_path: &Path<'_>, -) -> bool { +fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { is_type_lang_item(cx, expr, LangItem::String) && is_type_lang_item(cx, recv, LangItem::String) && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) } /// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`. -fn check_collections(cx: &LateContext<'_>, expr: ty::Ty<'_>, recv: ty::Ty<'_>) -> Option<&'static str> { +fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> { types_match_diagnostic_item(cx, expr, recv, sym::HashSet) .then_some("HashSet") .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap")) @@ -83,9 +72,10 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re expr.span, &format!("you seem to be trying to move all elements into a new `{typename}`"), "consider using `mem::take`", - match recv_ty.kind() { - ty::Ref(..) => format!("std::mem::take({recv})"), - _ => format!("std::mem::take(&mut {recv})"), + if let ty::Ref(..) = recv_ty.kind() { + format!("std::mem::take({recv})") + } else { + format!("std::mem::take(&mut {recv})") }, Applicability::MachineApplicable, ); -- cgit 1.4.1-3-g733a5 From 20ae597ec4dc593bb07bcd436b3ca42fcb64df42 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 8 Jun 2023 19:54:33 +0200 Subject: add a description --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index faddb036eaa..bed70207f28 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3281,7 +3281,7 @@ declare_clippy_lint! { #[clippy::version = "1.71.0"] pub DRAIN_COLLECT, perf, - "description" + "calling `.drain(..).collect()` to move all elements into a new collection" } pub struct Methods { -- cgit 1.4.1-3-g733a5 From 5821fbbc3072c16bc941a5e207bfd3a5e401304b Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:16:39 +0200 Subject: add test case for not whole length, move sugg into variable --- clippy_lints/src/methods/drain_collect.rs | 12 +++++++----- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/drain_collect.fixed | 4 ++++ tests/ui/drain_collect.rs | 4 ++++ 4 files changed, 16 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 8bd8f88a214..d0c79dc11b0 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -66,17 +66,19 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs)) { let recv = snippet(cx, recv.span, ""); + let sugg = if let ty::Ref(..) = recv_ty.kind() { + format!("std::mem::take({recv})") + } else { + format!("std::mem::take(&mut {recv})") + }; + span_lint_and_sugg( cx, DRAIN_COLLECT, expr.span, &format!("you seem to be trying to move all elements into a new `{typename}`"), "consider using `mem::take`", - if let ty::Ref(..) = recv_ty.kind() { - format!("std::mem::take({recv})") - } else { - format!("std::mem::take(&mut {recv})") - }, + sugg, Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bed70207f28..99c984ba65a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3260,7 +3260,7 @@ declare_clippy_lint! { /// When using `mem::take`, the old collection is replaced with an empty one and ownership of /// the old collection is returned. /// - /// ### Drawback + /// ### Known issues /// `mem::take(&mut vec)` is almost equivalent to `vec.drain(..).collect()`, except that /// it also moves the **capacity**. The user might have explicitly written it this way /// to keep the capacity on the original `Vec`. diff --git a/tests/ui/drain_collect.fixed b/tests/ui/drain_collect.fixed index 0d40a648378..11001bd319f 100644 --- a/tests/ui/drain_collect.fixed +++ b/tests/ui/drain_collect.fixed @@ -70,4 +70,8 @@ fn string_dont_lint(b: &mut String) -> HashSet { b.drain(..).collect() } +fn not_whole_length(v: &mut Vec) -> Vec { + v.drain(1..).collect() +} + fn main() {} diff --git a/tests/ui/drain_collect.rs b/tests/ui/drain_collect.rs index 7144a1847ca..373a3ca3506 100644 --- a/tests/ui/drain_collect.rs +++ b/tests/ui/drain_collect.rs @@ -70,4 +70,8 @@ fn string_dont_lint(b: &mut String) -> HashSet { b.drain(..).collect() } +fn not_whole_length(v: &mut Vec) -> Vec { + v.drain(1..).collect() +} + fn main() {} -- cgit 1.4.1-3-g733a5 From 6331c943ff85c8d5d86f6db940fd4e9dee3da15f Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 17 Jun 2023 20:48:56 +0200 Subject: include a ref if argument is not just a numeric literal --- clippy_lints/src/methods/get_unwrap.rs | 23 +++++++++++------- tests/ui/get_unwrap.fixed | 13 ++++++++++ tests/ui/get_unwrap.rs | 13 ++++++++++ tests/ui/get_unwrap.stderr | 44 +++++++++++++++++++++++++++++++++- 4 files changed, 84 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index ffc3a4d780e..209d42ebabd 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -25,13 +25,13 @@ pub(super) fn check<'tcx>( let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability); let mut needs_ref; let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() { - needs_ref = get_args_str.parse::().is_ok(); + needs_ref = true; "slice" } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) { - needs_ref = get_args_str.parse::().is_ok(); + needs_ref = true; "Vec" } else if is_type_diagnostic_item(cx, expr_ty, sym::VecDeque) { - needs_ref = get_args_str.parse::().is_ok(); + needs_ref = true; "VecDeque" } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::HashMap) { needs_ref = true; @@ -45,16 +45,23 @@ pub(super) fn check<'tcx>( let mut span = expr.span; - // Handle the case where the result is immediately dereferenced - // by not requiring ref and pulling the dereference into the - // suggestion. + // Handle the case where the result is immediately dereferenced, + // either directly be the user, or as a result of a method call or the like + // by not requiring an explicit reference if_chain! { if needs_ref; if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind; + if let hir::ExprKind::Unary(hir::UnOp::Deref, _) + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Index(..) = parent.kind; then { + if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { + // if the user explicitly dereferences the result, we can adjust + // the span to also include the deref part + span = parent.span; + } needs_ref = false; - span = parent.span; } } diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 9061c9aa404..3e4c2b499e4 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -69,4 +69,17 @@ fn main() { let _ = some_vec[0..1].to_vec(); let _ = some_vec[0..1].to_vec(); } + issue9909(); +} +fn issue9909() { + let f = &[1, 2, 3]; + + let _x: &i32 = &f[1 + 2]; + // ^ include a borrow in the suggestion, even if the argument is not just a numeric literal + + let _x = f[1 + 2].to_string(); + // ^ don't include a borrow here + + let _x = f[1 + 2].abs(); + // ^ don't include a borrow here } diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index b5e4e472037..a967971a7dc 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -69,4 +69,17 @@ fn main() { let _ = some_vec.get(0..1).unwrap().to_vec(); let _ = some_vec.get_mut(0..1).unwrap().to_vec(); } + issue9909(); +} +fn issue9909() { + let f = &[1, 2, 3]; + + let _x: &i32 = f.get(1 + 2).unwrap(); + // ^ include a borrow in the suggestion, even if the argument is not just a numeric literal + + let _x = f.get(1 + 2).unwrap().to_string(); + // ^ don't include a borrow here + + let _x = f.get(1 + 2).unwrap().abs(); + // ^ don't include a borrow here } diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index a6a34620e92..6221c236830 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -187,5 +187,47 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message -error: aborting due to 26 previous errors +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:77:20 + | +LL | let _x: &i32 = f.get(1 + 2).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `&f[1 + 2]` + +error: used `unwrap()` on an `Option` value + --> $DIR/get_unwrap.rs:77:20 + | +LL | let _x: &i32 = f.get(1 + 2).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:80:14 + | +LL | let _x = f.get(1 + 2).unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` + +error: used `unwrap()` on an `Option` value + --> $DIR/get_unwrap.rs:80:14 + | +LL | let _x = f.get(1 + 2).unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:83:14 + | +LL | let _x = f.get(1 + 2).unwrap().abs(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` + +error: used `unwrap()` on an `Option` value + --> $DIR/get_unwrap.rs:83:14 + | +LL | let _x = f.get(1 + 2).unwrap().abs(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + +error: aborting due to 32 previous errors -- cgit 1.4.1-3-g733a5 From c5a9adc2bef3afcaf8bcdb260e218a82911a034e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 18 Jun 2023 22:20:10 +0200 Subject: new lint: `type_id_on_box` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 35 ++++++++++++++++ clippy_lints/src/methods/type_id_on_box.rs | 64 ++++++++++++++++++++++++++++++ tests/ui/type_id_on_box.fixed | 20 ++++++++++ tests/ui/type_id_on_box.rs | 20 ++++++++++ tests/ui/type_id_on_box.stderr | 25 ++++++++++++ 7 files changed, 166 insertions(+) create mode 100644 clippy_lints/src/methods/type_id_on_box.rs create mode 100644 tests/ui/type_id_on_box.fixed create mode 100644 tests/ui/type_id_on_box.rs create mode 100644 tests/ui/type_id_on_box.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 269be545b0a..f82a3739259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5230,6 +5230,7 @@ Released 2018-09-13 [`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity +[`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds [`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction [`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7690e8f7247..0a2db21ca95 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -403,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, + crate::methods::TYPE_ID_ON_BOX_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, crate::methods::UNIT_HASH_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 99c984ba65a..e98fe99eac7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -87,6 +87,7 @@ mod suspicious_command_arg_space; mod suspicious_map; mod suspicious_splitn; mod suspicious_to_owned; +mod type_id_on_box; mod uninit_assumed_init; mod unit_hash; mod unnecessary_filter_map; @@ -2922,6 +2923,37 @@ declare_clippy_lint! { "use of sort() when sort_unstable() is equivalent" } +declare_clippy_lint! { + /// ### What it does + /// Looks for calls to ` as Any>::type_id`. + /// + /// ### Why is this bad? + /// This most certainly does not do what the user expects and is very easy to miss. + /// Calling `type_id` on a `Box` calls `type_id` on the `Box<..>` itself, + /// so this will return the `TypeId` of the `Box` type (not the type id + /// of the value referenced by the box!). + /// + /// ### Example + /// ```rust,ignore + /// use std::any::{Any, TypeId}; + /// + /// let any_box: Box = Box::new(42_i32); + /// assert_eq!(any_box.type_id(), TypeId::of::()); // ⚠️ this fails! + /// ``` + /// Use instead: + /// ```rust + /// use std::any::{Any, TypeId}; + /// + /// let any_box: Box = Box::new(42_i32); + /// assert_eq!((*any_box).type_id(), TypeId::of::()); + /// // ^ dereference first, to call `type_id` on `dyn Any` + /// ``` + #[clippy::version = "1.47.0"] + pub TYPE_ID_ON_BOX, + suspicious, + "calling `.type_id()` on `Box`" +} + declare_clippy_lint! { /// ### What it does /// Detects `().hash(_)`. @@ -3878,6 +3910,9 @@ impl Methods { ("to_os_string" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, + ("type_id", []) => { + type_id_on_box::check(cx, recv, expr.span); + } ("unwrap", []) => { match method_call(recv) { Some(("get", recv, [get_arg], _, _)) => { diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs new file mode 100644 index 00000000000..8ccbd0d8d1b --- /dev/null +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -0,0 +1,64 @@ +use crate::methods::TYPE_ID_ON_BOX; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::Adjust; +use rustc_middle::ty::adjustment::Adjustment; +use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, ExistentialPredicate}; +use rustc_span::{sym, Span}; + +fn is_dyn_trait(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + if let ty::Dynamic(preds, ..) = ty.kind() { + preds.iter().any(|p| match p.skip_binder() { + ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id), + _ => false, + }) + } else { + false + } +} + +pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) { + let recv_adjusts = cx.typeck_results().expr_adjustments(receiver); + + if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last() + && let ty::Ref(_, ty, _) = recv_ty.kind() + && let ty::Adt(adt, substs) = ty.kind() + && adt.is_box() + && is_dyn_trait(cx, substs.type_at(0)) + { + span_lint_and_then( + cx, + TYPE_ID_ON_BOX, + call_span, + "calling `.type_id()` on a `Box`", + |diag| { + let derefs = recv_adjusts + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(None))) + .count(); + + let mut sugg = "*".repeat(derefs + 1); + sugg += &snippet(cx, receiver.span, ""); + + diag.note( + "this returns the type id of the literal type `Box` instead of the \ + type id of the boxed value, which is most likely not what you want" + ) + .note( + "if this is intentional, use `TypeId::of::>()` instead, \ + which makes it more clear" + ) + .span_suggestion( + receiver.span, + "consider dereferencing first", + format!("({sugg})"), + Applicability::MaybeIncorrect, + ); + }, + ); + } +} diff --git a/tests/ui/type_id_on_box.fixed b/tests/ui/type_id_on_box.fixed new file mode 100644 index 00000000000..fc177afacd4 --- /dev/null +++ b/tests/ui/type_id_on_box.fixed @@ -0,0 +1,20 @@ +//@run-rustfix + +#![warn(clippy::type_id_on_box)] + +use std::any::{Any, TypeId}; + +fn existential() -> impl Any { + Box::new(1) as Box +} + +fn main() { + let any_box: Box = Box::new(0usize); + let _ = (*any_box).type_id(); + let _ = TypeId::of::>(); // don't lint, user probably explicitly wants to do this + let _ = (*any_box).type_id(); + let any_box: &Box = &(Box::new(0usize) as Box); + let _ = (**any_box).type_id(); // 2 derefs are needed here + let b = existential(); + let _ = b.type_id(); // don't lint +} diff --git a/tests/ui/type_id_on_box.rs b/tests/ui/type_id_on_box.rs new file mode 100644 index 00000000000..36cf631a092 --- /dev/null +++ b/tests/ui/type_id_on_box.rs @@ -0,0 +1,20 @@ +//@run-rustfix + +#![warn(clippy::type_id_on_box)] + +use std::any::{Any, TypeId}; + +fn existential() -> impl Any { + Box::new(1) as Box +} + +fn main() { + let any_box: Box = Box::new(0usize); + let _ = any_box.type_id(); + let _ = TypeId::of::>(); // don't lint, user probably explicitly wants to do this + let _ = (*any_box).type_id(); + let any_box: &Box = &(Box::new(0usize) as Box); + let _ = any_box.type_id(); // 2 derefs are needed here + let b = existential(); + let _ = b.type_id(); // don't lint +} diff --git a/tests/ui/type_id_on_box.stderr b/tests/ui/type_id_on_box.stderr new file mode 100644 index 00000000000..47e0e814daf --- /dev/null +++ b/tests/ui/type_id_on_box.stderr @@ -0,0 +1,25 @@ +error: calling `.type_id()` on a `Box` + --> $DIR/type_id_on_box.rs:13:13 + | +LL | let _ = any_box.type_id(); + | -------^^^^^^^^^^ + | | + | help: consider dereferencing first: `(*any_box)` + | + = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + = note: `-D clippy::type-id-on-box` implied by `-D warnings` + +error: calling `.type_id()` on a `Box` + --> $DIR/type_id_on_box.rs:17:13 + | +LL | let _ = any_box.type_id(); // 2 derefs are needed here + | -------^^^^^^^^^^ + | | + | help: consider dereferencing first: `(**any_box)` + | + = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 9ab1e8e95c45cbe9cdf657bded08a7d874e48fbd Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 18 Jun 2023 22:27:20 +0200 Subject: that was definitely not the right version --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e98fe99eac7..255a8cc0a95 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2948,7 +2948,7 @@ declare_clippy_lint! { /// assert_eq!((*any_box).type_id(), TypeId::of::()); /// // ^ dereference first, to call `type_id` on `dyn Any` /// ``` - #[clippy::version = "1.47.0"] + #[clippy::version = "1.72.0"] pub TYPE_ID_ON_BOX, suspicious, "calling `.type_id()` on `Box`" -- cgit 1.4.1-3-g733a5 From 26ac76c15f4a12b2debde692dfff02a08d516f6e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 18 Jun 2023 22:36:08 +0200 Subject: add it to the methods lint pass --- clippy_lints/src/methods/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 255a8cc0a95..6c0e15d16d7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3389,6 +3389,7 @@ impl_lint_pass!(Methods => [ STRING_EXTEND_CHARS, ITER_CLONED_COLLECT, ITER_WITH_DRAIN, + TYPE_ID_ON_BOX, USELESS_ASREF, UNNECESSARY_FOLD, UNNECESSARY_FILTER_MAP, -- cgit 1.4.1-3-g733a5 From 1b6738ba39bf5ecd4d32f95a53966662baabc1e0 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 20 Jun 2023 17:33:32 +0200 Subject: s/is_dyn_trait/is_dyn_any --- clippy_lints/src/methods/type_id_on_box.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index 8ccbd0d8d1b..88adba504aa 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::Ty; use rustc_middle::ty::{self, ExistentialPredicate}; use rustc_span::{sym, Span}; -fn is_dyn_trait(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { +fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if let ty::Dynamic(preds, ..) = ty.kind() { preds.iter().any(|p| match p.skip_binder() { ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id), @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) && let ty::Ref(_, ty, _) = recv_ty.kind() && let ty::Adt(adt, substs) = ty.kind() && adt.is_box() - && is_dyn_trait(cx, substs.type_at(0)) + && is_dyn_any(cx, substs.type_at(0)) { span_lint_and_then( cx, -- cgit 1.4.1-3-g733a5 From 3122e3d78f91bc28becf205193fc4ce67955520a Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 21 Jun 2023 09:04:40 +0200 Subject: use let chains, move assignments out of block, add tests --- clippy_lints/src/methods/get_unwrap.rs | 30 ++++++++-------------- tests/ui/get_unwrap.fixed | 44 +++++++++++++++++++++++++------- tests/ui/get_unwrap.rs | 44 +++++++++++++++++++++++++------- tests/ui/get_unwrap.stderr | 46 +++++++++++----------------------- 4 files changed, 95 insertions(+), 69 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index 209d42ebabd..ba5aae28bd6 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -23,21 +22,16 @@ pub(super) fn check<'tcx>( let mut applicability = Applicability::MachineApplicable; let expr_ty = cx.typeck_results().expr_ty(recv); let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability); - let mut needs_ref; + let mut needs_ref = true; let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() { - needs_ref = true; "slice" } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) { - needs_ref = true; "Vec" } else if is_type_diagnostic_item(cx, expr_ty, sym::VecDeque) { - needs_ref = true; "VecDeque" } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::HashMap) { - needs_ref = true; "HashMap" } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::BTreeMap) { - needs_ref = true; "BTreeMap" } else { return; // caller is not a type that we want to lint @@ -48,21 +42,19 @@ pub(super) fn check<'tcx>( // Handle the case where the result is immediately dereferenced, // either directly be the user, or as a result of a method call or the like // by not requiring an explicit reference - if_chain! { - if needs_ref; - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(hir::UnOp::Deref, _) + if needs_ref + && let Some(parent) = get_parent_expr(cx, expr) + && let hir::ExprKind::Unary(hir::UnOp::Deref, _) | hir::ExprKind::MethodCall(..) | hir::ExprKind::Field(..) - | hir::ExprKind::Index(..) = parent.kind; - then { - if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { - // if the user explicitly dereferences the result, we can adjust - // the span to also include the deref part - span = parent.span; - } - needs_ref = false; + | hir::ExprKind::Index(..) = parent.kind + { + if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { + // if the user explicitly dereferences the result, we can adjust + // the span to also include the deref part + span = parent.span; } + needs_ref = false; } let mut_str = if is_mut { "_mut" } else { "" }; diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 3e4c2b499e4..f0d28dd9349 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -69,17 +69,43 @@ fn main() { let _ = some_vec[0..1].to_vec(); let _ = some_vec[0..1].to_vec(); } - issue9909(); } -fn issue9909() { - let f = &[1, 2, 3]; +mod issue9909 { + #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] - let _x: &i32 = &f[1 + 2]; - // ^ include a borrow in the suggestion, even if the argument is not just a numeric literal + fn reduced() { + let f = &[1, 2, 3]; - let _x = f[1 + 2].to_string(); - // ^ don't include a borrow here + let _x: &i32 = &f[1 + 2]; + // ^ include a borrow in the suggestion, even if the argument is not just a numeric literal - let _x = f[1 + 2].abs(); - // ^ don't include a borrow here + let _x = f[1 + 2].to_string(); + // ^ don't include a borrow here + + let _x = f[1 + 2].abs(); + // ^ don't include a borrow here + } + + // original code: + fn linidx(row: usize, col: usize) -> usize { + row * 1 + col * 3 + } + + fn main_() { + let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0]; + + for i in 0..2 { + for j in i + 1..3 { + if mat[linidx(j, 3)] > mat[linidx(i, 3)] { + for k in 0..4 { + let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); + let a = x.last_mut().unwrap(); + let b = &mut rest[linidx(j, k) - linidx(i, k) - 1]; + ::std::mem::swap(a, b); + } + } + } + } + assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat); + } } diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index a967971a7dc..21c1ecb0af2 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -69,17 +69,43 @@ fn main() { let _ = some_vec.get(0..1).unwrap().to_vec(); let _ = some_vec.get_mut(0..1).unwrap().to_vec(); } - issue9909(); } -fn issue9909() { - let f = &[1, 2, 3]; +mod issue9909 { + #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] - let _x: &i32 = f.get(1 + 2).unwrap(); - // ^ include a borrow in the suggestion, even if the argument is not just a numeric literal + fn reduced() { + let f = &[1, 2, 3]; - let _x = f.get(1 + 2).unwrap().to_string(); - // ^ don't include a borrow here + let _x: &i32 = f.get(1 + 2).unwrap(); + // ^ include a borrow in the suggestion, even if the argument is not just a numeric literal - let _x = f.get(1 + 2).unwrap().abs(); - // ^ don't include a borrow here + let _x = f.get(1 + 2).unwrap().to_string(); + // ^ don't include a borrow here + + let _x = f.get(1 + 2).unwrap().abs(); + // ^ don't include a borrow here + } + + // original code: + fn linidx(row: usize, col: usize) -> usize { + row * 1 + col * 3 + } + + fn main_() { + let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0]; + + for i in 0..2 { + for j in i + 1..3 { + if mat[linidx(j, 3)] > mat[linidx(i, 3)] { + for k in 0..4 { + let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); + let a = x.last_mut().unwrap(); + let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); + ::std::mem::swap(a, b); + } + } + } + } + assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat); + } } diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index 6221c236830..154083ea654 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -188,46 +188,28 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:77:20 + --> $DIR/get_unwrap.rs:79:24 | -LL | let _x: &i32 = f.get(1 + 2).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `&f[1 + 2]` - -error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:77:20 - | -LL | let _x: &i32 = f.get(1 + 2).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message +LL | let _x: &i32 = f.get(1 + 2).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `&f[1 + 2]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:80:14 - | -LL | let _x = f.get(1 + 2).unwrap().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` - -error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:80:14 - | -LL | let _x = f.get(1 + 2).unwrap().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/get_unwrap.rs:82:18 | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message +LL | let _x = f.get(1 + 2).unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:83:14 + --> $DIR/get_unwrap.rs:85:18 | -LL | let _x = f.get(1 + 2).unwrap().abs(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` +LL | let _x = f.get(1 + 2).unwrap().abs(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` -error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:83:14 - | -LL | let _x = f.get(1 + 2).unwrap().abs(); - | ^^^^^^^^^^^^^^^^^^^^^ +error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:103:33 | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message +LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut rest[linidx(j, k) - linidx(i, k) - 1]` -error: aborting due to 32 previous errors +error: aborting due to 30 previous errors -- cgit 1.4.1-3-g733a5 From bdb2a1710774e0d77058c81fa3c7182f27565ddd Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 21 Jun 2023 09:16:25 +0200 Subject: declare needs_ref later --- clippy_lints/src/methods/get_unwrap.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index ba5aae28bd6..e35fb12ed79 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -22,7 +22,6 @@ pub(super) fn check<'tcx>( let mut applicability = Applicability::MachineApplicable; let expr_ty = cx.typeck_results().expr_ty(recv); let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability); - let mut needs_ref = true; let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() { "slice" } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) { @@ -42,8 +41,7 @@ pub(super) fn check<'tcx>( // Handle the case where the result is immediately dereferenced, // either directly be the user, or as a result of a method call or the like // by not requiring an explicit reference - if needs_ref - && let Some(parent) = get_parent_expr(cx, expr) + let needs_ref = if let Some(parent) = get_parent_expr(cx, expr) && let hir::ExprKind::Unary(hir::UnOp::Deref, _) | hir::ExprKind::MethodCall(..) | hir::ExprKind::Field(..) @@ -54,8 +52,10 @@ pub(super) fn check<'tcx>( // the span to also include the deref part span = parent.span; } - needs_ref = false; - } + false + } else { + true + }; let mut_str = if is_mut { "_mut" } else { "" }; let borrow_str = if !needs_ref { -- cgit 1.4.1-3-g733a5 From 242807a9c1cb24ef5e0d665fa9ac696d2a095c71 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 20 Jun 2023 00:39:22 -0500 Subject: Don't lint `iter_nth_zero` in `next` --- clippy_lints/src/methods/iter_nth.rs | 4 ++-- clippy_lints/src/methods/iter_nth_zero.rs | 35 ++++++++++++++++--------------- tests/ui/iter_nth.stderr | 8 +++---- tests/ui/iter_nth_zero.fixed | 15 +++++++++++++ tests/ui/iter_nth_zero.rs | 15 +++++++++++++ 5 files changed, 54 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index ceee12784cb..12104310405 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -20,9 +20,9 @@ pub(super) fn check<'tcx>( let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() { "slice" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) { - "Vec" + "`Vec`" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) { - "VecDeque" + "`VecDeque`" } else { iter_nth_zero::check(cx, expr, nth_recv, nth_arg); return; // caller is not a type that we want to lint diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index d1609eebfdc..e1f950d5a4a 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,8 +1,8 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; +use clippy_utils::{is_lang_item_or_ctor, is_trait_method}; +use hir::{LangItem, OwnerNode}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -11,20 +11,21 @@ use rustc_span::sym; use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - if_chain! { - if is_trait_method(cx, expr, sym::Iterator); - if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_NTH_ZERO, - expr.span, - "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", - "try calling `.next()` instead of `.nth(0)`", - format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)), - applicability, - ); - } + if let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id)) + && let def_id = item.owner_id.to_def_id() + && is_trait_method(cx, expr, sym::Iterator) + && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) + && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext) + { + let mut app = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NTH_ZERO, + expr.span, + "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", + "try calling `.next()` instead of `.nth(0)`", + format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut app)), + app, + ); } } diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr index 975a5a62ad5..24be814548a 100644 --- a/tests/ui/iter_nth.stderr +++ b/tests/ui/iter_nth.stderr @@ -1,4 +1,4 @@ -error: called `.iter().nth()` on a Vec +error: called `.iter().nth()` on a `Vec` --> $DIR/iter_nth.rs:34:23 | LL | let bad_vec = some_vec.iter().nth(3); @@ -23,7 +23,7 @@ LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | = help: calling `.get()` is both faster and more readable -error: called `.iter().nth()` on a VecDeque +error: called `.iter().nth()` on a `VecDeque` --> $DIR/iter_nth.rs:37:29 | LL | let bad_vec_deque = some_vec_deque.iter().nth(3); @@ -31,7 +31,7 @@ LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | = help: calling `.get()` is both faster and more readable -error: called `.iter_mut().nth()` on a Vec +error: called `.iter_mut().nth()` on a `Vec` --> $DIR/iter_nth.rs:42:23 | LL | let bad_vec = some_vec.iter_mut().nth(3); @@ -47,7 +47,7 @@ LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | = help: calling `.get_mut()` is both faster and more readable -error: called `.iter_mut().nth()` on a VecDeque +error: called `.iter_mut().nth()` on a `VecDeque` --> $DIR/iter_nth.rs:48:29 | LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); diff --git a/tests/ui/iter_nth_zero.fixed b/tests/ui/iter_nth_zero.fixed index 587b0d1d366..91f4a7ba0d2 100644 --- a/tests/ui/iter_nth_zero.fixed +++ b/tests/ui/iter_nth_zero.fixed @@ -29,3 +29,18 @@ fn main() { let mut iter2 = s3.iter(); let _unwrapped = iter2.next().unwrap(); } + +struct Issue9820; + +impl Iterator for Issue9820 { + type Item = (); + + fn nth(&mut self, _n: usize) -> Option { + todo!() + } + + // Don't lint in implementations of `next`, as calling `next` in `next` is incorrect + fn next(&mut self) -> Option { + self.nth(0) + } +} diff --git a/tests/ui/iter_nth_zero.rs b/tests/ui/iter_nth_zero.rs index 93b576ec56f..160a895bb7b 100644 --- a/tests/ui/iter_nth_zero.rs +++ b/tests/ui/iter_nth_zero.rs @@ -29,3 +29,18 @@ fn main() { let mut iter2 = s3.iter(); let _unwrapped = iter2.nth(0).unwrap(); } + +struct Issue9820; + +impl Iterator for Issue9820 { + type Item = (); + + fn nth(&mut self, _n: usize) -> Option { + todo!() + } + + // Don't lint in implementations of `next`, as calling `next` in `next` is incorrect + fn next(&mut self) -> Option { + self.nth(0) + } +} -- cgit 1.4.1-3-g733a5 From 9b7d8d1dc7cee007ec90a8c82e159bb504655615 Mon Sep 17 00:00:00 2001 From: darklyspaced Date: Mon, 26 Jun 2023 13:13:42 +0800 Subject: suggests `is_some_and` over `map().unwrap_or(false)` --- clippy_lints/src/methods/mod.rs | 2 ++ clippy_lints/src/methods/option_map_unwrap_or.rs | 28 +++++++++++++++++++++--- tests/ui/map_unwrap_or.rs | 4 ++++ tests/ui/map_unwrap_or.stderr | 20 +++++++++++++---- 4 files changed, 47 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 99c984ba65a..403fac123a9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -513,6 +513,7 @@ declare_clippy_lint! { /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } /// option.map(|a| a + 1).unwrap_or(0); + /// option.map(|a| a > 10).unwrap_or(false); /// result.map(|a| a + 1).unwrap_or_else(some_function); /// ``` /// @@ -522,6 +523,7 @@ declare_clippy_lint! { /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } /// option.map_or(0, |a| a + 1); + /// option.is_some_and(|a| a > 10); /// result.map_or_else(some_function, |a| a + 1); /// ``` #[clippy::version = "1.45.0"] diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index e931c6277f4..6a4d288abbf 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -74,16 +74,32 @@ pub(super) fn check<'tcx>( return; } + let mut suggest_is_some_and = false; + // argument to `unwrap_or` is false; should suggest using `is_some_and` + if let ExprKind::Lit(unwrap_lit) = &unwrap_arg.kind { + if let rustc_ast::LitKind::Bool(false) = unwrap_lit.node { + suggest_is_some_and = true; + } + } + let mut applicability = Applicability::MachineApplicable; // get snippet for unwrap_or() let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); // lint message // comparing the snippet from source to raw text ("None") below is safe // because we already have checked the type. - let arg = if unwrap_snippet == "None" { "None" } else { "" }; + let arg = if unwrap_snippet == "None" { + "None" + } else if suggest_is_some_and { + "false" + } else { + "" + }; let unwrap_snippet_none = unwrap_snippet == "None"; let suggest = if unwrap_snippet_none { "and_then()" + } else if suggest_is_some_and { + "is_some_and()" } else { "map_or(, )" }; @@ -98,12 +114,18 @@ pub(super) fn check<'tcx>( let mut suggestion = vec![ ( map_span, - String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }), + String::from(if unwrap_snippet_none { + "and_then" + } else if suggest_is_some_and { + "is_some_and" + } else { + "map_or" + }), ), (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), ]; - if !unwrap_snippet_none { + if !unwrap_snippet_none && !suggest_is_some_and { suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); } diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 0cd49dd7760..51b88c7cf2e 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -56,6 +56,10 @@ fn option_methods() { .unwrap_or_else(|| 0 ); + + // Check for `map(f).unwrap_or(false)` use. + let _ = opt.map(|x| x > 5).unwrap_or(false); + } #[rustfmt::skip] diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 41781b050fa..6f23d2e4f88 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -126,8 +126,20 @@ LL | | 0 LL | | ); | |_________^ +error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead + --> $DIR/map_unwrap_or.rs:61:13 + | +LL | let _ = opt.map(|x| x > 5).unwrap_or(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `is_some_and()` instead + | +LL - let _ = opt.map(|x| x > 5).unwrap_or(false); +LL + let _ = opt.is_some_and(|x| x > 5); + | + error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead - --> $DIR/map_unwrap_or.rs:67:13 + --> $DIR/map_unwrap_or.rs:71:13 | LL | let _ = res.map(|x| { | _____________^ @@ -137,7 +149,7 @@ LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead - --> $DIR/map_unwrap_or.rs:71:13 + --> $DIR/map_unwrap_or.rs:75:13 | LL | let _ = res.map(|x| x + 1) | _____________^ @@ -147,10 +159,10 @@ LL | | }); | |__________^ error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead - --> $DIR/map_unwrap_or.rs:95:13 + --> $DIR/map_unwrap_or.rs:99:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors -- cgit 1.4.1-3-g733a5 From c60222dc12c4868a4aee439d98b007b129edc4cb Mon Sep 17 00:00:00 2001 From: darklyspaced Date: Mon, 26 Jun 2023 13:39:45 +0800 Subject: changed the msrv to 1.70 to suggest `is_some_and` if the msrv is not >= 1.70 then the `map_or` is suggested instead of `is_some_and` (even when `unwrap_or` returns false) --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 12 +++++++---- clippy_utils/src/msrvs.rs | 1 + tests/ui/map_unwrap_or.rs | 14 +++++++++++++ tests/ui/map_unwrap_or.stderr | 26 +++++++++++++++++++++++- 5 files changed, 49 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 403fac123a9..b1d3b61aea3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3906,7 +3906,7 @@ impl Methods { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, Some(("map", m_recv, [m_arg], span, _)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv); }, Some(("then_some", t_recv, [t_arg], _, _)) => { obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 6a4d288abbf..4387090fe23 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; @@ -27,6 +28,7 @@ pub(super) fn check<'tcx>( unwrap_recv: &rustc_hir::Expr<'_>, unwrap_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, + msrv: &Msrv, ) { // lint if the caller of `map()` is an `Option` if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { @@ -75,10 +77,12 @@ pub(super) fn check<'tcx>( } let mut suggest_is_some_and = false; - // argument to `unwrap_or` is false; should suggest using `is_some_and` - if let ExprKind::Lit(unwrap_lit) = &unwrap_arg.kind { - if let rustc_ast::LitKind::Bool(false) = unwrap_lit.node { - suggest_is_some_and = true; + // argument to `unwrap_or` is false & is_some_and is stabilised; should suggest using `is_some_and` + if msrv.meets(msrvs::OPT_IS_SOME_AND) { + if let ExprKind::Lit(unwrap_lit) = &unwrap_arg.kind { + if let rustc_ast::LitKind::Bool(false) = unwrap_lit.node { + suggest_is_some_and = true; + } } } diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 0a4c3418a08..1541dc8392c 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,6 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,70,0 { OPT_IS_SOME_AND } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 51b88c7cf2e..bb36cb2c598 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -99,6 +99,20 @@ fn msrv_1_41() { let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); } +#[clippy::msrv = "1.69"] +fn msrv_1_69() { + let opt: Option = Some(1); + + let _ = opt.map(|x| x > 5).unwrap_or(false); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70() { + let opt: Option = Some(1); + + let _ = opt.map(|x| x > 5).unwrap_or(false); +} + mod issue_10579 { // Different variations of the same issue. fn v1() { diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 6f23d2e4f88..9f4a4a9ae6b 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -164,5 +164,29 @@ error: called `map().unwrap_or_else()` on a `Result` value. This can be do LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` -error: aborting due to 13 previous errors +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead + --> $DIR/map_unwrap_or.rs:106:13 + | +LL | let _ = opt.map(|x| x > 5).unwrap_or(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - let _ = opt.map(|x| x > 5).unwrap_or(false); +LL + let _ = opt.map_or(false, |x| x > 5); + | + +error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead + --> $DIR/map_unwrap_or.rs:113:13 + | +LL | let _ = opt.map(|x| x > 5).unwrap_or(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `is_some_and()` instead + | +LL - let _ = opt.map(|x| x > 5).unwrap_or(false); +LL + let _ = opt.is_some_and(|x| x > 5); + | + +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From b832175b2d51a02fdac3bb8110b71f9a1e1d30b4 Mon Sep 17 00:00:00 2001 From: darklyspaced Date: Mon, 26 Jun 2023 14:05:41 +0800 Subject: now passes dogfood by wrapping unwrap_recv and unwrap_arg into a tuple was previously failing due to `check` having to many arguments. --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b1d3b61aea3..cdabb168912 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3906,7 +3906,7 @@ impl Methods { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, Some(("map", m_recv, [m_arg], span, _)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv); + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, (recv, u_arg), span, &self.msrv); }, Some(("then_some", t_recv, [t_arg], _, _)) => { obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 4387090fe23..b0d902e6088 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -25,11 +25,11 @@ pub(super) fn check<'tcx>( expr: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>, map_arg: &'tcx rustc_hir::Expr<'_>, - unwrap_recv: &rustc_hir::Expr<'_>, - unwrap_arg: &'tcx rustc_hir::Expr<'_>, + unwrap: (&rustc_hir::Expr<'_>, &'tcx rustc_hir::Expr<'_>), map_span: Span, msrv: &Msrv, ) { + let (unwrap_recv, unwrap_arg) = unwrap; // lint if the caller of `map()` is an `Option` if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { -- cgit 1.4.1-3-g733a5 From c378bf9ddf10e191fce5753a02a09bb0ab8961fb Mon Sep 17 00:00:00 2001 From: darklyspaced Date: Mon, 26 Jun 2023 14:43:36 +0800 Subject: Revert "now passes dogfood by wrapping unwrap_recv and unwrap_arg into a tuple" This reverts commit 7b91844a3207d90d4200a7b53d0ae1a7a1dca73a. --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index cdabb168912..b1d3b61aea3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3906,7 +3906,7 @@ impl Methods { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, Some(("map", m_recv, [m_arg], span, _)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, (recv, u_arg), span, &self.msrv); + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv); }, Some(("then_some", t_recv, [t_arg], _, _)) => { obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index b0d902e6088..4387090fe23 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -25,11 +25,11 @@ pub(super) fn check<'tcx>( expr: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>, map_arg: &'tcx rustc_hir::Expr<'_>, - unwrap: (&rustc_hir::Expr<'_>, &'tcx rustc_hir::Expr<'_>), + unwrap_recv: &rustc_hir::Expr<'_>, + unwrap_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, msrv: &Msrv, ) { - let (unwrap_recv, unwrap_arg) = unwrap; // lint if the caller of `map()` is an `Option` if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { -- cgit 1.4.1-3-g733a5 From ca00b138b21d87cff24d085dd9d9dce2bf26b530 Mon Sep 17 00:00:00 2001 From: darklyspaced Date: Mon, 26 Jun 2023 14:47:05 +0800 Subject: ignore too_many_arguments on `check` --- clippy_lints/src/methods/option_map_unwrap_or.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 4387090fe23..e836a1395a2 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -20,6 +20,7 @@ use rustc_span::sym; use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or()` for `Option`s +#[expect(clippy::too_many_arguments)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &rustc_hir::Expr<'_>, -- cgit 1.4.1-3-g733a5 From a693cbc1bca16c753dfb1aa853e970bd2028634c Mon Sep 17 00:00:00 2001 From: darklyspaced Date: Tue, 27 Jun 2023 11:28:45 +0800 Subject: changed msrv name for consistency & changed nested if for style --- clippy_lints/src/methods/option_map_unwrap_or.rs | 13 ++++--------- clippy_utils/src/msrvs.rs | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index e836a1395a2..f4f158c0439 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -77,15 +77,10 @@ pub(super) fn check<'tcx>( return; } - let mut suggest_is_some_and = false; - // argument to `unwrap_or` is false & is_some_and is stabilised; should suggest using `is_some_and` - if msrv.meets(msrvs::OPT_IS_SOME_AND) { - if let ExprKind::Lit(unwrap_lit) = &unwrap_arg.kind { - if let rustc_ast::LitKind::Bool(false) = unwrap_lit.node { - suggest_is_some_and = true; - } - } - } + // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead + let suggest_is_some_and = msrv.meets(msrvs::OPTION_IS_SOME_AND) + && matches!(&unwrap_arg.kind, ExprKind::Lit(lit) + if matches!(lit.node, rustc_ast::LitKind::Bool(false))); let mut applicability = Applicability::MachineApplicable; // get snippet for unwrap_or() diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 1541dc8392c..5aacca45146 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,7 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,70,0 { OPT_IS_SOME_AND } + 1,70,0 { OPTION_IS_SOME_AND } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } -- cgit 1.4.1-3-g733a5 From 9a8347ded53a14fb381f404abd32302e59ef20a9 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Fri, 23 Jun 2023 06:02:39 -0500 Subject: New lint [`redundant_rest_pattern`] --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/needless_collect.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 31 +++++++++++++++++ .../src/misc_early/redundant_rest_pattern.rs | 26 ++++++++++++++ clippy_utils/src/sugg.rs | 2 +- tests/ui/manual_let_else_match.rs | 2 +- tests/ui/match_on_vec_items.rs | 2 +- tests/ui/redundant_rest_pattern.fixed | 27 +++++++++++++++ tests/ui/redundant_rest_pattern.rs | 27 +++++++++++++++ tests/ui/redundant_rest_pattern.stderr | 40 ++++++++++++++++++++++ 12 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 clippy_lints/src/misc_early/redundant_rest_pattern.rs create mode 100644 tests/ui/redundant_rest_pattern.fixed create mode 100644 tests/ui/redundant_rest_pattern.rs create mode 100644 tests/ui/redundant_rest_pattern.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 941efb1abff..6350d9c118f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5141,6 +5141,7 @@ Released 2018-09-13 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate +[`redundant_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_rest_pattern [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 0eec18a91bc..13b0f9d5ee3 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -431,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO, crate::misc_early::REDUNDANT_PATTERN_INFO, + crate::misc_early::REDUNDANT_REST_PATTERN_INFO, crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO, crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO, crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO, diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 99f810c27cf..3c3919dffe5 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection - if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { + if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); self.visit_expr(recv); diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 5ea12c44184..88a3c2620a4 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -289,7 +289,7 @@ fn parse_iter_usage<'tcx>( ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else { + let ExprKind::MethodCall(name, _, args, _) = e.kind else { return None; }; let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 78253ab6cdc..fcf19f17958 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -3,6 +3,7 @@ mod double_neg; mod literal_suffix; mod mixed_case_hex_literals; mod redundant_pattern; +mod redundant_rest_pattern; mod unneeded_field_pattern; mod unneeded_wildcard_pattern; mod zero_prefixed_literal; @@ -318,6 +319,34 @@ declare_clippy_lint! { "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `[all @ ..]` patterns. + /// + /// ### Why is this bad? + /// In all cases, `all` works fine and can often make code simpler, as you possibly won't need + /// to convert from say a `Vec` to a slice by dereferencing. + /// + /// ### Example + /// ```rust,ignore + /// if let [all @ ..] = &*v { + /// // NOTE: Type is a slice here + /// println!("all elements: {all:#?}"); + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// if let all = v { + /// // NOTE: Type is a `Vec` here + /// println!("all elements: {all:#?}"); + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub REDUNDANT_REST_PATTERN, + complexity, + "checks for `[all @ ..]` where `all` would suffice" +} + declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, @@ -329,6 +358,7 @@ declare_lint_pass!(MiscEarlyLints => [ BUILTIN_TYPE_SHADOW, REDUNDANT_PATTERN, UNNEEDED_WILDCARD_PATTERN, + REDUNDANT_REST_PATTERN, ]); impl EarlyLintPass for MiscEarlyLints { @@ -345,6 +375,7 @@ impl EarlyLintPass for MiscEarlyLints { unneeded_field_pattern::check(cx, pat); redundant_pattern::check(cx, pat); + redundant_rest_pattern::check(cx, pat); unneeded_wildcard_pattern::check(cx, pat); } diff --git a/clippy_lints/src/misc_early/redundant_rest_pattern.rs b/clippy_lints/src/misc_early/redundant_rest_pattern.rs new file mode 100644 index 00000000000..87e1ed8317c --- /dev/null +++ b/clippy_lints/src/misc_early/redundant_rest_pattern.rs @@ -0,0 +1,26 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::{Pat, PatKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, LintContext}; +use rustc_middle::lint::in_external_macro; + +use super::REDUNDANT_REST_PATTERN; + +pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { + if !in_external_macro(cx.sess(), pat.span) + && let PatKind::Slice(slice) = &pat.kind + && let [one] = &**slice + && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind + && let PatKind::Rest = rest.kind + { + span_lint_and_sugg( + cx, + REDUNDANT_REST_PATTERN, + pat.span, + "using a rest pattern to bind an entire slice to a local", + "this is better represented with just the binding", + format!("{}{ident}", annotation.prefix_str()), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index f477524eec5..bc3e58169e6 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -942,7 +942,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { }, // item is used in a call // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` - ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => { + ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) => { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs index 07cd5a53a7c..073094ea789 100644 --- a/tests/ui/manual_let_else_match.rs +++ b/tests/ui/manual_let_else_match.rs @@ -1,5 +1,5 @@ #![allow(unused_braces, unused_variables, dead_code)] -#![allow(clippy::collapsible_else_if, clippy::let_unit_value)] +#![allow(clippy::collapsible_else_if, clippy::let_unit_value, clippy::redundant_rest_pattern)] #![warn(clippy::manual_let_else)] // Ensure that we don't conflict with match -> if let lints #![warn(clippy::single_match_else, clippy::single_match)] diff --git a/tests/ui/match_on_vec_items.rs b/tests/ui/match_on_vec_items.rs index d82a736963a..fe214904365 100644 --- a/tests/ui/match_on_vec_items.rs +++ b/tests/ui/match_on_vec_items.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_on_vec_items)] -#![allow(clippy::useless_vec)] +#![allow(clippy::redundant_rest_pattern, clippy::useless_vec)] fn match_with_wildcard() { let arr = vec![0, 1, 2, 3]; diff --git a/tests/ui/redundant_rest_pattern.fixed b/tests/ui/redundant_rest_pattern.fixed new file mode 100644 index 00000000000..d9a98622c42 --- /dev/null +++ b/tests/ui/redundant_rest_pattern.fixed @@ -0,0 +1,27 @@ +//@run-rustfix +//@aux-build:proc_macros.rs +#![allow(irrefutable_let_patterns, unused)] +#![warn(clippy::redundant_rest_pattern)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + if let a = [()] {} + if let ref a = [()] {} + if let mut a = [()] {} + if let ref mut a = [()] {} + let v = vec![()]; + if let a = &*v {} + let s = &[()]; + if let a = s {} + // Don't lint + if let [..] = &*v {} + if let [a] = &*v {} + if let [()] = &*v {} + if let [first, rest @ ..] = &*v {} + if let a = [()] {} + external! { + if let [a @ ..] = [()] {} + } +} diff --git a/tests/ui/redundant_rest_pattern.rs b/tests/ui/redundant_rest_pattern.rs new file mode 100644 index 00000000000..60a12bfd6fb --- /dev/null +++ b/tests/ui/redundant_rest_pattern.rs @@ -0,0 +1,27 @@ +//@run-rustfix +//@aux-build:proc_macros.rs +#![allow(irrefutable_let_patterns, unused)] +#![warn(clippy::redundant_rest_pattern)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + if let [a @ ..] = [()] {} + if let [ref a @ ..] = [()] {} + if let [mut a @ ..] = [()] {} + if let [ref mut a @ ..] = [()] {} + let v = vec![()]; + if let [a @ ..] = &*v {} + let s = &[()]; + if let [a @ ..] = s {} + // Don't lint + if let [..] = &*v {} + if let [a] = &*v {} + if let [()] = &*v {} + if let [first, rest @ ..] = &*v {} + if let a = [()] {} + external! { + if let [a @ ..] = [()] {} + } +} diff --git a/tests/ui/redundant_rest_pattern.stderr b/tests/ui/redundant_rest_pattern.stderr new file mode 100644 index 00000000000..630909a0a16 --- /dev/null +++ b/tests/ui/redundant_rest_pattern.stderr @@ -0,0 +1,40 @@ +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_rest_pattern.rs:10:12 + | +LL | if let [a @ ..] = [()] {} + | ^^^^^^^^ help: this is better represented with just the binding: `a` + | + = note: `-D clippy::redundant-rest-pattern` implied by `-D warnings` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_rest_pattern.rs:11:12 + | +LL | if let [ref a @ ..] = [()] {} + | ^^^^^^^^^^^^ help: this is better represented with just the binding: `ref a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_rest_pattern.rs:12:12 + | +LL | if let [mut a @ ..] = [()] {} + | ^^^^^^^^^^^^ help: this is better represented with just the binding: `mut a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_rest_pattern.rs:13:12 + | +LL | if let [ref mut a @ ..] = [()] {} + | ^^^^^^^^^^^^^^^^ help: this is better represented with just the binding: `ref mut a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_rest_pattern.rs:15:12 + | +LL | if let [a @ ..] = &*v {} + | ^^^^^^^^ help: this is better represented with just the binding: `a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_rest_pattern.rs:17:12 + | +LL | if let [a @ ..] = s {} + | ^^^^^^^^ help: this is better represented with just the binding: `a` + +error: aborting due to 6 previous errors + -- cgit 1.4.1-3-g733a5 From 648d1ae8e08ab8617d17c4c815a067dd7d7e550f Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 14 Jun 2023 03:44:05 +0200 Subject: lint on matches and pattern matching --- clippy_lints/src/methods/filter_map.rs | 320 +++++++++++++++++++++++++++------ clippy_utils/src/higher.rs | 1 + tests/ui/manual_filter_map.fixed | 24 +++ tests/ui/manual_filter_map.rs | 28 +++ tests/ui/manual_filter_map.stderr | 73 +++++++- tests/ui/manual_find_map.stderr | 53 ++++++ 6 files changed, 440 insertions(+), 59 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index fc80f2eeae0..4271f2041fe 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,7 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::macros::{is_panic, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; +use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; +use hir::{Body, HirId, MatchSource, Pat}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -10,7 +12,7 @@ use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::source_map::Span; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{sym, Ident, Symbol}; use std::borrow::Cow; use super::MANUAL_FILTER_MAP; @@ -50,6 +52,214 @@ fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_ar is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } +#[derive(Debug, Copy, Clone)] +enum OffendingFilterExpr<'tcx> { + /// `.filter(|opt| opt.is_some())` + IsSome { + /// The receiver expression + receiver: &'tcx Expr<'tcx>, + /// If `Some`, then this contains the span of an expression that possibly contains side + /// effects: `.filter(|opt| side_effect(opt).is_some())` + /// ^^^^^^^^^^^^^^^^ + /// + /// We will use this later for warning the user that the suggested fix may change + /// the behavior. + side_effect_expr_span: Option, + }, + /// `.filter(|res| res.is_ok())` + IsOk { + /// The receiver expression + receiver: &'tcx Expr<'tcx>, + /// See `IsSome` + side_effect_expr_span: Option, + }, + /// `.filter(|enum| matches!(enum, Enum::A(_)))` + Matches { + /// The DefId of the variant being matched + variant_def_id: hir::def_id::DefId, + }, +} + +#[derive(Debug)] +enum CalledMethod { + OptionIsSome, + ResultIsOk, +} + +/// The result of checking a `map` call, returned by `OffendingFilterExpr::check_map_call` +#[derive(Debug)] +enum CheckResult<'tcx> { + Method { + map_arg: &'tcx Expr<'tcx>, + /// The method that was called inside of `filter` + method: CalledMethod, + /// See `OffendingFilterExpr::IsSome` + side_effect_expr_span: Option, + }, + PatternMatching { + /// The span of the variant being matched + /// if let Some(s) = enum + /// ^^^^^^^ + variant_span: Span, + /// if let Some(s) = enum + /// ^ + variant_ident: Ident, + }, +} + +impl<'tcx> OffendingFilterExpr<'tcx> { + pub fn check_map_call( + &mut self, + cx: &LateContext<'tcx>, + map_body: &'tcx Body<'tcx>, + map_param_id: HirId, + filter_param_id: HirId, + is_filter_param_ref: bool, + ) -> Option> { + match *self { + OffendingFilterExpr::IsSome { + receiver, + side_effect_expr_span, + } + | OffendingFilterExpr::IsOk { + receiver, + side_effect_expr_span, + } => { + // check if closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind + && matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or) + // .map(|y| f(y).copied().unwrap()) + // ~~~~ + && let map_arg_peeled = match map_arg.kind { + ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { + original_arg + }, + _ => map_arg, + } + // .map(|y| y[.acceptable_method()].unwrap()) + && let simple_equal = (path_to_local_id(receiver, filter_param_id) + && path_to_local_id(map_arg_peeled, map_param_id)) + && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; + then { expr_path } else { a } + }; + // let the filter closure arg and the map closure arg be equal + path_to_local_id(a_path, filter_param_id) + && path_to_local_id(b, map_param_id) + && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + }) + && (simple_equal + || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled)) + { + Some(CheckResult::Method { + map_arg, + side_effect_expr_span, + method: match self { + OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome, + OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk, + OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"), + } + }) + } else { + None + } + }, + OffendingFilterExpr::Matches { variant_def_id } => { + let expr_uses_local = |pat: &Pat<'_>, expr: &Expr<'_>| { + if let PatKind::TupleStruct(QPath::Resolved(_, path), [subpat], _) = pat.kind + && let PatKind::Binding(_, local_id, ident, _) = subpat.kind + && path_to_local_id(expr.peel_blocks(), local_id) + && let Some(local_variant_def_id) = path.res.opt_def_id() + && local_variant_def_id == variant_def_id + { + Some((ident, pat.span)) + } else { + None + } + }; + + // look for: + // `if let Variant (v) = enum { v } else { unreachable!() }` + // ^^^^^^^ ^ ^^^^ ^^^^^^^^^^^^^^^^^^ + // variant_span variant_ident scrutinee else_ (blocks peeled later) + // OR + // `match enum { Variant (v) => v, _ => unreachable!() }` + // ^^^^ ^^^^^^^ ^ ^^^^^^^^^^^^^^ + // scrutinee variant_span variant_ident else_ + let (scrutinee, else_, variant_ident, variant_span) = + match higher::IfLetOrMatch::parse(cx, map_body.value) { + // For `if let` we want to check that the variant matching arm references the local created by its pattern + Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_))) + if let Some((ident, span)) = expr_uses_local(pat, then) => + { + (sc, else_, ident, span) + }, + // For `match` we want to check that the "else" arm is the wildcard (`_`) pattern + // and that the variant matching arm references the local created by its pattern + Some(higher::IfLetOrMatch::Match(sc, [arm, wild_arm], MatchSource::Normal)) + if let PatKind::Wild = wild_arm.pat.kind + && let Some((ident, span)) = expr_uses_local(arm.pat, arm.body.peel_blocks()) => + { + (sc, wild_arm.body, ident, span) + }, + _ => return None, + }; + + if path_to_local_id(scrutinee, map_param_id) + // else branch should be a `panic!` or `unreachable!` macro call + && let Some(mac) = root_macro_call(else_.peel_blocks().span) + && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable)) + { + Some(CheckResult::PatternMatching { variant_span, variant_ident }) + } else { + None + } + }, + } + } + + fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -> Option { + if let ExprKind::MethodCall(path, receiver, [], _) = expr.kind + && let Some(recv_ty) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def() + { + // we still want to lint if the expression possibly contains side effects, + // *but* it can't be machine-applicable then, because that can change the behavior of the program: + // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap()) + // vs. + // .filter_map(|x| effect(x)) + // + // the latter only calls `effect` once + let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); + + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) + && path.ident.name == sym!(is_some) + { + Some(Self::IsSome { receiver, side_effect_expr_span }) + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) + && path.ident.name == sym!(is_ok) + { + Some(Self::IsOk { receiver, side_effect_expr_span }) + } else { + None + } + } else if let Some(macro_call) = root_macro_call(expr.span) + && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro) + // we know for a fact that the wildcard pattern is the second arm + && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind + && path_to_local_id(scrutinee, filter_param_id) + && let PatKind::TupleStruct(QPath::Resolved(_, path), ..) = arm.pat.kind + && let Some(variant_def_id) = path.res.opt_def_id() + { + Some(OffendingFilterExpr::Matches { variant_def_id }) + } else { + None + } + } +} + /// is `filter(|x| x.is_some()).map(|x| x.unwrap())` fn is_filter_some_map_unwrap( cx: &LateContext<'_>, @@ -104,55 +314,18 @@ pub(super) fn check( } else { (filter_param.pat, false) }; - // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { - Some(false) - } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { - Some(true) - } else { - None - }; - if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + if let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id); - // ...map(|x| ...unwrap()) if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; let map_body = cx.tcx.hir().body(map_body_id); if let [map_param] = map_body.params; if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; - // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); - - // .filter(..).map(|y| f(y).copied().unwrap()) - // ~~~~ - let map_arg_peeled = match map_arg.kind { - ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { - original_arg - }, - _ => map_arg, - }; - // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) - let simple_equal = path_to_local_id(filter_arg, filter_param_id) - && path_to_local_id(map_arg_peeled, map_param_id); + if let Some(check_result) = + offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref); - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; - // let the filter closure arg and the map closure arg be equal - path_to_local_id(a_path, filter_param_id) - && path_to_local_id(b, map_param_id) - && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) - }; - - if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); then { let span = filter_span.with_hi(expr.span.hi()); let (filter_name, lint) = if is_find { @@ -161,22 +334,53 @@ pub(super) fn check( ("filter", MANUAL_FILTER_MAP) }; let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); - let (to_opt, deref) = if is_result { - (".ok()", String::new()) - } else { - let derefs = cx.typeck_results() - .expr_adjustments(map_arg) - .iter() - .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) - .count(); - ("", "*".repeat(derefs)) + let (sugg, note_and_span, applicability) = match check_result { + CheckResult::Method { map_arg, method, side_effect_expr_span } => { + let (to_opt, deref) = match method { + CalledMethod::ResultIsOk => (".ok()", String::new()), + CalledMethod::OptionIsSome => { + let derefs = cx.typeck_results() + .expr_adjustments(map_arg) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); + + ("", "*".repeat(derefs)) + } + }; + + let sugg = format!( + "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", + snippet(cx, map_arg.span, ".."), + ); + let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span { + let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \ + because this expression potentially contains side effects and will only execute once"; + + (Some((note, span)), Applicability::MaybeIncorrect) + } else { + (None, Applicability::MachineApplicable) + }; + + (sugg, note_and_span, applicability) + } + CheckResult::PatternMatching { variant_span, variant_ident } => { + let pat = snippet(cx, variant_span, ""); + + (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \ + {pat} => Some({variant_ident}), \ + _ => None \ + }})"), None, Applicability::MachineApplicable) + } }; - let sugg = format!( - "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", - snippet(cx, map_arg.span, ".."), - ); - span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + span_lint_and_then(cx, lint, span, &msg, |diag| { + diag.span_suggestion(span, "try", sugg, applicability); + + if let Some((note, span)) = note_and_span { + diag.span_note(span, note); + } + }); } } } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index a61e4c38088..e6dc81127dd 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -138,6 +138,7 @@ impl<'hir> IfLet<'hir> { } /// An `if let` or `match` expression. Useful for lints that trigger on one or the other. +#[derive(Debug)] pub enum IfLetOrMatch<'hir> { /// Any `match` expression Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource), diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index 9dd376df2b4..35872a39a71 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -120,3 +120,27 @@ fn issue_8920() { .iter() .filter_map(|f| f.result_field.to_owned().ok()); } + +fn issue8010() { + #[derive(Clone)] + enum Enum { + A(i32), + B, + } + + let iter = [Enum::A(123), Enum::B].into_iter(); + + let _x = iter.clone().filter_map(|x| match x { Enum::A(s) => Some(s), _ => None }); + let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x { + Enum::A(s) => s, + _ => unreachable!(), + }); + let _x = iter + .clone() + .filter_map(|x| match x { Enum::A(s) => Some(s), _ => None }); + #[allow(clippy::unused_unit)] + let _x = iter + .clone() + .filter(|x| matches!(x, Enum::B)) + .map(|x| if let Enum::B = x { () } else { unreachable!() }); +} diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 6dd1e066aeb..50d8d2722c2 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -133,3 +133,31 @@ fn issue_8920() { .filter(|f| f.result_field.is_ok()) .map(|f| f.result_field.to_owned().unwrap()); } + +fn issue8010() { + #[derive(Clone)] + enum Enum { + A(i32), + B, + } + + let iter = [Enum::A(123), Enum::B].into_iter(); + + let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x { + Enum::A(s) => s, + _ => unreachable!(), + }); + let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x { + Enum::A(s) => s, + _ => unreachable!(), + }); + let _x = iter + .clone() + .filter(|x| matches!(x, Enum::A(_))) + .map(|x| if let Enum::A(s) = x { s } else { unreachable!() }); + #[allow(clippy::unused_unit)] + let _x = iter + .clone() + .filter(|x| matches!(x, Enum::B)) + .map(|x| if let Enum::B = x { () } else { unreachable!() }); +} diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index 882468b0f5f..0e8672c0293 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -4,6 +4,11 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)` LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:9:30 + | +LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + | ^^^^^^^^^^ = note: `-D clippy::manual-filter-map` implied by `-D warnings` error: `filter(..).map(..)` can be simplified as `filter_map(..)` @@ -11,12 +16,24 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)` | LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:12:31 + | +LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:15:19 | LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:15:31 + | +LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:18:10 @@ -25,6 +42,12 @@ LL | .filter(|&x| to_ref(to_opt(x)).is_some()) | __________^ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:18:22 + | +LL | .filter(|&x| to_ref(to_opt(x)).is_some()) + | ^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:21:10 @@ -33,6 +56,12 @@ LL | .filter(|x| to_ref(to_opt(*x)).is_some()) | __________^ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:21:21 + | +LL | .filter(|x| to_ref(to_opt(*x)).is_some()) + | ^^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:25:10 @@ -41,6 +70,12 @@ LL | .filter(|&x| to_ref(to_res(x)).is_ok()) | __________^ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:25:22 + | +LL | .filter(|&x| to_ref(to_res(x)).is_ok()) + | ^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:28:10 @@ -49,6 +84,12 @@ LL | .filter(|x| to_ref(to_res(*x)).is_ok()) | __________^ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:28:21 + | +LL | .filter(|x| to_ref(to_res(*x)).is_ok()) + | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_filter_map.rs:34:27 @@ -75,6 +116,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:37:41 + | +LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_filter_map.rs:39:30 @@ -117,6 +164,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_filter_map.rs:45:45 + | +LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:93:10 @@ -190,5 +243,23 @@ LL | .filter(|f| f.result_field.is_ok()) LL | | .map(|f| f.result_field.to_owned().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())` -error: aborting due to 27 previous errors +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:146:27 + | +LL | let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x { + | ___________________________^ +LL | | Enum::A(s) => s, +LL | | _ => unreachable!(), +LL | | }); + | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })` + +error: `filter(..).map(..)` can be simplified as `filter_map(..)` + --> $DIR/manual_filter_map.rs:156:10 + | +LL | .filter(|x| matches!(x, Enum::A(_))) + | __________^ +LL | | .map(|x| if let Enum::A(s) = x { s } else { unreachable!() }); + | |_____________________________________________________________________^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })` + +error: aborting due to 29 previous errors diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index 693a06bb559..4e52b5efacf 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -4,6 +4,11 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:9:28 + | +LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + | ^^^^^^^^^^ = note: `-D clippy::manual-find-map` implied by `-D warnings` error: `find(..).map(..)` can be simplified as `find_map(..)` @@ -11,12 +16,24 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` | LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:12:29 + | +LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:15:19 | LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:15:29 + | +LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:18:10 @@ -25,6 +42,12 @@ LL | .find(|&x| to_ref(to_opt(x)).is_some()) | __________^ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:18:20 + | +LL | .find(|&x| to_ref(to_opt(x)).is_some()) + | ^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:21:10 @@ -33,6 +56,12 @@ LL | .find(|x| to_ref(to_opt(*x)).is_some()) | __________^ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:21:19 + | +LL | .find(|x| to_ref(to_opt(*x)).is_some()) + | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:25:10 @@ -41,6 +70,12 @@ LL | .find(|&x| to_ref(to_res(x)).is_ok()) | __________^ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:25:20 + | +LL | .find(|&x| to_ref(to_res(x)).is_ok()) + | ^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:28:10 @@ -49,6 +84,12 @@ LL | .find(|x| to_ref(to_res(*x)).is_ok()) | __________^ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:28:19 + | +LL | .find(|x| to_ref(to_res(*x)).is_ok()) + | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:34:26 @@ -91,6 +132,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:40:41 + | +LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:42:30 @@ -133,6 +180,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` + | +note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once + --> $DIR/manual_find_map.rs:48:45 + | +LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); + | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:96:10 -- cgit 1.4.1-3-g733a5 From 420f3d11e8cc0f6353f65f578c21ffef3c369314 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 1 Jul 2023 07:08:01 -0400 Subject: "try this" -> "try" --- clippy_lints/src/dereference.rs | 8 +-- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/init_numbered_fields.rs | 2 +- clippy_lints/src/loops/missing_spin_loop.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 6 +- .../src/matches/infallible_destructuring_match.rs | 2 +- clippy_lints/src/matches/manual_filter.rs | 2 +- clippy_lints/src/matches/manual_map.rs | 2 +- clippy_lints/src/matches/match_as_ref.rs | 2 +- clippy_lints/src/matches/match_like_matches.rs | 2 +- clippy_lints/src/matches/match_on_vec_items.rs | 2 +- clippy_lints/src/matches/match_wild_enum.rs | 4 +- .../src/matches/redundant_pattern_match.rs | 4 +- clippy_lints/src/matches/single_match.rs | 2 +- clippy_lints/src/matches/try_err.rs | 2 +- clippy_lints/src/methods/bind_instead_of_map.rs | 4 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 4 +- clippy_lints/src/methods/extend_with_drain.rs | 2 +- clippy_lints/src/methods/filter_map_next.rs | 2 +- clippy_lints/src/methods/filter_next.rs | 2 +- clippy_lints/src/methods/get_unwrap.rs | 2 +- clippy_lints/src/methods/iter_overeager_cloned.rs | 2 +- clippy_lints/src/methods/iter_with_drain.rs | 2 +- clippy_lints/src/methods/manual_str_repeat.rs | 2 +- .../src/methods/map_collect_result_unit.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- .../src/methods/needless_option_as_deref.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 4 +- clippy_lints/src/methods/or_then_unwrap.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 4 +- clippy_lints/src/methods/string_extend_chars.rs | 2 +- clippy_lints/src/methods/useless_asref.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/strlen_on_c_strings.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/write.rs | 2 +- tests/lint_message_convention.rs | 6 +- .../uninlined_format_args.stderr | 2 +- tests/ui-toml/unwrap_used/unwrap_used.stderr | 30 ++++----- tests/ui/bind_instead_of_map.stderr | 2 +- tests/ui/bind_instead_of_map_multipart.stderr | 10 +-- tests/ui/crashes/ice-7169.stderr | 2 +- tests/ui/crashes/ice-8250.stderr | 2 +- tests/ui/deref_addrof.stderr | 20 +++--- tests/ui/deref_addrof_double_trigger.stderr | 6 +- tests/ui/entry.stderr | 20 +++--- tests/ui/entry_btree.stderr | 2 +- tests/ui/entry_with_else.stderr | 14 ++-- tests/ui/expect_fun_call.stderr | 30 ++++----- tests/ui/explicit_auto_deref.stderr | 78 +++++++++++----------- tests/ui/explicit_deref_methods.stderr | 24 +++---- tests/ui/explicit_write.stderr | 26 ++++---- tests/ui/extend_with_drain.stderr | 8 +-- tests/ui/filter_map_next_fixable.stderr | 4 +- tests/ui/get_unwrap.stderr | 34 +++++----- tests/ui/infallible_destructuring_match.stderr | 8 +-- tests/ui/iter_overeager_cloned.stderr | 14 ++-- tests/ui/iter_with_drain.stderr | 12 ++-- tests/ui/manual_filter.stderr | 30 ++++----- tests/ui/manual_map_option.stderr | 42 ++++++------ tests/ui/manual_map_option_2.stderr | 10 +-- tests/ui/manual_split_once.stderr | 28 ++++---- tests/ui/manual_str_repeat.stderr | 20 +++--- tests/ui/map_collect_result_unit.stderr | 4 +- tests/ui/map_unwrap_or.stderr | 2 +- tests/ui/map_unwrap_or_fixable.stderr | 4 +- tests/ui/match_as_ref.stderr | 6 +- tests/ui/match_expr_like_matches_macro.stderr | 28 ++++---- tests/ui/match_on_vec_items.stderr | 16 ++--- tests/ui/match_ref_pats.stderr | 4 +- tests/ui/match_same_arms2.stderr | 2 +- tests/ui/match_wildcard_for_single_variants.stderr | 20 +++--- tests/ui/methods_fixable.stderr | 2 +- tests/ui/missing_spin_loop.stderr | 12 ++-- tests/ui/missing_spin_loop_no_std.stderr | 2 +- tests/ui/needless_borrow_pat.stderr | 24 +++---- tests/ui/needless_option_as_deref.stderr | 6 +- tests/ui/needless_splitn.stderr | 26 ++++---- tests/ui/numbered_fields.stderr | 4 +- tests/ui/option_map_unit_fn_fixable.stderr | 38 +++++------ tests/ui/or_fun_call.stderr | 56 ++++++++-------- tests/ui/or_then_unwrap.stderr | 6 +- tests/ui/print_literal.stderr | 24 +++---- .../redundant_pattern_matching_drop_order.stderr | 44 ++++++------ tests/ui/redundant_pattern_matching_ipaddr.stderr | 36 +++++----- tests/ui/redundant_pattern_matching_option.stderr | 56 ++++++++-------- tests/ui/redundant_pattern_matching_poll.stderr | 36 +++++----- tests/ui/redundant_pattern_matching_result.stderr | 56 ++++++++-------- tests/ui/ref_binding_to_reference.stderr | 14 ++-- tests/ui/result_map_unit_fn_fixable.stderr | 36 +++++----- tests/ui/result_map_unit_fn_unfixable.stderr | 12 ++-- tests/ui/single_match.stderr | 36 +++++----- tests/ui/single_match_else.stderr | 18 ++--- tests/ui/string_extend.stderr | 8 +-- tests/ui/strlen_on_c_strings.stderr | 14 ++-- tests/ui/to_digit_is_some.stderr | 4 +- tests/ui/try_err.stderr | 22 +++--- tests/ui/unnecessary_clone.stderr | 12 ++-- tests/ui/unwrap_or.stderr | 4 +- tests/ui/useless_asref.stderr | 22 +++--- tests/ui/wildcard_enum_match_arm.stderr | 12 ++-- tests/ui/write_literal.stderr | 24 +++---- tests/ui/write_literal_2.stderr | 28 ++++---- 105 files changed, 682 insertions(+), 680 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 73556c1053e..20378849c22 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -589,7 +589,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { pat.spans, "this pattern creates a reference to a reference", |diag| { - diag.multipart_suggestion("try this", replacements, app); + diag.multipart_suggestion("try", replacements, app); }, ); } @@ -1531,7 +1531,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data Mutability::Not => "explicit `deref` method call", Mutability::Mut => "explicit `deref_mut` method call", }, - "try this", + "try", format!("{addr_of_str}{deref_str}{expr_str}"), app, ); @@ -1593,7 +1593,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data } else { format!("{prefix}{snip}") }; - diag.span_suggestion(data.span, "try this", sugg, app); + diag.span_suggestion(data.span, "try", sugg, app); }, ); }, @@ -1620,7 +1620,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data |diag| { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0; - diag.span_suggestion(data.span, "try this", snip.into_owned(), app); + diag.span_suggestion(data.span, "try", snip.into_owned(), app); }, ); }, diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index ee5a875ade7..86e94a62a78 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { MAP_ENTRY, expr.span, &format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()), - "try this", + "try", sugg, app, ); diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 315df6c714f..4b9ca8c917e 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { EXPLICIT_WRITE, expr.span, &format!("use of `{used}.unwrap()`"), - "try this", + "try", format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, ); diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index 7e1548531f1..f95d2c2edb1 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields { INIT_NUMBERED_FIELDS, e.span, "used a field initializer for a tuple struct", - "try this instead", + "try", snippet, appl, ); diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs index 8412875b11b..f3bfe9e927d 100644 --- a/clippy_lints/src/loops/missing_spin_loop.rs +++ b/clippy_lints/src/loops/missing_spin_loop.rs @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' MISSING_SPIN_LOOP, body.span, "busy-waiting loop should at least have a spin loop hint", - "try this", + "try", (if is_no_std_crate(cx) { "{ core::hint::spin_loop() }" } else { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index edcab6968cb..1b3a47e4acd 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -226,7 +226,7 @@ fn lint_map_unit_fn( ); span_lint_and_then(cx, lint, expr.span, &msg, |diag| { - diag.span_suggestion(stmt.span, "try this", suggestion, applicability); + diag.span_suggestion(stmt.span, "try", suggestion, applicability); }); } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) { let msg = suggestion_msg("closure", map_type); @@ -241,7 +241,7 @@ fn lint_map_unit_fn( snippet_with_applicability(cx, var_arg.span, "_", &mut applicability), snippet_with_context(cx, reduced_expr_span, var_arg.span.ctxt(), "_", &mut applicability).0, ); - diag.span_suggestion(stmt.span, "try this", suggestion, applicability); + diag.span_suggestion(stmt.span, "try", suggestion, applicability); } else { let suggestion = format!( "if let {0}({1}) = {2} {{ ... }}", @@ -249,7 +249,7 @@ fn lint_map_unit_fn( snippet(cx, binding.pat.span, "_"), snippet(cx, var_arg.span, "_"), ); - diag.span_suggestion(stmt.span, "try this", suggestion, Applicability::HasPlaceholders); + diag.span_suggestion(stmt.span, "try", suggestion, Applicability::HasPlaceholders); } }); } diff --git a/clippy_lints/src/matches/infallible_destructuring_match.rs b/clippy_lints/src/matches/infallible_destructuring_match.rs index d18c92caba2..3329f93b73c 100644 --- a/clippy_lints/src/matches/infallible_destructuring_match.rs +++ b/clippy_lints/src/matches/infallible_destructuring_match.rs @@ -28,7 +28,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool { local.span, "you seem to be trying to use `match` to destructure a single infallible pattern. \ Consider using `let`", - "try this", + "try", format!( "let {}({}{}) = {};", snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index f6bf0e7aa1a..e0181a4757c 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -143,7 +143,7 @@ fn check<'tcx>( MANUAL_FILTER, expr.span, "manual implementation of `Option::filter`", - "try this", + "try", if sugg_info.needs_brackets { format!( "{{ {}{}.filter({body_str}) }}", diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index aaba239677f..ed3d8b09fdc 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -58,7 +58,7 @@ fn check<'tcx>( MANUAL_MAP, expr.span, "manual implementation of `Option::map`", - "try this", + "try", if sugg_info.needs_brackets { format!( "{{ {}{}.map({}) }}", diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 2818f030b7a..a6392b7aaec 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -46,7 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: MATCH_AS_REF, expr.span, &format!("use `{suggestion}()` instead"), - "try this", + "try", format!( "{}.{suggestion}(){cast}", snippet_with_applicability(cx, ex.span, "_", &mut applicability), diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 0064619ef89..69f6c59beb3 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -139,7 +139,7 @@ where MATCH_LIKE_MATCHES_MACRO, expr.span, &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }), - "try this", + "try", format!( "{}matches!({}, {pat_and_guard})", if b0 { "" } else { "!" }, diff --git a/clippy_lints/src/matches/match_on_vec_items.rs b/clippy_lints/src/matches/match_on_vec_items.rs index 2917f85c45f..89dcac4d849 100644 --- a/clippy_lints/src/matches/match_on_vec_items.rs +++ b/clippy_lints/src/matches/match_on_vec_items.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { MATCH_ON_VEC_ITEMS, scrutinee.span, "indexing into a vector may panic", - "try this", + "try", format!( "{}.get({})", snippet(cx, vec.span, ".."), diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 3126b590180..8d22ceb47f8 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -143,7 +143,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { MATCH_WILDCARD_FOR_SINGLE_VARIANTS, wildcard_span, "wildcard matches only a single variant and will also match any future added variants", - "try this", + "try", format_suggestion(x), Applicability::MaybeIncorrect, ), @@ -161,7 +161,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { WILDCARD_ENUM_MATCH_ARM, wildcard_span, message, - "try this", + "try", suggestions.join(" | "), Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 479cfd83512..43d2ab9f60e 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -175,7 +175,7 @@ fn find_sugg_for_if_let<'tcx>( .maybe_par() .to_string(); - diag.span_suggestion(span, "try this", format!("{keyword} {sugg}.{good_method}"), app); + diag.span_suggestion(span, "try", format!("{keyword} {sugg}.{good_method}"), app); if needs_drop { diag.note("this will change drop order of the result, as well as all temporaries"); @@ -200,7 +200,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op REDUNDANT_PATTERN_MATCHING, span, &format!("redundant pattern matching, consider using `{good_method}`"), - "try this", + "try", format!("{}.{good_method}", snippet(cx, result_expr.span, "_")), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 35627d6c649..6b05c6bfffd 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -136,7 +136,7 @@ fn report_single_pattern( } }; - span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app); + span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app); } fn check_opt_like<'a>( diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 3a7f1e034f3..99a748489b4 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine TRY_ERR, expr.span, "returning an `Err(_)` with the `?` operator", - "try this", + "try", suggestion, applicability, ); diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 00853348840..883a5505827 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -87,7 +87,7 @@ pub(crate) trait BindInsteadOfMap { BIND_INSTEAD_OF_MAP, expr.span, &msg, - "try this", + "try", note, app, ); @@ -124,7 +124,7 @@ pub(crate) trait BindInsteadOfMap { span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| { multispan_sugg_with_applicability( diag, - "try this", + "try", Applicability::MachineApplicable, std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain( suggs diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 5e8ad0861f3..ddf3c9f27df 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -42,7 +42,7 @@ pub(super) fn check( CLONE_ON_REF_PTR, expr.span, "using `.clone()` on a ref-counted pointer", - "try this", + "try", format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), app, ); diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 92d21bb8932..862a7cec775 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -144,7 +144,7 @@ pub(super) fn check<'tcx>( EXPECT_FUN_CALL, span_replace_word, &format!("use of `{name}` followed by a function call"), - "try this", + "try", format!("unwrap_or_else({closure_args} panic!({sugg}))"), applicability, ); @@ -162,7 +162,7 @@ pub(super) fn check<'tcx>( EXPECT_FUN_CALL, span_replace_word, &format!("use of `{name}` followed by a function call"), - "try this", + "try", format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"), applicability, ); diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index 37b28463527..495b266529b 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: EXTEND_WITH_DRAIN, expr.span, "use of `extend` instead of `append` for adding the full range of a second vector", - "try this", + "try", format!( "{}.append({}{})", snippet_with_applicability(cx, recv.span, "..", &mut applicability), diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 175e04f8ac0..3f89e593148 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( FILTER_MAP_NEXT, expr.span, msg, - "try this", + "try", format!("{iter_snippet}.find_map({filter_snippet})"), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index edcec0fc101..ad71b494619 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( FILTER_NEXT, expr.span, msg, - "try this", + "try", format!("{iter_snippet}.find({filter_snippet})"), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index e35fb12ed79..a8f090d1de1 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -71,7 +71,7 @@ pub(super) fn check<'tcx>( GET_UNWRAP, span, &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), - "try this", + "try", format!( "{borrow_str}{}[{get_args_str}]", snippet_with_applicability(cx, recv.span, "..", &mut applicability) diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index b4210d87510..9f7ec19aa59 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( if let Some(mut snip) = snippet_opt(cx, method_span) { snip.push_str(trailing_clone); let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try this", snip, Applicability::MachineApplicable); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); } } ); diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index f6772c5c6b3..2ab721ace84 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span ITER_WITH_DRAIN, span.with_hi(expr.span.hi()), &format!("`drain(..)` used on a `{ty_name}`"), - "try this", + "try", "into_iter()".to_string(), Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index a08f7254053..ab13d30d845 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -88,7 +88,7 @@ pub(super) fn check( MANUAL_STR_REPEAT, collect_expr.span, "manual implementation of `str::repeat` using iterators", - "try this", + "try", format!("{val_str}.repeat({count_snip})"), app ) diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index a0300d27870..36c7ddc973c 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr MAP_COLLECT_RESULT_UNIT, expr.span, "`.map().collect()` can be replaced with `.try_for_each()`", - "try this", + "try", format!( "{}.try_for_each({})", snippet(cx, iter.span, ".."), diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 3122f72ee91..2c60e85fa90 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -63,7 +63,7 @@ pub(super) fn check<'tcx>( MAP_UNWRAP_OR, expr.span, msg, - "try this", + "try", format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 7030baf19ff..c18bfa1b802 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name NEEDLESS_OPTION_AS_DEREF, expr.span, "derefed type is same as origin", - "try this", + "try", snippet_opt(cx, recv.span).unwrap(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 7ce28ea93e0..9165c1248f0 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( OR_FUN_CALL, method_span.with_hi(span.hi()), &format!("use of `{name}` followed by a call to `{path}`"), - "try this", + "try", format!("{sugg}()"), Applicability::MachineApplicable, ); @@ -139,7 +139,7 @@ pub(super) fn check<'tcx>( OR_FUN_CALL, span_replace_word, &format!("use of `{name}` followed by a function call"), - "try this", + "try", format!("{name}_{suffix}({sugg})"), app, ); diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 55ba6e262df..d65082173b3 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>( OR_THEN_UNWRAP, unwrap_expr.span.with_lo(or_span.lo()), title, - "try this", + "try", suggestion, applicability, ); diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 88a3c2620a4..41986551da4 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -55,7 +55,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_ NEEDLESS_SPLITN, expr.span, &format!("unnecessary use of `{r}splitn`"), - "try this", + "try", format!( "{}.{r}split({})", snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut app).0, @@ -110,7 +110,7 @@ fn check_manual_split_once( IterUsageKind::Nth(_) => return, }; - span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app); + span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try", sugg, app); } /// checks for diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index 2c20c6d752d..c7885f689d7 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -34,7 +34,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr STRING_EXTEND_CHARS, expr.span, "calling `.extend(_.chars())`", - "try this", + "try", format!( "{}.push_str({ref_str}{})", snippet_with_applicability(cx, recv.span, "..", &mut applicability), diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index c1139d84e2f..b5f810eddf4 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, USELESS_ASREF, expr.span, &format!("this call to `{call_name}` does nothing"), - "try this", + "try", snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, ); diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index a642e2da3ba..db870ec4c5b 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -94,7 +94,7 @@ impl EarlyLintPass for DerefAddrOf { DEREF_ADDROF, e.span, "immediately dereferencing a reference", - "try this", + "try", sugg.to_string(), applicability, ); diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 2f2e84fa35a..b3db5e9a422 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { STRLEN_ON_C_STRINGS, span, "using `libc::strlen` on a `CString` or `CStr` value", - "try this", + "try", format!("{val_name}.{method_name}().len()"), app, ); diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 2512500a6be..f1b703fde0e 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { TO_DIGIT_IS_SOME, expr.span, "use of `.to_digit(..).is_some()`", - "try this", + "try", if is_method_call { format!("{char_arg_snip}.is_digit({radix_snip})") } else { diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index f194dc5d4b2..8f1363b6074 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -522,7 +522,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { { let replacement = replacement.replace('{', "{{").replace('}', "}}"); diag.multipart_suggestion( - "try this", + "try", vec![(*placeholder_span, replacement), (removal_span, String::new())], Applicability::MachineApplicable, ); diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index 15e5cdd6992..98019c75527 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -18,18 +18,20 @@ impl Message { fn new(path: PathBuf) -> Self { // we don't want the first letter after "error: ", "help: " ... to be capitalized // also no punctuation (except for "?" ?) at the end of a line + // Prefer "try" over "try this". static REGEX_SET: LazyLock = LazyLock::new(|| { RegexSet::new([ "error: [A-Z]", "help: [A-Z]", "warning: [A-Z]", "note: [A-Z]", - "try this: [A-Z]", + "try: [A-Z]", "error: .*[.!]$", "help: .*[.!]$", "warning: .*[.!]$", "note: .*[.!]$", - "try this: .*[.!]$", + "try: .*[.!]$", + "try this", ]) .unwrap() }); diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr index 6ec79a618de..eb1180e60b8 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr @@ -30,7 +30,7 @@ LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^ | = note: `-D clippy::print-literal` implied by `-D warnings` -help: try this +help: try | LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); LL + println!("Hello x is {:.*}", local_i32, local_f64); diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index eb66a5cf50b..aed29a51c1d 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -2,7 +2,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/unwrap_used.rs:40:17 | LL | let _ = boxed_slice.get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` | = note: `-D clippy::get-unwrap` implied by `-D warnings` @@ -19,7 +19,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/unwrap_used.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:41:17 @@ -33,7 +33,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc --> $DIR/unwrap_used.rs:42:17 | LL | let _ = some_vec.get(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:42:17 @@ -47,7 +47,7 @@ error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more --> $DIR/unwrap_used.rs:43:17 | LL | let _ = some_vecdeque.get(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:43:17 @@ -61,7 +61,7 @@ error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more --> $DIR/unwrap_used.rs:44:17 | LL | let _ = some_hashmap.get(&1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:44:17 @@ -75,7 +75,7 @@ error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more --> $DIR/unwrap_used.rs:45:17 | LL | let _ = some_btreemap.get(&1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:45:17 @@ -89,7 +89,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/unwrap_used.rs:49:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:49:22 @@ -103,7 +103,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor --> $DIR/unwrap_used.rs:54:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:54:10 @@ -117,7 +117,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor --> $DIR/unwrap_used.rs:55:9 | LL | *some_slice.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:55:10 @@ -131,7 +131,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more --> $DIR/unwrap_used.rs:56:9 | LL | *some_vec.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:56:10 @@ -145,7 +145,7 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and --> $DIR/unwrap_used.rs:57:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:57:10 @@ -159,7 +159,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc --> $DIR/unwrap_used.rs:69:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:69:17 @@ -173,7 +173,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more --> $DIR/unwrap_used.rs:70:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:70:17 @@ -187,13 +187,13 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/unwrap_used.rs:77:13 | LL | let _ = boxed_slice.get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:95:17 | LL | let _ = Box::new([0]).get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&Box::new([0])[1]` error: aborting due to 28 previous errors diff --git a/tests/ui/bind_instead_of_map.stderr b/tests/ui/bind_instead_of_map.stderr index b6a81d21bb2..f17fee7460d 100644 --- a/tests/ui/bind_instead_of_map.stderr +++ b/tests/ui/bind_instead_of_map.stderr @@ -14,7 +14,7 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed --> $DIR/bind_instead_of_map.rs:10:13 | LL | let _ = x.and_then(|o| Some(o + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map(|o| o + 1)` error: using `Result.and_then(Ok)`, which is a no-op --> $DIR/bind_instead_of_map.rs:16:13 diff --git a/tests/ui/bind_instead_of_map_multipart.stderr b/tests/ui/bind_instead_of_map_multipart.stderr index 0152a93feee..cedbca78561 100644 --- a/tests/ui/bind_instead_of_map_multipart.stderr +++ b/tests/ui/bind_instead_of_map_multipart.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(clippy::bind_instead_of_map)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: try this +help: try | LL | let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); | ~~~ ~ ~~~~~~~ @@ -20,7 +20,7 @@ error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as LL | let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try this +help: try | LL | let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); | ~~~ ~ ~~~~~~~ @@ -31,7 +31,7 @@ error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as LL | let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try this +help: try | LL | let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() }); | ~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~ @@ -48,7 +48,7 @@ LL | | } LL | | }); | |______^ | -help: try this +help: try | LL ~ Some("42").map(|s| { LL | if { @@ -82,7 +82,7 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed LL | let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try this +help: try | LL | let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) }); | ~~~ ~~~~ ~~~~~~~~ diff --git a/tests/ui/crashes/ice-7169.stderr b/tests/ui/crashes/ice-7169.stderr index 84e0af3f0d0..0cd02851640 100644 --- a/tests/ui/crashes/ice-7169.stderr +++ b/tests/ui/crashes/ice-7169.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/ice-7169.rs:10:12 | LL | if let Ok(_) = Ok::<_, ()>(A::::default()) {} - | -------^^^^^-------------------------------------- help: try this: `if Ok::<_, ()>(A::::default()).is_ok()` + | -------^^^^^-------------------------------------- help: try: `if Ok::<_, ()>(A::::default()).is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` diff --git a/tests/ui/crashes/ice-8250.stderr b/tests/ui/crashes/ice-8250.stderr index 8ed8f3b3a06..e6f3644ef34 100644 --- a/tests/ui/crashes/ice-8250.stderr +++ b/tests/ui/crashes/ice-8250.stderr @@ -2,7 +2,7 @@ error: unnecessary use of `splitn` --> $DIR/ice-8250.rs:2:13 | LL | let _ = s[1..].splitn(2, '.').next()?; - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split('.')` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s[1..].split('.')` | = note: `-D clippy::needless-splitn` implied by `-D warnings` diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index e0287522fc5..9dd1e246b3e 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -2,7 +2,7 @@ error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:24:13 | LL | let b = *&a; - | ^^^ help: try this: `a` + | ^^^ help: try: `a` | = note: `-D clippy::deref-addrof` implied by `-D warnings` @@ -10,49 +10,49 @@ error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:26:13 | LL | let b = *&get_number(); - | ^^^^^^^^^^^^^^ help: try this: `get_number()` + | ^^^^^^^^^^^^^^ help: try: `get_number()` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:31:13 | LL | let b = *&bytes[1..2][0]; - | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]` + | ^^^^^^^^^^^^^^^^ help: try: `bytes[1..2][0]` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:35:13 | LL | let b = *&(a); - | ^^^^^ help: try this: `(a)` + | ^^^^^ help: try: `(a)` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:37:13 | LL | let b = *(&a); - | ^^^^^ help: try this: `a` + | ^^^^^ help: try: `a` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:40:13 | LL | let b = *((&a)); - | ^^^^^^^ help: try this: `a` + | ^^^^^^^ help: try: `a` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:42:13 | LL | let b = *&&a; - | ^^^^ help: try this: `&a` + | ^^^^ help: try: `&a` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:44:14 | LL | let b = **&aref; - | ^^^^^^ help: try this: `aref` + | ^^^^^^ help: try: `aref` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:54:17 | LL | inline!(*& $(@expr self)) - | ^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` + | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` | = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:58:17 | LL | inline!(*&mut $(@expr self)) - | ^^^^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` + | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` | = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/deref_addrof_double_trigger.stderr b/tests/ui/deref_addrof_double_trigger.stderr index 2c55a4ed6ac..6fa5069b6b4 100644 --- a/tests/ui/deref_addrof_double_trigger.stderr +++ b/tests/ui/deref_addrof_double_trigger.stderr @@ -2,7 +2,7 @@ error: immediately dereferencing a reference --> $DIR/deref_addrof_double_trigger.rs:10:14 | LL | let b = **&&a; - | ^^^^ help: try this: `&a` + | ^^^^ help: try: `&a` | = note: `-D clippy::deref-addrof` implied by `-D warnings` @@ -10,13 +10,13 @@ error: immediately dereferencing a reference --> $DIR/deref_addrof_double_trigger.rs:14:17 | LL | let y = *&mut x; - | ^^^^^^^ help: try this: `x` + | ^^^^^^^ help: try: `x` error: immediately dereferencing a reference --> $DIR/deref_addrof_double_trigger.rs:21:18 | LL | let y = **&mut &mut x; - | ^^^^^^^^^^^^ help: try this: `&mut x` + | ^^^^^^^^^^^^ help: try: `&mut x` error: aborting due to 3 previous errors diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index 2c4c49d2522..e8a003e9cf6 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -4,7 +4,7 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` LL | / if !m.contains_key(&k) { LL | | m.insert(k, v); LL | | } - | |_____^ help: try this: `m.entry(k).or_insert(v);` + | |_____^ help: try: `m.entry(k).or_insert(v);` | = note: `-D clippy::map-entry` implied by `-D warnings` @@ -20,7 +20,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ m.entry(k).or_insert_with(|| { LL + if true { @@ -43,7 +43,7 @@ LL | | }; LL | | } | |_____^ | -help: try this +help: try | LL ~ m.entry(k).or_insert_with(|| { LL + if true { @@ -66,7 +66,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { LL + if true { @@ -87,7 +87,7 @@ LL | | m.insert(k, v); LL | | } | |_____^ | -help: try this +help: try | LL ~ m.entry(k).or_insert_with(|| { LL + foo(); @@ -107,7 +107,7 @@ LL | | }; LL | | } | |_____^ | -help: try this +help: try | LL ~ m.entry(k).or_insert_with(|| { LL + match 0 { @@ -133,7 +133,7 @@ LL | | }; LL | | } | |_____^ | -help: try this +help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { LL + match 0 { @@ -157,7 +157,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ m.entry(k).or_insert_with(|| { LL + foo(); @@ -192,7 +192,7 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` LL | / if !m.contains_key(&m!(k)) { LL | | m.insert(m!(k), m!(v)); LL | | } - | |_____^ help: try this: `m.entry(m!(k)).or_insert_with(|| m!(v));` + | |_____^ help: try: `m.entry(m!(k)).or_insert_with(|| m!(v));` error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:152:5 @@ -204,7 +204,7 @@ LL | | m.insert(k, v); LL | | } | |_____^ | -help: try this +help: try | LL ~ m.entry(k).or_insert_with(|| { LL + let x = (String::new(), String::new()); diff --git a/tests/ui/entry_btree.stderr b/tests/ui/entry_btree.stderr index 5c6fcdf1a28..8f41581d6b6 100644 --- a/tests/ui/entry_btree.stderr +++ b/tests/ui/entry_btree.stderr @@ -8,7 +8,7 @@ LL | | } | |_____^ | = note: `-D clippy::map-entry` implied by `-D warnings` -help: try this +help: try | LL ~ if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { LL + e.insert(v); diff --git a/tests/ui/entry_with_else.stderr b/tests/ui/entry_with_else.stderr index e0f6671b460..0d0eb964937 100644 --- a/tests/ui/entry_with_else.stderr +++ b/tests/ui/entry_with_else.stderr @@ -9,7 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::map-entry` implied by `-D warnings` -help: try this +help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Vacant(e) => { @@ -31,7 +31,7 @@ LL | | m.insert(k, v2); LL | | } | |_____^ | -help: try this +help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Occupied(mut e) => { @@ -53,7 +53,7 @@ LL | | foo(); LL | | } | |_____^ | -help: try this +help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { LL + e.insert(v); @@ -72,7 +72,7 @@ LL | | m.insert(k, v); LL | | } | |_____^ | -help: try this +help: try | LL ~ if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) { LL + e.insert(v); @@ -91,7 +91,7 @@ LL | | m.insert(k, v2); LL | | } | |_____^ | -help: try this +help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Vacant(e) => { @@ -113,7 +113,7 @@ LL | | m.insert(k, v) LL | | }; | |_____^ | -help: try this +help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Occupied(mut e) => { @@ -137,7 +137,7 @@ LL | | None LL | | }; | |_____^ | -help: try this +help: try | LL ~ if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) { LL + foo(); diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index 36fb0e5de15..a621f681d98 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -2,7 +2,7 @@ error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:38:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` | = note: `-D clippy::expect-fun-call` implied by `-D warnings` @@ -10,85 +10,85 @@ error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:41:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:44:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:54:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:57:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:69:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:90:21 | LL | Some("foo").expect(&get_string()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:91:21 | LL | Some("foo").expect(get_string().as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:92:21 | LL | Some("foo").expect(get_string().as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:94:21 | LL | Some("foo").expect(get_static_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:95:21 | LL | Some("foo").expect(get_non_static_str(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:99:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:105:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:109:20 | LL | format_capture.expect(&format!("{error_code}")); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}"))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:112:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` error: aborting due to 15 previous errors diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 91863abcc5d..afc311e3f7c 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -2,7 +2,7 @@ error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:70:19 | LL | let _: &str = &*s; - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` | = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` @@ -10,229 +10,229 @@ error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:71:19 | LL | let _: &str = &*{ String::new() }; - | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }` + | ^^^^^^^^^^^^^^^^^^^ help: try: `&{ String::new() }` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:72:19 | LL | let _: &str = &mut *{ String::new() }; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut { String::new() }` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:76:11 | LL | f_str(&*s); - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:80:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:83:24 | LL | let _: &Box = &**b; - | ^^^^ help: try this: `&b` + | ^^^^ help: try: `&b` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:89:7 | LL | c(&*s); - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:95:9 | LL | &**x - | ^^^^ help: try this: `x` + | ^^^^ help: try: `x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:99:11 | LL | { &**x } - | ^^^^ help: try this: `x` + | ^^^^ help: try: `x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:103:9 | LL | &**{ x } - | ^^^^^^^^ help: try this: `{ x }` + | ^^^^^^^^ help: try: `{ x }` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:107:9 | LL | &***x - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:124:12 | LL | f1(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:125:12 | LL | f2(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:126:12 | LL | f3(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:127:27 | LL | f4.callable_str()(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:128:12 | LL | f5(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:129:12 | LL | f6(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:130:27 | LL | f7.callable_str()(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:131:25 | LL | f8.callable_t()(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:132:12 | LL | f9(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:133:13 | LL | f10(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:134:26 | LL | f11.callable_t()(&*x); - | ^^^ help: try this: `&x` + | ^^^ help: try: `&x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:138:16 | LL | let _ = S1(&*s); - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:143:21 | LL | let _ = S2 { s: &*s }; - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:159:30 | LL | let _ = Self::S1(&**s); - | ^^^^ help: try this: `s` + | ^^^^ help: try: `s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:160:35 | LL | let _ = Self::S2 { s: &**s }; - | ^^^^ help: try this: `s` + | ^^^^ help: try: `s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:163:20 | LL | let _ = E1::S1(&*s); - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:164:25 | LL | let _ = E1::S2 { s: &*s }; - | ^^^ help: try this: `&s` + | ^^^ help: try: `&s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:182:13 | LL | let _ = (*b).foo; - | ^^^^ help: try this: `b` + | ^^^^ help: try: `b` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:183:13 | LL | let _ = (**b).foo; - | ^^^^^ help: try this: `b` + | ^^^^^ help: try: `b` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:198:19 | LL | let _ = f_str(*ref_str); - | ^^^^^^^^ help: try this: `ref_str` + | ^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:200:19 | LL | let _ = f_str(**ref_ref_str); - | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` + | ^^^^^^^^^^^^^ help: try: `ref_ref_str` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:210:13 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references - | ^^^^^^^^ help: try this: `ref_str` + | ^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:211:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference - | ^^^^^^^^^^ help: try this: `ref_str` + | ^^^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:220:41 | LL | let _ = || -> &'static str { return *s }; - | ^^ help: try this: `s` + | ^^ help: try: `s` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:239:9 | LL | &**x - | ^^^^ help: try this: `x` + | ^^^^ help: try: `x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:262:8 | LL | c1(*x); - | ^^ help: try this: `x` + | ^^ help: try: `x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:265:20 | LL | return *x; - | ^^ help: try this: `x` + | ^^ help: try: `x` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:267:9 | LL | *x - | ^^ help: try this: `x` + | ^^ help: try: `x` error: aborting due to 39 previous errors diff --git a/tests/ui/explicit_deref_methods.stderr b/tests/ui/explicit_deref_methods.stderr index d025035b789..362e559b21a 100644 --- a/tests/ui/explicit_deref_methods.stderr +++ b/tests/ui/explicit_deref_methods.stderr @@ -2,7 +2,7 @@ error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:54:19 | LL | let b: &str = a.deref(); - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` | = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` @@ -10,67 +10,67 @@ error: explicit `deref_mut` method call --> $DIR/explicit_deref_methods.rs:56:23 | LL | let b: &mut str = a.deref_mut(); - | ^^^^^^^^^^^^^ help: try this: `&mut **a` + | ^^^^^^^^^^^^^ help: try: `&mut **a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:59:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:59:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:61:20 | LL | println!("{}", a.deref()); - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:64:11 | LL | match a.deref() { - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:68:28 | LL | let b: String = concat(a.deref()); - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:70:13 | LL | let b = just_return(a).deref(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:72:28 | LL | let b: String = concat(just_return(a).deref()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:74:19 | LL | let b: &str = a.deref().deref(); - | ^^^^^^^^^^^^^^^^^ help: try this: `&**a` + | ^^^^^^^^^^^^^^^^^ help: try: `&**a` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:77:13 | LL | let b = opt_a.unwrap().deref(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()` error: explicit `deref` method call --> $DIR/explicit_deref_methods.rs:114:31 | LL | let b: &str = expr_deref!(a.deref()); - | ^^^^^^^^^ help: try this: `&*a` + | ^^^^^^^^^ help: try: `&*a` error: aborting due to 12 previous errors diff --git a/tests/ui/explicit_write.stderr b/tests/ui/explicit_write.stderr index 457e9c62718..b3aa7274c6d 100644 --- a/tests/ui/explicit_write.stderr +++ b/tests/ui/explicit_write.stderr @@ -2,7 +2,7 @@ error: use of `write!(stdout(), ...).unwrap()` --> $DIR/explicit_write.rs:24:9 | LL | write!(std::io::stdout(), "test").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")` | = note: `-D clippy::explicit-write` implied by `-D warnings` @@ -10,73 +10,73 @@ error: use of `write!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:25:9 | LL | write!(std::io::stderr(), "test").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` --> $DIR/explicit_write.rs:26:9 | LL | writeln!(std::io::stdout(), "test").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test")` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:27:9 | LL | writeln!(std::io::stderr(), "test").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test")` error: use of `stdout().write_fmt(...).unwrap()` --> $DIR/explicit_write.rs:28:9 | LL | std::io::stdout().write_fmt(format_args!("test")).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")` error: use of `stderr().write_fmt(...).unwrap()` --> $DIR/explicit_write.rs:29:9 | LL | std::io::stderr().write_fmt(format_args!("test")).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` --> $DIR/explicit_write.rs:32:9 | LL | writeln!(std::io::stdout(), "test/ntest").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test/ntest")` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:33:9 | LL | writeln!(std::io::stderr(), "test/ntest").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test/ntest")` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:36:9 | LL | writeln!(std::io::stderr(), "with {}", value).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {}", value)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {}", value)` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:37:9 | LL | writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {} {}", 2, value)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {} {}", 2, value)` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:38:9 | LL | writeln!(std::io::stderr(), "with {value}").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {value}")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {value}")` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:39:9 | LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("macro arg {}", one!())` error: use of `writeln!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:41:9 | LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("{:w$}", value, w = width)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("{:w$}", value, w = width)` error: aborting due to 13 previous errors diff --git a/tests/ui/extend_with_drain.stderr b/tests/ui/extend_with_drain.stderr index da14ddb25b3..eb2dd304d37 100644 --- a/tests/ui/extend_with_drain.stderr +++ b/tests/ui/extend_with_drain.stderr @@ -2,7 +2,7 @@ error: use of `extend` instead of `append` for adding the full range of a second --> $DIR/extend_with_drain.rs:9:5 | LL | vec2.extend(vec1.drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec2.append(&mut vec1)` | = note: `-D clippy::extend-with-drain` implied by `-D warnings` @@ -10,19 +10,19 @@ error: use of `extend` instead of `append` for adding the full range of a second --> $DIR/extend_with_drain.rs:14:5 | LL | vec4.extend(vec3.drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec4.append(&mut vec3)` error: use of `extend` instead of `append` for adding the full range of a second vector --> $DIR/extend_with_drain.rs:18:5 | LL | vec11.extend(return_vector().drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec11.append(&mut return_vector())` error: use of `extend` instead of `append` for adding the full range of a second vector --> $DIR/extend_with_drain.rs:49:5 | LL | y.extend(ref_x.drain(..)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `y.append(ref_x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `y.append(ref_x)` error: aborting due to 4 previous errors diff --git a/tests/ui/filter_map_next_fixable.stderr b/tests/ui/filter_map_next_fixable.stderr index a9fc6abe88f..26d9c5e19da 100644 --- a/tests/ui/filter_map_next_fixable.stderr +++ b/tests/ui/filter_map_next_fixable.stderr @@ -2,7 +2,7 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly --> $DIR/filter_map_next_fixable.rs:9:32 | LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())` | = note: `-D clippy::filter-map-next` implied by `-D warnings` @@ -10,7 +10,7 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly --> $DIR/filter_map_next_fixable.rs:22:26 | LL | let _: Option = a.iter().filter_map(|s| s.parse().ok()).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())` error: aborting due to 2 previous errors diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index fd961420dc4..e705bebac57 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -2,7 +2,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/get_unwrap.rs:40:17 | LL | let _ = boxed_slice.get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` | note: the lint level is defined here --> $DIR/get_unwrap.rs:10:9 @@ -23,7 +23,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/get_unwrap.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:41:17 @@ -37,7 +37,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc --> $DIR/get_unwrap.rs:42:17 | LL | let _ = some_vec.get(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:42:17 @@ -51,7 +51,7 @@ error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more --> $DIR/get_unwrap.rs:43:17 | LL | let _ = some_vecdeque.get(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:43:17 @@ -65,7 +65,7 @@ error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more --> $DIR/get_unwrap.rs:44:17 | LL | let _ = some_hashmap.get(&1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:44:17 @@ -79,7 +79,7 @@ error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more --> $DIR/get_unwrap.rs:45:17 | LL | let _ = some_btreemap.get(&1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:45:17 @@ -93,7 +93,7 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/get_unwrap.rs:49:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:49:22 @@ -107,7 +107,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor --> $DIR/get_unwrap.rs:54:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:54:10 @@ -121,7 +121,7 @@ error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and mor --> $DIR/get_unwrap.rs:55:9 | LL | *some_slice.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:55:10 @@ -135,7 +135,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more --> $DIR/get_unwrap.rs:56:9 | LL | *some_vec.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:56:10 @@ -149,7 +149,7 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and --> $DIR/get_unwrap.rs:57:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:57:10 @@ -163,7 +163,7 @@ error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more conc --> $DIR/get_unwrap.rs:69:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:69:17 @@ -177,7 +177,7 @@ error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more --> $DIR/get_unwrap.rs:70:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value --> $DIR/get_unwrap.rs:70:17 @@ -191,25 +191,25 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more co --> $DIR/get_unwrap.rs:80:24 | LL | let _x: &i32 = f.get(1 + 2).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `&f[1 + 2]` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:83:18 | LL | let _x = f.get(1 + 2).unwrap().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:86:18 | LL | let _x = f.get(1 + 2).unwrap().abs(); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]` error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:103:33 | LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut rest[linidx(j, k) - linidx(i, k) - 1]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]` error: aborting due to 30 previous errors diff --git a/tests/ui/infallible_destructuring_match.stderr b/tests/ui/infallible_destructuring_match.stderr index f8a50f0223d..004260a1d64 100644 --- a/tests/ui/infallible_destructuring_match.stderr +++ b/tests/ui/infallible_destructuring_match.stderr @@ -4,7 +4,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p LL | / let data = match wrapper { LL | | SingleVariantEnum::Variant(i) => i, LL | | }; - | |______^ help: try this: `let SingleVariantEnum::Variant(data) = wrapper;` + | |______^ help: try: `let SingleVariantEnum::Variant(data) = wrapper;` | = note: `-D clippy::infallible-destructuring-match` implied by `-D warnings` @@ -14,7 +14,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p LL | / let data = match wrapper { LL | | TupleStruct(i) => i, LL | | }; - | |______^ help: try this: `let TupleStruct(data) = wrapper;` + | |______^ help: try: `let TupleStruct(data) = wrapper;` error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let` --> $DIR/infallible_destructuring_match.rs:85:5 @@ -22,7 +22,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p LL | / let data = match wrapper { LL | | TupleStructWithNonCopy(ref n) => n, LL | | }; - | |______^ help: try this: `let TupleStructWithNonCopy(ref data) = wrapper;` + | |______^ help: try: `let TupleStructWithNonCopy(ref data) = wrapper;` error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let` --> $DIR/infallible_destructuring_match.rs:104:5 @@ -30,7 +30,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p LL | / let data = match wrapper { LL | | Ok(i) => i, LL | | }; - | |______^ help: try this: `let Ok(data) = wrapper;` + | |______^ help: try: `let Ok(data) = wrapper;` error: aborting due to 4 previous errors diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index dcae7cecd33..eaac48be880 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -4,7 +4,7 @@ error: unnecessarily eager cloning of iterator items LL | let _: Option = vec.iter().cloned().last(); | ^^^^^^^^^^---------------- | | - | help: try this: `.last().cloned()` + | help: try: `.last().cloned()` | = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings` @@ -14,7 +14,7 @@ error: unnecessarily eager cloning of iterator items LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- | | - | help: try this: `.next().cloned()` + | help: try: `.next().cloned()` error: unneeded cloning of iterator items --> $DIR/iter_overeager_cloned.rs:12:20 @@ -22,7 +22,7 @@ error: unneeded cloning of iterator items LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------- | | - | help: try this: `.count()` + | help: try: `.count()` | = note: `-D clippy::redundant-clone` implied by `-D warnings` @@ -32,7 +32,7 @@ error: unnecessarily eager cloning of iterator items LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); | ^^^^^^^^^^----------------- | | - | help: try this: `.take(2).cloned()` + | help: try: `.take(2).cloned()` error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:16:21 @@ -40,7 +40,7 @@ error: unnecessarily eager cloning of iterator items LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); | ^^^^^^^^^^----------------- | | - | help: try this: `.skip(2).cloned()` + | help: try: `.skip(2).cloned()` error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:18:13 @@ -48,7 +48,7 @@ error: unnecessarily eager cloning of iterator items LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- | | - | help: try this: `.nth(2).cloned()` + | help: try: `.nth(2).cloned()` error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:20:13 @@ -60,7 +60,7 @@ LL | | .cloned() LL | | .flatten(); | |__________________^ | -help: try this +help: try | LL ~ .iter() LL ~ .flatten().cloned(); diff --git a/tests/ui/iter_with_drain.stderr b/tests/ui/iter_with_drain.stderr index aa394439fa6..bfaed29a099 100644 --- a/tests/ui/iter_with_drain.stderr +++ b/tests/ui/iter_with_drain.stderr @@ -2,7 +2,7 @@ error: `drain(..)` used on a `Vec` --> $DIR/iter_with_drain.rs:11:34 | LL | let mut a: BinaryHeap<_> = a.drain(..).collect(); - | ^^^^^^^^^ help: try this: `into_iter()` + | ^^^^^^^^^ help: try: `into_iter()` | = note: `-D clippy::iter-with-drain` implied by `-D warnings` @@ -10,31 +10,31 @@ error: `drain(..)` used on a `VecDeque` --> $DIR/iter_with_drain.rs:14:27 | LL | let mut a: Vec<_> = a.drain(..).collect(); - | ^^^^^^^^^ help: try this: `into_iter()` + | ^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `Vec` --> $DIR/iter_with_drain.rs:15:34 | LL | let mut a: HashMap<_, _> = a.drain(..).map(|x| (x.clone(), x)).collect(); - | ^^^^^^^^^ help: try this: `into_iter()` + | ^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `Vec` --> $DIR/iter_with_drain.rs:21:34 | LL | let mut a: BinaryHeap<_> = a.drain(0..).collect(); - | ^^^^^^^^^^ help: try this: `into_iter()` + | ^^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `VecDeque` --> $DIR/iter_with_drain.rs:24:27 | LL | let mut a: Vec<_> = a.drain(..a.len()).collect(); - | ^^^^^^^^^^^^^^^^ help: try this: `into_iter()` + | ^^^^^^^^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `Vec` --> $DIR/iter_with_drain.rs:25:34 | LL | let mut a: HashMap<_, _> = a.drain(0..a.len()).map(|x| (x.clone(), x)).collect(); - | ^^^^^^^^^^^^^^^^^ help: try this: `into_iter()` + | ^^^^^^^^^^^^^^^^^ help: try: `into_iter()` error: aborting due to 6 previous errors diff --git a/tests/ui/manual_filter.stderr b/tests/ui/manual_filter.stderr index 53dea922930..f62d3e96059 100644 --- a/tests/ui/manual_filter.stderr +++ b/tests/ui/manual_filter.stderr @@ -8,7 +8,7 @@ LL | | if x > 0 { ... | LL | | }, LL | | }; - | |_____^ help: try this: `Some(0).filter(|&x| x <= 0)` + | |_____^ help: try: `Some(0).filter(|&x| x <= 0)` | = note: `-D clippy::manual-filter` implied by `-D warnings` @@ -22,7 +22,7 @@ LL | | None ... | LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(1).filter(|&x| x <= 0)` + | |_____^ help: try: `Some(1).filter(|&x| x <= 0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:29:5 @@ -34,7 +34,7 @@ LL | | None ... | LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(2).filter(|&x| x <= 0)` + | |_____^ help: try: `Some(2).filter(|&x| x <= 0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:40:5 @@ -46,7 +46,7 @@ LL | | Some(x) ... | LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(3).filter(|&x| x > 0)` + | |_____^ help: try: `Some(3).filter(|&x| x > 0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:52:5 @@ -58,7 +58,7 @@ LL | | Some(x) => { ... | LL | | }, LL | | }; - | |_____^ help: try this: `y.filter(|&x| x <= 0)` + | |_____^ help: try: `y.filter(|&x| x <= 0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:64:5 @@ -70,7 +70,7 @@ LL | | Some(x) ... | LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(5).filter(|&x| x > 0)` + | |_____^ help: try: `Some(5).filter(|&x| x > 0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:75:5 @@ -82,7 +82,7 @@ LL | | Some(x) ... | LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(6).as_ref().filter(|&x| x > &0)` + | |_____^ help: try: `Some(6).as_ref().filter(|&x| x > &0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:87:5 @@ -94,7 +94,7 @@ LL | | Some(x) ... | LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(String::new()).filter(|x| external_cond)` + | |_____^ help: try: `Some(String::new()).filter(|x| external_cond)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:98:5 @@ -104,7 +104,7 @@ LL | | if external_cond { Some(x) } else { None } LL | | } else { LL | | None LL | | }; - | |_____^ help: try this: `Some(7).filter(|&x| external_cond)` + | |_____^ help: try: `Some(7).filter(|&x| external_cond)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:104:5 @@ -116,7 +116,7 @@ LL | | Some(x) ... | LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(8).filter(|&x| x != 0)` + | |_____^ help: try: `Some(8).filter(|&x| x != 0)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:115:5 @@ -128,7 +128,7 @@ LL | | Some(x) ... | LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(9).filter(|&x| x > 10 && x < 100)` + | |_____^ help: try: `Some(9).filter(|&x| x > 10 && x < 100)` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:141:5 @@ -142,7 +142,7 @@ LL | | None => None, LL | | }; | |_____^ | -help: try this +help: try | LL ~ Some(11).filter(|&x| { LL + println!("foo"); @@ -161,7 +161,7 @@ LL | | Some(x) ... | LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(14).filter(|&x| unsafe { f(x) })` + | |_____^ help: try: `Some(14).filter(|&x| unsafe { f(x) })` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:195:13 @@ -173,7 +173,7 @@ LL | | if f(x) { Some(x) } else { None } LL | | }, LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(15).filter(|&x| unsafe { f(x) })` + | |_____^ help: try: `Some(15).filter(|&x| unsafe { f(x) })` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:205:12 @@ -185,7 +185,7 @@ LL | | if x % 2 == 0 { Some(x) } else { None } LL | | } else { LL | | None LL | | }; - | |_____^ help: try this: `{ Some(16).filter(|&x| x % 2 == 0) }` + | |_____^ help: try: `{ Some(16).filter(|&x| x % 2 == 0) }` error: aborting due to 15 previous errors diff --git a/tests/ui/manual_map_option.stderr b/tests/ui/manual_map_option.stderr index cdc2c0e62a9..3f9caad4e89 100644 --- a/tests/ui/manual_map_option.stderr +++ b/tests/ui/manual_map_option.stderr @@ -5,7 +5,7 @@ LL | / match Some(0) { LL | | Some(_) => Some(2), LL | | None:: => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|_| 2)` + | |_____^ help: try: `Some(0).map(|_| 2)` | = note: `-D clippy::manual-map` implied by `-D warnings` @@ -16,7 +16,7 @@ LL | / match Some(0) { LL | | Some(x) => Some(x + 1), LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|x| x + 1)` + | |_____^ help: try: `Some(0).map(|x| x + 1)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:25:5 @@ -25,7 +25,7 @@ LL | / match Some("") { LL | | Some(x) => Some(x.is_empty()), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some("").map(|x| x.is_empty())` + | |_____^ help: try: `Some("").map(|x| x.is_empty())` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:30:5 @@ -35,7 +35,7 @@ LL | | Some(!x) LL | | } else { LL | | None LL | | }; - | |_____^ help: try this: `Some(0).map(|x| !x)` + | |_____^ help: try: `Some(0).map(|x| !x)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:37:5 @@ -44,7 +44,7 @@ LL | / match Some(0) { LL | | Some(x) => { Some(std::convert::identity(x)) } LL | | None => { None } LL | | }; - | |_____^ help: try this: `Some(0).map(std::convert::identity)` + | |_____^ help: try: `Some(0).map(std::convert::identity)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:42:5 @@ -53,7 +53,7 @@ LL | / match Some(&String::new()) { LL | | Some(x) => Some(str::len(x)), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))` + | |_____^ help: try: `Some(&String::new()).map(|x| str::len(x))` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:52:5 @@ -62,7 +62,7 @@ LL | / match &Some([0, 1]) { LL | | Some(x) => Some(x[0]), LL | | &None => None, LL | | }; - | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])` + | |_____^ help: try: `Some([0, 1]).as_ref().map(|x| x[0])` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:57:5 @@ -71,7 +71,7 @@ LL | / match &Some(0) { LL | | &Some(x) => Some(x * 2), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|x| x * 2)` + | |_____^ help: try: `Some(0).map(|x| x * 2)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:62:5 @@ -80,7 +80,7 @@ LL | / match Some(String::new()) { LL | | Some(ref x) => Some(x.is_empty()), LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` + | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:67:5 @@ -89,7 +89,7 @@ LL | / match &&Some(String::new()) { LL | | Some(x) => Some(x.len()), LL | | _ => None, LL | | }; - | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` + | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:72:5 @@ -98,7 +98,7 @@ LL | / match &&Some(0) { LL | | &&Some(x) => Some(x + x), LL | | &&_ => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|x| x + x)` + | |_____^ help: try: `Some(0).map(|x| x + x)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:85:9 @@ -107,7 +107,7 @@ LL | / match &mut Some(String::new()) { LL | | Some(x) => Some(x.push_str("")), LL | | None => None, LL | | }; - | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))` + | |_________^ help: try: `Some(String::new()).as_mut().map(|x| x.push_str(""))` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:91:5 @@ -116,7 +116,7 @@ LL | / match &mut Some(String::new()) { LL | | Some(ref x) => Some(x.len()), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` + | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:96:5 @@ -125,7 +125,7 @@ LL | / match &mut &Some(String::new()) { LL | | Some(x) => Some(x.is_empty()), LL | | &mut _ => None, LL | | }; - | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` + | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:101:5 @@ -134,7 +134,7 @@ LL | / match Some((0, 1, 2)) { LL | | Some((x, y, z)) => Some(x + y + z), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)` + | |_____^ help: try: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:106:5 @@ -143,7 +143,7 @@ LL | / match Some([1, 2, 3]) { LL | | Some([first, ..]) => Some(first), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)` + | |_____^ help: try: `Some([1, 2, 3]).map(|[first, ..]| first)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:111:5 @@ -152,7 +152,7 @@ LL | / match &Some((String::new(), "test")) { LL | | Some((x, y)) => Some((y, x)), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))` + | |_____^ help: try: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:169:5 @@ -161,7 +161,7 @@ LL | / match Some(0) { LL | | Some(x) => Some(vec![x]), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|x| vec![x])` + | |_____^ help: try: `Some(0).map(|x| vec![x])` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:174:5 @@ -170,7 +170,7 @@ LL | / match option_env!("") { LL | | Some(x) => Some(String::from(x)), LL | | None => None, LL | | }; - | |_____^ help: try this: `option_env!("").map(String::from)` + | |_____^ help: try: `option_env!("").map(String::from)` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:194:12 @@ -181,7 +181,7 @@ LL | | Some(x + 1) LL | | } else { LL | | None LL | | }; - | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }` + | |_____^ help: try: `{ Some(0).map(|x| x + 1) }` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:202:12 @@ -192,7 +192,7 @@ LL | | Some(x + 1) LL | | } else { LL | | None LL | | }; - | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }` + | |_____^ help: try: `{ Some(0).map(|x| x + 1) }` error: aborting due to 21 previous errors diff --git a/tests/ui/manual_map_option_2.stderr b/tests/ui/manual_map_option_2.stderr index d35b6252fb8..8c78fcffca8 100644 --- a/tests/ui/manual_map_option_2.stderr +++ b/tests/ui/manual_map_option_2.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____^ | = note: `-D clippy::manual-map` implied by `-D warnings` -help: try this +help: try | LL ~ let _ = Some(0).map(|x| { LL + let y = (String::new(), String::new()); @@ -32,7 +32,7 @@ LL | | None => None, LL | | }; | |_____^ | -help: try this +help: try | LL ~ let _ = s.as_ref().map(|x| { LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() } @@ -47,7 +47,7 @@ LL | let _ = match Some(0) { LL | | Some(x) => Some(f(x)), LL | | None => None, LL | | }; - | |_________^ help: try this: `Some(0).map(|x| f(x))` + | |_________^ help: try: `Some(0).map(|x| f(x))` error: manual implementation of `Option::map` --> $DIR/manual_map_option_2.rs:67:13 @@ -57,7 +57,7 @@ LL | let _ = match Some(0) { LL | | Some(x) => unsafe { Some(f(x)) }, LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|x| unsafe { f(x) })` + | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })` error: manual implementation of `Option::map` --> $DIR/manual_map_option_2.rs:71:13 @@ -67,7 +67,7 @@ LL | let _ = match Some(0) { LL | | Some(x) => Some(unsafe { f(x) }), LL | | None => None, LL | | }; - | |_____^ help: try this: `Some(0).map(|x| unsafe { f(x) })` + | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })` error: aborting due to 5 previous errors diff --git a/tests/ui/manual_split_once.stderr b/tests/ui/manual_split_once.stderr index 78da5a16cc5..f454f95b41d 100644 --- a/tests/ui/manual_split_once.stderr +++ b/tests/ui/manual_split_once.stderr @@ -2,7 +2,7 @@ error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:13:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` | = note: `-D clippy::manual-split-once` implied by `-D warnings` @@ -10,73 +10,73 @@ error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:14:13 | LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:15:18 | LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=')` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=')` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:18:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:21:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:24:13 | LL | let _ = s.splitn(2, '=').skip(1).next().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:27:17 | LL | let _ = s.splitn(2, '=').nth(1)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:28:17 | LL | let _ = s.splitn(2, '=').skip(1).next()?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:29:17 | LL | let _ = s.rsplitn(2, '=').nth(1)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:30:17 | LL | let _ = s.rsplitn(2, '=').skip(1).next()?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:38:13 | LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').unwrap().0` error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:39:18 | LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` error: manual implementation of `rsplit_once` --> $DIR/manual_split_once.rs:40:13 | LL | let _ = s.rsplitn(2, '=').nth(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=').map(|x| x.0)` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:44:5 @@ -182,7 +182,7 @@ error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:141:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:143:5 diff --git a/tests/ui/manual_str_repeat.stderr b/tests/ui/manual_str_repeat.stderr index bdfee7cab26..331bb6ea575 100644 --- a/tests/ui/manual_str_repeat.stderr +++ b/tests/ui/manual_str_repeat.stderr @@ -2,7 +2,7 @@ error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:9:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` | = note: `-D clippy::manual-str-repeat` implied by `-D warnings` @@ -10,55 +10,55 @@ error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:10:21 | LL | let _: String = std::iter::repeat('x').take(10).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"x".repeat(10)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:11:21 | LL | let _: String = std::iter::repeat('/'').take(10).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"'".repeat(10)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:12:21 | LL | let _: String = std::iter::repeat('"').take(10).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"/"".repeat(10)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:16:13 | LL | let _ = repeat(x).take(count + 2).collect::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count + 2)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:25:21 | LL | let _: String = repeat(*x).take(count).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*x).repeat(count)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:34:21 | LL | let _: String = repeat(x).take(count).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:46:21 | LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Cow::Borrowed("test").repeat(count)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:49:21 | LL | let _: String = repeat(x).take(count).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:64:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` error: aborting due to 10 previous errors diff --git a/tests/ui/map_collect_result_unit.stderr b/tests/ui/map_collect_result_unit.stderr index 8b06e13baa6..596e51e5741 100644 --- a/tests/ui/map_collect_result_unit.stderr +++ b/tests/ui/map_collect_result_unit.stderr @@ -2,7 +2,7 @@ error: `.map().collect()` can be replaced with `.try_for_each()` --> $DIR/map_collect_result_unit.rs:6:17 | LL | let _ = (0..3).map(|t| Err(t + 1)).collect::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(0..3).try_for_each(|t| Err(t + 1))` | = note: `-D clippy::map-collect-result-unit` implied by `-D warnings` @@ -10,7 +10,7 @@ error: `.map().collect()` can be replaced with `.try_for_each()` --> $DIR/map_collect_result_unit.rs:7:32 | LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(0..3).try_for_each(|t| Err(t + 1))` error: aborting due to 2 previous errors diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 9f4a4a9ae6b..5b3c61acf74 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -162,7 +162,7 @@ error: called `map().unwrap_or_else()` on a `Result` value. This can be do --> $DIR/map_unwrap_or.rs:99:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead --> $DIR/map_unwrap_or.rs:106:13 diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index 1837bc2ca3b..71dc009f2ce 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.map(|x| x + 1) | _____________^ LL | | // Should lint even though this call is on a separate line. LL | | .unwrap_or_else(|| 0); - | |_____________________________^ help: try this: `opt.map_or_else(|| 0, |x| x + 1)` + | |_____________________________^ help: try: `opt.map_or_else(|| 0, |x| x + 1)` | = note: `-D clippy::map-unwrap-or` implied by `-D warnings` @@ -16,7 +16,7 @@ LL | let _ = res.map(|x| x + 1) | _____________^ LL | | // should lint even though this call is on a separate line LL | | .unwrap_or_else(|_e| 0); - | |_______________________________^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` + | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: aborting due to 2 previous errors diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index c3b62849cb3..252abf74bca 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -6,7 +6,7 @@ LL | let borrowed: Option<&()> = match owned { LL | | None => None, LL | | Some(ref v) => Some(v), LL | | }; - | |_____^ help: try this: `owned.as_ref()` + | |_____^ help: try: `owned.as_ref()` | = note: `-D clippy::match-as-ref` implied by `-D warnings` @@ -18,7 +18,7 @@ LL | let borrow_mut: Option<&mut ()> = match mut_owned { LL | | None => None, LL | | Some(ref mut v) => Some(v), LL | | }; - | |_____^ help: try this: `mut_owned.as_mut()` + | |_____^ help: try: `mut_owned.as_mut()` error: use `as_ref()` instead --> $DIR/match_as_ref.rs:30:13 @@ -27,7 +27,7 @@ LL | / match self.source { LL | | Some(ref s) => Some(s), LL | | None => None, LL | | } - | |_____________^ help: try this: `self.source.as_ref().map(|x| x as _)` + | |_____________^ help: try: `self.source.as_ref().map(|x| x as _)` error: aborting due to 3 previous errors diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr index b72fe10b748..c8c1e5da05f 100644 --- a/tests/ui/match_expr_like_matches_macro.stderr +++ b/tests/ui/match_expr_like_matches_macro.stderr @@ -6,7 +6,7 @@ LL | let _y = match x { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(x, Some(0))` + | |_____^ help: try: `matches!(x, Some(0))` | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` @@ -18,7 +18,7 @@ LL | let _w = match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_some()` + | |_____^ help: try: `x.is_some()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -30,7 +30,7 @@ LL | let _z = match x { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `x.is_none()` + | |_____^ help: try: `x.is_none()` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:33:15 @@ -40,13 +40,13 @@ LL | let _zz = match x { LL | | Some(r) if r == 0 => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)` + | |_____^ help: try: `!matches!(x, Some(r) if r == 0)` error: if let .. else expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:39:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:63:20 @@ -57,7 +57,7 @@ LL | | E::A(_) => true, LL | | E::B(_) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))` + | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:73:20 @@ -70,7 +70,7 @@ LL | | } LL | | E::B(_) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))` + | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:83:20 @@ -81,7 +81,7 @@ LL | | E::B(_) => false, LL | | E::C => false, LL | | _ => true, LL | | }; - | |_________^ help: try this: `!matches!(x, E::B(_) | E::C)` + | |_________^ help: try: `!matches!(x, E::B(_) | E::C)` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:143:18 @@ -91,7 +91,7 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(z, Some(3))` + | |_________^ help: try: `matches!(z, Some(3))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:152:18 @@ -101,7 +101,7 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(&z, Some(3))` + | |_________^ help: try: `matches!(&z, Some(3))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:169:21 @@ -111,7 +111,7 @@ LL | let _ = match &z { LL | | AnEnum::X => true, LL | | _ => false, LL | | }; - | |_____________^ help: try this: `matches!(&z, AnEnum::X)` + | |_____________^ help: try: `matches!(&z, AnEnum::X)` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:183:20 @@ -121,7 +121,7 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(&val, &Some(ref _a))` + | |_________^ help: try: `matches!(&val, &Some(ref _a))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:195:20 @@ -131,7 +131,7 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(&val, &Some(ref _a))` + | |_________^ help: try: `matches!(&val, &Some(ref _a))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:253:14 @@ -141,7 +141,7 @@ LL | let _y = match Some(5) { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(Some(5), Some(0))` + | |_____^ help: try: `matches!(Some(5), Some(0))` error: aborting due to 14 previous errors diff --git a/tests/ui/match_on_vec_items.stderr b/tests/ui/match_on_vec_items.stderr index 9b1f052867e..fc4a3ce1946 100644 --- a/tests/ui/match_on_vec_items.stderr +++ b/tests/ui/match_on_vec_items.stderr @@ -2,7 +2,7 @@ error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:10:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` | = note: `-D clippy::match-on-vec-items` implied by `-D warnings` @@ -10,43 +10,43 @@ error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:17:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:30:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:37:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:50:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:57:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:70:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:77:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: aborting due to 8 previous errors diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index 7d9646c842e..1294e0fe56f 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -35,7 +35,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/match_ref_pats.rs:38:12 | LL | if let &None = a { - | -------^^^^^---- help: try this: `if a.is_none()` + | -------^^^^^---- help: try: `if a.is_none()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -43,7 +43,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/match_ref_pats.rs:43:12 | LL | if let &None = &b { - | -------^^^^^----- help: try this: `if b.is_none()` + | -------^^^^^----- help: try: `if b.is_none()` error: you don't need to add `&` to all patterns --> $DIR/match_ref_pats.rs:103:9 diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 7f0c70745ac..a7348187573 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -144,7 +144,7 @@ LL | | E::A => false, LL | | E::B => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `!matches!(x, E::A | E::B)` + | |_____^ help: try: `!matches!(x, E::A | E::B)` | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr index 105b4c4b41d..40ff4fbd316 100644 --- a/tests/ui/match_wildcard_for_single_variants.stderr +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -2,7 +2,7 @@ error: wildcard matches only a single variant and will also match any future add --> $DIR/match_wildcard_for_single_variants.rs:24:13 | LL | _ => (), - | ^ help: try this: `Self::Rgb(..)` + | ^ help: try: `Self::Rgb(..)` | = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` @@ -10,55 +10,55 @@ error: wildcard matches only a single variant and will also match any future add --> $DIR/match_wildcard_for_single_variants.rs:34:9 | LL | _ => {}, - | ^ help: try this: `Foo::C` + | ^ help: try: `Foo::C` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:44:9 | LL | _ => {}, - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:52:9 | LL | _ => {}, - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:58:9 | LL | _ => {}, - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:75:9 | LL | &_ => (), - | ^^ help: try this: `Color::Blue` + | ^^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:84:9 | LL | _ => (), - | ^ help: try this: `C::Blue` + | ^ help: try: `C::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:91:9 | LL | _ => (), - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:126:13 | LL | _ => (), - | ^ help: try this: `Enum::__Private` + | ^ help: try: `Enum::__Private` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:153:13 | LL | _ => 2, - | ^ help: try this: `Foo::B` + | ^ help: try: `Foo::B` error: aborting due to 10 previous errors diff --git a/tests/ui/methods_fixable.stderr b/tests/ui/methods_fixable.stderr index 187714c75fb..6f45d100d28 100644 --- a/tests/ui/methods_fixable.stderr +++ b/tests/ui/methods_fixable.stderr @@ -2,7 +2,7 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expr --> $DIR/methods_fixable.rs:11:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)` | = note: `-D clippy::filter-next` implied by `-D warnings` diff --git a/tests/ui/missing_spin_loop.stderr b/tests/ui/missing_spin_loop.stderr index 485da00dc64..5795c2c2190 100644 --- a/tests/ui/missing_spin_loop.stderr +++ b/tests/ui/missing_spin_loop.stderr @@ -2,7 +2,7 @@ error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:11:37 | LL | while b.load(Ordering::Acquire) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` | = note: `-D clippy::missing-spin-loop` implied by `-D warnings` @@ -10,31 +10,31 @@ error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:13:37 | LL | while !b.load(Ordering::SeqCst) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:15:46 | LL | while b.load(Ordering::Acquire) == false {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:17:49 | LL | while { true == b.load(Ordering::Acquire) } {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:19:93 | LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:21:94 | LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: aborting due to 6 previous errors diff --git a/tests/ui/missing_spin_loop_no_std.stderr b/tests/ui/missing_spin_loop_no_std.stderr index 2b3b6873c3c..3322a7aae5f 100644 --- a/tests/ui/missing_spin_loop_no_std.stderr +++ b/tests/ui/missing_spin_loop_no_std.stderr @@ -2,7 +2,7 @@ error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop_no_std.rs:13:37 | LL | while b.load(Ordering::Acquire) {} - | ^^ help: try this: `{ core::hint::spin_loop() }` + | ^^ help: try: `{ core::hint::spin_loop() }` | = note: `-D clippy::missing-spin-loop` implied by `-D warnings` diff --git a/tests/ui/needless_borrow_pat.stderr b/tests/ui/needless_borrow_pat.stderr index db3b52b8850..2d9b8f15902 100644 --- a/tests/ui/needless_borrow_pat.stderr +++ b/tests/ui/needless_borrow_pat.stderr @@ -2,7 +2,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:59:14 | LL | Some(ref x) => x, - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` | = note: `-D clippy::needless-borrow` implied by `-D warnings` @@ -12,7 +12,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => *x, | ^^^^^ | -help: try this +help: try | LL | Some(x) => x, | ~ ~ @@ -23,7 +23,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => { | ^^^^^ | -help: try this +help: try | LL ~ Some(x) => { LL | f1(x); @@ -34,13 +34,13 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:81:14 | LL | Some(ref x) => m1!(x), - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:86:15 | LL | let _ = |&ref x: &&String| { - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:91:10 @@ -48,7 +48,7 @@ error: this pattern creates a reference to a reference LL | let (ref y,) = (&x,); | ^^^^^ | -help: try this +help: try | LL ~ let (y,) = (&x,); LL ~ let _: &String = y; @@ -58,7 +58,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:101:14 | LL | Some(ref x) => x.0, - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:111:14 @@ -66,7 +66,7 @@ error: this pattern creates a reference to a reference LL | E::A(ref x) | E::B(ref x) => *x, | ^^^^^ ^^^^^ | -help: try this +help: try | LL | E::A(x) | E::B(x) => x, | ~ ~ ~ @@ -75,7 +75,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:117:21 | LL | if let Some(ref x) = Some(&String::new()); - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:125:12 @@ -83,7 +83,7 @@ error: this pattern creates a reference to a reference LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ | -help: try this +help: try | LL ~ fn f2<'a>(&x: &&'a String) -> &'a String { LL | let _: &String = x; @@ -94,7 +94,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:132:11 | LL | fn f(&ref x: &&String) { - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:140:11 @@ -102,7 +102,7 @@ error: this pattern creates a reference to a reference LL | fn f(&ref x: &&String) { | ^^^^^ | -help: try this +help: try | LL ~ fn f(&x: &&String) { LL ~ let _: &String = x; diff --git a/tests/ui/needless_option_as_deref.stderr b/tests/ui/needless_option_as_deref.stderr index 20d28a968c9..4c0d502a203 100644 --- a/tests/ui/needless_option_as_deref.stderr +++ b/tests/ui/needless_option_as_deref.stderr @@ -2,7 +2,7 @@ error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:9:29 | LL | let _: Option<&usize> = Some(&1).as_deref(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)` + | ^^^^^^^^^^^^^^^^^^^ help: try: `Some(&1)` | = note: `-D clippy::needless-option-as-deref` implied by `-D warnings` @@ -10,13 +10,13 @@ error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:10:33 | LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&mut 1)` error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:14:13 | LL | let _ = x.as_deref_mut(); - | ^^^^^^^^^^^^^^^^ help: try this: `x` + | ^^^^^^^^^^^^^^^^ help: try: `x` error: aborting due to 3 previous errors diff --git a/tests/ui/needless_splitn.stderr b/tests/ui/needless_splitn.stderr index f607d8e1ab5..0005f758104 100644 --- a/tests/ui/needless_splitn.stderr +++ b/tests/ui/needless_splitn.stderr @@ -2,7 +2,7 @@ error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:14:13 | LL | let _ = str.splitn(2, '=').next(); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` | = note: `-D clippy::needless-splitn` implied by `-D warnings` @@ -10,73 +10,73 @@ error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:15:13 | LL | let _ = str.splitn(2, '=').nth(0); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:18:18 | LL | let (_, _) = str.splitn(3, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:21:13 | LL | let _ = str.rsplitn(2, '=').next(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:22:13 | LL | let _ = str.rsplitn(2, '=').nth(0); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:25:18 | LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:27:13 | LL | let _ = str.splitn(5, '=').next(); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:28:13 | LL | let _ = str.splitn(5, '=').nth(3); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:34:13 | LL | let _ = s.splitn(2, '=').next()?; - | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')` + | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:35:13 | LL | let _ = s.splitn(2, '=').nth(0)?; - | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')` + | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:36:13 | LL | let _ = s.rsplitn(2, '=').next()?; - | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')` + | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:37:13 | LL | let _ = s.rsplitn(2, '=').nth(0)?; - | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')` + | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:45:13 | LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split('=')` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split('=')` error: aborting due to 13 previous errors diff --git a/tests/ui/numbered_fields.stderr b/tests/ui/numbered_fields.stderr index 60c0d789806..26f7ad9048b 100644 --- a/tests/ui/numbered_fields.stderr +++ b/tests/ui/numbered_fields.stderr @@ -7,7 +7,7 @@ LL | | 0: 1u32, LL | | 1: 42, LL | | 2: 23u8, LL | | }; - | |_____^ help: try this instead: `TupleStruct(1u32, 42, 23u8)` + | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)` | = note: `-D clippy::init-numbered-fields` implied by `-D warnings` @@ -20,7 +20,7 @@ LL | | 0: 1u32, LL | | 2: 2u8, LL | | 1: 3u32, LL | | }; - | |_____^ help: try this instead: `TupleStruct(1u32, 3u32, 2u8)` + | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)` error: aborting due to 2 previous errors diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index 0305387b9f8..5be5f10b017 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -4,7 +4,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }` | = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` @@ -14,7 +14,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:42:5 @@ -22,7 +22,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` + | help: try: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:48:5 @@ -30,7 +30,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` + | help: try: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:50:5 @@ -38,7 +38,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:53:5 @@ -46,7 +46,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:55:5 @@ -54,7 +54,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:57:5 @@ -62,7 +62,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:59:5 @@ -70,7 +70,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:62:5 @@ -78,7 +78,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` + | help: try: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:64:5 @@ -86,7 +86,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` + | help: try: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:66:5 @@ -94,7 +94,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` + | help: try: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:68:5 @@ -102,7 +102,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` + | help: try: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:73:5 @@ -110,7 +110,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:75:5 @@ -118,7 +118,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:77:5 @@ -126,7 +126,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:80:5 @@ -134,7 +134,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:82:5 @@ -142,7 +142,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | option().map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(a) = option() { do_nothing(a) }` + | help: try: `if let Some(a) = option() { do_nothing(a) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:84:5 @@ -150,7 +150,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | option().map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = option() { println!("{:?}", value) }` + | help: try: `if let Some(value) = option() { println!("{:?}", value) }` error: aborting due to 19 previous errors diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 0b5c686bec0..3965ae52aed 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -2,7 +2,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:54:22 | LL | with_constructor.unwrap_or(make()); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` + | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)` | = note: `-D clippy::or-fun-call` implied by `-D warnings` @@ -10,163 +10,163 @@ error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:57:14 | LL | with_new.unwrap_or(Vec::new()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:60:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:63:14 | LL | with_err.unwrap_or(make()); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` + | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:66:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` --> $DIR/or_fun_call.rs:69:24 | LL | with_default_trait.unwrap_or(Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` --> $DIR/or_fun_call.rs:72:23 | LL | with_default_type.unwrap_or(u64::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:75:18 | LL | self_default.unwrap_or(::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(::default)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(::default)` error: use of `unwrap_or` followed by a call to `default` --> $DIR/or_fun_call.rs:78:18 | LL | real_default.unwrap_or(::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:81:14 | LL | with_vec.unwrap_or(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:84:21 | LL | without_default.unwrap_or(Foo::new()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:87:19 | LL | map.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:90:23 | LL | map_vec.entry(42).or_insert(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:93:21 | LL | btree.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:96:25 | LL | btree_vec.entry(42).or_insert(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:99:21 | LL | let _ = stringy.unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:107:21 | LL | let _ = Some(1).unwrap_or(map[&1]); - | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:109:21 | LL | let _ = Some(1).unwrap_or(map[&1]); - | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call --> $DIR/or_fun_call.rs:133:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:172:14 | LL | None.unwrap_or(ptr_to_ref(s)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:178:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:180:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:194:14 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:207:14 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:219:14 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:230:10 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `map_or` followed by a function call --> $DIR/or_fun_call.rs:255:25 | LL | let _ = Some(4).map_or(g(), |v| v); - | ^^^^^^^^^^^^^^^^^^ help: try this: `map_or_else(g, |v| v)` + | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` error: use of `map_or` followed by a function call --> $DIR/or_fun_call.rs:256:25 | LL | let _ = Some(4).map_or(g(), f); - | ^^^^^^^^^^^^^^ help: try this: `map_or_else(g, f)` + | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` error: aborting due to 28 previous errors diff --git a/tests/ui/or_then_unwrap.stderr b/tests/ui/or_then_unwrap.stderr index da88154c59f..2a1a52407dc 100644 --- a/tests/ui/or_then_unwrap.stderr +++ b/tests/ui/or_then_unwrap.stderr @@ -2,7 +2,7 @@ error: found `.or(Some(…)).unwrap()` --> $DIR/or_then_unwrap.rs:24:20 | LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` | = note: `-D clippy::or-then-unwrap` implied by `-D warnings` @@ -10,13 +10,13 @@ error: found `.or(Ok(…)).unwrap()` --> $DIR/or_then_unwrap.rs:27:20 | LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` error: found `.or(Some(…)).unwrap()` --> $DIR/or_then_unwrap.rs:31:31 | LL | let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` error: aborting due to 3 previous errors diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 6404dacdafa..71c8d188f16 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -5,7 +5,7 @@ LL | print!("Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::print-literal` implied by `-D warnings` -help: try this +help: try | LL - print!("Hello {}", "world"); LL + print!("Hello world"); @@ -17,7 +17,7 @@ error: literal with an empty format string LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("Hello {} {}", world, "world"); LL + println!("Hello {} world", world); @@ -29,7 +29,7 @@ error: literal with an empty format string LL | println!("Hello {}", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("Hello {}", "world"); LL + println!("Hello world"); @@ -41,7 +41,7 @@ error: literal with an empty format string LL | println!("{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ | -help: try this +help: try | LL - println!("{} {:.4}", "a literal", 5); LL + println!("a literal {:.4}", 5); @@ -53,7 +53,7 @@ error: literal with an empty format string LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{0} {1}", "hello", "world"); LL + println!("hello {1}", "world"); @@ -65,7 +65,7 @@ error: literal with an empty format string LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{0} {1}", "hello", "world"); LL + println!("{0} world", "hello"); @@ -77,7 +77,7 @@ error: literal with an empty format string LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{1} {0}", "hello", "world"); LL + println!("world {0}", "hello"); @@ -89,7 +89,7 @@ error: literal with an empty format string LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{1} {0}", "hello", "world"); LL + println!("{1} hello", "world"); @@ -101,7 +101,7 @@ error: literal with an empty format string LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{foo} {bar}", foo = "hello", bar = "world"); LL + println!("hello {bar}", bar = "world"); @@ -113,7 +113,7 @@ error: literal with an empty format string LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{foo} {bar}", foo = "hello", bar = "world"); LL + println!("{foo} world", foo = "hello"); @@ -125,7 +125,7 @@ error: literal with an empty format string LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); LL + println!("world {foo}", foo = "hello"); @@ -137,7 +137,7 @@ error: literal with an empty format string LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); LL + println!("{bar} hello", bar = "world"); diff --git a/tests/ui/redundant_pattern_matching_drop_order.stderr b/tests/ui/redundant_pattern_matching_drop_order.stderr index e9ea3f2e688..28f33f0c95d 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:17:12 | LL | if let Ok(_) = m.lock() {} - | -------^^^^^----------- help: try this: `if m.lock().is_ok()` + | -------^^^^^----------- help: try: `if m.lock().is_ok()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -12,7 +12,7 @@ error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:18:12 | LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} - | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>(m.lock().unwrap().0).is_err()` + | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>(m.lock().unwrap().0).is_err()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -21,7 +21,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:21:16 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} - | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -30,7 +30,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:23:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { - | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -39,31 +39,31 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:26:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} - | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:27:12 | LL | if let Err(_) = Err::, _>(()) {} - | -------^^^^^^------------------------------------------ help: try this: `if Err::, _>(()).is_err()` + | -------^^^^^^------------------------------------------ help: try: `if Err::, _>(()).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:29:12 | LL | if let Ok(_) = Ok::<_, ()>(String::new()) {} - | -------^^^^^----------------------------- help: try this: `if Ok::<_, ()>(String::new()).is_ok()` + | -------^^^^^----------------------------- help: try: `if Ok::<_, ()>(String::new()).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:30:12 | LL | if let Err(_) = Err::<(), _>((String::new(), ())) {} - | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>((String::new(), ())).is_err()` + | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>((String::new(), ())).is_err()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:33:12 | LL | if let Some(_) = Some(m.lock()) {} - | -------^^^^^^^----------------- help: try this: `if Some(m.lock()).is_some()` + | -------^^^^^^^----------------- help: try: `if Some(m.lock()).is_some()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -72,7 +72,7 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:34:12 | LL | if let Some(_) = Some(m.lock().unwrap().0) {} - | -------^^^^^^^---------------------------- help: try this: `if Some(m.lock().unwrap().0).is_some()` + | -------^^^^^^^---------------------------- help: try: `if Some(m.lock().unwrap().0).is_some()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -81,7 +81,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_drop_order.rs:37:16 | LL | if let None = None::> {} - | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` + | -------^^^^------------------------------------ help: try: `if None::>.is_none()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -90,7 +90,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_drop_order.rs:39:12 | LL | if let None = None::> { - | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` + | -------^^^^------------------------------------ help: try: `if None::>.is_none()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -99,25 +99,25 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_drop_order.rs:43:12 | LL | if let None = None::> {} - | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` + | -------^^^^------------------------------------ help: try: `if None::>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:45:12 | LL | if let Some(_) = Some(String::new()) {} - | -------^^^^^^^---------------------- help: try this: `if Some(String::new()).is_some()` + | -------^^^^^^^---------------------- help: try: `if Some(String::new()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:46:12 | LL | if let Some(_) = Some((String::new(), ())) {} - | -------^^^^^^^---------------------------- help: try this: `if Some((String::new(), ())).is_some()` + | -------^^^^^^^---------------------------- help: try: `if Some((String::new(), ())).is_some()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:49:12 | LL | if let Ready(_) = Ready(m.lock()) {} - | -------^^^^^^^^------------------ help: try this: `if Ready(m.lock()).is_ready()` + | -------^^^^^^^^------------------ help: try: `if Ready(m.lock()).is_ready()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -126,7 +126,7 @@ error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:50:12 | LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} - | -------^^^^^^^^----------------------------- help: try this: `if Ready(m.lock().unwrap().0).is_ready()` + | -------^^^^^^^^----------------------------- help: try: `if Ready(m.lock().unwrap().0).is_ready()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -135,7 +135,7 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_drop_order.rs:53:16 | LL | if let Pending = Pending::> {} - | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` + | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -144,7 +144,7 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_drop_order.rs:55:12 | LL | if let Pending = Pending::> { - | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` + | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -153,19 +153,19 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_drop_order.rs:59:12 | LL | if let Pending = Pending::> {} - | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` + | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:61:12 | LL | if let Ready(_) = Ready(String::new()) {} - | -------^^^^^^^^----------------------- help: try this: `if Ready(String::new()).is_ready()` + | -------^^^^^^^^----------------------- help: try: `if Ready(String::new()).is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:62:12 | LL | if let Ready(_) = Ready((String::new(), ())) {} - | -------^^^^^^^^----------------------------- help: try this: `if Ready((String::new(), ())).is_ready()` + | -------^^^^^^^^----------------------------- help: try: `if Ready((String::new(), ())).is_ready()` error: aborting due to 22 previous errors diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index 6d1fb296463..f34dc709833 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 | LL | if let V4(_) = &ipaddr {} - | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()` + | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,25 +10,25 @@ error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:22:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:26:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:36:5 @@ -37,7 +37,7 @@ LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:41:5 @@ -46,7 +46,7 @@ LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` + | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:46:5 @@ -55,7 +55,7 @@ LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:51:5 @@ -64,49 +64,49 @@ LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` + | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:56:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { - | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:64:20 | LL | let _ = if let V4(_) = gen_ipaddr() { - | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()` + | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:66:19 | LL | } else if let V6(_) = gen_ipaddr() { - | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()` + | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:80:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:84:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:86:5 @@ -115,7 +115,7 @@ LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:91:5 @@ -124,7 +124,7 @@ LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: aborting due to 18 previous errors diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 717b603c496..097ca827a42 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:15:12 | LL | if let None = None::<()> {} - | -------^^^^------------- help: try this: `if None::<()>.is_none()` + | -------^^^^------------- help: try: `if None::<()>.is_none()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,37 +10,37 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:17:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:19:12 | LL | if let Some(_) = Some(42) { - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:25:15 | LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:27:15 | LL | while let None = Some(42) {} - | ----------^^^^----------- help: try this: `while Some(42).is_none()` + | ----------^^^^----------- help: try: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:29:15 | LL | while let None = None::<()> {} - | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:32:15 | LL | while let Some(_) = v.pop() { - | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` + | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:40:5 @@ -49,7 +49,7 @@ LL | / match Some(42) { LL | | Some(_) => true, LL | | None => false, LL | | }; - | |_____^ help: try this: `Some(42).is_some()` + | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:45:5 @@ -58,7 +58,7 @@ LL | / match None::<()> { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` + | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:50:13 @@ -68,55 +68,55 @@ LL | let _ = match None::<()> { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` + | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:56:20 | LL | let _ = if let Some(_) = opt { true } else { false }; - | -------^^^^^^^------ help: try this: `if opt.is_some()` + | -------^^^^^^^------ help: try: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:62:20 | LL | let _ = if let Some(_) = gen_opt() { - | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` + | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:64:19 | LL | } else if let None = gen_opt() { - | -------^^^^------------ help: try this: `if gen_opt().is_none()` + | -------^^^^------------ help: try: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:70:12 | LL | if let Some(..) = gen_opt() {} - | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` + | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:85:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:87:12 | LL | if let None = None::<()> {} - | -------^^^^------------- help: try this: `if None::<()>.is_none()` + | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:89:15 | LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:91:15 | LL | while let None = None::<()> {} - | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:93:5 @@ -125,7 +125,7 @@ LL | / match Some(42) { LL | | Some(_) => true, LL | | None => false, LL | | }; - | |_____^ help: try this: `Some(42).is_some()` + | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:98:5 @@ -134,19 +134,19 @@ LL | / match None::<()> { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` + | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:106:12 | LL | if let None = *(&None::<()>) {} - | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` + | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:107:12 | LL | if let None = *&None::<()> {} - | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` + | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:113:5 @@ -155,7 +155,7 @@ LL | / match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_some()` + | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:118:5 @@ -164,7 +164,7 @@ LL | / match x { LL | | None => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_none()` + | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:123:5 @@ -173,7 +173,7 @@ LL | / match x { LL | | Some(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_none()` + | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:128:5 @@ -182,19 +182,19 @@ LL | / match x { LL | | None => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_some()` + | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:143:13 | LL | let _ = matches!(x, Some(_)); - | ^^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_some()` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:145:13 | LL | let _ = matches!(x, None); - | ^^^^^^^^^^^^^^^^^ help: try this: `x.is_none()` + | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` error: aborting due to 28 previous errors diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index b89fde35fcf..28d3606c4fb 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:17:12 | LL | if let Pending = Pending::<()> {} - | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,31 +10,31 @@ error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:19:12 | LL | if let Ready(_) = Ready(42) {} - | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:21:12 | LL | if let Ready(_) = Ready(42) { - | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:27:15 | LL | while let Ready(_) = Ready(42) {} - | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:29:15 | LL | while let Pending = Ready(42) {} - | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` + | ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:31:15 | LL | while let Pending = Pending::<()> {} - | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:37:5 @@ -43,7 +43,7 @@ LL | / match Ready(42) { LL | | Ready(_) => true, LL | | Pending => false, LL | | }; - | |_____^ help: try this: `Ready(42).is_ready()` + | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:42:5 @@ -52,7 +52,7 @@ LL | / match Pending::<()> { LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try this: `Pending::<()>.is_pending()` + | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:47:13 @@ -62,49 +62,49 @@ LL | let _ = match Pending::<()> { LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try this: `Pending::<()>.is_pending()` + | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:53:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; - | -------^^^^^^^^------- help: try this: `if poll.is_ready()` + | -------^^^^^^^^------- help: try: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:57:20 | LL | let _ = if let Ready(_) = gen_poll() { - | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` + | -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:59:19 | LL | } else if let Pending = gen_poll() { - | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` + | -------^^^^^^^------------- help: try: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:75:12 | LL | if let Ready(_) = Ready(42) {} - | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:77:12 | LL | if let Pending = Pending::<()> {} - | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:79:15 | LL | while let Ready(_) = Ready(42) {} - | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:81:15 | LL | while let Pending = Pending::<()> {} - | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:83:5 @@ -113,7 +113,7 @@ LL | / match Ready(42) { LL | | Ready(_) => true, LL | | Pending => false, LL | | }; - | |_____^ help: try this: `Ready(42).is_ready()` + | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:88:5 @@ -122,7 +122,7 @@ LL | / match Pending::<()> { LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try this: `Pending::<()>.is_pending()` + | |_____^ help: try: `Pending::<()>.is_pending()` error: aborting due to 18 previous errors diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index f6ce666bb4f..2b1ce9f5465 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:16:12 | LL | if let Ok(_) = &result {} - | -------^^^^^---------- help: try this: `if result.is_ok()` + | -------^^^^^---------- help: try: `if result.is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,25 +10,25 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:20:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` + | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:22:15 | LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` + | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:24:15 | LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` + | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:34:5 @@ -37,7 +37,7 @@ LL | / match Ok::(42) { LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try this: `Ok::(42).is_ok()` + | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:39:5 @@ -46,7 +46,7 @@ LL | / match Ok::(42) { LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try this: `Ok::(42).is_err()` + | |_____^ help: try: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:44:5 @@ -55,7 +55,7 @@ LL | / match Err::(42) { LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try this: `Err::(42).is_err()` + | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:49:5 @@ -64,73 +64,73 @@ LL | / match Err::(42) { LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try this: `Err::(42).is_ok()` + | |_____^ help: try: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:54:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; - | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` + | -------^^^^^--------------------- help: try: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:62:20 | LL | let _ = if let Ok(_) = gen_res() { - | -------^^^^^------------ help: try this: `if gen_res().is_ok()` + | -------^^^^^------------ help: try: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:64:19 | LL | } else if let Err(_) = gen_res() { - | -------^^^^^^------------ help: try this: `if gen_res().is_err()` + | -------^^^^^^------------ help: try: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:87:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` + | ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:88:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` + | -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:94:12 | LL | if let Some(_) = m!() {} - | -------^^^^^^^------- help: try this: `if m!().is_some()` + | -------^^^^^^^------- help: try: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:95:15 | LL | while let Some(_) = m!() {} - | ----------^^^^^^^------- help: try this: `while m!().is_some()` + | ----------^^^^^^^------- help: try: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:113:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:115:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` + | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:117:15 | LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` + | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:119:15 | LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` + | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:121:5 @@ -139,7 +139,7 @@ LL | / match Ok::(42) { LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try this: `Ok::(42).is_ok()` + | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:126:5 @@ -148,7 +148,7 @@ LL | / match Err::(42) { LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try this: `Err::(42).is_err()` + | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:136:5 @@ -157,7 +157,7 @@ LL | / match x { LL | | Ok(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_ok()` + | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:141:5 @@ -166,7 +166,7 @@ LL | / match x { LL | | Ok(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_err()` + | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:146:5 @@ -175,7 +175,7 @@ LL | / match x { LL | | Err(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_err()` + | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:151:5 @@ -184,19 +184,19 @@ LL | / match x { LL | | Err(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_ok()` + | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:172:13 | LL | let _ = matches!(x, Ok(_)); - | ^^^^^^^^^^^^^^^^^^ help: try this: `x.is_ok()` + | ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:174:13 | LL | let _ = matches!(x, Err(_)); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_err()` + | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` error: aborting due to 28 previous errors diff --git a/tests/ui/ref_binding_to_reference.stderr b/tests/ui/ref_binding_to_reference.stderr index eb36cd516a2..016feb103df 100644 --- a/tests/ui/ref_binding_to_reference.stderr +++ b/tests/ui/ref_binding_to_reference.stderr @@ -5,7 +5,7 @@ LL | Some(ref x) => x, | ^^^^^ | = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings` -help: try this +help: try | LL | Some(x) => &x, | ~ ~~ @@ -16,7 +16,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => { | ^^^^^ | -help: try this +help: try | LL ~ Some(x) => { LL | f1(x); @@ -30,7 +30,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => m2!(x), | ^^^^^ | -help: try this +help: try | LL | Some(x) => m2!(&x), | ~ ~~ @@ -41,7 +41,7 @@ error: this pattern creates a reference to a reference LL | let _ = |&ref x: &&String| { | ^^^^^ | -help: try this +help: try | LL ~ let _ = |&x: &&String| { LL ~ let _: &&String = &x; @@ -53,7 +53,7 @@ error: this pattern creates a reference to a reference LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ | -help: try this +help: try | LL ~ fn f2<'a>(&x: &&'a String) -> &'a String { LL ~ let _: &&String = &x; @@ -66,7 +66,7 @@ error: this pattern creates a reference to a reference LL | fn f(&ref x: &&String) { | ^^^^^ | -help: try this +help: try | LL ~ fn f(&x: &&String) { LL ~ let _: &&String = &x; @@ -78,7 +78,7 @@ error: this pattern creates a reference to a reference LL | fn f(&ref x: &&String) { | ^^^^^ | -help: try this +help: try | LL ~ fn f(&x: &&String) { LL ~ let _: &&String = &x; diff --git a/tests/ui/result_map_unit_fn_fixable.stderr b/tests/ui/result_map_unit_fn_fixable.stderr index 782febd5264..ad941fa8bcc 100644 --- a/tests/ui/result_map_unit_fn_fixable.stderr +++ b/tests/ui/result_map_unit_fn_fixable.stderr @@ -4,7 +4,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }` | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` @@ -14,7 +14,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:39:5 @@ -22,7 +22,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }` + | help: try: `if let Ok(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:45:5 @@ -30,7 +30,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| x.do_result_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` + | help: try: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:47:5 @@ -38,7 +38,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:50:5 @@ -46,7 +46,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:52:5 @@ -54,7 +54,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:54:5 @@ -62,7 +62,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:56:5 @@ -70,7 +70,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:59:5 @@ -78,7 +78,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:61:5 @@ -86,7 +86,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:63:5 @@ -94,7 +94,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:65:5 @@ -102,7 +102,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:70:5 @@ -110,7 +110,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:72:5 @@ -118,7 +118,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:74:5 @@ -126,7 +126,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:77:5 @@ -134,7 +134,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:79:5 @@ -142,7 +142,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { println!("{:?}", value) }` + | help: try: `if let Ok(value) = x.field { println!("{:?}", value) }` error: aborting due to 18 previous errors diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr index d0e534f6356..75ec1ba8024 100644 --- a/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/tests/ui/result_map_unit_fn_unfixable.stderr @@ -4,7 +4,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { ... }` + | help: try: `if let Ok(value) = x.field { ... }` | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` @@ -14,7 +14,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { ... }` + | help: try: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:29:5 @@ -23,7 +23,7 @@ LL | // x.field.map(|value| { LL | || do_nothing(value); LL | || do_nothing(value) LL | || }); - | ||______^- help: try this: `if let Ok(value) = x.field { ... }` + | ||______^- help: try: `if let Ok(value) = x.field { ... }` | |______| | @@ -33,7 +33,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { ... }` + | help: try: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:37:5 @@ -41,7 +41,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | "12".parse::().map(diverge); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(a) = "12".parse::() { diverge(a) }` + | help: try: `if let Ok(a) = "12".parse::() { diverge(a) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:43:5 @@ -49,7 +49,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(_y) = y { do_nothing(_y) }` + | help: try: `if let Ok(_y) = y { do_nothing(_y) }` error: aborting due to 6 previous errors diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index ef901513240..76f7e789589 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -10,7 +10,7 @@ LL | | }; | |_____^ | = note: `-D clippy::single-match` implied by `-D warnings` -help: try this +help: try | LL ~ if let Some(y) = x { LL + println!("{:?}", y); @@ -27,7 +27,7 @@ LL | | // is expanded before we can do anything. LL | | Some(y) => println!("{:?}", y), LL | | _ => (), LL | | } - | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }` + | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:31:5 @@ -36,7 +36,7 @@ LL | / match z { LL | | (2..=3, 7..=9) => dummy(), LL | | _ => {}, LL | | }; - | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }` + | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:60:5 @@ -45,7 +45,7 @@ LL | / match x { LL | | Some(y) => dummy(), LL | | None => (), LL | | }; - | |_____^ help: try this: `if let Some(y) = x { dummy() }` + | |_____^ help: try: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:65:5 @@ -54,7 +54,7 @@ LL | / match y { LL | | Ok(y) => dummy(), LL | | Err(..) => (), LL | | }; - | |_____^ help: try this: `if let Ok(y) = y { dummy() }` + | |_____^ help: try: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:72:5 @@ -63,7 +63,7 @@ LL | / match c { LL | | Cow::Borrowed(..) => dummy(), LL | | Cow::Owned(..) => (), LL | | }; - | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }` + | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:93:5 @@ -72,7 +72,7 @@ LL | / match x { LL | | "test" => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == "test" { println!() }` + | |_____^ help: try: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:106:5 @@ -81,7 +81,7 @@ LL | / match x { LL | | Foo::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == Foo::A { println!() }` + | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:112:5 @@ -90,7 +90,7 @@ LL | / match x { LL | | FOO_C => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == FOO_C { println!() }` + | |_____^ help: try: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:117:5 @@ -99,7 +99,7 @@ LL | / match &&x { LL | | Foo::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == Foo::A { println!() }` + | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:123:5 @@ -108,7 +108,7 @@ LL | / match &x { LL | | Foo::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == &Foo::A { println!() }` + | |_____^ help: try: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:140:5 @@ -117,7 +117,7 @@ LL | / match x { LL | | Bar::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if let Bar::A = x { println!() }` + | |_____^ help: try: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:148:5 @@ -126,7 +126,7 @@ LL | / match x { LL | | None => println!(), LL | | _ => (), LL | | }; - | |_____^ help: try this: `if let None = x { println!() }` + | |_____^ help: try: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:170:5 @@ -135,7 +135,7 @@ LL | / match x { LL | | (Some(_), _) => {}, LL | | (None, _) => {}, LL | | } - | |_____^ help: try this: `if let (Some(_), _) = x {}` + | |_____^ help: try: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:176:5 @@ -144,7 +144,7 @@ LL | / match x { LL | | (Some(E::V), _) => todo!(), LL | | (_, _) => {}, LL | | } - | |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }` + | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:182:5 @@ -153,7 +153,7 @@ LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, LL | | (..) => {}, LL | | } - | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` + | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:254:5 @@ -167,7 +167,7 @@ LL | | _ => {}, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { unsafe { LL + let r = &v as *const i32; @@ -187,7 +187,7 @@ LL | | _ => {}, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { LL + unsafe { diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 228236f3bb8..5e7d4062efe 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____^ | = note: `-D clippy::single-match-else` implied by `-D warnings` -help: try this +help: try | LL ~ let _ = if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { LL + let x = 5; @@ -32,7 +32,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else { LL + println!("else block"); @@ -52,7 +52,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else { LL + println!("else block"); @@ -72,7 +72,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Ok(a) = Result::::Ok(1) { println!("${:?}", a) } else { LL + println!("else block"); @@ -92,7 +92,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Cow::Owned(a) = Cow::from("moo") { println!("${:?}", a) } else { LL + println!("else block"); @@ -112,7 +112,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { unsafe { LL + let r = &v as *const i32; @@ -135,7 +135,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { LL + println!("Some"); @@ -159,7 +159,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { unsafe { LL + let r = &v as *const i32; @@ -183,7 +183,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { LL + unsafe { diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index b35c77fd961..34b43290147 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -2,7 +2,7 @@ error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:18:5 | LL | s.extend(abc.chars()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(abc)` | = note: `-D clippy::string-extend-chars` implied by `-D warnings` @@ -10,19 +10,19 @@ error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:21:5 | LL | s.extend("abc".chars()); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str("abc")` error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:24:5 | LL | s.extend(def.chars()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&def)` error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:34:5 | LL | s.extend(abc[0..2].chars()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&abc[0..2])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&abc[0..2])` error: aborting due to 4 previous errors diff --git a/tests/ui/strlen_on_c_strings.stderr b/tests/ui/strlen_on_c_strings.stderr index 296268a5f1d..fcd17f68940 100644 --- a/tests/ui/strlen_on_c_strings.stderr +++ b/tests/ui/strlen_on_c_strings.stderr @@ -2,7 +2,7 @@ error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:15:13 | LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstring.as_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.as_bytes().len()` | = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` @@ -10,37 +10,37 @@ error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:19:13 | LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:21:13 | LL | let _ = unsafe { strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:24:22 | LL | let _ = unsafe { strlen((*pcstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*pcstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*pcstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:29:22 | LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe_identity(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe_identity(cstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:30:13 | LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:33:22 | LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `f(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `f(cstr).to_bytes().len()` error: aborting due to 7 previous errors diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr index 10a1b393a39..c4718825dc2 100644 --- a/tests/ui/to_digit_is_some.stderr +++ b/tests/ui/to_digit_is_some.stderr @@ -2,7 +2,7 @@ error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:9:13 | LL | let _ = d.to_digit(8).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(8)` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d.is_digit(8)` | = note: `-D clippy::to-digit-is-some` implied by `-D warnings` @@ -10,7 +10,7 @@ error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:10:13 | LL | let _ = char::to_digit(c, 8).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)` error: aborting due to 2 previous errors diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 4ad0e2e56a4..79f7b70224a 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -2,7 +2,7 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:19:9 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err)` + | ^^^^^^^^^ help: try: `return Err(err)` | note: the lint level is defined here --> $DIR/try_err.rs:4:9 @@ -14,25 +14,25 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:29:9 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err.into())` + | ^^^^^^^^^ help: try: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:49:17 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err)` + | ^^^^^^^^^ help: try: `return Err(err)` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:68:17 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err.into())` + | ^^^^^^^^^ help: try: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:88:23 | LL | Err(_) => Err(1)?, - | ^^^^^^^ help: try this: `return Err(1)` + | ^^^^^^^ help: try: `return Err(1)` | = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -40,7 +40,7 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:95:23 | LL | Err(_) => Err(inline!(1))?, - | ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))` + | ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))` | = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -48,31 +48,31 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:122:9 | LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:148:16 | LL | return Err(42)?; - | ^^^^^^^^ help: try this: `Err(42)` + | ^^^^^^^^ help: try: `Err(42)` error: aborting due to 11 previous errors diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5686ab6b453..23639f6d41a 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -2,7 +2,7 @@ error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:23:5 | LL | rc.clone(); - | ^^^^^^^^^^ help: try this: `Rc::::clone(&rc)` + | ^^^^^^^^^^ help: try: `Rc::::clone(&rc)` | = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` @@ -10,25 +10,25 @@ error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:26:5 | LL | arc.clone(); - | ^^^^^^^^^^^ help: try this: `Arc::::clone(&arc)` + | ^^^^^^^^^^^ help: try: `Arc::::clone(&arc)` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:29:5 | LL | rcweak.clone(); - | ^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&rcweak)` + | ^^^^^^^^^^^^^^ help: try: `Weak::::clone(&rcweak)` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:32:5 | LL | arc_weak.clone(); - | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` + | ^^^^^^^^^^^^^^^^ help: try: `Weak::::clone(&arc_weak)` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:36:33 | LL | let _: Arc = x.clone(); - | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` + | ^^^^^^^^^ help: try: `Arc::::clone(&x)` error: using `clone` on type `T` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:40:5 @@ -54,7 +54,7 @@ error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:95:14 | LL | Some(try_opt!(Some(rc)).clone()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Rc::::clone(&try_opt!(Some(rc)))` error: aborting due to 9 previous errors diff --git a/tests/ui/unwrap_or.stderr b/tests/ui/unwrap_or.stderr index cf720eaaf05..e384bbbb015 100644 --- a/tests/ui/unwrap_or.stderr +++ b/tests/ui/unwrap_or.stderr @@ -2,7 +2,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/unwrap_or.rs:5:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())` | = note: `-D clippy::or-fun-call` implied by `-D warnings` @@ -10,7 +10,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/unwrap_or.rs:9:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())` error: aborting due to 2 previous errors diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 67ce8b64e0e..1f51831b2e9 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -2,7 +2,7 @@ error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:43:18 | LL | foo_rstr(rstr.as_ref()); - | ^^^^^^^^^^^^^ help: try this: `rstr` + | ^^^^^^^^^^^^^ help: try: `rstr` | note: the lint level is defined here --> $DIR/useless_asref.rs:2:9 @@ -14,61 +14,61 @@ error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:45:20 | LL | foo_rslice(rslice.as_ref()); - | ^^^^^^^^^^^^^^^ help: try this: `rslice` + | ^^^^^^^^^^^^^^^ help: try: `rslice` error: this call to `as_mut` does nothing --> $DIR/useless_asref.rs:49:21 | LL | foo_mrslice(mrslice.as_mut()); - | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` + | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:51:20 | LL | foo_rslice(mrslice.as_ref()); - | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` + | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:58:20 | LL | foo_rslice(rrrrrslice.as_ref()); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` + | ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:60:18 | LL | foo_rstr(rrrrrstr.as_ref()); - | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` + | ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr` error: this call to `as_mut` does nothing --> $DIR/useless_asref.rs:65:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:67:20 | LL | foo_rslice(mrrrrrslice.as_ref()); - | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:71:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)` error: this call to `as_mut` does nothing --> $DIR/useless_asref.rs:121:13 | LL | foo_mrt(mrt.as_mut()); - | ^^^^^^^^^^^^ help: try this: `mrt` + | ^^^^^^^^^^^^ help: try: `mrt` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:123:12 | LL | foo_rt(mrt.as_ref()); - | ^^^^^^^^^^^^ help: try this: `mrt` + | ^^^^^^^^^^^^ help: try: `mrt` error: aborting due to 11 previous errors diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index 30d29aa4e77..5b88ae4ab66 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -2,7 +2,7 @@ error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:40:9 | LL | _ => eprintln!("Not red"), - | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` + | ^ help: try: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` | note: the lint level is defined here --> $DIR/wildcard_enum_match_arm.rs:3:9 @@ -14,31 +14,31 @@ error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:44:9 | LL | _not_red => eprintln!("Not red"), - | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` + | ^^^^^^^^ help: try: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:48:9 | LL | not_red => format!("{:?}", not_red), - | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` + | ^^^^^^^ help: try: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:64:9 | LL | _ => "No red", - | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` + | ^ help: try: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: wildcard matches known variants and will also match future added variants --> $DIR/wildcard_enum_match_arm.rs:81:9 | LL | _ => {}, - | ^ help: try this: `ErrorKind::PermissionDenied | _` + | ^ help: try: `ErrorKind::PermissionDenied | _` error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:99:13 | LL | _ => (), - | ^ help: try this: `Enum::B | Enum::__Private` + | ^ help: try: `Enum::B | Enum::__Private` error: aborting due to 6 previous errors diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 1e306ae28a2..8b72c8bd282 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -5,7 +5,7 @@ LL | write!(v, "Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` -help: try this +help: try | LL - write!(v, "Hello {}", "world"); LL + write!(v, "Hello world"); @@ -17,7 +17,7 @@ error: literal with an empty format string LL | writeln!(v, "Hello {} {}", world, "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "Hello {} {}", world, "world"); LL + writeln!(v, "Hello {} world", world); @@ -29,7 +29,7 @@ error: literal with an empty format string LL | writeln!(v, "Hello {}", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "Hello {}", "world"); LL + writeln!(v, "Hello world"); @@ -41,7 +41,7 @@ error: literal with an empty format string LL | writeln!(v, "{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{} {:.4}", "a literal", 5); LL + writeln!(v, "a literal {:.4}", 5); @@ -53,7 +53,7 @@ error: literal with an empty format string LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{0} {1}", "hello", "world"); LL + writeln!(v, "hello {1}", "world"); @@ -65,7 +65,7 @@ error: literal with an empty format string LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{0} {1}", "hello", "world"); LL + writeln!(v, "{0} world", "hello"); @@ -77,7 +77,7 @@ error: literal with an empty format string LL | writeln!(v, "{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{1} {0}", "hello", "world"); LL + writeln!(v, "world {0}", "hello"); @@ -89,7 +89,7 @@ error: literal with an empty format string LL | writeln!(v, "{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{1} {0}", "hello", "world"); LL + writeln!(v, "{1} hello", "world"); @@ -101,7 +101,7 @@ error: literal with an empty format string LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); LL + writeln!(v, "hello {bar}", bar = "world"); @@ -113,7 +113,7 @@ error: literal with an empty format string LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); LL + writeln!(v, "{foo} world", foo = "hello"); @@ -125,7 +125,7 @@ error: literal with an empty format string LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); LL + writeln!(v, "world {foo}", foo = "hello"); @@ -137,7 +137,7 @@ error: literal with an empty format string LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); LL + writeln!(v, "{bar} hello", bar = "world"); diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index 18591250aad..c30ec385b35 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -13,7 +13,7 @@ LL | writeln!(v, "{}", "{hello}"); | ^^^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` -help: try this +help: try | LL - writeln!(v, "{}", "{hello}"); LL + writeln!(v, "{{hello}}"); @@ -25,7 +25,7 @@ error: literal with an empty format string LL | writeln!(v, r"{}", r"{hello}"); | ^^^^^^^^^^ | -help: try this +help: try | LL - writeln!(v, r"{}", r"{hello}"); LL + writeln!(v, r"{{hello}}"); @@ -37,7 +37,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", '/''); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", '/''); LL + writeln!(v, "'"); @@ -49,7 +49,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", '"'); | ^^^ | -help: try this +help: try | LL - writeln!(v, "{}", '"'); LL + writeln!(v, "/""); @@ -67,7 +67,7 @@ error: literal with an empty format string LL | writeln!(v, r"{}", '/''); | ^^^^ | -help: try this +help: try | LL - writeln!(v, r"{}", '/''); LL + writeln!(v, r"'"); @@ -80,7 +80,7 @@ LL | / "hello / LL | | world!" | |_______________^ | -help: try this +help: try | LL ~ "some hello / LL ~ world!" @@ -92,7 +92,7 @@ error: literal with an empty format string LL | "1", "2", "3", | ^^^ | -help: try this +help: try | LL ~ "some 1/ LL ~ {} // {}", "2", "3", @@ -104,7 +104,7 @@ error: literal with an empty format string LL | "1", "2", "3", | ^^^ | -help: try this +help: try | LL ~ 2 // {}", LL ~ "1", "3", @@ -116,7 +116,7 @@ error: literal with an empty format string LL | "1", "2", "3", | ^^^ | -help: try this +help: try | LL ~ {} // 3", LL ~ "1", "2", @@ -128,7 +128,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", "//"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", "//"); LL + writeln!(v, "//"); @@ -140,7 +140,7 @@ error: literal with an empty format string LL | writeln!(v, r"{}", "//"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, r"{}", "//"); LL + writeln!(v, r"/"); @@ -152,7 +152,7 @@ error: literal with an empty format string LL | writeln!(v, r#"{}"#, "//"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, r#"{}"#, "//"); LL + writeln!(v, r#"/"#); @@ -164,7 +164,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", r"/"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", r"/"); LL + writeln!(v, "//"); @@ -176,7 +176,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", "/r"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", "/r"); LL + writeln!(v, "/r"); -- cgit 1.4.1-3-g733a5 From 354172a18efcf104db76fd7dba884b329e9bac7d Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Fri, 23 Jun 2023 05:43:53 -0500 Subject: New lint `manual_try_fold` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/manual_try_fold.rs | 55 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 33 +++++++++++- clippy_utils/src/msrvs.rs | 1 + tests/ui/manual_try_fold.rs | 84 +++++++++++++++++++++++++++++ tests/ui/manual_try_fold.stderr | 22 ++++++++ 7 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/manual_try_fold.rs create mode 100644 tests/ui/manual_try_fold.rs create mode 100644 tests/ui/manual_try_fold.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index ff39c6a0a6c..14d822083d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4959,6 +4959,7 @@ Released 2018-09-13 [`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap +[`manual_try_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or [`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 52bc2010207..9d9ee6ba307 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -364,6 +364,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, crate::methods::MANUAL_STR_REPEAT_INFO, + crate::methods::MANUAL_TRY_FOLD_INFO, crate::methods::MAP_CLONE_INFO, crate::methods::MAP_COLLECT_RESULT_UNIT_INFO, crate::methods::MAP_ERR_IGNORE_INFO, diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs new file mode 100644 index 00000000000..9f92524d356 --- /dev/null +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -0,0 +1,55 @@ +use clippy_utils::{ + diagnostics::span_lint_and_sugg, + is_from_proc_macro, + msrvs::{Msrv, ITERATOR_TRY_FOLD}, + source::snippet_opt, + ty::implements_trait, +}; +use rustc_errors::Applicability; +use rustc_hir::{ + def::{DefKind, Res}, + Expr, ExprKind, +}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_span::Span; + +use super::MANUAL_TRY_FOLD; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + init: &Expr<'_>, + acc: &Expr<'_>, + fold_span: Span, + msrv: &Msrv, +) { + if !in_external_macro(cx.sess(), fold_span) + && msrv.meets(ITERATOR_TRY_FOLD) + && let init_ty = cx.typeck_results().expr_ty(init) + && let Some(try_trait) = cx.tcx.lang_items().try_trait() + && implements_trait(cx, init_ty, try_trait, &[]) + && let ExprKind::Call(path, [first, rest @ ..]) = init.kind + && let ExprKind::Path(qpath) = path.kind + && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) + && let ExprKind::Closure(closure) = acc.kind + && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span)) + && !is_from_proc_macro(cx, expr) + { + let init_snip = rest + .is_empty() + .then_some(first.span) + .and_then(|span| snippet_opt(cx, span)) + .unwrap_or("...".to_owned()); + + span_lint_and_sugg( + cx, + MANUAL_TRY_FOLD, + fold_span, + "you seem to be using `Iterator::fold` on a type that implements `Try`", + "use `try_fold` instead", + format!("try_fold({init_snip}, {args_snip}, ...)", ), + Applicability::HasPlaceholders, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b1d3b61aea3..a8d03bb95e6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -50,6 +50,7 @@ mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; +mod manual_try_fold; mod map_clone; mod map_collect_result_unit; mod map_err_ignore; @@ -3286,6 +3287,30 @@ declare_clippy_lint! { "calling `.drain(..).collect()` to move all elements into a new collection" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `Iterator::fold` with a type that implements `Try`. + /// + /// ### Why is this bad? + /// This is better represented with `try_fold`, but this has one major difference: It will + /// short-circuit on failure. *This is almost always what you want*. This can also open the door + /// for additional optimizations as well, as rustc can guarantee the function is never + /// called on `None`, `Err`, etc., alleviating otherwise necessary checks. + /// + /// ### Example + /// ```rust + /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)); + /// ``` + /// Use instead: + /// ```rust + /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)); + /// ``` + #[clippy::version = "1.72.0"] + pub MANUAL_TRY_FOLD, + perf, + "checks for usage of `Iterator::fold` with a type that implements `Try`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3416,7 +3441,8 @@ impl_lint_pass!(Methods => [ CLEAR_WITH_DRAIN, MANUAL_NEXT_BACK, UNNECESSARY_LITERAL_UNWRAP, - DRAIN_COLLECT + DRAIN_COLLECT, + MANUAL_TRY_FOLD, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3709,7 +3735,10 @@ impl Methods { Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), _ => {}, }, - ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), + ("fold", [init, acc]) => { + manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); + unnecessary_fold::check(cx, expr, init, acc, span); + }, ("for_each", [_]) => { if let Some(("inspect", _, [_], span2, _)) = method_call(recv) { inspect_for_each::check(cx, expr, span2); diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 1f70f11bd67..3637476c408 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -44,6 +44,7 @@ msrv_aliases! { 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,28,0 { FROM_BOOL } + 1,27,0 { ITERATOR_TRY_FOLD } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } 1,24,0 { IS_ASCII_DIGIT } 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } diff --git a/tests/ui/manual_try_fold.rs b/tests/ui/manual_try_fold.rs new file mode 100644 index 00000000000..f43519dd44f --- /dev/null +++ b/tests/ui/manual_try_fold.rs @@ -0,0 +1,84 @@ +//@aux-build:proc_macros.rs +#![allow(clippy::unnecessary_fold, unused)] +#![warn(clippy::manual_try_fold)] +#![feature(try_trait_v2)] + +use std::ops::ControlFlow; +use std::ops::FromResidual; +use std::ops::Try; + +#[macro_use] +extern crate proc_macros; + +// Test custom `Try` with more than 1 argument +struct NotOption(i32, i32); + +impl FromResidual for NotOption { + fn from_residual(_: R) -> Self { + todo!() + } +} + +impl Try for NotOption { + type Output = (); + type Residual = (); + + fn from_output(_: Self::Output) -> Self { + todo!() + } + + fn branch(self) -> ControlFlow { + todo!() + } +} + +// Test custom `Try` with only 1 argument +#[derive(Default)] +struct NotOptionButWorse(i32); + +impl FromResidual for NotOptionButWorse { + fn from_residual(_: R) -> Self { + todo!() + } +} + +impl Try for NotOptionButWorse { + type Output = (); + type Residual = (); + + fn from_output(_: Self::Output) -> Self { + todo!() + } + + fn branch(self) -> ControlFlow { + todo!() + } +} + +fn main() { + [1, 2, 3] + .iter() + .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + .unwrap(); + [1, 2, 3] + .iter() + .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); + [1, 2, 3] + .iter() + .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); + // Do not lint + [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); + [1, 2, 3].iter().fold(0i32, |sum, i| sum + i); + [1, 2, 3] + .iter() + .fold(NotOptionButWorse::default(), |sum, i| NotOptionButWorse::default()); + external! { + [1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)).unwrap(); + [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); + } + with_span! { + span + [1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)).unwrap(); + [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); + } +} diff --git a/tests/ui/manual_try_fold.stderr b/tests/ui/manual_try_fold.stderr new file mode 100644 index 00000000000..1a17435b459 --- /dev/null +++ b/tests/ui/manual_try_fold.stderr @@ -0,0 +1,22 @@ +error: you seem to be using `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:61:10 + | +LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i|, ...)` + | + = note: `-D clippy::manual-try-fold` implied by `-D warnings` + +error: you seem to be using `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:65:10 + | +LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i|, ...)` + +error: you seem to be using `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:68:10 + | +LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i|, ...)` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 04b08576911cf06bc444fb0615f50c29ec82e675 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Sun, 25 Jun 2023 09:01:06 -0500 Subject: Typo --- clippy_lints/src/methods/manual_try_fold.rs | 4 ++-- tests/ui/manual_try_fold.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 9f92524d356..a1d83cf1419 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -33,8 +33,8 @@ pub(super) fn check<'tcx>( && let ExprKind::Path(qpath) = path.kind && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) && let ExprKind::Closure(closure) = acc.kind - && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span)) && !is_from_proc_macro(cx, expr) + && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span)) { let init_snip = rest .is_empty() @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( fold_span, "you seem to be using `Iterator::fold` on a type that implements `Try`", "use `try_fold` instead", - format!("try_fold({init_snip}, {args_snip}, ...)", ), + format!("try_fold({init_snip}, {args_snip} ...)", ), Applicability::HasPlaceholders, ); } diff --git a/tests/ui/manual_try_fold.stderr b/tests/ui/manual_try_fold.stderr index 0c8a08e6c7d..2c0b0c67fd1 100644 --- a/tests/ui/manual_try_fold.stderr +++ b/tests/ui/manual_try_fold.stderr @@ -2,7 +2,7 @@ error: you seem to be using `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:61:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i|, ...)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` | = note: `-D clippy::manual-try-fold` implied by `-D warnings` @@ -10,19 +10,19 @@ error: you seem to be using `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:65:10 | LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i|, ...)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i| ...)` error: you seem to be using `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:68:10 | LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i|, ...)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` error: you seem to be using `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:98:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i|, ...)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From fbb3f759e2c6d90456f42a72eaaa741201d8e463 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:32:01 -0500 Subject: update docs --- clippy_lints/src/methods/mod.rs | 13 +++++++++---- tests/ui/manual_try_fold.rs | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a8d03bb95e6..2cd7ca02755 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3292,10 +3292,15 @@ declare_clippy_lint! { /// Checks for usage of `Iterator::fold` with a type that implements `Try`. /// /// ### Why is this bad? - /// This is better represented with `try_fold`, but this has one major difference: It will - /// short-circuit on failure. *This is almost always what you want*. This can also open the door - /// for additional optimizations as well, as rustc can guarantee the function is never - /// called on `None`, `Err`, etc., alleviating otherwise necessary checks. + /// This should use `try_fold` instead, which short-circuits on failure, thus opening the door + /// for additional optimizations not possible with `fold` as rustc can guarantee the function is + /// never called on `None`, `Err`, etc., alleviating otherwise necessary checks. It's also + /// slightly more idiomatic. + /// + /// ### Known issues + /// This lint doesn't take into account whether a function does something on the failure case, + /// i.e., whether short-circuiting will affect behavior. Refactoring to `try_fold` is not + /// desirable in those cases. /// /// ### Example /// ```rust diff --git a/tests/ui/manual_try_fold.rs b/tests/ui/manual_try_fold.rs index e00371eb228..4521e9fa1a5 100644 --- a/tests/ui/manual_try_fold.rs +++ b/tests/ui/manual_try_fold.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(clippy::unnecessary_fold, unused)] #![warn(clippy::manual_try_fold)] #![feature(try_trait_v2)] -- cgit 1.4.1-3-g733a5 From cb5d7e344a4f42eefb5b7d3df42f8899a684e73b Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Thu, 29 Jun 2023 02:26:45 -0500 Subject: address comments --- book/src/lint_configuration.md | 1 + clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/mod.rs | 8 ++++---- clippy_lints/src/utils/conf.rs | 2 +- tests/ui/manual_try_fold.stderr | 8 ++++---- 5 files changed, 11 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index ae0b5140316..60d7ce6e615 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -150,6 +150,7 @@ The minimum rust version that the project supports * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) +* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) ## `cognitive-complexity-threshold` diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index a1d83cf1419..576a58499b1 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( cx, MANUAL_TRY_FOLD, fold_span, - "you seem to be using `Iterator::fold` on a type that implements `Try`", + "usage of `Iterator::fold` on a type that implements `Try`", "use `try_fold` instead", format!("try_fold({init_snip}, {args_snip} ...)", ), Applicability::HasPlaceholders, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2cd7ca02755..24dbe8c1d75 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3292,10 +3292,10 @@ declare_clippy_lint! { /// Checks for usage of `Iterator::fold` with a type that implements `Try`. /// /// ### Why is this bad? - /// This should use `try_fold` instead, which short-circuits on failure, thus opening the door - /// for additional optimizations not possible with `fold` as rustc can guarantee the function is - /// never called on `None`, `Err`, etc., alleviating otherwise necessary checks. It's also - /// slightly more idiomatic. + /// The code should use `try_fold` instead, which short-circuits on failure, thus opening the + /// door for additional optimizations not possible with `fold` as rustc can guarantee the + /// function is never called on `None`, `Err`, etc., alleviating otherwise necessary checks. It's + /// also slightly more idiomatic. /// /// ### Known issues /// This lint doesn't take into account whether a function does something on the failure case, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 89063964622..f1d05c7529b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -294,7 +294,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/tests/ui/manual_try_fold.stderr b/tests/ui/manual_try_fold.stderr index 2c0b0c67fd1..a0cf5b3b5fc 100644 --- a/tests/ui/manual_try_fold.stderr +++ b/tests/ui/manual_try_fold.stderr @@ -1,4 +1,4 @@ -error: you seem to be using `Iterator::fold` on a type that implements `Try` +error: usage of `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:61:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) @@ -6,19 +6,19 @@ LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) | = note: `-D clippy::manual-try-fold` implied by `-D warnings` -error: you seem to be using `Iterator::fold` on a type that implements `Try` +error: usage of `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:65:10 | LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i| ...)` -error: you seem to be using `Iterator::fold` on a type that implements `Try` +error: usage of `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:68:10 | LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` -error: you seem to be using `Iterator::fold` on a type that implements `Try` +error: usage of `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:98:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) -- cgit 1.4.1-3-g733a5 From 885a18207fb66fc736496a4c9cb8c010881c1ab5 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Sat, 1 Jul 2023 19:33:08 -0500 Subject: Fix typos --- book/src/lint_configuration.md | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 3 ++- clippy_lints/src/min_ident_chars.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_utils/src/attrs.rs | 4 ++-- clippy_utils/src/check_proc_macro.rs | 2 +- clippy_utils/src/comparisons.rs | 4 ++-- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/higher.rs | 8 ++++---- clippy_utils/src/lib.rs | 5 +++-- clippy_utils/src/sugg.rs | 2 +- tests/ui/needless_else.stderr | 2 +- 14 files changed, 22 insertions(+), 20 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index ae0b5140316..1ade6e3f481 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -174,7 +174,7 @@ The maximum amount of nesting a block can reside in ## `disallowed-names` The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value -`".."` can be used as part of the list to indicate, that the configured values should be appended to the +`".."` can be used as part of the list to indicate that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. **Default Value:** `["foo", "baz", "quux"]` (`Vec`) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 3122f72ee91..72156bbd1b0 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -11,7 +11,8 @@ use rustc_span::symbol::sym; use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s -/// Return true if lint triggered +/// +/// Returns true if the lint was emitted pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index d49bb0ca6e2..23593e0d4d9 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// for m in movies { - /// let title = m.t; + /// let title = m.t; /// } /// ``` /// Use instead: diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 4ff1bf7ffc0..23d4a7b9586 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -51,7 +51,7 @@ impl EarlyLintPass for NeedlessElse { cx, NEEDLESS_ELSE, span, - "this else branch is empty", + "this `else` branch is empty", "you can remove it", String::new(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 89063964622..59e99758829 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -319,7 +319,7 @@ define_Conf! { /// Lint: DISALLOWED_NAMES. /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: SEMICOLON_INSIDE_BLOCK. diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 49cb9718ef6..e4cc86f6800 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -143,13 +143,13 @@ pub fn get_unique_attr<'a>( unique_attr } -/// Return true if the attributes contain any of `proc_macro`, +/// Returns true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) } -/// Return true if the attributes contain `#[doc(hidden)]` +/// Returns true if the attributes contain `#[doc(hidden)]` pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { attrs .iter() diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index c6d0b654f57..62792d60652 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -339,7 +339,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")), TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), TyKind::Path(qpath) => qpath_search_pat(&qpath), - // NOTE: This is missing `TraitObject`. It always return true then. + // NOTE: This is missing `TraitObject`. It will always return true then. _ => (Pat::Str(""), Pat::Str("")), } } diff --git a/clippy_utils/src/comparisons.rs b/clippy_utils/src/comparisons.rs index 7a18d5e818f..5e6bf227844 100644 --- a/clippy_utils/src/comparisons.rs +++ b/clippy_utils/src/comparisons.rs @@ -1,11 +1,11 @@ -//! Utility functions about comparison operators. +//! Utility functions for comparison operators. #![deny(clippy::missing_docs_in_private_items)] use rustc_hir::{BinOpKind, Expr}; #[derive(PartialEq, Eq, Debug, Copy, Clone)] -/// Represent a normalized comparison operator. +/// Represents a normalized comparison operator. pub enum Rel { /// `<` Lt, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 068820801df..87d85d742ce 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -267,7 +267,7 @@ pub fn constant_with_source<'tcx>( res.map(|x| (x, ctxt.source)) } -/// Attempts to evaluate an expression only if it's value is not dependent on other items. +/// Attempts to evaluate an expression only if its value is not dependent on other items. pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 4a845ca63b4..eda739bceb5 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -1,7 +1,7 @@ //! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa. //! //! Things to consider: -//! - has the expression side-effects? +//! - does the expression have side-effects? //! - is the expression computationally expensive? //! //! See lints: diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index a61e4c38088..357ac40b455 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -13,7 +13,7 @@ use rustc_lint::LateContext; use rustc_span::{sym, symbol, Span}; /// The essential nodes of a desugared for loop as well as the entire span: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`. +/// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. pub struct ForLoop<'tcx> { /// `for` loop item pub pat: &'tcx hir::Pat<'tcx>, @@ -264,7 +264,7 @@ impl<'a> Range<'a> { } } -/// Represent the pre-expansion arguments of a `vec!` invocation. +/// Represents the pre-expansion arguments of a `vec!` invocation. pub enum VecArgs<'a> { /// `vec![elem; len]` Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>), @@ -398,7 +398,7 @@ impl<'hir> WhileLet<'hir> { } } -/// Converts a hir binary operator to the corresponding `ast` type. +/// Converts a `hir` binary operator to the corresponding `ast` type. #[must_use] pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind { match op { @@ -436,7 +436,7 @@ pub enum VecInitKind { WithExprCapacity(HirId), } -/// Checks if given expression is an initialization of `Vec` and returns its kind. +/// Checks if the given expression is an initialization of `Vec` and returns its kind. pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { if let ExprKind::Call(func, args) = expr.kind { match func.kind { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 727b59f1f43..272228cebd0 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -823,7 +823,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< false } -/// Return true if the expr is equal to `Default::default` when evaluated. +/// Returns true if the expr is equal to `Default::default` when evaluated. pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool { if_chain! { if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind; @@ -2527,7 +2527,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { }); } -/// Return all the comments a given span contains +/// Returns all the comments a given span contains +/// /// Comments are returned wrapped with their relevant delimiters pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index cf781e18cd6..de3aad64757 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -395,7 +395,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { } } -/// Return `true` if `sugg` is enclosed in parenthesis. +/// Returns `true` if `sugg` is enclosed in parenthesis. pub fn has_enclosing_paren(sugg: impl AsRef) -> bool { let mut chars = sugg.as_ref().chars(); if chars.next() == Some('(') { diff --git a/tests/ui/needless_else.stderr b/tests/ui/needless_else.stderr index ea693085164..49cd78501ea 100644 --- a/tests/ui/needless_else.stderr +++ b/tests/ui/needless_else.stderr @@ -1,4 +1,4 @@ -error: this else branch is empty +error: this `else` branch is empty --> $DIR/needless_else.rs:24:7 | LL | } else { -- cgit 1.4.1-3-g733a5 From 8fad54e8f942e545458c7f339f0444513c5fcb1e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 17 Jun 2023 01:41:11 +0200 Subject: new lint: `read_line_without_trim` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 34 ++++++++++ clippy_lints/src/methods/read_line_without_trim.rs | 74 ++++++++++++++++++++++ tests/ui/read_line_without_trim.fixed | 19 ++++++ tests/ui/read_line_without_trim.rs | 19 ++++++ tests/ui/read_line_without_trim.stderr | 31 +++++++++ 7 files changed, 179 insertions(+) create mode 100644 clippy_lints/src/methods/read_line_without_trim.rs create mode 100644 tests/ui/read_line_without_trim.fixed create mode 100644 tests/ui/read_line_without_trim.rs create mode 100644 tests/ui/read_line_without_trim.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index f9310b4ab31..e2004c2931d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5134,6 +5134,7 @@ Released 2018-09-13 [`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer [`rc_clone_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_clone_in_vec_init [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex +[`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim [`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e1dbe500396..ca97db04079 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -389,6 +389,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, + crate::methods::READ_LINE_WITHOUT_TRIM_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, crate::methods::SEARCH_IS_SOME_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ab97cf0e53d..c99f7c1fdd9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -72,6 +72,7 @@ mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; +mod read_line_without_trim; mod repeat_once; mod search_is_some; mod seek_from_current; @@ -3348,6 +3349,35 @@ declare_clippy_lint! { "checks for usage of `Iterator::fold` with a type that implements `Try`" } +declare_clippy_lint! { + /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input + /// into a string, then later attempting to parse this string into a type without first trimming it, which will + /// always fail because the string has a trailing newline in it. + /// + /// ### Why is this bad? + /// The `.parse()` call will always fail. + /// + /// ### Example + /// ```rust,ignore + /// let mut input = String::new(); + /// std::io::stdin().read_line(&mut input).expect("Failed to read a line"); + /// let num: i32 = input.parse().expect("Not a number!"); + /// assert_eq!(num, 42); // we never even get here! + /// ``` + /// Use instead: + /// ```rust,ignore + /// let mut input = String::new(); + /// std::io::stdin().read_line(&mut input).expect("Failed to read a line"); + /// let num: i32 = input.trim_end().parse().expect("Not a number!"); + /// // ^^^^^^^^^^^ remove the trailing newline + /// assert_eq!(num, 42); + /// ``` + #[clippy::version = "1.72.0"] + pub READ_LINE_WITHOUT_TRIM, + correctness, + "calling `Stdin::read_line`, then trying to parse it without first trimming" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3468,6 +3498,7 @@ impl_lint_pass!(Methods => [ REPEAT_ONCE, STABLE_SORT_PRIMITIVE, UNIT_HASH, + READ_LINE_WITHOUT_TRIM, UNNECESSARY_SORT_BY, VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, @@ -3879,6 +3910,9 @@ impl Methods { ("read_to_string", [_]) => { verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); }, + ("read_line", [arg]) => { + read_line_without_trim::check(cx, expr, recv, arg); + } ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs new file mode 100644 index 00000000000..49e4f1acaa6 --- /dev/null +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -0,0 +1,74 @@ +use std::ops::ControlFlow; + +use clippy_utils::{ + diagnostics::span_lint_and_then, get_parent_expr, match_def_path, source::snippet, ty::is_type_diagnostic_item, + visitors::for_each_local_use_after_expr, +}; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_hir::QPath; +use rustc_hir::{def::Res, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; + +use super::READ_LINE_WITHOUT_TRIM; + +/// Will a `.parse::()` call fail if the input has a trailing newline? +fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool { + // only allow a very limited set of types for now, for which we 100% know parsing will fail + matches!(ty.kind(), ty::Float(_) | ty::Bool | ty::Int(_) | ty::Uint(_)) +} + +pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { + if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"]) + && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind + && let Res::Local(local_id) = path.res + { + // We've checked that `call` is a call to `Stdin::read_line()` with the right receiver, + // now let's check if the first use of the string passed to `::read_line()` is + // parsed into a type that will always fail if it has a trailing newline. + for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| { + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(segment, .., span) = parent.kind + && segment.ident.name == sym!(parse) + && let parse_result_ty = cx.typeck_results().expr_ty(parent) + && is_type_diagnostic_item(cx, parse_result_ty, sym::Result) + && let ty::Adt(_, substs) = parse_result_ty.kind() + && let Some(ok_ty) = substs[0].as_type() + && parse_fails_on_trailing_newline(ok_ty) + { + let local_snippet = snippet(cx, expr.span, ""); + span_lint_and_then( + cx, + READ_LINE_WITHOUT_TRIM, + span, + "calling `.parse()` without trimming the trailing newline character", + |diag| { + diag.span_note(call.span, "call to `.read_line()` here, \ + which leaves a trailing newline character in the buffer, \ + which in turn will cause `.parse()` to fail"); + + diag.span_suggestion( + expr.span, + "try", + format!("{local_snippet}.trim_end()"), + Applicability::MachineApplicable, + ); + } + ); + } + + // only consider the first use to prevent this scenario: + // ``` + // let mut s = String::new(); + // std::io::stdin().read_line(&mut s); + // s.pop(); + // let _x: i32 = s.parse().unwrap(); + // ``` + // this is actually fine, because the pop call removes the trailing newline. + ControlFlow::<(), ()>::Break(()) + }); + } +} diff --git a/tests/ui/read_line_without_trim.fixed b/tests/ui/read_line_without_trim.fixed new file mode 100644 index 00000000000..5995c8f523e --- /dev/null +++ b/tests/ui/read_line_without_trim.fixed @@ -0,0 +1,19 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::read_line_without_trim)] + +fn main() { + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + input.pop(); + let _x: i32 = input.parse().unwrap(); // don't trigger here, newline character is popped + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x: i32 = input.trim_end().parse().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.trim_end().parse::().unwrap(); +} diff --git a/tests/ui/read_line_without_trim.rs b/tests/ui/read_line_without_trim.rs new file mode 100644 index 00000000000..84527b624b6 --- /dev/null +++ b/tests/ui/read_line_without_trim.rs @@ -0,0 +1,19 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::read_line_without_trim)] + +fn main() { + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + input.pop(); + let _x: i32 = input.parse().unwrap(); // don't trigger here, newline character is popped + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x: i32 = input.parse().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.parse::().unwrap(); +} diff --git a/tests/ui/read_line_without_trim.stderr b/tests/ui/read_line_without_trim.stderr new file mode 100644 index 00000000000..f0f7a61e9ff --- /dev/null +++ b/tests/ui/read_line_without_trim.stderr @@ -0,0 +1,31 @@ +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:14:25 + | +LL | let _x: i32 = input.parse().unwrap(); + | ----- ^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:13:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::read-line-without-trim` implied by `-D warnings` + +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:18:20 + | +LL | let _x = input.parse::().unwrap(); + | ----- ^^^^^^^^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:17:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 6868c0a74bb1edeff8c078bb8b09994075e826cb Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 5 Jul 2023 12:30:39 +0200 Subject: [`unnecessary_literal_unwrap`]: don't lint if binding initializer is expn --- clippy_lints/src/methods/unnecessary_literal_unwrap.rs | 5 +++++ tests/ui/unnecessary_literal_unwrap.fixed | 10 ++++++++++ tests/ui/unnecessary_literal_unwrap.rs | 10 ++++++++++ 3 files changed, 25 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 7877f6a386c..ce93d7c3eb3 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -29,6 +29,11 @@ pub(super) fn check( args: &[hir::Expr<'_>], ) { let init = clippy_utils::expr_or_init(cx, recv); + if init.span.from_expansion() { + // don't lint if the receiver or binding initializer comes from a macro + // (e.g. `let x = option_env!(..); x.unwrap()`) + return; + } let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind { let Some(qpath) = call.qpath_opt() else { return }; diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 630a1bea3c8..092bf78feab 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -68,6 +68,16 @@ fn unwrap_methods_result() { 1; } +fn unwrap_from_binding() { + macro_rules! from_macro { + () => { + Some("") + }; + } + let val = from_macro!(); + let _ = val.unwrap_or(""); +} + fn main() { unwrap_option_some(); unwrap_option_none(); diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 14f92cb370f..b9df893d1d2 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -68,6 +68,16 @@ fn unwrap_methods_result() { Ok::<_, ()>(1).unwrap_or_else(|_| 2); } +fn unwrap_from_binding() { + macro_rules! from_macro { + () => { + Some("") + }; + } + let val = from_macro!(); + let _ = val.unwrap_or(""); +} + fn main() { unwrap_option_some(); unwrap_option_none(); -- cgit 1.4.1-3-g733a5 From 23ac72316d7cf0c7979bf94544b2cc8f3ea3f89f Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 23 Jun 2023 23:23:36 +0200 Subject: adjust applicability and suggest making binding mutable --- clippy_lints/src/methods/filter_next.rs | 51 ++++++++++++++++++++++++++------- tests/ui/methods_unfixable.rs | 10 +++++++ tests/ui/methods_unfixable.stderr | 15 ++++++++++ 3 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 tests/ui/methods_unfixable.rs create mode 100644 tests/ui/methods_unfixable.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index ad71b494619..ce7f9997b5a 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,6 +1,7 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; +use rustc_ast::{BindingAnnotation, Mutability}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -8,6 +9,21 @@ use rustc_span::sym; use super::FILTER_NEXT; +fn path_to_local(expr: &hir::Expr<'_>) -> Option { + match expr.kind { + hir::ExprKind::Field(f, _) => path_to_local(f), + hir::ExprKind::Index(recv, _) => path_to_local(recv), + hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { + res: rustc_hir::def::Res::Local(local), + .. + }, + )) => Some(*local), + _ => None, + } +} + /// lint use of `filter().next()` for `Iterators` pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -26,15 +42,30 @@ pub(super) fn check<'tcx>( if filter_snippet.lines().count() <= 1 { let iter_snippet = snippet(cx, recv.span, ".."); // add note if not multi-line - span_lint_and_sugg( - cx, - FILTER_NEXT, - expr.span, - msg, - "try", - format!("{iter_snippet}.find({filter_snippet})"), - Applicability::MachineApplicable, - ); + span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { + let (applicability, pat) = if let Some(id) = path_to_local(recv) + && let Some(hir::Node::Pat(pat)) = cx.tcx.hir().find(id) + && let hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind + { + (Applicability::Unspecified, Some((pat.span, ident))) + } else { + (Applicability::MachineApplicable, None) + }; + + diag.span_suggestion( + expr.span, + "try", + format!("{iter_snippet}.find({filter_snippet})"), + applicability, + ); + + if let Some((pat_span, ident)) = pat { + diag.span_help( + pat_span, + format!("you will also need to make `{ident}` mutable, because `find` takes `&mut self`"), + ); + } + }); } else { span_lint(cx, FILTER_NEXT, expr.span, msg); } diff --git a/tests/ui/methods_unfixable.rs b/tests/ui/methods_unfixable.rs new file mode 100644 index 00000000000..3d88ce4b6bb --- /dev/null +++ b/tests/ui/methods_unfixable.rs @@ -0,0 +1,10 @@ +#![warn(clippy::filter_next)] + +fn main() { + issue10029(); +} + +pub fn issue10029() { + let iter = (0..10); + let _ = iter.filter(|_| true).next(); +} diff --git a/tests/ui/methods_unfixable.stderr b/tests/ui/methods_unfixable.stderr new file mode 100644 index 00000000000..6e101fe16b0 --- /dev/null +++ b/tests/ui/methods_unfixable.stderr @@ -0,0 +1,15 @@ +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead + --> $DIR/methods_unfixable.rs:9:13 + | +LL | let _ = iter.filter(|_| true).next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` + | +help: you will also need to make `iter` mutable, because `find` takes `&mut self` + --> $DIR/methods_unfixable.rs:8:9 + | +LL | let iter = (0..10); + | ^^^^ + = note: `-D clippy::filter-next` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From cd1c8532e99c4c594c6704be6d4274131bb71004 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:29:14 +0200 Subject: [`unnecessary_literal_unwrap`]: lint `unwrap_unchecked` --- clippy_lints/src/methods/mod.rs | 3 + .../src/methods/unnecessary_literal_unwrap.rs | 16 +++++ tests/ui/unnecessary_literal_unwrap.fixed | 10 +++ tests/ui/unnecessary_literal_unwrap.rs | 10 +++ tests/ui/unnecessary_literal_unwrap.stderr | 74 +++++++++++++++++++++- 5 files changed, 112 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c99f7c1fdd9..6e936e92cbd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4000,6 +4000,9 @@ impl Methods { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, + ("unwrap_unchecked", []) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + } ("unwrap_err", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests); diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index ce93d7c3eb3..13895b67ed0 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -67,6 +67,22 @@ pub(super) fn check( (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), (expr.span.with_lo(args[0].span.hi()), ")".to_string()), ]), + ("Some" | "Ok", "unwrap_unchecked", _) => { + let mut suggs = vec![ + (recv.span.with_hi(call_args[0].span.lo()), String::new()), + (expr.span.with_lo(call_args[0].span.hi()), String::new()), + ]; + // try to also remove the unsafe block if present + if let hir::Node::Block(block) = cx.tcx.hir().get_parent(expr.hir_id) + && let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules + { + suggs.extend([ + (block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()), + (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()) + ]); + } + Some(suggs) + }, (_, _, Some(_)) => None, ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ ( diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 092bf78feab..0e7ba6bcbbb 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -78,6 +78,15 @@ fn unwrap_from_binding() { let _ = val.unwrap_or(""); } +fn unwrap_unchecked() { + let _ = 1; + let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe block + let _ = 1 + 1; + let _ = 1; + let _ = unsafe { 1 + *(&1 as *const i32) }; + let _ = 1 + 1; +} + fn main() { unwrap_option_some(); unwrap_option_none(); @@ -85,4 +94,5 @@ fn main() { unwrap_result_err(); unwrap_methods_option(); unwrap_methods_result(); + unwrap_unchecked(); } diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index b9df893d1d2..fda7fd36ff9 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -78,6 +78,15 @@ fn unwrap_from_binding() { let _ = val.unwrap_or(""); } +fn unwrap_unchecked() { + let _ = unsafe { Some(1).unwrap_unchecked() }; + let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block + let _ = unsafe { Some(1).unwrap_unchecked() } + 1; + let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; + let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; + let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; +} + fn main() { unwrap_option_some(); unwrap_option_none(); @@ -85,4 +94,5 @@ fn main() { unwrap_result_err(); unwrap_methods_option(); unwrap_methods_result(); + unwrap_unchecked(); } diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 0c71ee05323..e5b93c3d9af 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -409,5 +409,77 @@ LL - Ok::<_, ()>(1).unwrap_or_else(|_| 2); LL + 1; | -error: aborting due to 36 previous errors +error: used `unwrap_unchecked()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:82:22 + | +LL | let _ = unsafe { Some(1).unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_unchecked()` + | +LL - let _ = unsafe { Some(1).unwrap_unchecked() }; +LL + let _ = 1; + | + +error: used `unwrap_unchecked()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:83:22 + | +LL | let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_unchecked()` + | +LL - let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block +LL + let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe block + | + +error: used `unwrap_unchecked()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:84:22 + | +LL | let _ = unsafe { Some(1).unwrap_unchecked() } + 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_unchecked()` + | +LL - let _ = unsafe { Some(1).unwrap_unchecked() } + 1; +LL + let _ = 1 + 1; + | + +error: used `unwrap_unchecked()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:85:22 + | +LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_unchecked()` + | +LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; +LL + let _ = 1; + | + +error: used `unwrap_unchecked()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:86:22 + | +LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_unchecked()` + | +LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; +LL + let _ = unsafe { 1 + *(&1 as *const i32) }; + | + +error: used `unwrap_unchecked()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:87:22 + | +LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_unchecked()` + | +LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; +LL + let _ = 1 + 1; + | + +error: aborting due to 42 previous errors -- cgit 1.4.1-3-g733a5 From 0b5dac09757237a407a1cdfbff16eeb4606f6390 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:49:18 +0200 Subject: [`unnecessary_literal_unwrap`]: also handle unwrap_err_unchecked --- clippy_lints/src/methods/mod.rs | 5 +---- clippy_lints/src/methods/unnecessary_literal_unwrap.rs | 2 +- tests/ui/unnecessary_literal_unwrap.fixed | 1 + tests/ui/unnecessary_literal_unwrap.rs | 1 + tests/ui/unnecessary_literal_unwrap.stderr | 14 +++++++++++++- 5 files changed, 17 insertions(+), 6 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6e936e92cbd..d6057ce45f6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4000,9 +4000,6 @@ impl Methods { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, - ("unwrap_unchecked", []) => { - unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - } ("unwrap_err", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests); @@ -4022,7 +4019,7 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or_default", []) => { + ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); } ("unwrap_or_else", [u_arg]) => { diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 13895b67ed0..54de300e6bc 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -67,7 +67,7 @@ pub(super) fn check( (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), (expr.span.with_lo(args[0].span.hi()), ")".to_string()), ]), - ("Some" | "Ok", "unwrap_unchecked", _) => { + ("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => { let mut suggs = vec![ (recv.span.with_hi(call_args[0].span.lo()), String::new()), (expr.span.with_lo(call_args[0].span.hi()), String::new()), diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 0e7ba6bcbbb..276cd800b89 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -85,6 +85,7 @@ fn unwrap_unchecked() { let _ = 1; let _ = unsafe { 1 + *(&1 as *const i32) }; let _ = 1 + 1; + let _ = 123; } fn main() { diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index fda7fd36ff9..3065778d779 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -85,6 +85,7 @@ fn unwrap_unchecked() { let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; + let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; } fn main() { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index e5b93c3d9af..5823313b736 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -481,5 +481,17 @@ LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; LL + let _ = 1 + 1; | -error: aborting due to 42 previous errors +error: used `unwrap_err_unchecked()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:88:22 + | +LL | let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err_unchecked()` + | +LL - let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; +LL + let _ = 123; + | + +error: aborting due to 43 previous errors -- cgit 1.4.1-3-g733a5 From 2811effe3478a3ce7d1bdde936c6ca8fb08de326 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 3 Jul 2023 17:42:48 +0000 Subject: Add `imports_granularity = "Module"` to rustfmt.toml --- clippy_lints/src/allow_attributes.rs | 3 +- clippy_lints/src/arc_with_non_send_sync.rs | 3 +- clippy_lints/src/attrs.rs | 6 +-- clippy_lints/src/blocks_in_if_conditions.rs | 3 +- clippy_lints/src/bool_to_int_with_if.rs | 4 +- clippy_lints/src/borrow_deref_ref.rs | 3 +- clippy_lints/src/box_default.rs | 14 +++-- clippy_lints/src/casts/as_ptr_cast_mut.rs | 6 +-- .../src/casts/cast_slice_different_sizes.rs | 6 ++- .../src/casts/cast_slice_from_raw_parts.rs | 3 +- clippy_lints/src/casts/ptr_cast_constness.rs | 4 +- clippy_lints/src/copies.rs | 3 +- clippy_lints/src/crate_in_macro_def.rs | 3 +- .../src/default_constructed_unit_structs.rs | 6 ++- clippy_lints/src/default_instead_of_iter_empty.rs | 3 +- clippy_lints/src/default_numeric_fallback.rs | 12 ++--- clippy_lints/src/dereference.rs | 13 ++--- clippy_lints/src/derivable_impls.rs | 5 +- clippy_lints/src/derive.rs | 3 +- clippy_lints/src/disallowed_names.rs | 3 +- clippy_lints/src/doc.rs | 3 +- clippy_lints/src/drop_forget_ref.rs | 3 +- clippy_lints/src/empty_drop.rs | 3 +- clippy_lints/src/empty_structs_with_brackets.rs | 3 +- clippy_lints/src/endian_bytes.rs | 6 ++- clippy_lints/src/entry.rs | 18 +++---- clippy_lints/src/escape.rs | 3 +- clippy_lints/src/excessive_nesting.rs | 11 ++-- clippy_lints/src/extra_unused_type_parameters.rs | 9 ++-- clippy_lints/src/floating_point_arithmetic.rs | 10 ++-- clippy_lints/src/format_args.rs | 6 +-- clippy_lints/src/format_impl.rs | 4 +- clippy_lints/src/from_over_into.rs | 3 +- clippy_lints/src/from_raw_with_void_ptr.rs | 3 +- clippy_lints/src/functions/impl_trait_in_params.rs | 6 ++- clippy_lints/src/functions/misnamed_getters.rs | 3 +- clippy_lints/src/functions/must_use.rs | 9 ++-- clippy_lints/src/if_let_mutex.rs | 3 +- clippy_lints/src/implicit_return.rs | 10 ++-- clippy_lints/src/incorrect_impls.rs | 14 ++--- clippy_lints/src/index_refutable_slice.rs | 3 +- clippy_lints/src/inherent_impl.rs | 3 +- clippy_lints/src/instant_subtraction.rs | 3 +- clippy_lints/src/items_after_test_module.rs | 3 +- clippy_lints/src/iter_not_returning_iterator.rs | 7 ++- clippy_lints/src/large_enum_variant.rs | 6 +-- clippy_lints/src/large_futures.rs | 3 +- clippy_lints/src/large_include_file.rs | 3 +- clippy_lints/src/large_stack_frames.rs | 6 +-- clippy_lints/src/len_zero.rs | 19 +++---- clippy_lints/src/let_if_seq.rs | 3 +- clippy_lints/src/let_underscore.rs | 3 +- clippy_lints/src/lib.rs | 7 ++- clippy_lints/src/lines_filter_map_ok.rs | 7 ++- clippy_lints/src/loops/manual_find.rs | 14 ++--- clippy_lints/src/loops/manual_flatten.rs | 3 +- clippy_lints/src/loops/manual_while_let_some.rs | 9 ++-- clippy_lints/src/loops/mut_range_bound.rs | 3 +- clippy_lints/src/loops/never_loop.rs | 4 +- .../src/loops/while_immutable_condition.rs | 3 +- clippy_lints/src/loops/while_let_on_iterator.rs | 12 ++--- clippy_lints/src/macro_use.rs | 3 +- clippy_lints/src/manual_clamp.rs | 14 +++-- clippy_lints/src/manual_float_methods.rs | 10 ++-- clippy_lints/src/manual_is_ascii_check.rs | 8 ++- clippy_lints/src/manual_range_patterns.rs | 9 +--- clippy_lints/src/manual_strip.rs | 3 +- clippy_lints/src/match_result_ok.rs | 3 +- clippy_lints/src/matches/manual_utils.rs | 9 ++-- clippy_lints/src/matches/match_like_matches.rs | 4 +- clippy_lints/src/matches/match_same_arms.rs | 3 +- .../src/matches/redundant_pattern_match.rs | 3 +- clippy_lints/src/methods/bind_instead_of_map.rs | 3 +- .../case_sensitive_file_extension_comparisons.rs | 6 +-- clippy_lints/src/methods/chars_cmp.rs | 3 +- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 3 +- clippy_lints/src/methods/clone_on_copy.rs | 4 +- .../src/methods/collapsible_str_replace.rs | 3 +- clippy_lints/src/methods/drain_collect.rs | 9 +--- clippy_lints/src/methods/err_expect.rs | 3 +- clippy_lints/src/methods/filter_map.rs | 4 +- clippy_lints/src/methods/filter_map_identity.rs | 3 +- clippy_lints/src/methods/flat_map_identity.rs | 3 +- clippy_lints/src/methods/flat_map_option.rs | 3 +- clippy_lints/src/methods/inspect_for_each.rs | 3 +- clippy_lints/src/methods/is_digit_ascii_radix.rs | 6 +-- clippy_lints/src/methods/iter_kv_map.rs | 3 +- clippy_lints/src/methods/iter_skip_next.rs | 3 +- .../src/methods/manual_saturating_arithmetic.rs | 6 +-- clippy_lints/src/methods/manual_try_fold.rs | 18 +++---- clippy_lints/src/methods/map_flatten.rs | 3 +- clippy_lints/src/methods/map_identity.rs | 3 +- clippy_lints/src/methods/mut_mutex_lock.rs | 3 +- clippy_lints/src/methods/needless_collect.rs | 5 +- clippy_lints/src/methods/obfuscated_if_else.rs | 3 +- clippy_lints/src/methods/option_map_or_none.rs | 3 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 9 +--- clippy_lints/src/methods/or_then_unwrap.rs | 6 ++- clippy_lints/src/methods/range_zip_with_len.rs | 3 +- clippy_lints/src/methods/read_line_without_trim.rs | 14 ++--- clippy_lints/src/methods/seek_from_current.rs | 8 +-- .../src/methods/suspicious_command_arg_space.rs | 3 +- clippy_lints/src/methods/suspicious_to_owned.rs | 3 +- clippy_lints/src/methods/type_id_on_box.rs | 6 +-- clippy_lints/src/methods/uninit_assumed_init.rs | 3 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 3 +- clippy_lints/src/methods/unnecessary_fold.rs | 3 +- .../src/methods/unnecessary_iter_cloned.rs | 3 +- clippy_lints/src/methods/unnecessary_join.rs | 3 +- .../src/methods/unnecessary_literal_unwrap.rs | 3 +- clippy_lints/src/methods/unnecessary_sort_by.rs | 3 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 6 ++- clippy_lints/src/methods/unwrap_or_else_default.rs | 8 +-- clippy_lints/src/min_ident_chars.rs | 11 ++-- clippy_lints/src/missing_enforced_import_rename.rs | 7 ++- clippy_lints/src/missing_fields_in_debug.rs | 20 +++----- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 12 ++--- clippy_lints/src/needless_bool.rs | 4 +- clippy_lints/src/needless_else.rs | 4 +- clippy_lints/src/needless_for_each.rs | 9 ++-- clippy_lints/src/needless_if.rs | 5 +- .../src/needless_parens_on_range_literals.rs | 8 ++- clippy_lints/src/needless_pass_by_ref_mut.rs | 3 +- clippy_lints/src/needless_pass_by_value.rs | 4 +- clippy_lints/src/no_effect.rs | 3 +- clippy_lints/src/non_send_fields_in_send_ty.rs | 3 +- clippy_lints/src/nonstandard_macro_braces.rs | 6 +-- .../src/operators/arithmetic_side_effects.rs | 18 +++---- clippy_lints/src/operators/assign_op_pattern.rs | 3 +- clippy_lints/src/operators/eq_op.rs | 3 +- .../src/operators/misrefactored_assign_op.rs | 3 +- clippy_lints/src/operators/op_ref.rs | 4 +- clippy_lints/src/option_if_let_else.rs | 5 +- clippy_lints/src/partialeq_to_none.rs | 7 ++- clippy_lints/src/pass_by_ref_or_value.rs | 3 +- clippy_lints/src/ptr.rs | 3 +- clippy_lints/src/question_mark.rs | 11 ++-- clippy_lints/src/ranges.rs | 3 +- clippy_lints/src/raw_strings.rs | 12 ++--- clippy_lints/src/rc_clone_in_vec_init.rs | 3 +- clippy_lints/src/read_zero_byte_vec.rs | 10 ++-- clippy_lints/src/redundant_async_block.rs | 13 +++-- clippy_lints/src/redundant_closure_call.rs | 3 +- clippy_lints/src/returns.rs | 3 +- clippy_lints/src/significant_drop_tightening.rs | 23 ++++----- clippy_lints/src/single_call_fn.rs | 4 +- clippy_lints/src/single_component_path_imports.rs | 7 ++- clippy_lints/src/single_range_in_vec_init.rs | 10 ++-- clippy_lints/src/size_of_in_element_count.rs | 3 +- clippy_lints/src/size_of_ref.rs | 4 +- clippy_lints/src/std_instead_of_core.rs | 6 ++- clippy_lints/src/strings.rs | 6 ++- clippy_lints/src/suspicious_doc_comments.rs | 3 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 3 +- clippy_lints/src/swap.rs | 4 +- clippy_lints/src/tests_outside_test_module.rs | 9 ++-- .../src/transmute/transmute_int_to_non_zero.rs | 6 +-- .../src/transmute/transmute_undefined_repr.rs | 3 +- .../transmutes_expressible_as_ptr_casts.rs | 3 +- clippy_lints/src/transmute/utils.rs | 3 +- clippy_lints/src/tuple_array_conversions.rs | 12 ++--- clippy_lints/src/types/borrowed_box.rs | 5 +- clippy_lints/src/types/box_collection.rs | 3 +- clippy_lints/src/types/linked_list.rs | 3 +- clippy_lints/src/types/option_option.rs | 3 +- clippy_lints/src/types/rc_buffer.rs | 3 +- clippy_lints/src/types/rc_mutex.rs | 3 +- clippy_lints/src/types/redundant_allocation.rs | 3 +- clippy_lints/src/types/vec_box.rs | 3 +- clippy_lints/src/unnecessary_box_returns.rs | 6 ++- .../src/unnecessary_owned_empty_strings.rs | 3 +- .../src/unnecessary_struct_initialization.rs | 5 +- clippy_lints/src/unnecessary_wraps.rs | 3 +- clippy_lints/src/unnested_or_patterns.rs | 3 +- clippy_lints/src/unused_unit.rs | 3 +- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/use_self.rs | 11 ++-- clippy_lints/src/useless_conversion.rs | 3 +- .../src/utils/internal_lints/invalid_paths.rs | 3 +- .../utils/internal_lints/lint_without_lint_pass.rs | 3 +- .../src/utils/internal_lints/metadata_collector.rs | 19 +++---- .../src/utils/internal_lints/msrv_attr_impl.rs | 3 +- clippy_lints/src/visibility.rs | 6 ++- clippy_lints/src/wildcard_imports.rs | 6 +-- clippy_utils/src/attrs.rs | 3 +- clippy_utils/src/check_proc_macro.rs | 18 +++---- clippy_utils/src/consts.rs | 6 +-- clippy_utils/src/eager_or_lazy.rs | 6 +-- clippy_utils/src/hir_utils.rs | 3 +- clippy_utils/src/lib.rs | 13 ++--- clippy_utils/src/mir/possible_borrower.rs | 12 +++-- clippy_utils/src/qualify_min_const_fn.rs | 4 +- clippy_utils/src/source.rs | 3 +- clippy_utils/src/ty.rs | 10 ++-- clippy_utils/src/usage.rs | 6 +-- lintcheck/src/config.rs | 3 +- lintcheck/src/main.rs | 4 +- lintcheck/src/recursive.rs | 3 +- rustfmt.toml | 1 + .../excessive_nesting/auxiliary/proc_macros.rs | 11 ++-- tests/ui-toml/unwrap_used/unwrap_used.rs | 4 +- tests/ui-toml/unwrap_used/unwrap_used.stderr | 56 ++++++++++---------- tests/ui/as_conversions.rs | 3 +- tests/ui/as_conversions.stderr | 6 +-- tests/ui/auxiliary/macro_use_helper.rs | 3 +- tests/ui/auxiliary/proc_macro_attr.rs | 4 +- tests/ui/auxiliary/proc_macros.rs | 11 ++-- tests/ui/default_trait_access.fixed | 3 +- tests/ui/default_trait_access.rs | 3 +- tests/ui/default_trait_access.stderr | 16 +++--- tests/ui/get_first.fixed | 4 +- tests/ui/get_first.rs | 4 +- tests/ui/get_first.stderr | 6 +-- tests/ui/get_unwrap.fixed | 4 +- tests/ui/get_unwrap.rs | 4 +- tests/ui/get_unwrap.stderr | 60 +++++++++++----------- tests/ui/issue-7447.rs | 5 +- tests/ui/issue-7447.stderr | 4 +- tests/ui/iter_cloned_collect.fixed | 3 +- tests/ui/iter_cloned_collect.rs | 3 +- tests/ui/iter_cloned_collect.stderr | 10 ++-- tests/ui/let_underscore_lock.rs | 3 +- tests/ui/let_underscore_lock.stderr | 8 +-- tests/ui/let_underscore_untyped.rs | 3 +- tests/ui/let_underscore_untyped.stderr | 20 ++++---- tests/ui/manual_retain.fixed | 7 +-- tests/ui/manual_retain.rs | 7 +-- tests/ui/manual_retain.stderr | 38 +++++++------- tests/ui/manual_try_fold.rs | 4 +- tests/ui/manual_try_fold.stderr | 8 +-- tests/ui/match_as_ref.fixed | 4 +- tests/ui/match_as_ref.rs | 4 +- tests/ui/match_as_ref.stderr | 2 +- tests/ui/methods.rs | 5 +- tests/ui/methods.stderr | 4 +- tests/ui/min_ident_chars.rs | 3 +- tests/ui/min_ident_chars.stderr | 58 ++++++++++----------- tests/ui/min_max.rs | 4 +- tests/ui/min_max.stderr | 26 +++++----- tests/ui/missing_doc.rs | 4 +- tests/ui/mut_key.rs | 3 +- tests/ui/mut_key.stderr | 36 ++++++------- tests/ui/needless_if.fixed | 3 +- tests/ui/needless_if.rs | 3 +- tests/ui/needless_if.stderr | 14 ++--- tests/ui/or_fun_call.fixed | 3 +- tests/ui/or_fun_call.rs | 3 +- tests/ui/or_fun_call.stderr | 56 ++++++++++---------- tests/ui/redundant_allocation.rs | 9 ++-- tests/ui/redundant_allocation.stderr | 40 +++++++-------- tests/ui/redundant_allocation_fixable.fixed | 12 ++--- tests/ui/redundant_allocation_fixable.rs | 12 ++--- tests/ui/redundant_allocation_fixable.stderr | 24 ++++----- tests/ui/redundant_pattern_matching_ipaddr.fixed | 6 +-- tests/ui/redundant_pattern_matching_ipaddr.rs | 6 +-- tests/ui/redundant_pattern_matching_ipaddr.stderr | 36 ++++++------- tests/ui/significant_drop_in_scrutinee.rs | 3 +- tests/ui/significant_drop_in_scrutinee.stderr | 52 +++++++++---------- tests/ui/single_component_path_imports.fixed | 4 ++ tests/ui/single_component_path_imports.rs | 4 ++ tests/ui/single_component_path_imports.stderr | 4 +- .../single_component_path_imports_nested_first.rs | 2 + ...ngle_component_path_imports_nested_first.stderr | 4 +- .../ui/single_component_path_imports_self_after.rs | 1 + .../single_component_path_imports_self_before.rs | 1 + tests/ui/unnecessary_to_owned.fixed | 3 +- tests/ui/unnecessary_to_owned.rs | 3 +- tests/ui/unsafe_removed_from_name.rs | 8 +++ tests/ui/unsafe_removed_from_name.stderr | 16 +++++- tests/ui/unused_peekable.rs | 3 +- tests/ui/unused_peekable.stderr | 16 +++--- tests/ui/wildcard_imports.fixed | 1 + tests/ui/wildcard_imports.rs | 1 + tests/ui/wildcard_imports.stderr | 24 ++++----- tests/ui/wildcard_imports_2021.edition2018.fixed | 1 + tests/ui/wildcard_imports_2021.edition2018.stderr | 24 ++++----- tests/ui/wildcard_imports_2021.edition2021.fixed | 1 + tests/ui/wildcard_imports_2021.edition2021.stderr | 24 ++++----- tests/ui/wildcard_imports_2021.rs | 1 + 279 files changed, 990 insertions(+), 1055 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index eb21184713e..e1ef514edfd 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -1,5 +1,6 @@ use ast::{AttrStyle, Attribute}; -use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 98ee8a9a880..7adcd9ad055 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::last_path_segment; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; -use rustc_lint::LateContext; -use rustc_lint::LateLintPass; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2ba78f99569..2a5be275615 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,12 +1,10 @@ //! checks for attributes +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::is_from_proc_macro; use clippy_utils::macros::{is_panic, macro_backtrace}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; -use clippy_utils::{ - diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, - is_from_proc_macro, -}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 569bf27c3e7..1593d7b0fb3 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::get_parent_expr; -use clippy_utils::higher; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::{get_parent_expr, higher}; use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index bdb3a011602..1828dd65152 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -4,7 +4,9 @@ use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use clippy_utils::{in_constant, is_else_clause, is_integer_literal}; use rustc_errors::Applicability; declare_clippy_lint! { diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 814108ed8a7..b3dbbb08f8e 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -1,9 +1,8 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_parent_expr, is_lint_allowed}; +use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed}; use rustc_errors::Applicability; use rustc_hir::{ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index e42c3fe2432..fa9c525fc08 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -1,12 +1,10 @@ -use clippy_utils::{ - diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path, - path_def_id, paths, ty::expr_sig, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::macro_backtrace; +use clippy_utils::ty::expr_sig; +use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths}; use rustc_errors::Applicability; -use rustc_hir::{ - intravisit::{walk_ty, Visitor}, - Block, Expr, ExprKind, Local, Node, QPath, TyKind, -}; +use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 1633ffd589c..e3d1f7df294 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -3,10 +3,8 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::{ - mir::Mutability, - ty::{self, Ty, TypeAndMut}, -}; +use rustc_middle::mir::Mutability; +use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::AS_PTR_CAST_MUT; diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 27cc5a1c3f0..4d9cc4cacc3 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -1,10 +1,12 @@ +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{diagnostics::span_lint_and_then, source}; +use clippy_utils::source; use if_chain::if_chain; use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::CAST_SLICE_DIFFERENT_SIZES; diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 1233c632a79..5e0123842b0 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, Expr, ExprKind}; +use rustc_hir::def_id::DefId; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index f0c1df01430..ce1ab10910c 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,6 +1,6 @@ -use clippy_utils::msrvs::POINTER_CAST_CONSTNESS; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS}; use clippy_utils::sugg::Sugg; -use clippy_utils::{diagnostics::span_lint_and_sugg, msrvs::Msrv}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 1c321f46e2d..e3a09636e24 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -10,8 +10,7 @@ use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def_id::DefIdSet; -use rustc_hir::intravisit; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; +use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 7436e9ce811..726674d88f1 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -5,7 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{symbol::sym, Span}; +use rustc_span::symbol::sym; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index ca9514ccc7d..a294c693787 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,5 +1,7 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, is_ty_alias, match_def_path, paths}; -use hir::{def::Res, ExprKind}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_ty_alias, match_def_path, paths}; +use hir::def::Res; +use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index f296b80d283..572990aaba1 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::last_path_segment; use clippy_utils::source::snippet_with_context; -use clippy_utils::{match_def_path, paths}; +use clippy_utils::{last_path_segment, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index e53a9877b20..0708b1cabdb 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -4,15 +4,11 @@ use clippy_utils::{get_parent_node, numeric_literal}; use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{ - intravisit::{walk_expr, walk_stmt, Visitor}, - Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind, -}; +use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; +use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::{ - lint::in_external_macro, - ty::{self, FloatTy, IntTy, PolyFnSig, Ty}, -}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::iter; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index cdf64b96036..1b3bd268bf5 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -12,12 +12,11 @@ use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch}; use rustc_errors::Applicability; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, - def_id::{DefId, LocalDefId}, - BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, ImplItem, - ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem, + self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, + ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_index::bit_set::BitSet; @@ -30,9 +29,11 @@ use rustc_middle::ty::{ ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults, }; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::collections::VecDeque; declare_clippy_lint! { diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index ec0ca50cfec..0ff3ddd67de 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -3,10 +3,9 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{ - self as hir, - def::{CtorKind, CtorOf, DefKind, Res}, - Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, + self as hir, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCast}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a005a360e9c..aea8cf2f9ab 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::paths; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; -use clippy_utils::{is_lint_allowed, match_def_path}; +use clippy_utils::{is_lint_allowed, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 6e6615f08ee..04c2d44137a 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint, is_test_module_or_function}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_test_module_or_function; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Item, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 87d88f70752..2f474bf38e6 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -31,9 +31,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span}; use rustc_span::{sym, FileName, Pos}; -use std::io; use std::ops::Range; -use std::thread; +use std::{io, thread}; use url::Url; declare_clippy_lint! { diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 976ce47e869..14122abbf2c 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::get_parent_node; -use clippy_utils::is_must_use_func_call; use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; +use clippy_utils::{get_parent_node, is_must_use_func_call}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index ec063c0f777..209fb66fa40 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, peel_blocks}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::peel_blocks; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node}; diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index c3a020433de..282157181ab 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_then, source::snippet_opt}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{Item, ItemKind, VariantData}; use rustc_errors::Applicability; use rustc_lexer::TokenKind; diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index f470987833e..dda14b4df53 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -1,8 +1,10 @@ use crate::Lint; -use clippy_utils::{diagnostics::span_lint_and_then, is_lint_allowed}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_lint_allowed; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::{lint::in_external_macro, ty::Ty}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Symbol; use std::borrow::Cow; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 86e94a62a78..49aae6b3745 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,18 +1,14 @@ -use clippy_utils::higher; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ - can_move_expr_to_closure_no_visit, - diagnostics::span_lint_and_sugg, - is_expr_final_block_expr, is_expr_used_or_unified, match_def_path, paths, peel_hir_expr_while, - source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}, - SpanlessEq, + can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, match_def_path, + paths, peel_hir_expr_while, SpanlessEq, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; -use rustc_hir::{ - hir_id::HirIdSet, - intravisit::{walk_expr, Visitor}, - Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp, -}; +use rustc_hir::hir_id::HirIdSet; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{Span, SyntaxContext, DUMMY_SP}; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index a51a8ee09f6..dbe3453e7bf 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir; -use rustc_hir::intravisit; -use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; +use rustc_hir::{self, intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index d04d833e630..8911f1872c2 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -1,9 +1,8 @@ -use clippy_utils::{diagnostics::span_lint_and_help, source::snippet}; -use rustc_ast::{ - node_id::NodeSet, - visit::{walk_block, walk_item, Visitor}, - Block, Crate, Inline, Item, ItemKind, ModKind, NodeId, -}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet; +use rustc_ast::node_id::NodeSet; +use rustc_ast::visit::{walk_block, walk_item, Visitor}; +use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 126bed6789c..c18006a71c2 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::is_from_proc_macro; -use clippy_utils::trait_ref_of_method; +use clippy_utils::{is_from_proc_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; @@ -12,10 +11,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{ - def_id::{DefId, LocalDefId}, - Span, -}; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 5e0fcd74339..29e5315f88b 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,10 +1,8 @@ -use clippy_utils::consts::{ - constant, constant_simple, Constant, - Constant::{Int, F32, F64}, -}; +use clippy_utils::consts::Constant::{Int, F32, F64}; +use clippy_utils::consts::{constant, constant_simple, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ - diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, - numeric_literal, peel_blocks, sugg, + eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, numeric_literal, peel_blocks, sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 08e45ed7d0e..d27f5c24366 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -14,10 +14,8 @@ use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, FormatPlaceholder, FormatTrait, }; -use rustc_errors::{ - Applicability, - SuggestionStyle::{CompletelyHidden, ShowCode}, -}; +use rustc_errors::Applicability; +use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 3ddee1842a3..66b74d3b5ab 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -7,8 +7,8 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; -use rustc_span::{sym, symbol::kw, Symbol}; +use rustc_span::symbol::kw; +use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 92d67ef359d..9584bec40ee 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -10,7 +10,8 @@ use rustc_hir::{ TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::{hir::nested_filter::OnlyBodies, ty}; +use rustc_middle::hir::nested_filter::OnlyBodies; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{kw, sym}; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 096508dc4f1..5e859d97c62 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -4,8 +4,7 @@ use clippy_utils::{match_def_path, path_def_id, paths}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::RawPtr; -use rustc_middle::ty::TypeAndMut; +use rustc_middle::ty::{RawPtr, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index d3d0d91c1be..597fca88885 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,6 +1,8 @@ -use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_in_test_function; -use rustc_hir::{intravisit::FnKind, Body, HirId}; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, HirId}; use rustc_lint::LateContext; use rustc_span::Span; diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index b244b913314..169b70f0463 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_errors::Applicability; -use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety}; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index d0ad2628264..c211ca67937 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -1,14 +1,13 @@ use hir::FnSig; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::def_id::DefIdSet; -use rustc_hir::{self as hir, def::Res, QPath}; +use rustc_hir::{self as hir, QPath}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::{ - lint::in_external_macro, - ty::{self, Ty}, -}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Span, Symbol}; use clippy_utils::attrs::is_proc_macro; diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 9ea8c494cfc..e614a8f694f 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::SpanlessEq; +use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 372b6ead3fe..a6b035d5106 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,9 +1,7 @@ -use clippy_utils::{ - diagnostics::span_lint_hir_and_then, - get_async_fn_body, is_async_fn, - source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}, - visitors::for_each_expr, -}; +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs index 25e1cb36b74..166908ef4e4 100644 --- a/clippy_lints/src/incorrect_impls.rs +++ b/clippy_lints/src/incorrect_impls.rs @@ -1,15 +1,15 @@ -use clippy_utils::{ - diagnostics::{span_lint_and_sugg, span_lint_and_then}, - get_parent_node, is_res_lang_ctor, last_path_segment, path_res, - ty::implements_trait, -}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res}; use rustc_errors::Applicability; -use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp}; +use rustc_hir::def::Res; +use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{sym, symbol::kw}; +use rustc_span::sym; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 7a269e98ff1..01a7c497cbe 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -13,7 +13,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::Ident, Span}; +use rustc_span::symbol::Ident; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 7c41699f307..77e541d5b16 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -3,7 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 34e9991582c..8df7dfb8b9e 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -7,7 +7,8 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{source_map::Spanned, sym}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index f684847c0c2..55a43e91562 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, is_in_cfg_test}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{is_from_proc_macro, is_in_cfg_test}; use rustc_hir::{HirId, ItemId, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index c924d7361ce..c16717deee0 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -1,5 +1,8 @@ -use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait}; -use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::get_parent_node; +use clippy_utils::ty::implements_trait; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 1c99bd2f3d0..9caaec4e5cc 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,10 +1,8 @@ //! lint when there is a large size difference between variants on an enum +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{ - diagnostics::span_lint_and_then, - ty::{approx_ty_size, is_copy, AdtVariantInfo}, -}; +use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo}; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 087c4a65250..d67d5899350 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -1,5 +1,6 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait}; +use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 424c0d9e798..566901de347 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::is_lint_allowed; use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; -use rustc_hir::Expr; -use rustc_hir::ExprKind; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 9c0cc978a39..7aa1446d53d 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -4,11 +4,9 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::fn_has_unsatisfiable_preds; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; -use rustc_hir::Body; -use rustc_hir::FnDecl; +use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_tool_lint; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 17bd89efaee..e64d46bd6e3 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,22 +1,23 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; -use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators, sugg::Sugg}; +use clippy_utils::sugg::Sugg; +use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::def_id::DefIdSet; +use rustc_hir::def::Res; +use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_hir::lang_items::LangItem; use rustc_hir::{ - def::Res, def_id::DefId, lang_items::LangItem, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, - GenericBound, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, - QPath, TraitItemRef, TyKind, TypeBindingKind, + AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, + ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, QPath, TraitItemRef, TyKind, + TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{ - source_map::{Span, Spanned, Symbol}, - symbol::sym, -}; +use rustc_span::source_map::{Span, Spanned, Symbol}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index db41bc67da1..2f6f36c3960 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; -use clippy_utils::{path_to_local_id, visitors::is_local_used}; +use clippy_utils::visitors::is_local_used; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index e6614180920..b505a4e0af9 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; -use clippy_utils::{is_must_use_func_call, paths}; +use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths}; use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cebe2e44c0f..a60da13d053 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -348,11 +348,10 @@ mod zero_div_zero; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` +use crate::utils::conf::metadata::get_configuration_metadata; +use crate::utils::conf::TryConf; pub use crate::utils::conf::{lookup_conf_file, Conf}; -use crate::utils::{ - conf::{metadata::get_configuration_metadata, TryConf}, - FindAll, -}; +use crate::utils::FindAll; /// Register all pre expansion lints /// diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 09b2032e20f..49425ff0a8e 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -1,7 +1,6 @@ -use clippy_utils::{ - diagnostics::span_lint_and_then, is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths, - ty::match_type, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::match_type; +use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index 4bb9936e9cd..0aaa66e6bce 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -1,14 +1,14 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FIND; -use clippy_utils::{ - diagnostics::span_lint_and_then, higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt, - source::snippet_with_applicability, ty::implements_trait, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::implements_trait; +use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{ - def::Res, lang_items::LangItem, BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind, -}; +use rustc_hir::def::Res; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 1e02a30e35f..559a2c03f14 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -1,9 +1,8 @@ use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::higher; use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, peel_blocks_with_stmt}; +use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs index cb9c84be4c7..ca584a454d0 100644 --- a/clippy_lints/src/loops/manual_while_let_some.rs +++ b/clippy_lints/src/loops/manual_while_let_some.rs @@ -1,9 +1,6 @@ -use clippy_utils::{ - diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}, - match_def_path, paths, - source::snippet, - SpanlessEq, -}; +use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}; +use clippy_utils::source::snippet; +use clippy_utils::{match_def_path, paths, SpanlessEq}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 4dae93f6028..b83d148b5f2 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -7,7 +7,8 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::{mir::FakeReadCause, ty}; +use rustc_middle::mir::FakeReadCause; +use rustc_middle::ty; use rustc_span::source_map::Span; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index ee338c6beb0..7da9121fbb3 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -1,9 +1,9 @@ use super::utils::make_iterator_snippet; use super::NEVER_LOOP; -use clippy_utils::consts::constant; +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet; -use clippy_utils::{consts::Constant, diagnostics::span_lint_and_then}; use rustc_errors::Applicability; use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index d1a1f773f87..7f24f3c5dc2 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -6,8 +6,7 @@ use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::HirIdSet; -use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind, HirIdSet, QPath}; use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 55989f8a446..ed6af90ef04 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -1,18 +1,18 @@ use super::WHILE_LET_ON_ITERATOR; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{ - get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used, -}; +use clippy_utils::visitors::is_res_used; +use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::{symbol::sym, Symbol}; +use rustc_span::symbol::sym; +use rustc_span::Symbol; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index cb3bda96133..70c5182472a 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -8,7 +8,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{edition::Edition, sym, Span}; +use rustc_span::edition::Edition; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 440362b96b4..e75666e61f5 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -4,21 +4,19 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; -use clippy_utils::MaybePath; use clippy_utils::{ eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, - peel_blocks_with_stmt, + peel_blocks_with_stmt, MaybePath, }; use itertools::Itertools; -use rustc_errors::Applicability; -use rustc_errors::Diagnostic; -use rustc_hir::{ - def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind, -}; +use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir::def::Res; +use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span}; +use rustc_span::symbol::sym; +use rustc_span::Span; use std::ops::Deref; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 09b39634333..085c73a5f9f 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -1,9 +1,7 @@ -use clippy_utils::{ - consts::{constant, Constant}, - diagnostics::span_lint_and_then, - is_from_proc_macro, path_to_local, - source::snippet_opt, -}; +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 31264261f5d..f264424470d 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,12 +1,16 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::root_macro_call; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, sugg::Sugg}; +use clippy_utils::sugg::Sugg; +use clippy_utils::{higher, in_constant}; use rustc_ast::ast::RangeLimits; use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{def_id::DefId, sym, Span}; +use rustc_span::def_id::DefId; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 64d4c8e4566..39d8b20d38d 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -2,13 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::Expr; -use rustc_hir::ExprKind; -use rustc_hir::PatKind; -use rustc_hir::RangeEnd; -use rustc_hir::UnOp; -use rustc_lint::LintContext; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 93d977a5c96..2b9def1a688 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -8,8 +8,7 @@ use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::BinOpKind; -use rustc_hir::{BorrowKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 6ec9784038c..841c020f2d3 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; -use clippy_utils::is_res_lang_ctor; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{higher, is_res_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index 5b7644a5383..6b611f567ae 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -1,14 +1,17 @@ -use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF}; +use crate::map_unit_fn::OPTION_MAP_UNIT_FN; +use crate::matches::MATCH_AS_REF; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, - peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, sugg::Sugg, CaptureKind, + peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, }; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::{sym, SyntaxContext}; diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 69f6c59beb3..e2ddf11abe2 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -1,9 +1,7 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lint_allowed; -use clippy_utils::is_wild; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::span_contains_comment; +use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath}; diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 3d2fbea63f5..0553b41328e 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; use core::cmp::Ordering; -use core::iter; -use core::slice; +use core::{iter, slice}; use rustc_arena::DroplessArena; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 43d2ab9f60e..bddd57c9810 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -12,7 +12,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Symbol}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 883a5505827..3a8cc41748e 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,7 +1,8 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, snippet_with_context}; -use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions}; +use clippy_utils::visitors::find_all_ret_expressions; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 7711aa78b23..41b5cc12d6d 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; -use clippy_utils::source::{indent_of, reindent_multiline}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::{source_map::Spanned, Span}; +use rustc_span::source_map::Spanned; +use rustc_span::Span; use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 079df2226d1..0e41f3c2107 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -4,8 +4,7 @@ use clippy_utils::{method_chain_args, path_def_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_lint::Lint; +use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 8984b2cf8fd..c9d50a5b03d 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -5,8 +5,7 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_lint::Lint; +use rustc_lint::{LateContext, Lint}; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. pub(super) fn check( diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 65fd50dff58..7eb325ee7b5 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -5,7 +5,9 @@ use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::{self}; use rustc_span::symbol::{sym, Symbol}; use super::CLONE_ON_COPY; diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 5e01ed90ff0..5409ede6008 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -8,8 +8,7 @@ use rustc_hir as hir; use rustc_lint::LateContext; use std::collections::VecDeque; -use super::method_call; -use super::COLLAPSIBLE_STR_REPLACE; +use super::{method_call, COLLAPSIBLE_STR_REPLACE}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index d0c79dc11b0..6a82d8f756a 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -4,17 +4,12 @@ use clippy_utils::is_range_full; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; -use rustc_hir::Expr; -use rustc_hir::ExprKind; -use rustc_hir::LangItem; -use rustc_hir::Path; -use rustc_hir::QPath; +use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::query::Key; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::sym; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; /// Checks if both types match the given diagnostic item, e.g.: /// diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index ae03da0d3f9..98f470dff8a 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -1,8 +1,7 @@ use super::ERR_EXPECT; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::ty::has_debug_impl; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index fc80f2eeae0..597a423b537 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -13,9 +13,7 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol}; use std::borrow::Cow; -use super::MANUAL_FILTER_MAP; -use super::MANUAL_FIND_MAP; -use super::OPTION_FILTER_MAP; +use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP}; fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { match &expr.kind { diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index d1b5e945dfd..3337b250c0e 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -3,7 +3,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{source_map::Span, sym}; +use rustc_span::source_map::Span; +use rustc_span::sym; use super::FILTER_MAP_IDENTITY; diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 6f911d79d0b..84a21de0ac8 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -3,7 +3,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{source_map::Span, sym}; +use rustc_span::source_map::Span; +use rustc_span::sym; use super::FLAT_MAP_IDENTITY; diff --git a/clippy_lints/src/methods/flat_map_option.rs b/clippy_lints/src/methods/flat_map_option.rs index 615bde94133..367a8ae82bd 100644 --- a/clippy_lints/src/methods/flat_map_option.rs +++ b/clippy_lints/src/methods/flat_map_option.rs @@ -4,7 +4,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{source_map::Span, sym}; +use rustc_span::source_map::Span; +use rustc_span::sym; use super::FLAT_MAP_OPTION; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index 7fd3ef1a622..23cc192c38e 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{source_map::Span, sym}; +use rustc_span::source_map::Span; +use rustc_span::sym; use super::INSPECT_FOR_EACH; diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index 301aff5ae6a..120f3d5f42c 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,10 +1,10 @@ //! Lint for `c.is_digit(10)` use super::IS_DIGIT_ASCII_RADIX; +use clippy_utils::consts::{constant_full_int, FullInt}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{ - consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability, -}; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index c87f5daab6f..674d3451748 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -9,8 +9,7 @@ use clippy_utils::visitors::is_local_used; use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; -use rustc_span::sym; -use rustc_span::Span; +use rustc_span::{sym, Span}; /// lint use of: /// - `hashmap.iter().map(|(_, v)| v)` diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index 279175e20c3..39af52141bb 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_trait_method; -use clippy_utils::path_to_local; use clippy_utils::source::snippet; +use clippy_utils::{is_trait_method, path_to_local}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{BindingAnnotation, Node, PatKind}; diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index a7284c64497..7e62e7ad909 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -24,10 +24,8 @@ pub fn check( let Some(mm) = is_min_or_max(cx, unwrap_arg) else { return }; if ty.is_signed() { - use self::{ - MinMax::{Max, Min}, - Sign::{Neg, Pos}, - }; + use self::MinMax::{Max, Min}; + use self::Sign::{Neg, Pos}; let Some(sign) = lit_sign(arith_rhs) else { return; diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 576a58499b1..dabed0affcf 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,15 +1,11 @@ -use clippy_utils::{ - diagnostics::span_lint_and_sugg, - is_from_proc_macro, - msrvs::{Msrv, ITERATOR_TRY_FOLD}, - source::snippet_opt, - ty::implements_trait, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use clippy_utils::msrvs::{Msrv, ITERATOR_TRY_FOLD}; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{ - def::{DefKind, Res}, - Expr, ExprKind, -}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::Span; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 361ffcb5ef3..349caa6ea6c 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -6,7 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{symbol::sym, Span}; +use rustc_span::symbol::sym; +use rustc_span::Span; use super::MAP_FLATTEN; diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 0f25ef82ed4..7be1ce483f6 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -4,7 +4,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{source_map::Span, sym}; +use rustc_span::source_map::Span; +use rustc_span::sym; use super::MAP_IDENTITY; diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index d0aa39d0627..161a7aa7fd4 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item}; +use clippy_utils::expr_custom_deref_adjustment; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index ac209d01406..60fd64ec97f 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -4,10 +4,9 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; use clippy_utils::{ - can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, - CaptureKind, + can_move_expr_to_closure, fn_def_id, get_enclosing_block, get_parent_node, higher, is_trait_method, path_to_local, + path_to_local_id, CaptureKind, }; -use clippy_utils::{fn_def_id, higher}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index eada530d670..697eab32a33 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,5 +1,6 @@ use super::OBFUSCATED_IF_ELSE; -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 41ceef19e3a..cb6a2306857 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -8,8 +8,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use super::OPTION_MAP_OR_NONE; -use super::RESULT_MAP_OR_INTO_OPTION; +use super::{OPTION_MAP_OR_NONE, RESULT_MAP_OR_INTO_OPTION}; // The expression inside a closure may or may not have surrounding braces // which causes problems when generating a suggestion. diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index f4f158c0439..fcbe005fb28 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,17 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_copy; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_path, Visitor}; -use rustc_hir::ExprKind; -use rustc_hir::Node; -use rustc_hir::PatKind; -use rustc_hir::QPath; -use rustc_hir::{self, HirId, Path}; +use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index d65082173b3..7b0bdcf99e7 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -1,8 +1,10 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res}; +use clippy_utils::{is_res_lang_ctor, path_res}; use rustc_errors::Applicability; -use rustc_hir::{lang_items::LangItem, Expr, ExprKind}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 867a3b40237..f253d8de91f 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; -use clippy_utils::{higher, SpanlessEq}; -use clippy_utils::{is_integer_const, is_trait_method}; +use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs index 49e4f1acaa6..8add0656101 100644 --- a/clippy_lints/src/methods/read_line_without_trim.rs +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -1,13 +1,13 @@ use std::ops::ControlFlow; -use clippy_utils::{ - diagnostics::span_lint_and_then, get_parent_expr, match_def_path, source::snippet, ty::is_type_diagnostic_item, - visitors::for_each_local_use_after_expr, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::{get_parent_expr, match_def_path}; use rustc_errors::Applicability; -use rustc_hir::Expr; -use rustc_hir::QPath; -use rustc_hir::{def::Res, ExprKind}; +use rustc_hir::def::Res; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::sym; diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index c028e954381..f3d6a15ede0 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -3,10 +3,10 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use clippy_utils::{ - diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability, - ty::implements_trait, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::implements_trait; +use clippy_utils::{get_trait_def_id, match_def_path, paths}; use super::SEEK_FROM_CURRENT; diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs index 73632c5a357..bc8f0176764 100644 --- a/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::paths; use clippy_utils::ty::match_type; -use rustc_ast as ast; use rustc_errors::{Applicability, Diagnostic}; -use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::Span; +use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index e818f1892e5..9eb8d6e6e78 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -5,7 +5,8 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty::{self, print::with_forced_trimmed_paths}; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::{self}; use rustc_span::sym; use super::SUSPICIOUS_TO_OWNED; diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index 88adba504aa..35137c97101 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -4,10 +4,8 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::adjustment::Adjustment; -use rustc_middle::ty::Ty; -use rustc_middle::ty::{self, ExistentialPredicate}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::{self, ExistentialPredicate, Ty}; use rustc_span::{sym, Span}; fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index a1c6294737c..bc9c518dbcf 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty}; +use clippy_utils::is_path_diagnostic_item; +use clippy_utils::ty::is_uninit_value_valid_for_ty; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 1cef6226ad4..cc64a2e7948 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -11,8 +11,7 @@ use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::sym; -use super::UNNECESSARY_FILTER_MAP; -use super::UNNECESSARY_FIND_MAP; +use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) { if !is_trait_method(cx, expr, sym::Iterator) { diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 8ec15a1c1b7..6e23754bf46 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -8,7 +8,8 @@ use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{source_map::Span, sym}; +use rustc_span::source_map::Span; +use rustc_span::sym; use super::UNNECESSARY_FOLD; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 52a4ff7d1ae..0c72c13a3ca 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -5,7 +5,8 @@ use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::{fn_def_id, get_parent_expr}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, Expr, ExprKind}; +use rustc_hir::def_id::DefId; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::{sym, Symbol}; diff --git a/clippy_lints/src/methods/unnecessary_join.rs b/clippy_lints/src/methods/unnecessary_join.rs index 087e1e4343b..d0c62fb56dc 100644 --- a/clippy_lints/src/methods/unnecessary_join.rs +++ b/clippy_lints/src/methods/unnecessary_join.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 54de300e6bc..111bcaaecec 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_segment, path_res, MaybePath}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 67618f7038a..54b76bd04fe 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -6,7 +6,8 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, subst::GenericArgKind}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self}; use rustc_span::sym; use rustc_span::symbol::Ident; use std::iter; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 16ef24bd4e3..dcfec52fd71 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -7,7 +7,8 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_hir::def_id::DefId; +use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node}; use rustc_hir_typeck::{FnCtxt, Inherited}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; @@ -16,7 +17,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, ProjectionPredicate, TraitPredicate, Ty}; use rustc_span::{sym, Symbol}; -use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{Obligation, ObligationCause}; use super::UNNECESSARY_TO_OWNED; diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index 045f739e64d..474a33b67e1 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -1,10 +1,10 @@ //! Lint for `some_result_or_option.unwrap_or_else(Default::default)` use super::UNWRAP_OR_ELSE_DEFAULT; -use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability, - ty::is_type_diagnostic_item, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_default_equivalent_call; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index 23593e0d4d9..2a60f2faca0 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -1,10 +1,9 @@ -use clippy_utils::{diagnostics::span_lint, is_from_proc_macro}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{ - def::{DefKind, Res}, - intravisit::{walk_item, Visitor}, - GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, -}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::intravisit::{walk_item, Visitor}; +use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 773174679db..96d83e114a4 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,8 +1,11 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, UseKind}; +use rustc_hir::def::Res; +use rustc_hir::def_id::DefId; +use rustc_hir::{Item, ItemKind, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 497514fbcd6..2f63b9b9f0b 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -1,23 +1,17 @@ use std::ops::ControlFlow; -use clippy_utils::{ - diagnostics::span_lint_and_then, - is_path_lang_item, paths, - ty::match_type, - visitors::{for_each_expr, Visitable}, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::match_type; +use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::{is_path_lang_item, paths}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::Block; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - def::{DefKind, Res}, - Expr, ImplItemKind, LangItem, Node, + Block, Expr, ExprKind, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Node, QPath, TyKind, VariantData, }; -use rustc_hir::{ExprKind, Impl, ItemKind, QPath, TyKind}; -use rustc_hir::{ImplItem, Item, VariantData}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; -use rustc_middle::ty::TypeckResults; +use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span, Symbol}; diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index e6fd65f001a..fe35126aab2 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,12 +1,8 @@ -use clippy_utils::{ - diagnostics::span_lint_and_then, - visitors::{for_each_expr_with_closures, Descend, Visitable}, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable}; use core::ops::ControlFlow::Continue; -use hir::{ - def::{DefKind, Res}, - BlockCheckMode, ExprKind, QPath, UnOp, Unsafety, -}; +use hir::def::{DefKind, Res}; +use hir::{BlockCheckMode, ExprKind, QPath, UnOp, Unsafety}; use rustc_ast::Mutability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 34b74e180cb..46457400abc 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,9 +6,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, + get_parent_node, higher, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, + SpanlessEq, }; -use clippy_utils::{higher, SpanlessEq}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 23d4a7b9586..03bab86c6d7 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,5 +1,5 @@ -use clippy_utils::source::snippet_opt; -use clippy_utils::{diagnostics::span_lint_and_sugg, source::trim_span}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{snippet_opt, trim_span}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index c3b633fd6a0..463e188fc8e 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -1,11 +1,10 @@ use rustc_errors::Applicability; -use rustc_hir::{ - intravisit::{walk_expr, Visitor}, - Closure, Expr, ExprKind, Stmt, StmtKind, -}; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{source_map::Span, sym, Symbol}; +use rustc_span::source_map::Span; +use rustc_span::{sym, Symbol}; use if_chain::if_chain; diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index ad5c3e1dc82..1ed7ea6b325 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -1,4 +1,7 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, higher::If, is_from_proc_macro, source::snippet_opt}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::If; +use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index da1b9d99931..d17a383e882 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -1,8 +1,6 @@ -use clippy_utils::{ - diagnostics::span_lint_and_then, - higher, - source::{snippet, snippet_with_applicability}, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher; +use clippy_utils::source::{snippet, snippet_with_applicability}; use rustc_ast::ast; use rustc_errors::Applicability; diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 46c9b6c4141..cdb7ee48305 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -5,8 +5,7 @@ use clippy_utils::{is_from_proc_macro, is_self}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, FnDecl, HirId, Impl, ItemKind, Mutability, Node, PatKind}; -use rustc_hir::{HirIdMap, HirIdSet}; +use rustc_hir::{Body, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind}; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5d299f9355d..f35f120c852 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -10,9 +10,9 @@ use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind, + BindingAnnotation, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, + QPath, TyKind, }; -use rustc_hir::{HirIdSet, LangItem}; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index a4c7da7e48d..e6d3e72d1e6 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::peel_blocks; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; -use clippy_utils::{get_parent_node, is_lint_allowed}; +use clippy_utils::{get_parent_node, is_lint_allowed, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 7eaa7db78a4..24875855de3 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -7,7 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{FieldDef, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 2d79a5c9008..bd194b93584 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,5 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; +use std::fmt; +use std::hash::{Hash, Hasher}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 5c240276b76..41e8377e15e 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -1,20 +1,14 @@ use super::ARITHMETIC_SIDE_EFFECTS; -use clippy_utils::is_from_proc_macro; -use clippy_utils::{ - consts::{constant, constant_simple, Constant}, - diagnostics::span_lint, - is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, -}; -use rustc_ast as ast; +use clippy_utils::consts::{constant, constant_simple, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::{ - source_map::{Span, Spanned}, - Symbol, -}; +use rustc_span::source_map::{Span, Spanned}; +use rustc_span::Symbol; +use {rustc_ast as ast, rustc_hir as hir}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[ ["f32", "f32"], diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 9bbf385fb59..c4572a09db6 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,9 +1,8 @@ -use clippy_utils::binop_traits; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{eq_expr_value, trait_ref_of_method}; +use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 78965b7d6f7..88d56631841 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -1,6 +1,7 @@ +use clippy_utils::ast_utils::is_useless_with_eq_exprs; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; -use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; +use clippy_utils::{eq_expr_value, is_in_test_function}; use rustc_hir::{BinOpKind, Expr}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 015f6c14e76..5eabb349ec1 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::eq_expr_value; use clippy_utils::source::snippet_opt; -use clippy_utils::sugg; +use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs index d7917e86a86..932dd470f9e 100644 --- a/clippy_lints/src/operators/op_ref.rs +++ b/clippy_lints/src/operators/op_ref.rs @@ -4,7 +4,9 @@ use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind}; +use rustc_hir::def::Res; +use rustc_hir::def_id::DefId; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index abdccc47f54..40da002f4ff 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -6,10 +6,9 @@ use clippy_utils::{ }; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; -use rustc_hir::{ - def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp, -}; +use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::SyntaxContext; diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 456ded3fc02..d9f5d1642d7 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -1,7 +1,6 @@ -use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg, - ty::is_type_diagnostic_item, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0d78c3048ba..a8e16f2cb33 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -1,5 +1,4 @@ -use std::cmp; -use std::iter; +use std::{cmp, iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 866a04466c9..71c65e925e3 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -28,8 +28,7 @@ use rustc_span::sym; use rustc_span::symbol::Symbol; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use std::fmt; -use std::iter; +use std::{fmt, iter}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 9840d464b75..f5502cffb66 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,10 +4,9 @@ use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, pat_and_expr_can_be_question_mark, - path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, + eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_path_lang_item, is_res_lang_ctor, + pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, }; -use clippy_utils::{higher, is_path_lang_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -17,9 +16,9 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::declare_tool_lint; -use rustc_session::impl_lint_pass; -use rustc_span::{sym, symbol::Symbol}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; +use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index d2018aba9e3..3287675a82d 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,10 +1,9 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::higher; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, is_integer_const, path_to_local}; +use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 0e964ec4724..ccabb577cb7 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -1,10 +1,10 @@ -use std::{iter::once, ops::ControlFlow}; +use std::iter::once; +use std::ops::ControlFlow; -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; -use rustc_ast::{ - ast::{Expr, ExprKind}, - token::LitKind, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use rustc_ast::ast::{Expr, ExprKind}; +use rustc_ast::token::LitKind; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index e82aa3a7b98..a2e7ae6d79a 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; -use clippy_utils::last_path_segment; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::paths; use clippy_utils::source::{indent_of, snippet}; use clippy_utils::ty::match_type; +use clippy_utils::{last_path_segment, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index fa107858863..2bf90815caa 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -1,9 +1,7 @@ -use clippy_utils::{ - diagnostics::{span_lint, span_lint_and_sugg}, - higher::{get_vec_init_kind, VecInitKind}, - source::snippet, - visitors::for_each_expr, -}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::source::snippet; +use clippy_utils::visitors::for_each_expr; use core::ops::ControlFlow; use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 05e52e6b38b..534b2762ba7 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -1,15 +1,14 @@ use std::ops::ControlFlow; -use clippy_utils::{ - diagnostics::span_lint_and_sugg, - peel_blocks, - source::{snippet, walk_span_to_context}, - visitors::for_each_expr, -}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::peel_blocks; +use clippy_utils::source::{snippet, walk_span_to_context}; +use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::{lint::in_external_macro, ty::UpvarCapture}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::UpvarCapture; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index b6ce4ebc28f..4e3efe97b8c 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -6,8 +6,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit as hir_visit; -use rustc_hir::intravisit::Visitor as HirVisitor; -use rustc_hir::intravisit::Visitor; +use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index ad0167a3d32..0212deda146 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -9,7 +9,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index cc2dbae4bc4..bf1059a8b29 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,20 +1,17 @@ -use clippy_utils::{ - diagnostics::span_lint_and_then, - expr_or_init, get_attr, path_to_local, - source::{indent_of, snippet}, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::{expr_or_init, get_attr, path_to_local}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::Applicability; -use rustc_hir::{ - self as hir, - def::{DefKind, Res}, - intravisit::{walk_expr, Visitor}, -}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{self as hir}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{Ty, TypeAndMut}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::sym; -use rustc_span::{symbol::Ident, Span, DUMMY_SP}; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span, DUMMY_SP}; use std::borrow::Cow; declare_clippy_lint! { diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index 42753d2e951..7bbe98e0a7f 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{is_from_proc_macro, is_in_test_function}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl}; +use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 5743dd21c28..9c21d70c82c 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,11 +1,14 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::node_id::{NodeId, NodeMap}; +use rustc_ast::ptr::P; use rustc_ast::visit::{walk_expr, Visitor}; -use rustc_ast::{ptr::P, Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; +use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{edition::Edition, symbol::kw, Span, Symbol}; +use rustc_span::edition::Edition; +use rustc_span::symbol::kw; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index dfe8be7a6a6..321c8988988 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -1,7 +1,9 @@ -use clippy_utils::{ - diagnostics::span_lint_and_then, get_trait_def_id, higher::VecArgs, macros::root_macro_call_first_node, - source::snippet_opt, ty::implements_trait, -}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::get_trait_def_id; +use clippy_utils::higher::VecArgs; +use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index ac4e29e9dfd..a91dd21269c 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -4,8 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; -use rustc_hir::BinOpKind; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 8abec06c641..89ac8cd8ca9 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -1,4 +1,6 @@ -use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::path_def_id; +use clippy_utils::ty::peel_mid_ty_refs; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index a13bc7a5188..f239165276f 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_hir::{def::Res, HirId, Path, PathSegment}; +use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{sym, symbol::kw, Span}; +use rustc_span::symbol::kw; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 8658009eba4..58724852b3c 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq}; -use clippy_utils::{get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls}; +use clippy_utils::{ + get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls, + peel_blocks, SpanlessEq, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/suspicious_doc_comments.rs b/clippy_lints/src/suspicious_doc_comments.rs index e5746ca99ca..8be4ec3dc64 100644 --- a/clippy_lints/src/suspicious_doc_comments.rs +++ b/clippy_lints/src/suspicious_doc_comments.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}; use if_chain::if_chain; -use rustc_ast::{token::CommentKind, AttrKind, AttrStyle, Attribute, Item}; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrKind, AttrStyle, Attribute, Item}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 9c0dc8096d0..6fa49afe0ec 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -1,4 +1,5 @@ -use clippy_utils::{numeric_literal::NumericLiteral, source::snippet_with_context}; +use clippy_utils::numeric_literal::NumericLiteral; +use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index f7eef03d1d4..98158ed0aee 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -11,8 +11,8 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use rustc_span::SyntaxContext; -use rustc_span::{sym, symbol::Ident, Span}; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index 0a0a77082e0..b356666d852 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -1,8 +1,11 @@ -use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function}; -use rustc_hir::{intravisit::FnKind, Body, FnDecl}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{is_in_cfg_test, is_in_test_function}; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{def_id::LocalDefId, Span}; +use rustc_span::def_id::LocalDefId; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 5503653253c..c0d0d2b93dc 100644 --- a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -4,10 +4,8 @@ use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::{ - query::Key, - ty::{self, Ty}, -}; +use rustc_middle::query::Key; +use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; /// Checks for `transmute_int_to_non_zero` lint. diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 5e24213d07f..13b7eeb43a6 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -3,8 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_c_void; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::SubstsRef; -use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy}; +use rustc_middle::ty::{self, IntTy, SubstsRef, Ty, TypeAndMut, UintTy}; #[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 85cd74f23ef..513a913f56a 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -6,7 +6,8 @@ use rustc_ast::ExprPrecedence; use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; use rustc_lint::LateContext; -use rustc_middle::ty::{cast::CastKind, Ty}; +use rustc_middle::ty::cast::CastKind; +use rustc_middle::ty::Ty; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 62efd13b8d9..1cf6cf8548a 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -2,7 +2,8 @@ use rustc_hir as hir; use rustc_hir::Expr; use rustc_hir_typeck::{cast, FnCtxt, Inherited}; use rustc_lint::LateContext; -use rustc_middle::ty::{cast::CastKind, Ty}; +use rustc_middle::ty::cast::CastKind; +use rustc_middle::ty::Ty; use rustc_span::DUMMY_SP; // check if the component types of the transmuted collection and the result have different ABI, diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 258617467e9..2e00ed042a8 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -1,13 +1,11 @@ -use clippy_utils::{ - diagnostics::span_lint_and_help, - is_from_proc_macro, - msrvs::{self, Msrv}, - path_to_local, -}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind, HirId, Node, Pat}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::{lint::in_external_macro, ty}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use std::iter::once; diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index acdf5471069..306ca5724da 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -2,8 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{self as hir, GenericArg, GenericBounds, GenericParamKind}; -use rustc_hir::{HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind}; +use rustc_hir::{ + self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind, +}; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index 43665a922d4..4a5a94f2630 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{path_def_id, qpath_generic_tys}; -use rustc_hir::{self as hir, def_id::DefId, QPath}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; use rustc_span::{sym, Symbol}; diff --git a/clippy_lints/src/types/linked_list.rs b/clippy_lints/src/types/linked_list.rs index 5fb708741e5..fba804bbe08 100644 --- a/clippy_lints/src/types/linked_list.rs +++ b/clippy_lints/src/types/linked_list.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{self as hir, def_id::DefId}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index 8767e3c30a6..60622903af1 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::{path_def_id, qpath_generic_tys}; use if_chain::if_chain; -use rustc_hir::{self as hir, def_id::DefId, QPath}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 855137b14d8..8239630ac2d 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/types/rc_mutex.rs b/clippy_lints/src/types/rc_mutex.rs index a75972cf3dd..a616c3e4ea8 100644 --- a/clippy_lints/src/types/rc_mutex.rs +++ b/clippy_lints/src/types/rc_mutex.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{path_def_id, qpath_generic_tys}; use if_chain::if_chain; -use rustc_hir::{self as hir, def_id::DefId, QPath}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index f7adc9d3555..d369c6df919 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::LateContext; use rustc_middle::ty::TypeVisitableExt; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index d3062f3d2e3..decc183ad96 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -3,7 +3,8 @@ use clippy_utils::last_path_segment; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, GenericArg, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index e7449639f3a..58ccd47f837 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -1,6 +1,8 @@ -use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::approx_ty_size; use rustc_errors::Applicability; -use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 6e802794f5a..57a4a429e12 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -1,4 +1,5 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index 084b031982d..f4111186c64 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -1,4 +1,7 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_copy; +use clippy_utils::{get_parent_expr, path_to_local}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 5073eb02bd8..f34f8d0e353 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::visitors::find_all_ret_expressions; +use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index a57bf7ee822..c1cc7471d53 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -6,7 +6,8 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::over; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; +use rustc_ast::PatKind::*; +use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index cad8da18c2f..95e74718d80 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{position_before_rarrow, snippet_opt}; use if_chain::if_chain; -use rustc_ast::{ast, visit::FnKind, ClosureBinder}; +use rustc_ast::visit::FnKind; +use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 377d3fb6f4e..c99b0290c0c 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{path_to_local, usage::is_potentially_mutated}; +use clippy_utils::usage::is_potentially_mutated; +use clippy_utils::{higher, path_to_local}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5a02987453c..fcf77e8eab9 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -5,13 +5,12 @@ use clippy_utils::ty::same_type_and_consts; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; +use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; use rustc_hir::{ - self as hir, - def::{CtorOf, DefKind, Res}, - def_id::LocalDefId, - intravisit::{walk_inf, walk_ty, Visitor}, - Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, - ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, + self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, + HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index b6c11cfb355..c9c092c508f 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::is_ty_alias; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; +use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 9afe02c1e47..94b56304bca 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -7,7 +7,8 @@ use rustc_hir::def::DefKind; use rustc_hir::Item; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy}; +use rustc_middle::ty::fast_reject::SimplifiedType; +use rustc_middle::ty::{self, FloatTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index f718207654f..87380f14f9a 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -3,10 +3,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{is_lint_allowed, match_def_path, paths}; use if_chain::if_chain; -use rustc_ast as ast; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::Visitor; @@ -18,6 +16,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; +use {rustc_ast as ast, rustc_hir as hir}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 107a62806a8..f49c3fadb07 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -8,11 +8,8 @@ //! a simple mistake) use crate::renamed_lints::RENAMED_LINTS; -use crate::utils::{ - collect_configs, - internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}, - ClippyConfiguration, -}; +use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; +use crate::utils::{collect_configs, ClippyConfiguration}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -21,22 +18,22 @@ use if_chain::if_chain; use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{ - self as hir, def::DefKind, intravisit, intravisit::Visitor, Closure, ExprKind, Item, ItemKind, Mutability, QPath, -}; +use rustc_hir::def::DefKind; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath}; use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; use rustc_middle::hir::nested_filter; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::Ident; use rustc_span::{sym, Loc, Span, Symbol}; -use serde::{ser::SerializeStruct, Serialize, Serializer}; +use serde::ser::SerializeStruct; +use serde::{Serialize, Serializer}; use std::collections::{BTreeSet, BinaryHeap}; use std::fmt; use std::fmt::Write as _; use std::fs::{self, OpenOptions}; use std::io::prelude::*; -use std::path::Path; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Command; /// This is the json output file of the lint collector. diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 09f0f0d0adb..14855e9c331 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -7,7 +7,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{self, subst::GenericArgKind}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 43248bccc13..49637652001 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -1,10 +1,12 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{symbol::kw, Span}; +use rustc_span::symbol::kw; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 2a3d86988bb..d09d02a7dfd 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -3,10 +3,8 @@ use clippy_utils::is_test_module_or_function; use clippy_utils::source::{snippet, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{ - def::{DefKind, Res}, - Item, ItemKind, PathSegment, UseKind, -}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index e4cc86f6800..51771f78d4f 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -1,5 +1,4 @@ -use rustc_ast::ast; -use rustc_ast::attr; +use rustc_ast::{ast, attr}; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::sym; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 62792d60652..89f8a65c5ae 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -12,20 +12,20 @@ //! code was written, and check if the span contains that text. Note this will only work correctly //! if the span is not from a `macro_rules` based macro. -use rustc_ast::{ - ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy}, - token::CommentKind, - AttrStyle, -}; +use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy}; +use rustc_ast::token::CommentKind; +use rustc_ast::AttrStyle; +use rustc_hir::intravisit::FnKind; use rustc_hir::{ - intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, - Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, - TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, + Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, Impl, ImplItem, + ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, TraitItemKind, Ty, + TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::{symbol::Ident, Span, Symbol}; +use rustc_span::symbol::Ident; +use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; /// The search pattern to look for. Used by `span_matches_pat` diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 87d85d742ce..c61dc530e13 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -9,11 +9,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; -use rustc_middle::mir; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; -use rustc_middle::ty::{List, SubstsRef}; -use rustc_middle::{bug, span_bug}; +use rustc_middle::ty::{self, EarlyBinder, FloatTy, List, ScalarInt, SubstsRef, Ty, TyCtxt}; +use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; use std::cmp::Ordering::{self, Equal}; diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index eda739bceb5..29b73ab4cd5 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -12,14 +12,14 @@ use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp}; +use rustc_hir::{Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; use rustc_span::{sym, Symbol}; -use std::cmp; -use std::ops; +use std::{cmp, ops}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] enum EagernessSuggestion { diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 3e1d7356414..fb359ee3bbe 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -5,10 +5,9 @@ use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; -use rustc_hir::HirIdMap; use rustc_hir::{ ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, - GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, + GenericArgs, Guard, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 1ac106d5d59..5b433ed95bc 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -74,8 +74,7 @@ pub use self::hir_utils::{ use core::ops::ControlFlow; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; -use std::sync::OnceLock; -use std::sync::{Mutex, MutexGuard}; +use std::sync::{Mutex, MutexGuard, OnceLock}; use if_chain::if_chain; use itertools::Itertools; @@ -87,8 +86,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::LangItem::OptionSome; -use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local, @@ -106,15 +104,14 @@ use rustc_middle::ty::fast_reject::SimplifiedType::{ ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType, PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType, }; +use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - layout::IntegerExt, BorrowKind, ClosureKind, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture, + BorrowKind, ClosureKind, FloatTy, IntTy, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture, }; -use rustc_middle::ty::{FloatTy, IntTy, UintTy}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::sym; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::Integer; use crate::consts::{constant, miri_to_const, Constant}; diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 920ce8e655b..703985b9d4b 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -1,11 +1,15 @@ -use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation}; +use super::possible_origin::PossibleOriginVisitor; +use super::transitive_relation::TransitiveRelation; use crate::ty::is_copy; use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; -use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; -use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt}; -use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; +use rustc_middle::mir::visit::Visitor as _; +use rustc_middle::mir::{self, Mutability}; +use rustc_middle::ty::visit::TypeVisitor; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_mir_dataflow::impls::MaybeStorageLive; +use rustc_mir_dataflow::{Analysis, ResultsCursor}; use std::borrow::Cow; use std::ops::ControlFlow; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index c9938caefb0..a216d8c4f91 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -15,9 +15,9 @@ use rustc_middle::mir::{ Terminator, TerminatorKind, }; use rustc_middle::traits::{ImplSource, ObligationCause}; +use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; -use rustc_middle::ty::{BoundConstness, TraitRef}; +use rustc_middle::ty::{self, BoundConstness, TraitRef, Ty, TyCtxt}; use rustc_semver::RustcVersion; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 582337b47e8..dc4ee725681 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -8,8 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; use rustc_span::source_map::{original_sp, SourceMap}; -use rustc_span::{hygiene, SourceFile}; -use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{hygiene, BytePos, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; use std::ops::Range; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 9c39d22c61b..d73972b1c44 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -9,18 +9,16 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; -use rustc_infer::infer::{ - type_variable::{TypeVariableOrigin, TypeVariableOriginKind}, - TyCtxtInferExt, -}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; +use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, + self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, IntTy, List, ParamEnv, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; -use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{Size, VariantIdx}; diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 9855085216f..efb23825abb 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,16 +1,14 @@ -use crate as utils; use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend}; use core::ops::ControlFlow; -use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::HirIdSet; -use rustc_hir::{Expr, ExprKind, HirId, Node}; +use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Node}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; +use {crate as utils, rustc_hir as hir}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option { diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs index 3f01e9bb0a7..e678d40795e 100644 --- a/lintcheck/src/config.rs +++ b/lintcheck/src/config.rs @@ -1,5 +1,6 @@ use clap::Parser; -use std::{num::NonZeroUsize, path::PathBuf}; +use std::num::NonZeroUsize; +use std::path::PathBuf; #[derive(Clone, Debug, Parser)] pub(crate) struct LintcheckConfig { diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index de56a6f8275..3a022b343a4 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -15,16 +15,14 @@ use crate::config::LintcheckConfig; use crate::recursive::LintcheckServer; use std::collections::{HashMap, HashSet}; -use std::env; use std::env::consts::EXE_SUFFIX; use std::fmt::{self, Write as _}; -use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::thread; use std::time::Duration; +use std::{env, fs, thread}; use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel}; use cargo_metadata::Message; diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 49072e65192..994fa3c3b23 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -3,8 +3,7 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::ClippyWarning; -use crate::RecursiveOptions; +use crate::{ClippyWarning, RecursiveOptions}; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; diff --git a/rustfmt.toml b/rustfmt.toml index 18b2a33469d..4248f42f654 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -4,5 +4,6 @@ match_block_trailing_comma = true wrap_comments = true edition = "2021" error_on_line_overflow = true +imports_granularity = "Module" version = "Two" ignore = ["tests/ui/crashes/ice-10912.rs"] diff --git a/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs b/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs index ebadd4e440a..60fbaaea3d3 100644 --- a/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs +++ b/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs @@ -7,13 +7,10 @@ extern crate proc_macro; use core::mem; -use proc_macro::{ - token_stream::IntoIter, - Delimiter::{self, Brace, Parenthesis}, - Group, Ident, Literal, Punct, - Spacing::{self, Alone, Joint}, - Span, TokenStream, TokenTree as TT, -}; +use proc_macro::token_stream::IntoIter; +use proc_macro::Delimiter::{self, Brace, Parenthesis}; +use proc_macro::Spacing::{self, Alone, Joint}; +use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; type Result = core::result::Result; diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index dde1c6d7c37..e300ba18c33 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -9,9 +9,7 @@ #![warn(clippy::unwrap_used)] #![warn(clippy::get_unwrap)] -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::VecDeque; +use std::collections::{BTreeMap, HashMap, VecDeque}; struct GetFalsePositive { arr: [u32; 3], diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index aed29a51c1d..4c9bdfa9dba 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -1,5 +1,5 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:40:17 + --> $DIR/unwrap_used.rs:38:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` @@ -7,7 +7,7 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: `-D clippy::get-unwrap` implied by `-D warnings` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:40:17 + --> $DIR/unwrap_used.rs:38:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,13 +16,13 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:41:17 + --> $DIR/unwrap_used.rs:39:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:41:17 + --> $DIR/unwrap_used.rs:39:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,13 +30,13 @@ LL | let _ = some_slice.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:42:17 + --> $DIR/unwrap_used.rs:40:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:42:17 + --> $DIR/unwrap_used.rs:40:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,13 +44,13 @@ LL | let _ = some_vec.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:43:17 + --> $DIR/unwrap_used.rs:41:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:43:17 + --> $DIR/unwrap_used.rs:41:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,13 +58,13 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:44:17 + --> $DIR/unwrap_used.rs:42:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:44:17 + --> $DIR/unwrap_used.rs:42:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,13 +72,13 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:45:17 + --> $DIR/unwrap_used.rs:43:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:45:17 + --> $DIR/unwrap_used.rs:43:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -86,13 +86,13 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:49:21 + --> $DIR/unwrap_used.rs:47:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:49:22 + --> $DIR/unwrap_used.rs:47:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,13 +100,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:54:9 + --> $DIR/unwrap_used.rs:52:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:54:10 + --> $DIR/unwrap_used.rs:52:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,13 +114,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:55:9 + --> $DIR/unwrap_used.rs:53:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:55:10 + --> $DIR/unwrap_used.rs:53:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,13 +128,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:56:9 + --> $DIR/unwrap_used.rs:54:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:56:10 + --> $DIR/unwrap_used.rs:54:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,13 +142,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:57:9 + --> $DIR/unwrap_used.rs:55:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:57:10 + --> $DIR/unwrap_used.rs:55:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -156,13 +156,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:69:17 + --> $DIR/unwrap_used.rs:67:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:69:17 + --> $DIR/unwrap_used.rs:67:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,13 +170,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:70:17 + --> $DIR/unwrap_used.rs:68:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:70:17 + --> $DIR/unwrap_used.rs:68:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,13 +184,13 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:77:13 + --> $DIR/unwrap_used.rs:75:13 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:95:17 + --> $DIR/unwrap_used.rs:93:17 | LL | let _ = Box::new([0]).get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&Box::new([0])[1]` diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index 427842a51d9..69f1c541c4e 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -4,8 +4,7 @@ #![allow(clippy::borrow_as_ptr, unused)] extern crate proc_macros; -use proc_macros::external; -use proc_macros::with_span; +use proc_macros::{external, with_span}; fn main() { let i = 0u32 as u64; diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index ca41d1378aa..54037a64997 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:11:13 + --> $DIR/as_conversions.rs:10:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = note: `-D clippy::as-conversions` implied by `-D warnings` error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:13:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:13:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/macro_use_helper.rs b/tests/ui/auxiliary/macro_use_helper.rs index cab216b51ac..f20df6f0f09 100644 --- a/tests/ui/auxiliary/macro_use_helper.rs +++ b/tests/ui/auxiliary/macro_use_helper.rs @@ -15,8 +15,7 @@ pub mod inner { // RE-EXPORT // this will stick in `inner` module - pub use macro_rules::mut_mut; - pub use macro_rules::try_err; + pub use macro_rules::{mut_mut, try_err}; pub mod nested { pub use macro_rules::string_add; diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index fdfe5fc4181..c5879557516 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -8,11 +8,11 @@ extern crate syn; use proc_macro::TokenStream; use quote::{quote, quote_spanned}; -use syn::parse_macro_input; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type, + parse_macro_input, parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, + TraitItem, Type, }; #[proc_macro_attribute] diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 4d008c8cb59..43df654389b 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -5,13 +5,10 @@ extern crate proc_macro; use core::mem; -use proc_macro::{ - token_stream::IntoIter, - Delimiter::{self, Brace, Parenthesis}, - Group, Ident, Literal, Punct, - Spacing::{self, Alone, Joint}, - Span, TokenStream, TokenTree as TT, -}; +use proc_macro::token_stream::IntoIter; +use proc_macro::Delimiter::{self, Brace, Parenthesis}; +use proc_macro::Spacing::{self, Alone, Joint}; +use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; type Result = core::result::Result; diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 14eb6d572cf..6e541473cb3 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -7,9 +7,8 @@ extern crate proc_macros; use proc_macros::with_span; -use std::default; use std::default::Default as D2; -use std::string; +use std::{default, string}; fn main() { let s1: String = String::default(); diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index aa2ced0a7f0..2ffeb32fbdc 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -7,9 +7,8 @@ extern crate proc_macros; use proc_macros::with_span; -use std::default; use std::default::Default as D2; -use std::string; +use std::{default, string}; fn main() { let s1: String = Default::default(); diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index e4f73c08d19..103fccf6a1d 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,5 +1,5 @@ error: calling `String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:15:22 + --> $DIR/default_trait_access.rs:14:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `String::default()` @@ -11,43 +11,43 @@ LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:19:22 + --> $DIR/default_trait_access.rs:18:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `String::default()` error: calling `String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:21:22 + --> $DIR/default_trait_access.rs:20:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:25:22 + --> $DIR/default_trait_access.rs:24:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:35:46 + --> $DIR/default_trait_access.rs:34:46 | LL | let s11: GenericDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:41:36 + --> $DIR/default_trait_access.rs:40:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:43:36 + --> $DIR/default_trait_access.rs:42:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:47:42 + --> $DIR/default_trait_access.rs:46:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index a29c0918a6d..bc2f86566bc 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -1,9 +1,7 @@ //@run-rustfix #![warn(clippy::get_first)] #![allow(clippy::useless_vec)] -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::VecDeque; +use std::collections::{BTreeMap, HashMap, VecDeque}; struct Bar { arr: [u32; 3], diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index 2062f3ec23a..bc0e233fdee 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -1,9 +1,7 @@ //@run-rustfix #![warn(clippy::get_first)] #![allow(clippy::useless_vec)] -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::VecDeque; +use std::collections::{BTreeMap, HashMap, VecDeque}; struct Bar { arr: [u32; 3], diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr index 4e267ba9a3b..0899a5905f3 100644 --- a/tests/ui/get_first.stderr +++ b/tests/ui/get_first.stderr @@ -1,5 +1,5 @@ error: accessing first element with `x.get(0)` - --> $DIR/get_first.rs:20:13 + --> $DIR/get_first.rs:18:13 | LL | let _ = x.get(0); // Use x.first() | ^^^^^^^^ help: try: `x.first()` @@ -7,13 +7,13 @@ LL | let _ = x.get(0); // Use x.first() = note: `-D clippy::get-first` implied by `-D warnings` error: accessing first element with `y.get(0)` - --> $DIR/get_first.rs:25:13 + --> $DIR/get_first.rs:23:13 | LL | let _ = y.get(0); // Use y.first() | ^^^^^^^^ help: try: `y.first()` error: accessing first element with `z.get(0)` - --> $DIR/get_first.rs:30:13 + --> $DIR/get_first.rs:28:13 | LL | let _ = z.get(0); // Use z.first() | ^^^^^^^^ help: try: `z.first()` diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 56ee37f02d2..fda334407a9 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -9,9 +9,7 @@ #![warn(clippy::unwrap_used)] #![deny(clippy::get_unwrap)] -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::VecDeque; +use std::collections::{BTreeMap, HashMap, VecDeque}; struct GetFalsePositive { arr: [u32; 3], diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index af3a619adc5..eaf6b005a36 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -9,9 +9,7 @@ #![warn(clippy::unwrap_used)] #![deny(clippy::get_unwrap)] -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::VecDeque; +use std::collections::{BTreeMap, HashMap, VecDeque}; struct GetFalsePositive { arr: [u32; 3], diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index e705bebac57..c567ed319b5 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -1,5 +1,5 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:40:17 + --> $DIR/get_unwrap.rs:38:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` @@ -11,7 +11,7 @@ LL | #![deny(clippy::get_unwrap)] | ^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:40:17 + --> $DIR/get_unwrap.rs:38:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,13 +20,13 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:41:17 + --> $DIR/get_unwrap.rs:39:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:41:17 + --> $DIR/get_unwrap.rs:39:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,13 +34,13 @@ LL | let _ = some_slice.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:42:17 + --> $DIR/get_unwrap.rs:40:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:42:17 + --> $DIR/get_unwrap.rs:40:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,13 +48,13 @@ LL | let _ = some_vec.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:43:17 + --> $DIR/get_unwrap.rs:41:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:43:17 + --> $DIR/get_unwrap.rs:41:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,13 +62,13 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:44:17 + --> $DIR/get_unwrap.rs:42:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:44:17 + --> $DIR/get_unwrap.rs:42:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,13 +76,13 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:45:17 + --> $DIR/get_unwrap.rs:43:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:45:17 + --> $DIR/get_unwrap.rs:43:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,13 +90,13 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:49:21 + --> $DIR/get_unwrap.rs:47:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:49:22 + --> $DIR/get_unwrap.rs:47:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,13 +104,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:54:9 + --> $DIR/get_unwrap.rs:52:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:54:10 + --> $DIR/get_unwrap.rs:52:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,13 +118,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:55:9 + --> $DIR/get_unwrap.rs:53:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:55:10 + --> $DIR/get_unwrap.rs:53:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,13 +132,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:56:9 + --> $DIR/get_unwrap.rs:54:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:56:10 + --> $DIR/get_unwrap.rs:54:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,13 +146,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:57:9 + --> $DIR/get_unwrap.rs:55:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:57:10 + --> $DIR/get_unwrap.rs:55:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,13 +160,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:69:17 + --> $DIR/get_unwrap.rs:67:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:69:17 + --> $DIR/get_unwrap.rs:67:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,13 +174,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:70:17 + --> $DIR/get_unwrap.rs:68:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:70:17 + --> $DIR/get_unwrap.rs:68:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,25 +188,25 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:80:24 + --> $DIR/get_unwrap.rs:78:24 | LL | let _x: &i32 = f.get(1 + 2).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:83:18 + --> $DIR/get_unwrap.rs:81:18 | LL | let _x = f.get(1 + 2).unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:86:18 + --> $DIR/get_unwrap.rs:84:18 | LL | let _x = f.get(1 + 2).unwrap().abs(); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]` error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:103:33 + --> $DIR/get_unwrap.rs:101:33 | LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]` diff --git a/tests/ui/issue-7447.rs b/tests/ui/issue-7447.rs index fdb77f32257..de4362c4df7 100644 --- a/tests/ui/issue-7447.rs +++ b/tests/ui/issue-7447.rs @@ -1,4 +1,7 @@ -use std::{borrow::Cow, collections::BTreeMap, marker::PhantomData, sync::Arc}; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::marker::PhantomData; +use std::sync::Arc; fn byte_view<'a>(s: &'a ByteView<'_>) -> BTreeMap<&'a str, ByteView<'a>> { panic!() diff --git a/tests/ui/issue-7447.stderr b/tests/ui/issue-7447.stderr index 8d8c29f1385..7a113740c6a 100644 --- a/tests/ui/issue-7447.stderr +++ b/tests/ui/issue-7447.stderr @@ -1,5 +1,5 @@ error: sub-expression diverges - --> $DIR/issue-7447.rs:23:15 + --> $DIR/issue-7447.rs:26:15 | LL | byte_view(panic!()); | ^^^^^^^^ @@ -8,7 +8,7 @@ LL | byte_view(panic!()); = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: sub-expression diverges - --> $DIR/issue-7447.rs:24:19 + --> $DIR/issue-7447.rs:27:19 | LL | group_entries(panic!()); | ^^^^^^^^ diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 2baea06f84b..636f572a343 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -3,8 +3,7 @@ #![allow(unused)] #![allow(clippy::useless_vec)] -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{HashSet, VecDeque}; fn main() { let v = [1, 2, 3, 4, 5]; diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index 9eac94eb8d9..518cb75affe 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -3,8 +3,7 @@ #![allow(unused)] #![allow(clippy::useless_vec)] -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{HashSet, VecDeque}; fn main() { let v = [1, 2, 3, 4, 5]; diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index b38cf547dc5..b2cc497bf43 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -1,5 +1,5 @@ error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:11:27 + --> $DIR/iter_cloned_collect.rs:10:27 | LL | let v2: Vec = v.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` @@ -7,13 +7,13 @@ LL | let v2: Vec = v.iter().cloned().collect(); = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:16:38 + --> $DIR/iter_cloned_collect.rs:15:38 | LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:21:24 + --> $DIR/iter_cloned_collect.rs:20:24 | LL | .to_bytes() | ________________________^ @@ -23,13 +23,13 @@ LL | | .collect(); | |______________________^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:29:24 + --> $DIR/iter_cloned_collect.rs:28:24 | LL | let _: Vec<_> = arr.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:32:26 + --> $DIR/iter_cloned_collect.rs:31:26 | LL | let _: Vec = v.iter().copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` diff --git a/tests/ui/let_underscore_lock.rs b/tests/ui/let_underscore_lock.rs index 4dff4d766bc..87f12e2789f 100644 --- a/tests/ui/let_underscore_lock.rs +++ b/tests/ui/let_underscore_lock.rs @@ -3,7 +3,8 @@ extern crate parking_lot; fn main() { - use parking_lot::{lock_api::RawMutex, Mutex, RwLock}; + use parking_lot::lock_api::RawMutex; + use parking_lot::{Mutex, RwLock}; let p_m: Mutex<()> = Mutex::const_new(RawMutex::INIT, ()); let _ = p_m.lock(); diff --git a/tests/ui/let_underscore_lock.stderr b/tests/ui/let_underscore_lock.stderr index f137d411209..5027e6b3cbc 100644 --- a/tests/ui/let_underscore_lock.stderr +++ b/tests/ui/let_underscore_lock.stderr @@ -1,5 +1,5 @@ error: non-binding `let` on a synchronization lock - --> $DIR/let_underscore_lock.rs:9:5 + --> $DIR/let_underscore_lock.rs:10:5 | LL | let _ = p_m.lock(); | ^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = p_m.lock(); = note: `-D clippy::let-underscore-lock` implied by `-D warnings` error: non-binding `let` on a synchronization lock - --> $DIR/let_underscore_lock.rs:12:5 + --> $DIR/let_underscore_lock.rs:13:5 | LL | let _ = p_m1.lock(); | ^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = p_m1.lock(); = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` error: non-binding `let` on a synchronization lock - --> $DIR/let_underscore_lock.rs:15:5 + --> $DIR/let_underscore_lock.rs:16:5 | LL | let _ = p_rw.read(); | ^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = p_rw.read(); = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` error: non-binding `let` on a synchronization lock - --> $DIR/let_underscore_lock.rs:16:5 + --> $DIR/let_underscore_lock.rs:17:5 | LL | let _ = p_rw.write(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs index 431d83778e3..18630c27f41 100644 --- a/tests/ui/let_underscore_untyped.rs +++ b/tests/ui/let_underscore_untyped.rs @@ -7,8 +7,9 @@ extern crate proc_macros; use proc_macros::with_span; use clippy_utils::is_from_proc_macro; +use std::boxed::Box; +use std::fmt::Display; use std::future::Future; -use std::{boxed::Box, fmt::Display}; fn a() -> u32 { 1 diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr index bbf2508af10..e0c39b6eeaf 100644 --- a/tests/ui/let_underscore_untyped.stderr +++ b/tests/ui/let_underscore_untyped.stderr @@ -1,60 +1,60 @@ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:50:5 + --> $DIR/let_underscore_untyped.rs:51:5 | LL | let _ = a(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:50:10 + --> $DIR/let_underscore_untyped.rs:51:10 | LL | let _ = a(); | ^ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:51:5 + --> $DIR/let_underscore_untyped.rs:52:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:51:10 + --> $DIR/let_underscore_untyped.rs:52:10 | LL | let _ = b(1); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:53:5 + --> $DIR/let_underscore_untyped.rs:54:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:53:10 + --> $DIR/let_underscore_untyped.rs:54:10 | LL | let _ = d(&1); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:54:5 + --> $DIR/let_underscore_untyped.rs:55:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:54:10 + --> $DIR/let_underscore_untyped.rs:55:10 | LL | let _ = e(); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:55:5 + --> $DIR/let_underscore_untyped.rs:56:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:55:10 + --> $DIR/let_underscore_untyped.rs:56:10 | LL | let _ = f(); | ^ diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index 09fb0d75852..c95d40fecba 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,12 +1,7 @@ //@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::BinaryHeap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; fn main() { binary_heap_retain(); diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index 7fee4c95cea..9a3434f489d 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,12 +1,7 @@ //@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] -use std::collections::BTreeMap; -use std::collections::BTreeSet; -use std::collections::BinaryHeap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; fn main() { binary_heap_retain(); diff --git a/tests/ui/manual_retain.stderr b/tests/ui/manual_retain.stderr index 89316ce1d99..0936a23841c 100644 --- a/tests/ui/manual_retain.stderr +++ b/tests/ui/manual_retain.stderr @@ -1,5 +1,5 @@ error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:51:5 + --> $DIR/manual_retain.rs:46:5 | LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)` @@ -7,13 +7,13 @@ LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect() = note: `-D clippy::manual-retain` implied by `-D warnings` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:52:5 + --> $DIR/manual_retain.rs:47:5 | LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:53:5 + --> $DIR/manual_retain.rs:48:5 | LL | / btree_map = btree_map LL | | .into_iter() @@ -22,37 +22,37 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:75:5 + --> $DIR/manual_retain.rs:70:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:76:5 + --> $DIR/manual_retain.rs:71:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:77:5 + --> $DIR/manual_retain.rs:72:5 | LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:107:5 + --> $DIR/manual_retain.rs:102:5 | LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:108:5 + --> $DIR/manual_retain.rs:103:5 | LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:109:5 + --> $DIR/manual_retain.rs:104:5 | LL | / hash_map = hash_map LL | | .into_iter() @@ -61,61 +61,61 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:130:5 + --> $DIR/manual_retain.rs:125:5 | LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:131:5 + --> $DIR/manual_retain.rs:126:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:132:5 + --> $DIR/manual_retain.rs:127:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:161:5 + --> $DIR/manual_retain.rs:156:5 | LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:173:5 + --> $DIR/manual_retain.rs:168:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:174:5 + --> $DIR/manual_retain.rs:169:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:175:5 + --> $DIR/manual_retain.rs:170:5 | LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:197:5 + --> $DIR/manual_retain.rs:192:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:198:5 + --> $DIR/manual_retain.rs:193:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> $DIR/manual_retain.rs:199:5 + --> $DIR/manual_retain.rs:194:5 | LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` diff --git a/tests/ui/manual_try_fold.rs b/tests/ui/manual_try_fold.rs index 4521e9fa1a5..05c658579a5 100644 --- a/tests/ui/manual_try_fold.rs +++ b/tests/ui/manual_try_fold.rs @@ -3,9 +3,7 @@ #![warn(clippy::manual_try_fold)] #![feature(try_trait_v2)] -use std::ops::ControlFlow; -use std::ops::FromResidual; -use std::ops::Try; +use std::ops::{ControlFlow, FromResidual, Try}; #[macro_use] extern crate proc_macros; diff --git a/tests/ui/manual_try_fold.stderr b/tests/ui/manual_try_fold.stderr index a0cf5b3b5fc..f1bb97c6d0f 100644 --- a/tests/ui/manual_try_fold.stderr +++ b/tests/ui/manual_try_fold.stderr @@ -1,5 +1,5 @@ error: usage of `Iterator::fold` on a type that implements `Try` - --> $DIR/manual_try_fold.rs:61:10 + --> $DIR/manual_try_fold.rs:59:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` @@ -7,19 +7,19 @@ LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) = note: `-D clippy::manual-try-fold` implied by `-D warnings` error: usage of `Iterator::fold` on a type that implements `Try` - --> $DIR/manual_try_fold.rs:65:10 + --> $DIR/manual_try_fold.rs:63:10 | LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i| ...)` error: usage of `Iterator::fold` on a type that implements `Try` - --> $DIR/manual_try_fold.rs:68:10 + --> $DIR/manual_try_fold.rs:66:10 | LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` error: usage of `Iterator::fold` on a type that implements `Try` - --> $DIR/manual_try_fold.rs:98:10 + --> $DIR/manual_try_fold.rs:96:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index 8fa3f532587..61d414bdf4b 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -12,7 +12,9 @@ fn match_as_ref() { } mod issue4437 { - use std::{error::Error, fmt, num::ParseIntError}; + use std::error::Error; + use std::fmt; + use std::num::ParseIntError; #[derive(Debug)] struct E { diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 02a17791426..cd39514c59a 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -18,7 +18,9 @@ fn match_as_ref() { } mod issue4437 { - use std::{error::Error, fmt, num::ParseIntError}; + use std::error::Error; + use std::fmt; + use std::num::ParseIntError; #[derive(Debug)] struct E { diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index 252abf74bca..2e6955eb805 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -21,7 +21,7 @@ LL | | }; | |_____^ help: try: `mut_owned.as_mut()` error: use `as_ref()` instead - --> $DIR/match_as_ref.rs:30:13 + --> $DIR/match_as_ref.rs:32:13 | LL | / match self.source { LL | | Some(ref s) => Some(s), diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 589eab5cdfc..cb1f695c651 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -25,10 +25,7 @@ #[macro_use] extern crate option_helpers; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::collections::HashSet; -use std::collections::VecDeque; +use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::ops::Mul; use std::rc::{self, Rc}; use std::sync::{self, Arc}; diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 73ec48643e0..6be38b24fbd 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:106:5 + --> $DIR/methods.rs:103:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:127:13 + --> $DIR/methods.rs:124:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/tests/ui/min_ident_chars.rs b/tests/ui/min_ident_chars.rs index b5b9e66aa7a..0fab224a29d 100644 --- a/tests/ui/min_ident_chars.rs +++ b/tests/ui/min_ident_chars.rs @@ -3,8 +3,7 @@ #![warn(clippy::min_ident_chars)] extern crate proc_macros; -use proc_macros::external; -use proc_macros::with_span; +use proc_macros::{external, with_span}; struct A { a: u32, diff --git a/tests/ui/min_ident_chars.stderr b/tests/ui/min_ident_chars.stderr index 66a63f65756..4dff6588bb1 100644 --- a/tests/ui/min_ident_chars.stderr +++ b/tests/ui/min_ident_chars.stderr @@ -1,5 +1,5 @@ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:9:8 + --> $DIR/min_ident_chars.rs:8:8 | LL | struct A { | ^ @@ -7,169 +7,169 @@ LL | struct A { = note: `-D clippy::min-ident-chars` implied by `-D warnings` error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:10:5 + --> $DIR/min_ident_chars.rs:9:5 | LL | a: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:12:5 + --> $DIR/min_ident_chars.rs:11:5 | LL | A: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:13:5 + --> $DIR/min_ident_chars.rs:12:5 | LL | I: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:16:8 + --> $DIR/min_ident_chars.rs:15:8 | LL | struct B(u32); | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:18:8 + --> $DIR/min_ident_chars.rs:17:8 | LL | struct O { | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:19:5 + --> $DIR/min_ident_chars.rs:18:5 | LL | o: u32, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:24:6 + --> $DIR/min_ident_chars.rs:23:6 | LL | enum C { | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:25:5 + --> $DIR/min_ident_chars.rs:24:5 | LL | D, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:26:5 + --> $DIR/min_ident_chars.rs:25:5 | LL | E, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:27:5 + --> $DIR/min_ident_chars.rs:26:5 | LL | F, | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:51:9 + --> $DIR/min_ident_chars.rs:50:9 | LL | let h = 1; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:52:9 + --> $DIR/min_ident_chars.rs:51:9 | LL | let e = 2; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:53:9 + --> $DIR/min_ident_chars.rs:52:9 | LL | let l = 3; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:54:9 + --> $DIR/min_ident_chars.rs:53:9 | LL | let l = 4; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:55:9 + --> $DIR/min_ident_chars.rs:54:9 | LL | let o = 6; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:59:10 + --> $DIR/min_ident_chars.rs:58:10 | LL | let (h, o, w) = (1, 2, 3); | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:59:13 + --> $DIR/min_ident_chars.rs:58:13 | LL | let (h, o, w) = (1, 2, 3); | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:60:10 + --> $DIR/min_ident_chars.rs:59:10 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:60:14 + --> $DIR/min_ident_chars.rs:59:14 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:60:17 + --> $DIR/min_ident_chars.rs:59:17 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:62:16 + --> $DIR/min_ident_chars.rs:61:16 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:62:19 + --> $DIR/min_ident_chars.rs:61:19 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:62:29 + --> $DIR/min_ident_chars.rs:61:29 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:66:9 + --> $DIR/min_ident_chars.rs:65:9 | LL | let o = 1; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:67:9 + --> $DIR/min_ident_chars.rs:66:9 | LL | let o = O { o }; | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:81:4 + --> $DIR/min_ident_chars.rs:80:4 | LL | fn b() {} | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:82:21 + --> $DIR/min_ident_chars.rs:81:21 | LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ error: this ident consists of a single char - --> $DIR/min_ident_chars.rs:82:29 + --> $DIR/min_ident_chars.rs:81:29 | LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index 24e52afd691..1215a02286c 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,9 +1,7 @@ #![warn(clippy::all)] #![allow(clippy::manual_clamp)] -use std::cmp::max as my_max; -use std::cmp::min as my_min; -use std::cmp::{max, min}; +use std::cmp::{max as my_max, max, min as my_min, min}; const LARGE: usize = 3; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index 069d9068657..402b094f4f7 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,5 +1,5 @@ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:24:5 + --> $DIR/min_max.rs:22:5 | LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ @@ -7,73 +7,73 @@ LL | min(1, max(3, x)); = note: `-D clippy::min-max` implied by `-D warnings` error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:25:5 + --> $DIR/min_max.rs:23:5 | LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:26:5 + --> $DIR/min_max.rs:24:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:27:5 + --> $DIR/min_max.rs:25:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:29:5 + --> $DIR/min_max.rs:27:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:39:5 + --> $DIR/min_max.rs:37:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:40:5 + --> $DIR/min_max.rs:38:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:45:5 + --> $DIR/min_max.rs:43:5 | LL | x.min(1).max(3); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:46:5 + --> $DIR/min_max.rs:44:5 | LL | x.max(3).min(1); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:47:5 + --> $DIR/min_max.rs:45:5 | LL | f.max(3f32).min(1f32); | ^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:53:5 + --> $DIR/min_max.rs:51:5 | LL | max(x.min(1), 3); | ^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:56:5 + --> $DIR/min_max.rs:54:5 | LL | s.max("Zoo").min("Apple"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> $DIR/min_max.rs:57:5 + --> $DIR/min_max.rs:55:5 | LL | s.min("Apple").max("Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index cff1706a842..83ebf09c8a3 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -96,10 +96,8 @@ mod internal_impl { } /// dox pub mod public_interface { - pub use crate::internal_impl::documented as foo; pub use crate::internal_impl::globbed::*; - pub use crate::internal_impl::undocumented1 as bar; - pub use crate::internal_impl::{documented, undocumented2}; + pub use crate::internal_impl::{documented as foo, documented, undocumented1 as bar, undocumented2}; } fn main() {} diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index 1c0ba664580..15d68c08984 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -2,7 +2,8 @@ use std::cell::Cell; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::rc::Rc; -use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; struct Key(AtomicUsize); diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index fe1eeb31d07..02a0da86a4b 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -1,5 +1,5 @@ error: mutable key type - --> $DIR/mut_key.rs:30:32 + --> $DIR/mut_key.rs:31:32 | LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> Hash = note: `-D clippy::mutable-key-type` implied by `-D warnings` error: mutable key type - --> $DIR/mut_key.rs:30:72 + --> $DIR/mut_key.rs:31:72 | LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^ error: this argument is a mutable reference, but not used mutably - --> $DIR/mut_key.rs:30:32 + --> $DIR/mut_key.rs:31:32 | LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap` @@ -21,91 +21,91 @@ LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> Hash = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` error: mutable key type - --> $DIR/mut_key.rs:31:5 + --> $DIR/mut_key.rs:32:5 | LL | let _other: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:58:22 + --> $DIR/mut_key.rs:59:22 | LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:70:5 + --> $DIR/mut_key.rs:71:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:71:5 + --> $DIR/mut_key.rs:72:5 | LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:72:5 + --> $DIR/mut_key.rs:73:5 | LL | let _map = HashMap::<&mut usize, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:74:5 + --> $DIR/mut_key.rs:75:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:75:5 + --> $DIR/mut_key.rs:76:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:76:5 + --> $DIR/mut_key.rs:77:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:77:5 + --> $DIR/mut_key.rs:78:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:78:5 + --> $DIR/mut_key.rs:79:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:79:5 + --> $DIR/mut_key.rs:80:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:80:5 + --> $DIR/mut_key.rs:81:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:82:5 + --> $DIR/mut_key.rs:83:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:83:5 + --> $DIR/mut_key.rs:84:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:84:5 + --> $DIR/mut_key.rs:85:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_if.fixed b/tests/ui/needless_if.fixed index 5e6e140c2db..6001c9e9301 100644 --- a/tests/ui/needless_if.fixed +++ b/tests/ui/needless_if.fixed @@ -16,8 +16,7 @@ #![warn(clippy::needless_if)] extern crate proc_macros; -use proc_macros::external; -use proc_macros::with_span; +use proc_macros::{external, with_span}; fn maybe_side_effect() -> bool { true diff --git a/tests/ui/needless_if.rs b/tests/ui/needless_if.rs index eb28ce73be8..c6be4766dd8 100644 --- a/tests/ui/needless_if.rs +++ b/tests/ui/needless_if.rs @@ -16,8 +16,7 @@ #![warn(clippy::needless_if)] extern crate proc_macros; -use proc_macros::external; -use proc_macros::with_span; +use proc_macros::{external, with_span}; fn maybe_side_effect() -> bool { true diff --git a/tests/ui/needless_if.stderr b/tests/ui/needless_if.stderr index 5cb42c36921..14de400953b 100644 --- a/tests/ui/needless_if.stderr +++ b/tests/ui/needless_if.stderr @@ -1,5 +1,5 @@ error: this `if` branch is empty - --> $DIR/needless_if.rs:28:5 + --> $DIR/needless_if.rs:27:5 | LL | if (true) {} | ^^^^^^^^^^^^ help: you can remove it @@ -7,13 +7,13 @@ LL | if (true) {} = note: `-D clippy::needless-if` implied by `-D warnings` error: this `if` branch is empty - --> $DIR/needless_if.rs:30:5 + --> $DIR/needless_if.rs:29:5 | LL | if maybe_side_effect() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();` error: this `if` branch is empty - --> $DIR/needless_if.rs:35:5 + --> $DIR/needless_if.rs:34:5 | LL | / if { LL | | return; @@ -28,7 +28,7 @@ LL + }); | error: this `if` branch is empty - --> $DIR/needless_if.rs:47:5 + --> $DIR/needless_if.rs:46:5 | LL | / if { LL | | if let true = true && true { true } else { false } @@ -44,19 +44,19 @@ LL + } && true); | error: this `if` branch is empty - --> $DIR/needless_if.rs:85:5 + --> $DIR/needless_if.rs:84:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> $DIR/needless_if.rs:87:5 + --> $DIR/needless_if.rs:86:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> $DIR/needless_if.rs:91:5 + --> $DIR/needless_if.rs:90:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 703debb7a26..6deff0f3240 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -9,8 +9,7 @@ clippy::useless_vec )] -use std::collections::BTreeMap; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::time::Duration; /// Checks implementation of the `OR_FUN_CALL` lint. diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index bb86fe0d45f..b05b33e6ee2 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -9,8 +9,7 @@ clippy::useless_vec )] -use std::collections::BTreeMap; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::time::Duration; /// Checks implementation of the `OR_FUN_CALL` lint. diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 3965ae52aed..7342b0c2914 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:54:22 + --> $DIR/or_fun_call.rs:53:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)` @@ -7,163 +7,163 @@ LL | with_constructor.unwrap_or(make()); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:57:14 + --> $DIR/or_fun_call.rs:56:14 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:60:21 + --> $DIR/or_fun_call.rs:59:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:63:14 + --> $DIR/or_fun_call.rs:62:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:66:19 + --> $DIR/or_fun_call.rs:65:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:69:24 + --> $DIR/or_fun_call.rs:68:24 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:72:23 + --> $DIR/or_fun_call.rs:71:23 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:75:18 + --> $DIR/or_fun_call.rs:74:18 | LL | self_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(::default)` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:78:18 + --> $DIR/or_fun_call.rs:77:18 | LL | real_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:81:14 + --> $DIR/or_fun_call.rs:80:14 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:84:21 + --> $DIR/or_fun_call.rs:83:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:87:19 + --> $DIR/or_fun_call.rs:86:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:90:23 + --> $DIR/or_fun_call.rs:89:23 | LL | map_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:93:21 + --> $DIR/or_fun_call.rs:92:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:96:25 + --> $DIR/or_fun_call.rs:95:25 | LL | btree_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:99:21 + --> $DIR/or_fun_call.rs:98:21 | LL | let _ = stringy.unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:107:21 + --> $DIR/or_fun_call.rs:106:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:109:21 + --> $DIR/or_fun_call.rs:108:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:133:35 + --> $DIR/or_fun_call.rs:132:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:172:14 + --> $DIR/or_fun_call.rs:171:14 | LL | None.unwrap_or(ptr_to_ref(s)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:178:14 + --> $DIR/or_fun_call.rs:177:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:180:14 + --> $DIR/or_fun_call.rs:179:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:194:14 + --> $DIR/or_fun_call.rs:193:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:207:14 + --> $DIR/or_fun_call.rs:206:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:219:14 + --> $DIR/or_fun_call.rs:218:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:230:10 + --> $DIR/or_fun_call.rs:229:10 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `map_or` followed by a function call - --> $DIR/or_fun_call.rs:255:25 + --> $DIR/or_fun_call.rs:254:25 | LL | let _ = Some(4).map_or(g(), |v| v); | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` error: use of `map_or` followed by a function call - --> $DIR/or_fun_call.rs:256:25 + --> $DIR/or_fun_call.rs:255:25 | LL | let _ = Some(4).map_or(g(), f); | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs index 574d34aed2d..9eb58a3e53f 100644 --- a/tests/ui/redundant_allocation.rs +++ b/tests/ui/redundant_allocation.rs @@ -8,8 +8,7 @@ pub struct SubT { } mod outer_box { - use crate::MyStruct; - use crate::SubT; + use crate::{MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; @@ -28,8 +27,7 @@ mod outer_box { } mod outer_rc { - use crate::MyStruct; - use crate::SubT; + use crate::{MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; @@ -48,8 +46,7 @@ mod outer_rc { } mod outer_arc { - use crate::MyStruct; - use crate::SubT; + use crate::{MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr index e0826fefa6c..a9a1eed702b 100644 --- a/tests/ui/redundant_allocation.stderr +++ b/tests/ui/redundant_allocation.stderr @@ -1,5 +1,5 @@ error: usage of `Box>` - --> $DIR/redundant_allocation.rs:17:30 + --> $DIR/redundant_allocation.rs:16:30 | LL | pub fn box_test6(foo: Box>) {} | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | pub fn box_test6(foo: Box>) {} = note: `-D clippy::redundant-allocation` implied by `-D warnings` error: usage of `Box>` - --> $DIR/redundant_allocation.rs:19:30 + --> $DIR/redundant_allocation.rs:18:30 | LL | pub fn box_test7(foo: Box>) {} | ^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | pub fn box_test7(foo: Box>) {} = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> $DIR/redundant_allocation.rs:21:27 + --> $DIR/redundant_allocation.rs:20:27 | LL | pub fn box_test8() -> Box>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | pub fn box_test8() -> Box>> { = help: consider using just `Box>` or `Rc>` error: usage of `Box>` - --> $DIR/redundant_allocation.rs:25:30 + --> $DIR/redundant_allocation.rs:24:30 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> $DIR/redundant_allocation.rs:25:46 + --> $DIR/redundant_allocation.rs:24:46 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box>` or `Arc>` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:37:24 + --> $DIR/redundant_allocation.rs:35:24 | LL | pub fn rc_test5(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub fn rc_test5(a: Rc>) {} = help: consider using just `Rc` or `Box` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:39:24 + --> $DIR/redundant_allocation.rs:37:24 | LL | pub fn rc_test7(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | pub fn rc_test7(a: Rc>) {} = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:41:26 + --> $DIR/redundant_allocation.rs:39:26 | LL | pub fn rc_test8() -> Rc>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | pub fn rc_test8() -> Rc>> { = help: consider using just `Rc>` or `Box>` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:45:29 + --> $DIR/redundant_allocation.rs:43:29 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:45:44 + --> $DIR/redundant_allocation.rs:43:44 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc>` or `Arc>` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:57:25 + --> $DIR/redundant_allocation.rs:54:25 | LL | pub fn arc_test5(a: Arc>) {} | ^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | pub fn arc_test5(a: Arc>) {} = help: consider using just `Arc` or `Box` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:59:25 + --> $DIR/redundant_allocation.rs:56:25 | LL | pub fn arc_test6(a: Arc>) {} | ^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | pub fn arc_test6(a: Arc>) {} = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> $DIR/redundant_allocation.rs:61:27 + --> $DIR/redundant_allocation.rs:58:27 | LL | pub fn arc_test8() -> Arc>> { | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | pub fn arc_test8() -> Arc>> { = help: consider using just `Arc>` or `Box>` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:65:30 + --> $DIR/redundant_allocation.rs:62:30 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> $DIR/redundant_allocation.rs:65:45 + --> $DIR/redundant_allocation.rs:62:45 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc>` or `Rc>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:87:27 + --> $DIR/redundant_allocation.rs:84:27 | LL | pub fn test_rc_box(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | pub fn test_rc_box(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:119:31 + --> $DIR/redundant_allocation.rs:116:31 | LL | pub fn test_rc_box_str(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | pub fn test_rc_box_str(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:120:33 + --> $DIR/redundant_allocation.rs:117:33 | LL | pub fn test_rc_box_slice(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | pub fn test_rc_box_slice(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:121:32 + --> $DIR/redundant_allocation.rs:118:32 | LL | pub fn test_rc_box_path(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | pub fn test_rc_box_path(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:122:34 + --> $DIR/redundant_allocation.rs:119:34 | LL | pub fn test_rc_box_custom(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index edb7715f42c..b97863daf22 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -16,9 +16,7 @@ pub enum MyEnum { } mod outer_box { - use crate::MyEnum; - use crate::MyStruct; - use crate::SubT; + use crate::{MyEnum, MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; @@ -35,9 +33,7 @@ mod outer_box { } mod outer_rc { - use crate::MyEnum; - use crate::MyStruct; - use crate::SubT; + use crate::{MyEnum, MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; @@ -54,9 +50,7 @@ mod outer_rc { } mod outer_arc { - use crate::MyEnum; - use crate::MyStruct; - use crate::SubT; + use crate::{MyEnum, MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index c59422dd966..bffb6f8c000 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -16,9 +16,7 @@ pub enum MyEnum { } mod outer_box { - use crate::MyEnum; - use crate::MyStruct; - use crate::SubT; + use crate::{MyEnum, MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; @@ -35,9 +33,7 @@ mod outer_box { } mod outer_rc { - use crate::MyEnum; - use crate::MyStruct; - use crate::SubT; + use crate::{MyEnum, MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; @@ -54,9 +50,7 @@ mod outer_rc { } mod outer_arc { - use crate::MyEnum; - use crate::MyStruct; - use crate::SubT; + use crate::{MyEnum, MyStruct, SubT}; use std::boxed::Box; use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/redundant_allocation_fixable.stderr b/tests/ui/redundant_allocation_fixable.stderr index 8dd4a6a2687..524ca5bf467 100644 --- a/tests/ui/redundant_allocation_fixable.stderr +++ b/tests/ui/redundant_allocation_fixable.stderr @@ -1,5 +1,5 @@ error: usage of `Box<&T>` - --> $DIR/redundant_allocation_fixable.rs:26:30 + --> $DIR/redundant_allocation_fixable.rs:24:30 | LL | pub fn box_test1(foo: Box<&T>) {} | ^^^^^^^ help: try: `&T` @@ -8,7 +8,7 @@ LL | pub fn box_test1(foo: Box<&T>) {} = note: `-D clippy::redundant-allocation` implied by `-D warnings` error: usage of `Box<&MyStruct>` - --> $DIR/redundant_allocation_fixable.rs:28:27 + --> $DIR/redundant_allocation_fixable.rs:26:27 | LL | pub fn box_test2(foo: Box<&MyStruct>) {} | ^^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -16,7 +16,7 @@ LL | pub fn box_test2(foo: Box<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Box<&MyStruct>` allocates a pointer on the heap error: usage of `Box<&MyEnum>` - --> $DIR/redundant_allocation_fixable.rs:30:27 + --> $DIR/redundant_allocation_fixable.rs:28:27 | LL | pub fn box_test3(foo: Box<&MyEnum>) {} | ^^^^^^^^^^^^ help: try: `&MyEnum` @@ -24,7 +24,7 @@ LL | pub fn box_test3(foo: Box<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Box<&MyEnum>` allocates a pointer on the heap error: usage of `Box>` - --> $DIR/redundant_allocation_fixable.rs:34:30 + --> $DIR/redundant_allocation_fixable.rs:32:30 | LL | pub fn box_test5(foo: Box>) {} | ^^^^^^^^^^^ help: try: `Box` @@ -32,7 +32,7 @@ LL | pub fn box_test5(foo: Box>) {} = note: `Box` is already on the heap, `Box>` makes an extra allocation error: usage of `Rc<&T>` - --> $DIR/redundant_allocation_fixable.rs:45:29 + --> $DIR/redundant_allocation_fixable.rs:41:29 | LL | pub fn rc_test1(foo: Rc<&T>) {} | ^^^^^^ help: try: `&T` @@ -40,7 +40,7 @@ LL | pub fn rc_test1(foo: Rc<&T>) {} = note: `&T` is already a pointer, `Rc<&T>` allocates a pointer on the heap error: usage of `Rc<&MyStruct>` - --> $DIR/redundant_allocation_fixable.rs:47:26 + --> $DIR/redundant_allocation_fixable.rs:43:26 | LL | pub fn rc_test2(foo: Rc<&MyStruct>) {} | ^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -48,7 +48,7 @@ LL | pub fn rc_test2(foo: Rc<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Rc<&MyStruct>` allocates a pointer on the heap error: usage of `Rc<&MyEnum>` - --> $DIR/redundant_allocation_fixable.rs:49:26 + --> $DIR/redundant_allocation_fixable.rs:45:26 | LL | pub fn rc_test3(foo: Rc<&MyEnum>) {} | ^^^^^^^^^^^ help: try: `&MyEnum` @@ -56,7 +56,7 @@ LL | pub fn rc_test3(foo: Rc<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Rc<&MyEnum>` allocates a pointer on the heap error: usage of `Rc>` - --> $DIR/redundant_allocation_fixable.rs:53:24 + --> $DIR/redundant_allocation_fixable.rs:49:24 | LL | pub fn rc_test6(a: Rc>) {} | ^^^^^^^^^^^^ help: try: `Rc` @@ -64,7 +64,7 @@ LL | pub fn rc_test6(a: Rc>) {} = note: `Rc` is already on the heap, `Rc>` makes an extra allocation error: usage of `Arc<&T>` - --> $DIR/redundant_allocation_fixable.rs:64:30 + --> $DIR/redundant_allocation_fixable.rs:58:30 | LL | pub fn arc_test1(foo: Arc<&T>) {} | ^^^^^^^ help: try: `&T` @@ -72,7 +72,7 @@ LL | pub fn arc_test1(foo: Arc<&T>) {} = note: `&T` is already a pointer, `Arc<&T>` allocates a pointer on the heap error: usage of `Arc<&MyStruct>` - --> $DIR/redundant_allocation_fixable.rs:66:27 + --> $DIR/redundant_allocation_fixable.rs:60:27 | LL | pub fn arc_test2(foo: Arc<&MyStruct>) {} | ^^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -80,7 +80,7 @@ LL | pub fn arc_test2(foo: Arc<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Arc<&MyStruct>` allocates a pointer on the heap error: usage of `Arc<&MyEnum>` - --> $DIR/redundant_allocation_fixable.rs:68:27 + --> $DIR/redundant_allocation_fixable.rs:62:27 | LL | pub fn arc_test3(foo: Arc<&MyEnum>) {} | ^^^^^^^^^^^^ help: try: `&MyEnum` @@ -88,7 +88,7 @@ LL | pub fn arc_test3(foo: Arc<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Arc<&MyEnum>` allocates a pointer on the heap error: usage of `Arc>` - --> $DIR/redundant_allocation_fixable.rs:72:25 + --> $DIR/redundant_allocation_fixable.rs:66:25 | LL | pub fn arc_test7(a: Arc>) {} | ^^^^^^^^^^^^^^ help: try: `Arc` diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed index 75ed143446c..02f197aa26a 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -8,10 +8,8 @@ clippy::uninlined_format_args )] -use std::net::{ - IpAddr::{self, V4, V6}, - Ipv4Addr, Ipv6Addr, -}; +use std::net::IpAddr::{self, V4, V6}; +use std::net::{Ipv4Addr, Ipv6Addr}; fn main() { let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs index 9ac77409f79..5c1e1810f55 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -8,10 +8,8 @@ clippy::uninlined_format_args )] -use std::net::{ - IpAddr::{self, V4, V6}, - Ipv4Addr, Ipv6Addr, -}; +use std::net::IpAddr::{self, V4, V6}; +use std::net::{Ipv4Addr, Ipv6Addr}; fn main() { let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index f34dc709833..bec8d30884d 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:16:12 | LL | if let V4(_) = &ipaddr {} | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()` @@ -7,31 +7,31 @@ LL | if let V4(_) = &ipaddr {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:22:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:22:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:26:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:36:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:34:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:41:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:39:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:46:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:44:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:51:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:49:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => true, @@ -67,49 +67,49 @@ LL | | }; | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:56:20 + --> $DIR/redundant_pattern_matching_ipaddr.rs:54:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:64:20 + --> $DIR/redundant_pattern_matching_ipaddr.rs:62:20 | LL | let _ = if let V4(_) = gen_ipaddr() { | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:66:19 + --> $DIR/redundant_pattern_matching_ipaddr.rs:64:19 | LL | } else if let V6(_) = gen_ipaddr() { | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:76:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:80:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:80:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:84:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:86:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:84:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, @@ -118,7 +118,7 @@ LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:91:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:89:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 8c48b21f188..17df9f88fff 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -7,8 +7,7 @@ use std::num::ParseIntError; use std::ops::Deref; use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::RwLock; -use std::sync::{Mutex, MutexGuard}; +use std::sync::{Mutex, MutexGuard, RwLock}; struct State {} diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index 75063a8c987..b56ace200a8 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:56:11 + --> $DIR/significant_drop_in_scrutinee.rs:55:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:142:11 + --> $DIR/significant_drop_in_scrutinee.rs:141:11 | LL | match s.lock_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:163:11 + --> $DIR/significant_drop_in_scrutinee.rs:162:11 | LL | match s.lock_m_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:211:11 + --> $DIR/significant_drop_in_scrutinee.rs:210:11 | LL | match counter.temp_increment().len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:234:16 + --> $DIR/significant_drop_in_scrutinee.rs:233:16 | LL | match (mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL ~ match (value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:243:22 + --> $DIR/significant_drop_in_scrutinee.rs:242:22 | LL | match (true, mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL ~ match (true, value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:253:16 + --> $DIR/significant_drop_in_scrutinee.rs:252:16 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:253:54 + --> $DIR/significant_drop_in_scrutinee.rs:252:54 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:264:15 + --> $DIR/significant_drop_in_scrutinee.rs:263:15 | LL | match mutex3.lock().unwrap().s.as_str() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:274:22 + --> $DIR/significant_drop_in_scrutinee.rs:273:22 | LL | match (true, mutex3.lock().unwrap().s.as_str()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:293:11 + --> $DIR/significant_drop_in_scrutinee.rs:292:11 | LL | match mutex.lock().unwrap().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:300:11 + --> $DIR/significant_drop_in_scrutinee.rs:299:11 | LL | match 1 < mutex.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:318:11 + --> $DIR/significant_drop_in_scrutinee.rs:317:11 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:329:11 + --> $DIR/significant_drop_in_scrutinee.rs:328:11 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:364:11 + --> $DIR/significant_drop_in_scrutinee.rs:363:11 | LL | match get_mutex_guard().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -284,7 +284,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:381:11 + --> $DIR/significant_drop_in_scrutinee.rs:380:11 | LL | match match i { | ___________^ @@ -316,7 +316,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:407:11 + --> $DIR/significant_drop_in_scrutinee.rs:406:11 | LL | match if i > 1 { | ___________^ @@ -349,7 +349,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:461:11 + --> $DIR/significant_drop_in_scrutinee.rs:460:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:489:11 + --> $DIR/significant_drop_in_scrutinee.rs:488:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -380,7 +380,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:508:11 + --> $DIR/significant_drop_in_scrutinee.rs:507:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -399,7 +399,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:514:11 + --> $DIR/significant_drop_in_scrutinee.rs:513:11 | LL | match i = mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -418,7 +418,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:520:11 + --> $DIR/significant_drop_in_scrutinee.rs:519:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -437,7 +437,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:526:11 + --> $DIR/significant_drop_in_scrutinee.rs:525:11 | LL | match i += mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,7 +456,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:589:11 + --> $DIR/significant_drop_in_scrutinee.rs:588:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +467,7 @@ LL | }; = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> $DIR/significant_drop_in_scrutinee.rs:599:14 + --> $DIR/significant_drop_in_scrutinee.rs:598:14 | LL | for s in rwlock.read().unwrap().iter() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ LL | } = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> $DIR/significant_drop_in_scrutinee.rs:614:11 + --> $DIR/significant_drop_in_scrutinee.rs:613:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index d4d2cbbe57a..b6b6b0288c5 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -4,8 +4,12 @@ use core; + + use serde as edres; + pub use serde; + use std; macro_rules! m { diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 80d72115f43..a8c4d899085 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -3,9 +3,13 @@ #![allow(unused_imports)] use core; + use regex; + use serde as edres; + pub use serde; + use std; macro_rules! m { diff --git a/tests/ui/single_component_path_imports.stderr b/tests/ui/single_component_path_imports.stderr index d69a86470a5..853a2fe0e7b 100644 --- a/tests/ui/single_component_path_imports.stderr +++ b/tests/ui/single_component_path_imports.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports.rs:6:1 + --> $DIR/single_component_path_imports.rs:7:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely @@ -7,7 +7,7 @@ LL | use regex; = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports.rs:29:5 + --> $DIR/single_component_path_imports.rs:33:5 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/tests/ui/single_component_path_imports_nested_first.rs b/tests/ui/single_component_path_imports_nested_first.rs index c75beb74786..d6243c19f55 100644 --- a/tests/ui/single_component_path_imports_nested_first.rs +++ b/tests/ui/single_component_path_imports_nested_first.rs @@ -2,7 +2,9 @@ #![allow(unused_imports)] use regex; + use serde as edres; + pub use serde; fn main() { diff --git a/tests/ui/single_component_path_imports_nested_first.stderr b/tests/ui/single_component_path_imports_nested_first.stderr index 330f285202d..ff148355e12 100644 --- a/tests/ui/single_component_path_imports_nested_first.stderr +++ b/tests/ui/single_component_path_imports_nested_first.stderr @@ -7,7 +7,7 @@ LL | use regex; = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:13:10 + --> $DIR/single_component_path_imports_nested_first.rs:15:10 | LL | use {regex, serde}; | ^^^^^ @@ -15,7 +15,7 @@ LL | use {regex, serde}; = help: remove this import error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:13:17 + --> $DIR/single_component_path_imports_nested_first.rs:15:17 | LL | use {regex, serde}; | ^^^^^ diff --git a/tests/ui/single_component_path_imports_self_after.rs b/tests/ui/single_component_path_imports_self_after.rs index 48e8e530261..5723d480a2e 100644 --- a/tests/ui/single_component_path_imports_self_after.rs +++ b/tests/ui/single_component_path_imports_self_after.rs @@ -2,6 +2,7 @@ #![allow(unused_imports)] use self::regex::{Regex as xeger, RegexSet as tesxeger}; +#[rustfmt::skip] pub use self::{ regex::{Regex, RegexSet}, some_mod::SomeType, diff --git a/tests/ui/single_component_path_imports_self_before.rs b/tests/ui/single_component_path_imports_self_before.rs index 4fb0cf40b6e..8a4fbf0dc5b 100644 --- a/tests/ui/single_component_path_imports_self_before.rs +++ b/tests/ui/single_component_path_imports_self_before.rs @@ -4,6 +4,7 @@ use regex; use self::regex::{Regex as xeger, RegexSet as tesxeger}; +#[rustfmt::skip] pub use self::{ regex::{Regex, RegexSet}, some_mod::SomeType, diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 592a53f3a81..cb7562351e8 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -477,7 +477,8 @@ mod issue_10021 { mod issue_10033 { #![allow(dead_code)] - use std::{fmt::Display, ops::Deref}; + use std::fmt::Display; + use std::ops::Deref; fn _main() { let f = Foo; diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index f2e48b1c4a6..f82ddb2d25d 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -477,7 +477,8 @@ mod issue_10021 { mod issue_10033 { #![allow(dead_code)] - use std::{fmt::Display, ops::Deref}; + use std::fmt::Display; + use std::ops::Deref; fn _main() { let f = Foo; diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index d29888ac62f..04f6ef29a9a 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -8,9 +8,13 @@ use std::cell::UnsafeCell as TotallySafeCellAgain; // Shouldn't error use std::cell::RefCell as ProbablyNotUnsafe; + use std::cell::RefCell as RefCellThatCantBeUnsafe; + use std::cell::UnsafeCell as SuperDangerousUnsafeCell; + use std::cell::UnsafeCell as Dangerunsafe; + use std::cell::UnsafeCell as Bombsawayunsafe; mod mod_with_some_unsafe_things { @@ -20,8 +24,12 @@ mod mod_with_some_unsafe_things { use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; +// merged imports +use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B}; + // Shouldn't error use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime; + use mod_with_some_unsafe_things::Unsafe as SuperUnsafeModThing; #[allow(clippy::unsafe_removed_from_name)] diff --git a/tests/ui/unsafe_removed_from_name.stderr b/tests/ui/unsafe_removed_from_name.stderr index 4f871cbe41b..090d917bd38 100644 --- a/tests/ui/unsafe_removed_from_name.stderr +++ b/tests/ui/unsafe_removed_from_name.stderr @@ -13,10 +13,22 @@ LL | use std::cell::UnsafeCell as TotallySafeCellAgain; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: removed `unsafe` from the name of `Unsafe` in use as `LieAboutModSafety` - --> $DIR/unsafe_removed_from_name.rs:21:1 + --> $DIR/unsafe_removed_from_name.rs:25:1 | LL | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: removed `unsafe` from the name of `Unsafe` in use as `A` + --> $DIR/unsafe_removed_from_name.rs:28:1 + | +LL | use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: removed `unsafe` from the name of `Unsafe` in use as `B` + --> $DIR/unsafe_removed_from_name.rs:28:1 + | +LL | use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs index 7374dfdf92e..b227f8660f5 100644 --- a/tests/ui/unused_peekable.rs +++ b/tests/ui/unused_peekable.rs @@ -1,8 +1,7 @@ #![warn(clippy::unused_peekable)] #![allow(clippy::no_effect)] -use std::iter::Empty; -use std::iter::Peekable; +use std::iter::{Empty, Peekable}; fn main() { invalid(); diff --git a/tests/ui/unused_peekable.stderr b/tests/ui/unused_peekable.stderr index 54788f2fa2f..d969232fdf3 100644 --- a/tests/ui/unused_peekable.stderr +++ b/tests/ui/unused_peekable.stderr @@ -1,5 +1,5 @@ error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:14:9 + --> $DIR/unused_peekable.rs:13:9 | LL | let peekable = std::iter::empty::().peekable(); | ^^^^^^^^ @@ -8,7 +8,7 @@ LL | let peekable = std::iter::empty::().peekable(); = note: `-D clippy::unused-peekable` implied by `-D warnings` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:18:9 + --> $DIR/unused_peekable.rs:17:9 | LL | let new_local = old_local; | ^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let new_local = old_local; = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:22:9 + --> $DIR/unused_peekable.rs:21:9 | LL | let by_mut_ref = &mut by_mut_ref_test; | ^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let by_mut_ref = &mut by_mut_ref_test; = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:29:9 + --> $DIR/unused_peekable.rs:28:9 | LL | let peekable_from_fn = returns_peekable(); | ^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let peekable_from_fn = returns_peekable(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:32:13 + --> $DIR/unused_peekable.rs:31:13 | LL | let mut peekable_using_iterator_method = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let mut peekable_using_iterator_method = std::iter::empty::().peek = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:37:9 + --> $DIR/unused_peekable.rs:36:9 | LL | let passed_along_ref = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let passed_along_ref = std::iter::empty::().peekable(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:42:9 + --> $DIR/unused_peekable.rs:41:9 | LL | let _by_ref = by_ref_test.by_ref(); | ^^^^^^^ @@ -56,7 +56,7 @@ LL | let _by_ref = by_ref_test.by_ref(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:44:13 + --> $DIR/unused_peekable.rs:43:13 | LL | let mut peekable_in_for_loop = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 2961b062ec3..67173f40654 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -112,6 +112,7 @@ mod in_fn_test { } fn test_inner_nested() { + #[rustfmt::skip] use self::{inner::inner_foo, inner2::inner_bar}; inner_foo(); diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 28508a2538b..8223b693018 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -112,6 +112,7 @@ mod in_fn_test { } fn test_inner_nested() { + #[rustfmt::skip] use self::{inner::*, inner2::*}; inner_foo(); diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index c96b3041a00..f7baf234c2f 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -55,37 +55,37 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:115:20 + --> $DIR/wildcard_imports.rs:116:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:115:30 + --> $DIR/wildcard_imports.rs:116:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:122:13 + --> $DIR/wildcard_imports.rs:123:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:151:9 + --> $DIR/wildcard_imports.rs:152:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:160:9 + --> $DIR/wildcard_imports.rs:161:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:161:9 + --> $DIR/wildcard_imports.rs:162:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:172:13 + --> $DIR/wildcard_imports.rs:173:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:207:17 + --> $DIR/wildcard_imports.rs:208:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:215:13 + --> $DIR/wildcard_imports.rs:216:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:224:17 + --> $DIR/wildcard_imports.rs:225:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:233:13 + --> $DIR/wildcard_imports.rs:234:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:241:13 + --> $DIR/wildcard_imports.rs:242:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index 3aea013fb3a..8a63375676e 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -106,6 +106,7 @@ mod in_fn_test { } fn test_inner_nested() { + #[rustfmt::skip] use self::{inner::inner_foo, inner2::inner_bar}; inner_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr index acca9f651b4..af9ae6e786c 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -55,37 +55,37 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:109:20 + --> $DIR/wildcard_imports_2021.rs:110:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:109:30 + --> $DIR/wildcard_imports_2021.rs:110:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:116:13 + --> $DIR/wildcard_imports_2021.rs:117:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:145:9 + --> $DIR/wildcard_imports_2021.rs:146:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:154:9 + --> $DIR/wildcard_imports_2021.rs:155:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:156:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:166:13 + --> $DIR/wildcard_imports_2021.rs:167:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:201:17 + --> $DIR/wildcard_imports_2021.rs:202:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:209:13 + --> $DIR/wildcard_imports_2021.rs:210:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:218:17 + --> $DIR/wildcard_imports_2021.rs:219:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:227:13 + --> $DIR/wildcard_imports_2021.rs:228:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:235:13 + --> $DIR/wildcard_imports_2021.rs:236:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index 3aea013fb3a..8a63375676e 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -106,6 +106,7 @@ mod in_fn_test { } fn test_inner_nested() { + #[rustfmt::skip] use self::{inner::inner_foo, inner2::inner_bar}; inner_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr index acca9f651b4..af9ae6e786c 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -55,37 +55,37 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:109:20 + --> $DIR/wildcard_imports_2021.rs:110:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:109:30 + --> $DIR/wildcard_imports_2021.rs:110:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:116:13 + --> $DIR/wildcard_imports_2021.rs:117:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:145:9 + --> $DIR/wildcard_imports_2021.rs:146:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:154:9 + --> $DIR/wildcard_imports_2021.rs:155:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:156:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:166:13 + --> $DIR/wildcard_imports_2021.rs:167:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:201:17 + --> $DIR/wildcard_imports_2021.rs:202:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:209:13 + --> $DIR/wildcard_imports_2021.rs:210:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:218:17 + --> $DIR/wildcard_imports_2021.rs:219:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:227:13 + --> $DIR/wildcard_imports_2021.rs:228:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:235:13 + --> $DIR/wildcard_imports_2021.rs:236:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index 40c2d07527d..52cd2c82854 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -106,6 +106,7 @@ mod in_fn_test { } fn test_inner_nested() { + #[rustfmt::skip] use self::{inner::*, inner2::*}; inner_foo(); -- cgit 1.4.1-3-g733a5 From c2aaa622eb1b8ce390dc5766199ed7c63d4900d7 Mon Sep 17 00:00:00 2001 From: syvb Date: Wed, 5 Jul 2023 22:13:37 -0400 Subject: Fix ICE on None.unwrap_or_default() --- .../src/methods/unnecessary_literal_unwrap.rs | 12 ++ tests/ui/unnecessary_literal_unwrap.fixed | 2 + tests/ui/unnecessary_literal_unwrap.rs | 2 + tests/ui/unnecessary_literal_unwrap.stderr | 88 +++++----- tests/ui/unnecessary_literal_unwrap_unfixable.rs | 2 + .../ui/unnecessary_literal_unwrap_unfixable.stderr | 182 +++++++++++---------- 6 files changed, 165 insertions(+), 123 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 111bcaaecec..6d9a0451073 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -3,6 +3,8 @@ use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_middle::ty::print::with_forced_trimmed_paths; use super::UNNECESSARY_LITERAL_UNWRAP; @@ -84,6 +86,16 @@ pub(super) fn check( } Some(suggs) }, + ("None", "unwrap_or_default", _) => { + let ty = cx.typeck_results().expr_ty(expr); + let default_ty_string = if let ty::Adt(def, ..) = ty.kind() { + with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did()))) + } else { + "Default".to_string() + }; + Some(vec![(expr.span, format!("{default_ty_string}::default()"))]) + }, + _ if call_args.is_empty() => None, (_, _, Some(_)) => None, ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ ( diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 276cd800b89..5eaa117b8e8 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -19,9 +19,11 @@ fn unwrap_option_some() { fn unwrap_option_none() { let _val = panic!(); let _val = panic!("this always happens"); + let _val: String = String::default(); panic!(); panic!("this always happens"); + String::default(); } fn unwrap_result_ok() { diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 3065778d779..6408851b42a 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -19,9 +19,11 @@ fn unwrap_option_some() { fn unwrap_option_none() { let _val = None::<()>.unwrap(); let _val = None::<()>.expect("this always happens"); + let _val: String = None.unwrap_or_default(); None::<()>.unwrap(); None::<()>.expect("this always happens"); + None::.unwrap_or_default(); } fn unwrap_result_ok() { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index 5823313b736..acaf37b13a5 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -64,14 +64,20 @@ help: remove the `None` and `expect()` LL | let _val = panic!("this always happens"); | ~~~~~~~ ~ +error: used `unwrap_or_default()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:22:24 + | +LL | let _val: String = None.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` + error: used `unwrap()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:23:5 + --> $DIR/unnecessary_literal_unwrap.rs:24:5 | LL | None::<()>.unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` error: used `expect()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:24:5 + --> $DIR/unnecessary_literal_unwrap.rs:25:5 | LL | None::<()>.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,8 +87,14 @@ help: remove the `None` and `expect()` LL | panic!("this always happens"); | ~~~~~~~ ~ +error: used `unwrap_or_default()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:26:5 + | +LL | None::.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` + error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:28:16 + --> $DIR/unnecessary_literal_unwrap.rs:30:16 | LL | let _val = Ok::<_, ()>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +106,7 @@ LL + let _val = 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:29:16 + --> $DIR/unnecessary_literal_unwrap.rs:31:16 | LL | let _val = Ok::<_, ()>(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +118,7 @@ LL + let _val = 1; | error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:30:16 + --> $DIR/unnecessary_literal_unwrap.rs:32:16 | LL | let _val = Ok::<_, ()>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +129,7 @@ LL | let _val = panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:31:16 + --> $DIR/unnecessary_literal_unwrap.rs:33:16 | LL | let _val = Ok::<_, ()>(1).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,7 +140,7 @@ LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:33:5 + --> $DIR/unnecessary_literal_unwrap.rs:35:5 | LL | Ok::<_, ()>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +152,7 @@ LL + 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:34:5 + --> $DIR/unnecessary_literal_unwrap.rs:36:5 | LL | Ok::<_, ()>(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +164,7 @@ LL + 1; | error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:35:5 + --> $DIR/unnecessary_literal_unwrap.rs:37:5 | LL | Ok::<_, ()>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +175,7 @@ LL | panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:36:5 + --> $DIR/unnecessary_literal_unwrap.rs:38:5 | LL | Ok::<_, ()>(1).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,7 +186,7 @@ LL | panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:40:16 + --> $DIR/unnecessary_literal_unwrap.rs:42:16 | LL | let _val = Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -186,7 +198,7 @@ LL + let _val = 1; | error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:41:16 + --> $DIR/unnecessary_literal_unwrap.rs:43:16 | LL | let _val = Err::<(), _>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +210,7 @@ LL + let _val = 1; | error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:42:16 + --> $DIR/unnecessary_literal_unwrap.rs:44:16 | LL | let _val = Err::<(), _>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +221,7 @@ LL | let _val = panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:43:16 + --> $DIR/unnecessary_literal_unwrap.rs:45:16 | LL | let _val = Err::<(), _>(1).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +232,7 @@ LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:45:5 + --> $DIR/unnecessary_literal_unwrap.rs:47:5 | LL | Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,7 +244,7 @@ LL + 1; | error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:46:5 + --> $DIR/unnecessary_literal_unwrap.rs:48:5 | LL | Err::<(), _>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +256,7 @@ LL + 1; | error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:47:5 + --> $DIR/unnecessary_literal_unwrap.rs:49:5 | LL | Err::<(), _>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -255,7 +267,7 @@ LL | panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:48:5 + --> $DIR/unnecessary_literal_unwrap.rs:50:5 | LL | Err::<(), _>(1).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -266,7 +278,7 @@ LL | panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:52:16 + --> $DIR/unnecessary_literal_unwrap.rs:54:16 | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -278,7 +290,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:53:16 + --> $DIR/unnecessary_literal_unwrap.rs:55:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -290,7 +302,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:54:16 + --> $DIR/unnecessary_literal_unwrap.rs:56:16 | LL | let _val = Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -302,7 +314,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:56:5 + --> $DIR/unnecessary_literal_unwrap.rs:58:5 | LL | Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -314,7 +326,7 @@ LL + 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:57:5 + --> $DIR/unnecessary_literal_unwrap.rs:59:5 | LL | Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -326,7 +338,7 @@ LL + 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:58:5 + --> $DIR/unnecessary_literal_unwrap.rs:60:5 | LL | Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -338,7 +350,7 @@ LL + 1; | error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:62:16 + --> $DIR/unnecessary_literal_unwrap.rs:64:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +362,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:63:16 + --> $DIR/unnecessary_literal_unwrap.rs:65:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -362,7 +374,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:64:16 + --> $DIR/unnecessary_literal_unwrap.rs:66:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +386,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:66:5 + --> $DIR/unnecessary_literal_unwrap.rs:68:5 | LL | Ok::<_, ()>(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +398,7 @@ LL + 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:67:5 + --> $DIR/unnecessary_literal_unwrap.rs:69:5 | LL | Ok::<_, ()>(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -398,7 +410,7 @@ LL + 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:68:5 + --> $DIR/unnecessary_literal_unwrap.rs:70:5 | LL | Ok::<_, ()>(1).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -410,7 +422,7 @@ LL + 1; | error: used `unwrap_unchecked()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:82:22 + --> $DIR/unnecessary_literal_unwrap.rs:84:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -422,7 +434,7 @@ LL + let _ = 1; | error: used `unwrap_unchecked()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:83:22 + --> $DIR/unnecessary_literal_unwrap.rs:85:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +446,7 @@ LL + let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe | error: used `unwrap_unchecked()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:84:22 + --> $DIR/unnecessary_literal_unwrap.rs:86:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() } + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -446,7 +458,7 @@ LL + let _ = 1 + 1; | error: used `unwrap_unchecked()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:85:22 + --> $DIR/unnecessary_literal_unwrap.rs:87:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -458,7 +470,7 @@ LL + let _ = 1; | error: used `unwrap_unchecked()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:86:22 + --> $DIR/unnecessary_literal_unwrap.rs:88:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -470,7 +482,7 @@ LL + let _ = unsafe { 1 + *(&1 as *const i32) }; | error: used `unwrap_unchecked()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:87:22 + --> $DIR/unnecessary_literal_unwrap.rs:89:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -482,7 +494,7 @@ LL + let _ = 1 + 1; | error: used `unwrap_err_unchecked()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:88:22 + --> $DIR/unnecessary_literal_unwrap.rs:90:22 | LL | let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -493,5 +505,5 @@ LL - let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; LL + let _ = 123; | -error: aborting due to 43 previous errors +error: aborting due to 45 previous errors diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/tests/ui/unnecessary_literal_unwrap_unfixable.rs index 711fdce3962..41300aceb41 100644 --- a/tests/ui/unnecessary_literal_unwrap_unfixable.rs +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.rs @@ -21,6 +21,8 @@ fn unwrap_option_none() { let val = None::<()>; let _val2 = val.unwrap(); let _val2 = val.expect("this always happens"); + let _val3: u8 = None.unwrap_or_default(); + None::<()>.unwrap_or_default(); } fn unwrap_result_ok() { diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr index feb9325b77a..2d1270d4717 100644 --- a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr @@ -95,509 +95,521 @@ help: remove the `None` and `expect()` LL | let val = None::<()>; | ^^^^^^^^^^ +error: used `unwrap_or_default()` on `None` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:24:21 + | +LL | let _val3: u8 = None.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()` + +error: used `unwrap_or_default()` on `None` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:25:5 + | +LL | None::<()>.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()` + error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:32:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:33:17 | LL | let _val2 = val.expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:45:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:46:17 | LL | let _val2 = val.expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:49:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17 | LL | let _val2 = val.expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:53:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:54:17 | LL | let _val2 = val.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:62:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17 | LL | let _val2 = val.expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:66:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:67:17 | LL | let _val2 = val.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:70:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:73:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:74:17 | LL | let _val2 = val.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:81:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:84:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:85:17 | LL | let _val2 = val.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:88:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:91:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:92:17 | LL | let _val2 = val.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:99:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:102:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:103:17 | LL | let _val2 = val.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 50 previous errors +error: aborting due to 52 previous errors -- cgit 1.4.1-3-g733a5 From 8d258c15080f23b13b5268ac757c8f71adbe38b6 Mon Sep 17 00:00:00 2001 From: syvb Date: Wed, 5 Jul 2023 23:24:20 -0400 Subject: Add handling for None.unwrap_or(_else) --- .../src/methods/unnecessary_literal_unwrap.rs | 19 +++ tests/ui/unnecessary_literal_unwrap.fixed | 9 ++ tests/ui/unnecessary_literal_unwrap.rs | 9 ++ tests/ui/unnecessary_literal_unwrap.stderr | 180 ++++++++++++++++----- 4 files changed, 175 insertions(+), 42 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 6d9a0451073..937aac8d25e 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -24,6 +24,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) - } } +#[expect(clippy::too_many_lines)] pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -95,6 +96,24 @@ pub(super) fn check( }; Some(vec![(expr.span, format!("{default_ty_string}::default()"))]) }, + ("None", "unwrap_or", _) => Some(vec![ + (expr.span.with_hi(args[0].span.lo()), String::new()), + (expr.span.with_lo(args[0].span.hi()), String::new()), + ]), + ("None", "unwrap_or_else", _) => match args[0].kind { + hir::ExprKind::Closure(hir::Closure { + fn_decl: + hir::FnDecl { + output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }), + .. + }, + .. + }) => Some(vec![ + (expr.span.with_hi(span.hi()), String::new()), + (expr.span.with_lo(args[0].span.hi()), String::new()), + ]), + _ => None, + }, _ if call_args.is_empty() => None, (_, _, Some(_)) => None, ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 5eaa117b8e8..72d52c62355 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -16,14 +16,23 @@ fn unwrap_option_some() { 1; } +#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }` fn unwrap_option_none() { let _val = panic!(); let _val = panic!("this always happens"); let _val: String = String::default(); + let _val: u16 = 234; + let _val: u16 = 234; + let _val: u16 = { 234 }; + let _val: u16 = { 234 }; panic!(); panic!("this always happens"); String::default(); + 234; + 234; + { 234 }; + { 234 }; } fn unwrap_result_ok() { diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 6408851b42a..7d713ea205f 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -16,14 +16,23 @@ fn unwrap_option_some() { Some(1).expect("this never happens"); } +#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }` fn unwrap_option_none() { let _val = None::<()>.unwrap(); let _val = None::<()>.expect("this always happens"); let _val: String = None.unwrap_or_default(); + let _val: u16 = None.unwrap_or(234); + let _val: u16 = None.unwrap_or_else(|| 234); + let _val: u16 = None.unwrap_or_else(|| { 234 }); + let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 }); None::<()>.unwrap(); None::<()>.expect("this always happens"); None::.unwrap_or_default(); + None::.unwrap_or(234); + None::.unwrap_or_else(|| 234); + None::.unwrap_or_else(|| { 234 }); + None::.unwrap_or_else(|| -> u16 { 234 }); } fn unwrap_result_ok() { diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr index acaf37b13a5..7f603d6ef58 100644 --- a/tests/ui/unnecessary_literal_unwrap.stderr +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -48,13 +48,13 @@ LL + 1; | error: used `unwrap()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:20:16 + --> $DIR/unnecessary_literal_unwrap.rs:21:16 | LL | let _val = None::<()>.unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` error: used `expect()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:21:16 + --> $DIR/unnecessary_literal_unwrap.rs:22:16 | LL | let _val = None::<()>.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,19 +65,67 @@ LL | let _val = panic!("this always happens"); | ~~~~~~~ ~ error: used `unwrap_or_default()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:22:24 + --> $DIR/unnecessary_literal_unwrap.rs:23:24 | LL | let _val: String = None.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` +error: used `unwrap_or()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:24:21 + | +LL | let _val: u16 = None.unwrap_or(234); + | ^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or()` + | +LL - let _val: u16 = None.unwrap_or(234); +LL + let _val: u16 = 234; + | + +error: used `unwrap_or_else()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:25:21 + | +LL | let _val: u16 = None.unwrap_or_else(|| 234); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or_else()` + | +LL - let _val: u16 = None.unwrap_or_else(|| 234); +LL + let _val: u16 = 234; + | + +error: used `unwrap_or_else()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:26:21 + | +LL | let _val: u16 = None.unwrap_or_else(|| { 234 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or_else()` + | +LL - let _val: u16 = None.unwrap_or_else(|| { 234 }); +LL + let _val: u16 = { 234 }; + | + +error: used `unwrap_or_else()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:27:21 + | +LL | let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or_else()` + | +LL - let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 }); +LL + let _val: u16 = { 234 }; + | + error: used `unwrap()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:24:5 + --> $DIR/unnecessary_literal_unwrap.rs:29:5 | LL | None::<()>.unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` error: used `expect()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:25:5 + --> $DIR/unnecessary_literal_unwrap.rs:30:5 | LL | None::<()>.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,13 +136,61 @@ LL | panic!("this always happens"); | ~~~~~~~ ~ error: used `unwrap_or_default()` on `None` value - --> $DIR/unnecessary_literal_unwrap.rs:26:5 + --> $DIR/unnecessary_literal_unwrap.rs:31:5 | LL | None::.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` +error: used `unwrap_or()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:32:5 + | +LL | None::.unwrap_or(234); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or()` + | +LL - None::.unwrap_or(234); +LL + 234; + | + +error: used `unwrap_or_else()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:33:5 + | +LL | None::.unwrap_or_else(|| 234); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or_else()` + | +LL - None::.unwrap_or_else(|| 234); +LL + 234; + | + +error: used `unwrap_or_else()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:34:5 + | +LL | None::.unwrap_or_else(|| { 234 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or_else()` + | +LL - None::.unwrap_or_else(|| { 234 }); +LL + { 234 }; + | + +error: used `unwrap_or_else()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:35:5 + | +LL | None::.unwrap_or_else(|| -> u16 { 234 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap_or_else()` + | +LL - None::.unwrap_or_else(|| -> u16 { 234 }); +LL + { 234 }; + | + error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:30:16 + --> $DIR/unnecessary_literal_unwrap.rs:39:16 | LL | let _val = Ok::<_, ()>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +202,7 @@ LL + let _val = 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:31:16 + --> $DIR/unnecessary_literal_unwrap.rs:40:16 | LL | let _val = Ok::<_, ()>(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +214,7 @@ LL + let _val = 1; | error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:32:16 + --> $DIR/unnecessary_literal_unwrap.rs:41:16 | LL | let _val = Ok::<_, ()>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +225,7 @@ LL | let _val = panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:33:16 + --> $DIR/unnecessary_literal_unwrap.rs:42:16 | LL | let _val = Ok::<_, ()>(1).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +236,7 @@ LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:35:5 + --> $DIR/unnecessary_literal_unwrap.rs:44:5 | LL | Ok::<_, ()>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -152,7 +248,7 @@ LL + 1; | error: used `expect()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:36:5 + --> $DIR/unnecessary_literal_unwrap.rs:45:5 | LL | Ok::<_, ()>(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +260,7 @@ LL + 1; | error: used `unwrap_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:37:5 + --> $DIR/unnecessary_literal_unwrap.rs:46:5 | LL | Ok::<_, ()>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +271,7 @@ LL | panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect_err()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:38:5 + --> $DIR/unnecessary_literal_unwrap.rs:47:5 | LL | Ok::<_, ()>(1).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -186,7 +282,7 @@ LL | panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:42:16 + --> $DIR/unnecessary_literal_unwrap.rs:51:16 | LL | let _val = Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +294,7 @@ LL + let _val = 1; | error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:43:16 + --> $DIR/unnecessary_literal_unwrap.rs:52:16 | LL | let _val = Err::<(), _>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +306,7 @@ LL + let _val = 1; | error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:44:16 + --> $DIR/unnecessary_literal_unwrap.rs:53:16 | LL | let _val = Err::<(), _>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,7 +317,7 @@ LL | let _val = panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:45:16 + --> $DIR/unnecessary_literal_unwrap.rs:54:16 | LL | let _val = Err::<(), _>(1).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,7 +328,7 @@ LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:47:5 + --> $DIR/unnecessary_literal_unwrap.rs:56:5 | LL | Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +340,7 @@ LL + 1; | error: used `expect_err()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:48:5 + --> $DIR/unnecessary_literal_unwrap.rs:57:5 | LL | Err::<(), _>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -256,7 +352,7 @@ LL + 1; | error: used `unwrap()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:49:5 + --> $DIR/unnecessary_literal_unwrap.rs:58:5 | LL | Err::<(), _>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -267,7 +363,7 @@ LL | panic!("{:?}", 1); | ~~~~~~~~~~~~~~ ~ error: used `expect()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:50:5 + --> $DIR/unnecessary_literal_unwrap.rs:59:5 | LL | Err::<(), _>(1).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -278,7 +374,7 @@ LL | panic!("{1}: {:?}", 1, "this always happens"); | ~~~~~~~~~~~~~~~~~~~ ~ error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:54:16 + --> $DIR/unnecessary_literal_unwrap.rs:63:16 | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -290,7 +386,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:55:16 + --> $DIR/unnecessary_literal_unwrap.rs:64:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -302,7 +398,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:56:16 + --> $DIR/unnecessary_literal_unwrap.rs:65:16 | LL | let _val = Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -314,7 +410,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:58:5 + --> $DIR/unnecessary_literal_unwrap.rs:67:5 | LL | Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -326,7 +422,7 @@ LL + 1; | error: used `unwrap_or_default()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:59:5 + --> $DIR/unnecessary_literal_unwrap.rs:68:5 | LL | Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -338,7 +434,7 @@ LL + 1; | error: used `unwrap_or_else()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:60:5 + --> $DIR/unnecessary_literal_unwrap.rs:69:5 | LL | Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +446,7 @@ LL + 1; | error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:64:16 + --> $DIR/unnecessary_literal_unwrap.rs:73:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -362,7 +458,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:65:16 + --> $DIR/unnecessary_literal_unwrap.rs:74:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +470,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:66:16 + --> $DIR/unnecessary_literal_unwrap.rs:75:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +482,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:68:5 + --> $DIR/unnecessary_literal_unwrap.rs:77:5 | LL | Ok::<_, ()>(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -398,7 +494,7 @@ LL + 1; | error: used `unwrap_or_default()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:69:5 + --> $DIR/unnecessary_literal_unwrap.rs:78:5 | LL | Ok::<_, ()>(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -410,7 +506,7 @@ LL + 1; | error: used `unwrap_or_else()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:70:5 + --> $DIR/unnecessary_literal_unwrap.rs:79:5 | LL | Ok::<_, ()>(1).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -422,7 +518,7 @@ LL + 1; | error: used `unwrap_unchecked()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:84:22 + --> $DIR/unnecessary_literal_unwrap.rs:93:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +530,7 @@ LL + let _ = 1; | error: used `unwrap_unchecked()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:85:22 + --> $DIR/unnecessary_literal_unwrap.rs:94:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -446,7 +542,7 @@ LL + let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe | error: used `unwrap_unchecked()` on `Some` value - --> $DIR/unnecessary_literal_unwrap.rs:86:22 + --> $DIR/unnecessary_literal_unwrap.rs:95:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() } + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -458,7 +554,7 @@ LL + let _ = 1 + 1; | error: used `unwrap_unchecked()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:87:22 + --> $DIR/unnecessary_literal_unwrap.rs:96:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -470,7 +566,7 @@ LL + let _ = 1; | error: used `unwrap_unchecked()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:88:22 + --> $DIR/unnecessary_literal_unwrap.rs:97:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -482,7 +578,7 @@ LL + let _ = unsafe { 1 + *(&1 as *const i32) }; | error: used `unwrap_unchecked()` on `Ok` value - --> $DIR/unnecessary_literal_unwrap.rs:89:22 + --> $DIR/unnecessary_literal_unwrap.rs:98:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -494,7 +590,7 @@ LL + let _ = 1 + 1; | error: used `unwrap_err_unchecked()` on `Err` value - --> $DIR/unnecessary_literal_unwrap.rs:90:22 + --> $DIR/unnecessary_literal_unwrap.rs:99:22 | LL | let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -505,5 +601,5 @@ LL - let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; LL + let _ = 123; | -error: aborting due to 45 previous errors +error: aborting due to 53 previous errors -- cgit 1.4.1-3-g733a5 From c3881569afd049d391d6943bff9ee7317fe98211 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 7 Jul 2023 00:45:37 +0200 Subject: new lint: `format_collect` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/format_collect.rs | 33 ++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 35 +++++++++++++++++++++++- src/main.rs | 3 +- tests/ui/format_collect.rs | 26 ++++++++++++++++++ tests/ui/format_collect.stderr | 44 ++++++++++++++++++++++++++++++ 7 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/methods/format_collect.rs create mode 100644 tests/ui/format_collect.rs create mode 100644 tests/ui/format_collect.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b6e3b865f..ea8450ed5c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4865,6 +4865,7 @@ Released 2018-09-13 [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref +[`format_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_collect [`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args [`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string [`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 498d657b31f..7472158a81c 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -338,6 +338,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::FILTER_NEXT_INFO, crate::methods::FLAT_MAP_IDENTITY_INFO, crate::methods::FLAT_MAP_OPTION_INFO, + crate::methods::FORMAT_COLLECT_INFO, crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO, crate::methods::GET_FIRST_INFO, crate::methods::GET_LAST_WITH_LEN_INFO, diff --git a/clippy_lints/src/methods/format_collect.rs b/clippy_lints/src/methods/format_collect.rs new file mode 100644 index 00000000000..74eb80782d6 --- /dev/null +++ b/clippy_lints/src/methods/format_collect.rs @@ -0,0 +1,33 @@ +use super::FORMAT_COLLECT; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::is_format_macro; +use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::ty::is_type_lang_item; +use rustc_hir::Expr; +use rustc_hir::ExprKind; +use rustc_hir::LangItem; +use rustc_lint::LateContext; +use rustc_span::Span; + +fn tail_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + match expr.kind { + ExprKind::Block(block, _) if !expr.span.from_expansion() => block.expr, + _ => Some(expr), + } +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) { + if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) + && let ExprKind::Closure(closure) = map_arg.kind + && let body = cx.tcx.hir().body(closure.body) + && let Some(value) = tail_expr(body.value) + && let Some(mac) = root_macro_call_first_node(cx, value) + && is_format_macro(cx, mac.def_id) + { + span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| { + diag.span_help(map_span, "call `fold` instead") + .span_help(value.span.source_callsite(), "... and use the `write!` macro here") + .note("this can be written more efficiently by appending to a `String` directly"); + }); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2747ab5615c..f55a7727fad 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -26,6 +26,7 @@ mod filter_map_next; mod filter_next; mod flat_map_identity; mod flat_map_option; +mod format_collect; mod from_iter_instead_of_collect; mod get_first; mod get_last_with_len; @@ -3378,6 +3379,36 @@ declare_clippy_lint! { "calling `Stdin::read_line`, then trying to parse it without first trimming" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.map(|_| format!(..)).collect::()`. + /// + /// ### Why is this bad? + /// This allocates a new string for every element in the iterator. + /// This can be done more efficiently by creating the `String` once and appending to it using `Iterator::fold`. + /// + /// ### Example + /// ```rust + /// fn hex_encode(bytes: &[u8]) -> String { + /// bytes.iter().map(|b| format!("{b:02X}")).collect() + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::fmt::Write; + /// fn hex_encode(bytes: &[u8]) -> String { + /// bytes.iter().fold(String::new(), |mut output, b| { + /// let _ = write!(output, "{b:02X}"); + /// output + /// }) + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub FORMAT_COLLECT, + perf, + "`format!`ing every element in a collection, then collecting the strings into a new `String`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3512,6 +3543,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_LITERAL_UNWRAP, DRAIN_COLLECT, MANUAL_TRY_FOLD, + FORMAT_COLLECT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3733,8 +3765,9 @@ impl Methods { Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => { iter_cloned_collect::check(cx, name, expr, recv2); }, - Some(("map", m_recv, [m_arg], _, _)) => { + Some(("map", m_recv, [m_arg], m_ident_span, _)) => { map_collect_result_unit::check(cx, expr, m_recv, m_arg); + format_collect::check(cx, expr, m_arg, m_ident_span); }, Some(("take", take_self_arg, [take_arg], _, _)) => { if self.msrv.meets(msrvs::STR_REPEAT) { diff --git a/src/main.rs b/src/main.rs index cdc85cb33ca..26b655076cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,8 +132,7 @@ impl ClippyCmd { let clippy_args: String = self .clippy_args .iter() - .map(|arg| format!("{arg}__CLIPPY_HACKERY__")) - .collect(); + .fold(String::new(), |s, arg| s + arg + "__CLIPPY_HACKERY__"); // Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages. let terminal_width = termize::dimensions().map_or(0, |(w, _)| w); diff --git a/tests/ui/format_collect.rs b/tests/ui/format_collect.rs new file mode 100644 index 00000000000..ecadb43ecb4 --- /dev/null +++ b/tests/ui/format_collect.rs @@ -0,0 +1,26 @@ +#![allow(unused, dead_code)] +#![warn(clippy::format_collect)] + +fn hex_encode(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{b:02X}")).collect() +} + +macro_rules! fmt { + ($x:ident) => { + format!("{x:02X}", x = $x) + }; +} + +fn from_macro(bytes: &[u8]) -> String { + bytes.iter().map(|x| fmt!(x)).collect() +} + +fn with_block() -> String { + (1..10) + .map(|s| { + let y = 1; + format!("{s} {y}") + }) + .collect() +} +fn main() {} diff --git a/tests/ui/format_collect.stderr b/tests/ui/format_collect.stderr new file mode 100644 index 00000000000..cd71a853762 --- /dev/null +++ b/tests/ui/format_collect.stderr @@ -0,0 +1,44 @@ +error: use of `format!` to build up a string from an iterator + --> $DIR/format_collect.rs:5:5 + | +LL | bytes.iter().map(|b| format!("{b:02X}")).collect() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: call `fold` instead + --> $DIR/format_collect.rs:5:18 + | +LL | bytes.iter().map(|b| format!("{b:02X}")).collect() + | ^^^ +help: ... and use the `write!` macro here + --> $DIR/format_collect.rs:5:26 + | +LL | bytes.iter().map(|b| format!("{b:02X}")).collect() + | ^^^^^^^^^^^^^^^^^^ + = note: this can be written more efficiently by appending to a `String` directly + = note: `-D clippy::format-collect` implied by `-D warnings` + +error: use of `format!` to build up a string from an iterator + --> $DIR/format_collect.rs:19:5 + | +LL | / (1..10) +LL | | .map(|s| { +LL | | let y = 1; +LL | | format!("{s} {y}") +LL | | }) +LL | | .collect() + | |__________________^ + | +help: call `fold` instead + --> $DIR/format_collect.rs:20:10 + | +LL | .map(|s| { + | ^^^ +help: ... and use the `write!` macro here + --> $DIR/format_collect.rs:22:13 + | +LL | format!("{s} {y}") + | ^^^^^^^^^^^^^^^^^^ + = note: this can be written more efficiently by appending to a `String` directly + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From c83d58f5076f3a79ea79514395a02babd15687b1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:20:36 +0200 Subject: document that `write!`ing into a string never fails --- clippy_lints/src/methods/format_collect.rs | 16 ++++++++-------- clippy_lints/src/methods/mod.rs | 7 ++++++- tests/ui/format_collect.rs | 5 +++++ tests/ui/format_collect.stderr | 26 ++++++++++++++++++++++---- 4 files changed, 41 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/format_collect.rs b/clippy_lints/src/methods/format_collect.rs index 74eb80782d6..1f8863f8521 100644 --- a/clippy_lints/src/methods/format_collect.rs +++ b/clippy_lints/src/methods/format_collect.rs @@ -1,17 +1,17 @@ use super::FORMAT_COLLECT; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::is_format_macro; -use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::macros::{is_format_macro, root_macro_call_first_node}; use clippy_utils::ty::is_type_lang_item; -use rustc_hir::Expr; -use rustc_hir::ExprKind; -use rustc_hir::LangItem; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; use rustc_span::Span; -fn tail_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { +/// Same as `peel_blocks` but only actually considers blocks that are not from an expansion. +/// This is needed because always calling `peel_blocks` would otherwise remove parts of the +/// `format!` macro, which would cause `root_macro_call_first_node` to return `None`. +fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { match expr.kind { - ExprKind::Block(block, _) if !expr.span.from_expansion() => block.expr, + ExprKind::Block(block, _) if !expr.span.from_expansion() => peel_non_expn_blocks(block.expr?), _ => Some(expr), } } @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, m if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) && let ExprKind::Closure(closure) = map_arg.kind && let body = cx.tcx.hir().body(closure.body) - && let Some(value) = tail_expr(body.value) + && let Some(value) = peel_non_expn_blocks(body.value) && let Some(mac) = root_macro_call_first_node(cx, value) && is_format_macro(cx, mac.def_id) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f55a7727fad..81f59f68ec6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3385,7 +3385,12 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// This allocates a new string for every element in the iterator. - /// This can be done more efficiently by creating the `String` once and appending to it using `Iterator::fold`. + /// This can be done more efficiently by creating the `String` once and appending to it in `Iterator::fold`, + /// using either the `write!` macro which supports exactly the same syntax as the `format!` macro, + /// or concatenating with `+` in case the iterator yields `&str`/`String`. + /// + /// Note also that `write!`-ing into a `String` can never fail, despite the return type of `write!` being `std::fmt::Result`, + /// so it can be safely ignored or unwrapped. /// /// ### Example /// ```rust diff --git a/tests/ui/format_collect.rs b/tests/ui/format_collect.rs index ecadb43ecb4..c7f2b7b6950 100644 --- a/tests/ui/format_collect.rs +++ b/tests/ui/format_collect.rs @@ -5,6 +5,11 @@ fn hex_encode(bytes: &[u8]) -> String { bytes.iter().map(|b| format!("{b:02X}")).collect() } +#[rustfmt::skip] +fn hex_encode_deep(bytes: &[u8]) -> String { + bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect() +} + macro_rules! fmt { ($x:ident) => { format!("{x:02X}", x = $x) diff --git a/tests/ui/format_collect.stderr b/tests/ui/format_collect.stderr index cd71a853762..d918f1ed466 100644 --- a/tests/ui/format_collect.stderr +++ b/tests/ui/format_collect.stderr @@ -18,7 +18,25 @@ LL | bytes.iter().map(|b| format!("{b:02X}")).collect() = note: `-D clippy::format-collect` implied by `-D warnings` error: use of `format!` to build up a string from an iterator - --> $DIR/format_collect.rs:19:5 + --> $DIR/format_collect.rs:10:5 + | +LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: call `fold` instead + --> $DIR/format_collect.rs:10:18 + | +LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect() + | ^^^ +help: ... and use the `write!` macro here + --> $DIR/format_collect.rs:10:32 + | +LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect() + | ^^^^^^^^^^^^^^^^^^ + = note: this can be written more efficiently by appending to a `String` directly + +error: use of `format!` to build up a string from an iterator + --> $DIR/format_collect.rs:24:5 | LL | / (1..10) LL | | .map(|s| { @@ -29,16 +47,16 @@ LL | | .collect() | |__________________^ | help: call `fold` instead - --> $DIR/format_collect.rs:20:10 + --> $DIR/format_collect.rs:25:10 | LL | .map(|s| { | ^^^ help: ... and use the `write!` macro here - --> $DIR/format_collect.rs:22:13 + --> $DIR/format_collect.rs:27:13 | LL | format!("{s} {y}") | ^^^^^^^^^^^^^^^^^^ = note: this can be written more efficiently by appending to a `String` directly -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 9d08502496f8a61bdc1f8d20ba075b6d0a5a8b87 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:39:17 -0500 Subject: New lint [`string_lit_chars_any`] --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 39 +++++++++++++++- clippy_lints/src/methods/string_lit_chars_any.rs | 58 ++++++++++++++++++++++++ tests/ui/string_lit_chars_any.fixed | 50 ++++++++++++++++++++ tests/ui/string_lit_chars_any.rs | 50 ++++++++++++++++++++ tests/ui/string_lit_chars_any.stderr | 58 ++++++++++++++++++++++++ 7 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/methods/string_lit_chars_any.rs create mode 100644 tests/ui/string_lit_chars_any.fixed create mode 100644 tests/ui/string_lit_chars_any.rs create mode 100644 tests/ui/string_lit_chars_any.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index db18bc296f7..ece1111213c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5256,6 +5256,7 @@ Released 2018-09-13 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes +[`string_lit_chars_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_chars_any [`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 51035a9d66b..168dc9bf4e1 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -405,6 +405,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SKIP_WHILE_NEXT_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, + crate::methods::STRING_LIT_CHARS_ANY_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 81f59f68ec6..6efeff92091 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -86,6 +86,7 @@ mod skip_while_next; mod stable_sort_primitive; mod str_splitn; mod string_extend_chars; +mod string_lit_chars_any; mod suspicious_command_arg_space; mod suspicious_map; mod suspicious_splitn; @@ -115,7 +116,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; 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 clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; @@ -3379,6 +3380,34 @@ declare_clippy_lint! { "calling `Stdin::read_line`, then trying to parse it without first trimming" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.chars().any(|i| i == c)`. + /// + /// ### Why is this bad? + /// It's significantly slower than using a pattern instead, like + /// `matches!(c, '\\' | '.' | '+')`. + /// + /// Despite this being faster, this is not `perf` as this is pretty common, and is a rather nice + /// way to check if a `char` is any in a set. In any case, this `restriction` lint is available + /// for situations where that additional performance is absolutely necessary. + /// + /// ### Example + /// ```rust + /// # let c = 'c'; + /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + /// ``` + /// Use instead: + /// ```rust + /// # let c = 'c'; + /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + /// ``` + #[clippy::version = "1.72.0"] + pub STRING_LIT_CHARS_ANY, + restriction, + "checks for `.chars().any(|i| i == c)`" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `.map(|_| format!(..)).collect::()`. @@ -3549,6 +3578,7 @@ impl_lint_pass!(Methods => [ DRAIN_COLLECT, MANUAL_TRY_FOLD, FORMAT_COLLECT, + STRING_LIT_CHARS_ANY, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3923,6 +3953,13 @@ impl Methods { } } }, + ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params + && let Some(("chars", recv, _, _, _)) = method_call(recv) => + { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + } ("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), diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs new file mode 100644 index 00000000000..70da6ad58bd --- /dev/null +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -0,0 +1,58 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{Msrv, MATCHES_MACRO}; +use clippy_utils::source::snippet_opt; +use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; +use itertools::Itertools; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, Param, PatKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::STRING_LIT_CHARS_ANY; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &Expr<'_>, + param: &'tcx Param<'tcx>, + body: &Expr<'_>, + msrv: &Msrv, +) { + if msrv.meets(MATCHES_MACRO) + && is_trait_method(cx, expr, sym::Iterator) + && let PatKind::Binding(_, arg, _, _) = param.pat.kind + && let ExprKind::Lit(lit_kind) = recv.kind + && let LitKind::Str(val, _) = lit_kind.node + && let ExprKind::Binary(kind, lhs, rhs) = body.kind + && let BinOpKind::Eq = kind.node + && let Some(lhs_path) = path_to_local(lhs) + && let Some(rhs_path) = path_to_local(rhs) + && let scrutinee = match (lhs_path == arg, rhs_path == arg) { + (true, false) => rhs, + (false, true) => lhs, + _ => return, + } + && !is_from_proc_macro(cx, expr) + && let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span) + { + // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then + // something like `r"\"` will become `'\'`, which is of course invalid + let pat_snip = val.as_str().chars().map(|c| format!("{c:?}")).join(" | "); + + span_lint_and_then( + cx, + STRING_LIT_CHARS_ANY, + expr.span, + "usage of `.chars().any(...)` to check if a char matches any from a string literal", + |diag| { + diag.span_suggestion_verbose( + expr.span, + "use `matches!(...)` instead", + format!("matches!({scrutinee_snip}, {pat_snip})"), + Applicability::MachineApplicable, + ); + } + ); + } +} diff --git a/tests/ui/string_lit_chars_any.fixed b/tests/ui/string_lit_chars_any.fixed new file mode 100644 index 00000000000..d7ab9c3397a --- /dev/null +++ b/tests/ui/string_lit_chars_any.fixed @@ -0,0 +1,50 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)] +#![warn(clippy::string_lit_chars_any)] + +#[macro_use] +extern crate proc_macros; + +struct NotStringLit; + +impl NotStringLit { + fn chars(&self) -> impl Iterator { + "c".chars() + } +} + +fn main() { + let c = 'c'; + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + #[rustfmt::skip] + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + // Do not lint + NotStringLit.chars().any(|x| x == c); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| { + let c = 'c'; + x == c + }); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| { + 1; + x == c + }); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x); + "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c); + matches!( + c, + '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~' + ); + external! { + let c = 'c'; + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + } + with_span! { + span + let c = 'c'; + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + } +} diff --git a/tests/ui/string_lit_chars_any.rs b/tests/ui/string_lit_chars_any.rs new file mode 100644 index 00000000000..9408d7bb239 --- /dev/null +++ b/tests/ui/string_lit_chars_any.rs @@ -0,0 +1,50 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)] +#![warn(clippy::string_lit_chars_any)] + +#[macro_use] +extern crate proc_macros; + +struct NotStringLit; + +impl NotStringLit { + fn chars(&self) -> impl Iterator { + "c".chars() + } +} + +fn main() { + let c = 'c'; + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| c == x); + r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x); + #[rustfmt::skip] + "\\.+*?()|[]{}^$#&-~".chars().any(|x| { x == c }); + // Do not lint + NotStringLit.chars().any(|x| x == c); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| { + let c = 'c'; + x == c + }); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| { + 1; + x == c + }); + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x); + "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c); + matches!( + c, + '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~' + ); + external! { + let c = 'c'; + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + } + with_span! { + span + let c = 'c'; + "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + } +} diff --git a/tests/ui/string_lit_chars_any.stderr b/tests/ui/string_lit_chars_any.stderr new file mode 100644 index 00000000000..ff951b73ded --- /dev/null +++ b/tests/ui/string_lit_chars_any.stderr @@ -0,0 +1,58 @@ +error: usage of `.chars().any(...)` to check if a char matches any from a string literal + --> $DIR/string_lit_chars_any.rs:19:5 + | +LL | "//.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::string-lit-chars-any` implied by `-D warnings` +help: use `matches!(...)` instead + | +LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: usage of `.chars().any(...)` to check if a char matches any from a string literal + --> $DIR/string_lit_chars_any.rs:20:5 + | +LL | r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!(...)` instead + | +LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: usage of `.chars().any(...)` to check if a char matches any from a string literal + --> $DIR/string_lit_chars_any.rs:21:5 + | +LL | "//.+*?()|[]{}^$#&-~".chars().any(|x| c == x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!(...)` instead + | +LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: usage of `.chars().any(...)` to check if a char matches any from a string literal + --> $DIR/string_lit_chars_any.rs:22:5 + | +LL | r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!(...)` instead + | +LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: usage of `.chars().any(...)` to check if a char matches any from a string literal + --> $DIR/string_lit_chars_any.rs:24:5 + | +LL | "//.+*?()|[]{}^$#&-~".chars().any(|x| { x == c }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!(...)` instead + | +LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 5 previous errors + -- cgit 1.4.1-3-g733a5 From 4c79d8ace5bf19d6f839b52138af014da570284f Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Thu, 29 Jun 2023 04:55:07 -0500 Subject: new lint `iter_skip_zero` --- CHANGELOG.md | 1 + clippy_lints/src/casts/unnecessary_cast.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/iter_skip_zero.rs | 34 +++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 34 ++++++++++++++++++++++- tests/ui/iter_skip_zero.fixed | 25 +++++++++++++++++ tests/ui/iter_skip_zero.rs | 25 +++++++++++++++++ tests/ui/iter_skip_zero.stderr | 43 ++++++++++++++++++++++++++++++ 8 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/iter_skip_zero.rs create mode 100644 tests/ui/iter_skip_zero.fixed create mode 100644 tests/ui/iter_skip_zero.rs create mode 100644 tests/ui/iter_skip_zero.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index ece1111213c..acc9d8ffbf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4939,6 +4939,7 @@ Released 2018-09-13 [`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next +[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index ae56f38d9ad..4b45b0c9eac 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -257,7 +257,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx // Will this work for more complex types? Probably not! if !snippet .split("->") - .skip(0) + .skip(1) .map(|s| { s.trim() == cast_from.to_string() || s.split("where").any(|ty| ty.trim() == cast_from.to_string()) diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 168dc9bf4e1..47995fea9f9 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -360,6 +360,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_ON_SINGLE_ITEMS_INFO, crate::methods::ITER_OVEREAGER_CLONED_INFO, crate::methods::ITER_SKIP_NEXT_INFO, + crate::methods::ITER_SKIP_ZERO_INFO, crate::methods::ITER_WITH_DRAIN_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, diff --git a/clippy_lints/src/methods/iter_skip_zero.rs b/clippy_lints/src/methods/iter_skip_zero.rs new file mode 100644 index 00000000000..6b696b42a69 --- /dev/null +++ b/clippy_lints/src/methods/iter_skip_zero.rs @@ -0,0 +1,34 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{is_from_proc_macro, is_trait_method}; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::ITER_SKIP_ZERO; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) { + if !expr.span.from_expansion() + && is_trait_method(cx, expr, sym::Iterator) + && let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| { + if let Constant::Int(arg) = constant { + Some(arg) + } else { + None + } + }) + && arg == 0 + && !is_from_proc_macro(cx, expr) + { + span_lint_and_then(cx, ITER_SKIP_ZERO, arg_expr.span, "usage of `.skip(0)`", |diag| { + diag.span_suggestion( + arg_expr.span, + "if you meant to skip the first element, use", + "1", + Applicability::MaybeIncorrect, + ) + .note("this call to `skip` does nothing and is useless; remove it"); + }); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6efeff92091..be71072acd6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iter_nth_zero; mod iter_on_single_or_empty_collections; mod iter_overeager_cloned; mod iter_skip_next; +mod iter_skip_zero; mod iter_with_drain; mod iterator_step_by_zero; mod manual_next_back; @@ -3443,6 +3444,27 @@ declare_clippy_lint! { "`format!`ing every element in a collection, then collecting the strings into a new `String`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.skip(0)` on iterators. + /// + /// ### Why is this bad? + /// This was likely intended to be `.skip(1)` to skip the first element, as `.skip(0)` does + /// nothing. If not, the call should be removed. + /// + /// ### Example + /// ```rust + /// let v = vec![1, 2, 3]; + /// let x = v.iter().skip(0).collect::>(); + /// let y = v.iter().collect::>(); + /// assert_eq!(x, y); + /// ``` + #[clippy::version = "1.72.0"] + pub ITER_SKIP_ZERO, + correctness, + "disallows `.skip(0)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3579,6 +3601,7 @@ impl_lint_pass!(Methods => [ MANUAL_TRY_FOLD, FORMAT_COLLECT, STRING_LIT_CHARS_ANY, + ITER_SKIP_ZERO, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3901,7 +3924,16 @@ impl Methods { unnecessary_join::check(cx, expr, recv, join_arg, span); } }, - ("last", []) | ("skip", [_]) => { + ("skip", [arg]) => { + iter_skip_zero::check(cx, expr, arg); + + 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); + } + } + } + ("last", []) => { 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); diff --git a/tests/ui/iter_skip_zero.fixed b/tests/ui/iter_skip_zero.fixed new file mode 100644 index 00000000000..1eb0984fe07 --- /dev/null +++ b/tests/ui/iter_skip_zero.fixed @@ -0,0 +1,25 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::useless_vec, unused)] +#![warn(clippy::iter_skip_zero)] + +#[macro_use] +extern crate proc_macros; + +use std::iter::once; + +fn main() { + let _ = [1, 2, 3].iter().skip(1); + let _ = vec![1, 2, 3].iter().skip(1); + let _ = once([1, 2, 3]).skip(1); + let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(1)).skip(1); + // Don't lint + let _ = [1, 2, 3].iter().skip(1); + let _ = vec![1, 2, 3].iter().skip(1); + external! { + let _ = [1, 2, 3].iter().skip(0); + } + with_span! { + let _ = [1, 2, 3].iter().skip(0); + } +} diff --git a/tests/ui/iter_skip_zero.rs b/tests/ui/iter_skip_zero.rs new file mode 100644 index 00000000000..8c103ab1d5b --- /dev/null +++ b/tests/ui/iter_skip_zero.rs @@ -0,0 +1,25 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::useless_vec, unused)] +#![warn(clippy::iter_skip_zero)] + +#[macro_use] +extern crate proc_macros; + +use std::iter::once; + +fn main() { + let _ = [1, 2, 3].iter().skip(0); + let _ = vec![1, 2, 3].iter().skip(0); + let _ = once([1, 2, 3]).skip(0); + let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); + // Don't lint + let _ = [1, 2, 3].iter().skip(1); + let _ = vec![1, 2, 3].iter().skip(1); + external! { + let _ = [1, 2, 3].iter().skip(0); + } + with_span! { + let _ = [1, 2, 3].iter().skip(0); + } +} diff --git a/tests/ui/iter_skip_zero.stderr b/tests/ui/iter_skip_zero.stderr new file mode 100644 index 00000000000..80fecd59e6d --- /dev/null +++ b/tests/ui/iter_skip_zero.stderr @@ -0,0 +1,43 @@ +error: usage of `.skip(0)` + --> $DIR/iter_skip_zero.rs:12:35 + | +LL | let _ = [1, 2, 3].iter().skip(0); + | ^ help: if you meant to skip the first element, use: `1` + | + = note: this call to `skip` does nothing and is useless; remove it + = note: `-D clippy::iter-skip-zero` implied by `-D warnings` + +error: usage of `.skip(0)` + --> $DIR/iter_skip_zero.rs:13:39 + | +LL | let _ = vec![1, 2, 3].iter().skip(0); + | ^ help: if you meant to skip the first element, use: `1` + | + = note: this call to `skip` does nothing and is useless; remove it + +error: usage of `.skip(0)` + --> $DIR/iter_skip_zero.rs:14:34 + | +LL | let _ = once([1, 2, 3]).skip(0); + | ^ help: if you meant to skip the first element, use: `1` + | + = note: this call to `skip` does nothing and is useless; remove it + +error: usage of `.skip(0)` + --> $DIR/iter_skip_zero.rs:15:71 + | +LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); + | ^ help: if you meant to skip the first element, use: `1` + | + = note: this call to `skip` does nothing and is useless; remove it + +error: usage of `.skip(0)` + --> $DIR/iter_skip_zero.rs:15:62 + | +LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); + | ^ help: if you meant to skip the first element, use: `1` + | + = note: this call to `skip` does nothing and is useless; remove it + +error: aborting due to 5 previous errors + -- cgit 1.4.1-3-g733a5 From f583fd18e4d1ecb7a0c2c838a5ac0a10188f24db Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 9 Jul 2023 18:59:25 -0400 Subject: Fix `unwrap_or_else_default` false positive --- clippy_lints/src/methods/unwrap_or_else_default.rs | 6 +- clippy_utils/src/ty.rs | 3 + clippy_utils/src/ty/type_certainty/certainty.rs | 122 ++++++++ clippy_utils/src/ty/type_certainty/mod.rs | 315 +++++++++++++++++++++ tests/ui/unwrap_or_else_default.fixed | 37 +++ tests/ui/unwrap_or_else_default.rs | 37 +++ tests/ui/unwrap_or_else_default.stderr | 50 +++- 7 files changed, 568 insertions(+), 2 deletions(-) create mode 100644 clippy_utils/src/ty/type_certainty/certainty.rs create mode 100644 clippy_utils/src/ty/type_certainty/mod.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index 474a33b67e1..cfb1f7bbba8 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -4,7 +4,7 @@ use super::UNWRAP_OR_ELSE_DEFAULT; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_default_equivalent_call; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{expr_type_is_certain, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; @@ -17,6 +17,10 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'_>, u_arg: &'tcx hir::Expr<'_>, ) { + if !expr_type_is_certain(cx, recv) { + return; + } + // something.unwrap_or_else(Default::default) // ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 15a08370b6a..53152ab7e13 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -28,6 +28,9 @@ use std::iter; use crate::{match_def_path, path_res, paths}; +mod type_certainty; +pub use type_certainty::expr_type_is_certain; + /// Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty.is_copy_modulo_regions(cx.tcx, cx.param_env) diff --git a/clippy_utils/src/ty/type_certainty/certainty.rs b/clippy_utils/src/ty/type_certainty/certainty.rs new file mode 100644 index 00000000000..0e69ffa2212 --- /dev/null +++ b/clippy_utils/src/ty/type_certainty/certainty.rs @@ -0,0 +1,122 @@ +use rustc_hir::def_id::DefId; +use std::fmt::Debug; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Certainty { + /// Determining the type requires contextual information. + Uncertain, + + /// The type can be determined purely from subexpressions. If the argument is `Some(..)`, the + /// specific `DefId` is known. Such arguments are needed to handle path segments whose `res` is + /// `Res::Err`. + Certain(Option), + + /// The heuristic believes that more than one `DefId` applies to a type---this is a bug. + Contradiction, +} + +pub trait Meet { + fn meet(self, other: Self) -> Self; +} + +pub trait TryJoin: Sized { + fn try_join(self, other: Self) -> Option; +} + +impl Meet for Option { + fn meet(self, other: Self) -> Self { + match (self, other) { + (None, _) | (_, None) => None, + (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(lhs), + } + } +} + +impl TryJoin for Option { + fn try_join(self, other: Self) -> Option { + match (self, other) { + (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(Some(lhs)), + (Some(def_id), _) | (_, Some(def_id)) => Some(Some(def_id)), + (None, None) => Some(None), + } + } +} + +impl Meet for Certainty { + fn meet(self, other: Self) -> Self { + match (self, other) { + (Certainty::Uncertain, _) | (_, Certainty::Uncertain) => Certainty::Uncertain, + (Certainty::Certain(lhs), Certainty::Certain(rhs)) => Certainty::Certain(lhs.meet(rhs)), + (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner), + (Certainty::Contradiction, Certainty::Contradiction) => Certainty::Contradiction, + } + } +} + +impl Certainty { + /// Join two `Certainty`s preserving their `DefId`s (if any). Generally speaking, this method + /// should be used only when `self` and `other` refer directly to types. Otherwise, + /// `join_clearing_def_ids` should be used. + pub fn join(self, other: Self) -> Self { + match (self, other) { + (Certainty::Contradiction, _) | (_, Certainty::Contradiction) => Certainty::Contradiction, + + (Certainty::Certain(lhs), Certainty::Certain(rhs)) => { + if let Some(inner) = lhs.try_join(rhs) { + Certainty::Certain(inner) + } else { + debug_assert!(false, "Contradiction with {lhs:?} and {rhs:?}"); + Certainty::Contradiction + } + }, + + (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner), + + (Certainty::Uncertain, Certainty::Uncertain) => Certainty::Uncertain, + } + } + + /// Join two `Certainty`s after clearing their `DefId`s. This method should be used when `self` + /// or `other` do not necessarily refer to types, e.g., when they are aggregations of other + /// `Certainty`s. + pub fn join_clearing_def_ids(self, other: Self) -> Self { + self.clear_def_id().join(other.clear_def_id()) + } + + pub fn clear_def_id(self) -> Certainty { + if matches!(self, Certainty::Certain(_)) { + Certainty::Certain(None) + } else { + self + } + } + + pub fn with_def_id(self, def_id: DefId) -> Certainty { + if matches!(self, Certainty::Certain(_)) { + Certainty::Certain(Some(def_id)) + } else { + self + } + } + + pub fn to_def_id(self) -> Option { + match self { + Certainty::Certain(inner) => inner, + _ => None, + } + } + + pub fn is_certain(self) -> bool { + matches!(self, Self::Certain(_)) + } +} + +/// Think: `iter.all(/* is certain */)` +pub fn meet(iter: impl Iterator) -> Certainty { + iter.fold(Certainty::Certain(None), Certainty::meet) +} + +/// Think: `iter.any(/* is certain */)` +pub fn join(iter: impl Iterator) -> Certainty { + iter.fold(Certainty::Uncertain, Certainty::join) +} diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs new file mode 100644 index 00000000000..67c4a293a86 --- /dev/null +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -0,0 +1,315 @@ +//! A heuristic to tell whether an expression's type can be determined purely from its +//! subexpressions, and the arguments and locals they use. Put another way, `expr_type_is_certain` +//! tries to tell whether an expression's type can be determined without appeal to the surrounding +//! context. +//! +//! This is, in some sense, a counterpart to `let_unit_value`'s `expr_needs_inferred_result`. +//! Intuitively, that function determines whether an expression's type is needed for type inference, +//! whereas `expr_type_is_certain` determines whether type inference is needed for an expression's +//! type. +//! +//! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should +//! be considered a bug. + +use crate::def_path_res; +use rustc_hir::def::Res; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor}; +use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; +use rustc_span::{Span, Symbol}; + +mod certainty; +use certainty::{join, meet, Certainty, Meet}; + +pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + expr_type_certainty(cx, expr).is_certain() +} + +fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { + let certainty = match &expr.kind { + ExprKind::Unary(_, expr) + | ExprKind::Field(expr, _) + | ExprKind::Index(expr, _) + | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr), + + ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))), + + ExprKind::Call(callee, args) => { + let lhs = expr_type_certainty(cx, callee); + let rhs = if type_is_inferrable_from_arguments(cx, expr) { + meet(args.iter().map(|arg| expr_type_certainty(cx, arg))) + } else { + Certainty::Uncertain + }; + lhs.join_clearing_def_ids(rhs) + }, + + ExprKind::MethodCall(method, receiver, args, _) => { + let mut receiver_type_certainty = expr_type_certainty(cx, receiver); + // Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method + // identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`, + // for example. So update the `DefId` in `receiver_type_certainty` (if any). + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(self_ty_def_id) = adt_def_id(self_ty(cx, method_def_id)) + { + receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id); + }; + let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false); + let rhs = if type_is_inferrable_from_arguments(cx, expr) { + meet( + std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))), + ) + } else { + Certainty::Uncertain + }; + lhs.join(rhs) + }, + + ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))), + + ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)), + + ExprKind::Lit(_) => Certainty::Certain(None), + + ExprKind::Cast(_, ty) => type_certainty(cx, ty), + + ExprKind::If(_, if_expr, Some(else_expr)) => { + expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr)) + }, + + ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false), + + ExprKind::Struct(qpath, _, _) => qpath_certainty(cx, qpath, true), + + _ => Certainty::Uncertain, + }; + + let expr_ty = cx.typeck_results().expr_ty(expr); + if let Some(def_id) = adt_def_id(expr_ty) { + certainty.with_def_id(def_id) + } else { + certainty + } +} + +struct CertaintyVisitor<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + certainty: Certainty, +} + +impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> { + fn new(cx: &'cx LateContext<'tcx>) -> Self { + Self { + cx, + certainty: Certainty::Certain(None), + } + } +} + +impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> { + fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) { + self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true)); + if self.certainty != Certainty::Uncertain { + walk_qpath(self, qpath, hir_id); + } + } + + fn visit_ty(&mut self, ty: &'cx hir::Ty<'_>) { + if matches!(ty.kind, TyKind::Infer) { + self.certainty = Certainty::Uncertain; + } + if self.certainty != Certainty::Uncertain { + walk_ty(self, ty); + } + } +} + +fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty { + // Handle `TyKind::Path` specially so that its `DefId` can be preserved. + // + // Note that `CertaintyVisitor::new` initializes the visitor's internal certainty to + // `Certainty::Certain(None)`. Furthermore, if a `TyKind::Path` is encountered while traversing + // `ty`, the result of the call to `qpath_certainty` is combined with the visitor's internal + // certainty using `Certainty::meet`. Thus, if the `TyKind::Path` were not treated specially here, + // the resulting certainty would be `Certainty::Certain(None)`. + if let TyKind::Path(qpath) = &ty.kind { + return qpath_certainty(cx, qpath, true); + } + + let mut visitor = CertaintyVisitor::new(cx); + visitor.visit_ty(ty); + visitor.certainty +} + +fn generic_args_certainty(cx: &LateContext<'_>, args: &GenericArgs<'_>) -> Certainty { + let mut visitor = CertaintyVisitor::new(cx); + visitor.visit_generic_args(args); + visitor.certainty +} + +/// Tries to tell whether a `QPath` resolves to something certain, e.g., whether all of its path +/// segments generic arguments are are instantiated. +/// +/// `qpath` could refer to either a type or a value. The heuristic never needs the `DefId` of a +/// value. So `DefId`s are retained only when `resolves_to_type` is true. +fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bool) -> Certainty { + let certainty = match qpath { + QPath::Resolved(ty, path) => { + let len = path.segments.len(); + path.segments.iter().enumerate().fold( + ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)), + |parent_certainty, (i, path_segment)| { + path_segment_certainty(cx, parent_certainty, path_segment, i != len - 1 || resolves_to_type) + }, + ) + }, + + QPath::TypeRelative(ty, path_segment) => { + path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type) + }, + + QPath::LangItem(lang_item, _, _) => { + cx.tcx + .lang_items() + .get(*lang_item) + .map_or(Certainty::Uncertain, |def_id| { + let generics = cx.tcx.generics_of(def_id); + if generics.parent_count == 0 && generics.params.is_empty() { + Certainty::Certain(if resolves_to_type { Some(def_id) } else { None }) + } else { + Certainty::Uncertain + } + }) + }, + }; + debug_assert!(resolves_to_type || certainty.to_def_id().is_none()); + certainty +} + +fn path_segment_certainty( + cx: &LateContext<'_>, + parent_certainty: Certainty, + path_segment: &PathSegment<'_>, + resolves_to_type: bool, +) -> Certainty { + let certainty = match update_res(cx, parent_certainty, path_segment).unwrap_or(path_segment.res) { + // A definition's type is certain if it refers to something without generics (e.g., a crate or module, or + // an unparameterized type), or the generics are instantiated with arguments that are certain. + // + // If the parent is uncertain, then the current path segment must account for the parent's generic arguments. + // Consider the following examples, where the current path segment is `None`: + // - `Option::None` // uncertain; parent (i.e., `Option`) is uncertain + // - `Option::>::None` // certain; parent (i.e., `Option::<..>`) is certain + // - `Option::None::>` // certain; parent (i.e., `Option`) is uncertain + Res::Def(_, def_id) => { + // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE. + if cx.tcx.res_generics_def_id(path_segment.res).is_some() { + let generics = cx.tcx.generics_of(def_id); + let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && generics.params.is_empty() + { + Certainty::Certain(None) + } else { + Certainty::Uncertain + }; + let rhs = path_segment + .args + .map_or(Certainty::Uncertain, |args| generic_args_certainty(cx, args)); + // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value. + let certainty = lhs.join_clearing_def_ids(rhs); + if resolves_to_type { + certainty.with_def_id(def_id) + } else { + certainty + } + } else { + Certainty::Certain(None) + } + }, + + Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(_) => { + Certainty::Certain(None) + }, + + // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`. + Res::Local(hir_id) => match cx.tcx.hir().get_parent(hir_id) { + // An argument's type is always certain. + Node::Param(..) => Certainty::Certain(None), + // A local's type is certain if its type annotation is certain or it has an initializer whose + // type is certain. + Node::Local(local) => { + let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)); + let rhs = local + .init + .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init)); + let certainty = lhs.join(rhs); + if resolves_to_type { + certainty + } else { + certainty.clear_def_id() + } + }, + _ => Certainty::Uncertain, + }, + + _ => Certainty::Uncertain, + }; + debug_assert!(resolves_to_type || certainty.to_def_id().is_none()); + certainty +} + +/// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`. +/// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`. +fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option { + if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() { + let mut def_path = cx.get_def_path(def_id); + def_path.push(path_segment.ident.name); + let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::>()); + if let [res] = reses.as_slice() { Some(*res) } else { None } + } else { + None + } +} + +#[allow(clippy::cast_possible_truncation)] +fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let Some(callee_def_id) = (match expr.kind { + ExprKind::Call(callee, _) => { + let callee_ty = cx.typeck_results().expr_ty(callee); + if let ty::FnDef(callee_def_id, _) = callee_ty.kind() { + Some(*callee_def_id) + } else { + None + } + }, + ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id), + _ => None, + }) else { + return false; + }; + + let generics = cx.tcx.generics_of(callee_def_id); + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + + // Check that all type parameters appear in the functions input types. + (0..(generics.parent_count + generics.params.len()) as u32).all(|index| { + fn_sig + .inputs() + .iter() + .any(|input_ty| contains_param(*input_ty.skip_binder(), index)) + }) +} + +fn self_ty<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId) -> Ty<'tcx> { + cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()[0] +} + +fn adt_def_id(ty: Ty<'_>) -> Option { + ty.peel_refs().ty_adt_def().map(AdtDef::did) +} + +fn contains_param(ty: Ty<'_>, index: u32) -> bool { + ty.walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(ty) if ty.is_param(index))) +} diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 08b89a18bbb..e6b6ab359df 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -74,4 +74,41 @@ fn unwrap_or_else_default() { empty_string.unwrap_or_default(); } +fn type_certainty(option: Option>) { + option.unwrap_or_default().push(1); + + let option: std::option::Option> = None; + option.unwrap_or_default().push(1); + + let option: Option> = None; + option.unwrap_or_default().push(1); + + let option = std::option::Option::>::None; + option.unwrap_or_default().push(1); + + let option = Option::>::None; + option.unwrap_or_default().push(1); + + let option = std::option::Option::None::>; + option.unwrap_or_default().push(1); + + let option = Option::None::>; + option.unwrap_or_default().push(1); + + let option = None::>; + option.unwrap_or_default().push(1); + + // should not be changed: type annotation with infer, unconcretized initializer + let option: Option> = None; + option.unwrap_or_else(Vec::new).push(1); + + // should not be changed: no type annotation, unconcretized initializer + let option = Option::None; + option.unwrap_or_else(Vec::new).push(1); + + // should not be changed: no type annotation, unconcretized initializer + let option = None; + option.unwrap_or_else(Vec::new).push(1); +} + fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index ad2a744908f..38fa2e4595d 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -74,4 +74,41 @@ fn unwrap_or_else_default() { empty_string.unwrap_or_else(|| "".to_string()); } +fn type_certainty(option: Option>) { + option.unwrap_or_else(Vec::new).push(1); + + let option: std::option::Option> = None; + option.unwrap_or_else(Vec::new).push(1); + + let option: Option> = None; + option.unwrap_or_else(Vec::new).push(1); + + let option = std::option::Option::>::None; + option.unwrap_or_else(Vec::new).push(1); + + let option = Option::>::None; + option.unwrap_or_else(Vec::new).push(1); + + let option = std::option::Option::None::>; + option.unwrap_or_else(Vec::new).push(1); + + let option = Option::None::>; + option.unwrap_or_else(Vec::new).push(1); + + let option = None::>; + option.unwrap_or_else(Vec::new).push(1); + + // should not be changed: type annotation with infer, unconcretized initializer + let option: Option> = None; + option.unwrap_or_else(Vec::new).push(1); + + // should not be changed: no type annotation, unconcretized initializer + let option = Option::None; + option.unwrap_or_else(Vec::new).push(1); + + // should not be changed: no type annotation, unconcretized initializer + let option = None; + option.unwrap_or_else(Vec::new).push(1); +} + fn main() {} diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index d2b9212223f..a6815e8f916 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -36,5 +36,53 @@ error: use of `.unwrap_or_else(..)` to construct default value LL | empty_string.unwrap_or_else(|| "".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()` -error: aborting due to 6 previous errors +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:78:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:81:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:84:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:87:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:90:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:93:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:96:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:99:5 + | +LL | option.unwrap_or_else(Vec::new).push(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + +error: aborting due to 14 previous errors -- cgit 1.4.1-3-g733a5 From 84c411272d4ae8f0269747ce2d1fd7f4a3c2e158 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Wed, 19 Jul 2023 20:05:16 -0400 Subject: Merge `unwrap_or_else_default.rs` into `or_fun_call.rs` --- clippy_lints/src/methods/mod.rs | 33 +++++--- clippy_lints/src/methods/or_fun_call.rs | 93 ++++++++++++++++------ clippy_lints/src/methods/unwrap_or_else_default.rs | 70 ---------------- tests/ui/or_fun_call.fixed | 63 ++++++++++++++- tests/ui/or_fun_call.rs | 55 +++++++++++++ tests/ui/or_fun_call.stderr | 90 +++++++++++++-------- tests/ui/unwrap_or_else_default.fixed | 19 ++++- tests/ui/unwrap_or_else_default.rs | 19 ++++- tests/ui/unwrap_or_else_default.stderr | 92 +++++++++++---------- 9 files changed, 343 insertions(+), 191 deletions(-) delete mode 100644 clippy_lints/src/methods/unwrap_or_else_default.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index be71072acd6..ac3055f04ee 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -103,7 +103,6 @@ mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; mod unnecessary_sort_by; mod unnecessary_to_owned; -mod unwrap_or_else_default; mod unwrap_used; mod useless_asref; mod utils; @@ -476,29 +475,40 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and - /// `Result` values. + /// Checks for usages of the following functions with an argument that constructs a default value + /// (e.g., `Default::default` or `String::new`): + /// - `unwrap_or` + /// - `unwrap_or_else` + /// - `or_insert` + /// - `or_insert_with` /// /// ### Why is this bad? - /// Readability, these can be written as `_.unwrap_or_default`, which is - /// simpler and more concise. + /// Readability. Using `unwrap_or_default` in place of `unwrap_or`/`unwrap_or_else`, or `or_default` + /// in place of `or_insert`/`or_insert_with`, is simpler and more concise. + /// + /// ### Known problems + /// In some cases, the argument of `unwrap_or`, etc. is needed for type inference. The lint uses a + /// heuristic to try to identify such cases. However, the heuristic can produce false negatives. /// /// ### Examples /// ```rust /// # let x = Some(1); - /// x.unwrap_or_else(Default::default); - /// x.unwrap_or_else(u32::default); + /// # let mut map = std::collections::HashMap::::new(); + /// x.unwrap_or(Default::default()); + /// map.entry(42).or_insert_with(String::new); /// ``` /// /// Use instead: /// ```rust /// # let x = Some(1); + /// # let mut map = std::collections::HashMap::::new(); /// x.unwrap_or_default(); + /// map.entry(42).or_default(); /// ``` #[clippy::version = "1.56.0"] pub UNWRAP_OR_ELSE_DEFAULT, style, - "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`" + "using `.unwrap_or`, etc. with an argument that constructs a default value" } declare_clippy_lint! { @@ -3756,8 +3766,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); - let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) - .self_ty(); + let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); wrong_self_convention::check( cx, item.ident.name.as_str(), @@ -3774,8 +3783,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.owner_id); - let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) - .self_ty(); + let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); if !ret_ty.contains(self_ty); then { @@ -4134,7 +4142,6 @@ impl Methods { 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"); }, } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 9165c1248f0..1a5a65dbece 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,16 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{contains_return, is_trait_item, last_path_segment}; +use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item}; +use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty; use rustc_span::source_map::Span; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{self, sym, Symbol}; +use {rustc_ast as ast, rustc_hir as hir}; -use super::OR_FUN_CALL; +use super::{OR_FUN_CALL, UNWRAP_OR_ELSE_DEFAULT}; /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] @@ -24,44 +25,64 @@ pub(super) fn check<'tcx>( ) { /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`, /// `or_insert(T::new())` or `or_insert(T::default())`. + /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`, + /// `or_insert_with(T::new)` or `or_insert_with(T::default)`. #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, name: &str, + receiver: &hir::Expr<'_>, fun: &hir::Expr<'_>, - arg: &hir::Expr<'_>, - or_has_args: bool, + call_expr: Option<&hir::Expr<'_>>, span: Span, method_span: Span, ) -> bool { - let is_default_default = || is_trait_item(cx, fun, sym::Default); + if !expr_type_is_certain(cx, receiver) { + return false; + } + + let is_new = |fun: &hir::Expr<'_>| { + if let hir::ExprKind::Path(ref qpath) = fun.kind { + let path = last_path_segment(qpath).ident.name; + matches!(path, sym::new) + } else { + false + } + }; - let implements_default = |arg, default_trait_id| { - let arg_ty = cx.typeck_results().expr_ty(arg); - implements_trait(cx, arg_ty, default_trait_id, &[]) + let output_type_implements_default = |fun| { + let fun_ty = cx.typeck_results().expr_ty(fun); + if let ty::FnDef(def_id, substs) = fun_ty.kind() { + let output_ty = cx.tcx.fn_sig(def_id).subst(cx.tcx, substs).skip_binder().output(); + cx.tcx + .get_diagnostic_item(sym::Default) + .map_or(false, |default_trait_id| { + implements_trait(cx, output_ty, default_trait_id, substs) + }) + } else { + false + } }; if_chain! { - if !or_has_args; - if let Some(sugg) = match name { - "unwrap_or" => Some("unwrap_or_default"), - "or_insert" => Some("or_default"), + if let Some(sugg) = match (name, call_expr.is_some()) { + ("unwrap_or", true) | ("unwrap_or_else", false) => Some("unwrap_or_default"), + ("or_insert", true) | ("or_insert_with", false) => Some("or_default"), _ => None, }; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); - let path = last_path_segment(qpath).ident.name; // needs to target Default::default in particular or be *::new and have a Default impl // available - if (matches!(path, kw::Default) && is_default_default()) - || (matches!(path, sym::new) && implements_default(arg, default_trait_id)); - + if (is_new(fun) && output_type_implements_default(fun)) + || match call_expr { + Some(call_expr) => is_default_equivalent(cx, call_expr), + None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun), + }; then { span_lint_and_sugg( cx, - OR_FUN_CALL, + UNWRAP_OR_ELSE_DEFAULT, method_span.with_hi(span.hi()), - &format!("use of `{name}` followed by a call to `{path}`"), + &format!("use of `{name}` to construct default value"), "try", format!("{sugg}()"), Applicability::MachineApplicable, @@ -168,11 +189,16 @@ pub(super) fn check<'tcx>( match inner_arg.kind { hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) { + if or_has_args + || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span) + { let fun_span = if or_has_args { None } else { Some(fun.span) }; check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span); } }, + hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => { + check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span); + }, hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None); }, @@ -189,3 +215,22 @@ pub(super) fn check<'tcx>( } } } + +fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind { + let body = cx.tcx.hir().body(body); + + if body.params.is_empty() + && let hir::Expr{ kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind + && ident == &symbol::Ident::from_str("to_string") + && let hir::Expr{ kind, .. } = self_arg + && let hir::ExprKind::Lit(lit) = kind + && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node + { + return true; + } + } + + false +} diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs deleted file mode 100644 index cfb1f7bbba8..00000000000 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Lint for `some_result_or_option.unwrap_or_else(Default::default)` - -use super::UNWRAP_OR_ELSE_DEFAULT; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_default_equivalent_call; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{expr_type_is_certain, is_type_diagnostic_item}; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_span::{sym, symbol}; - -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - recv: &'tcx hir::Expr<'_>, - u_arg: &'tcx hir::Expr<'_>, -) { - if !expr_type_is_certain(cx, recv) { - return; - } - - // something.unwrap_or_else(Default::default) - // ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr - let recv_ty = cx.typeck_results().expr_ty(recv); - let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option); - let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result); - - if_chain! { - if is_option || is_result; - if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg); - then { - let mut applicability = Applicability::MachineApplicable; - - span_lint_and_sugg( - cx, - UNWRAP_OR_ELSE_DEFAULT, - expr.span, - "use of `.unwrap_or_else(..)` to construct default value", - "try", - format!( - "{}.unwrap_or_default()", - snippet_with_applicability(cx, recv.span, "..", &mut applicability) - ), - applicability, - ); - } - } -} - -fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind { - let body = cx.tcx.hir().body(body); - - if body.params.is_empty() - && let hir::Expr{ kind, .. } = &body.value - && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind - && ident == &symbol::Ident::from_str("to_string") - && let hir::Expr{ kind, .. } = self_arg - && let hir::ExprKind::Lit(lit) = kind - && let LitKind::Str(symbol::kw::Empty, _) = lit.node - { - return true; - } - } - - false -} diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 6deff0f3240..581f3ad45c7 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -190,7 +190,7 @@ mod issue8239 { acc.push_str(&f); acc }) - .unwrap_or_default(); + .unwrap_or(String::new()); } fn more_to_max_suggestion_highest_lines_1() { @@ -203,7 +203,7 @@ mod issue8239 { acc.push_str(&f); acc }) - .unwrap_or_default(); + .unwrap_or(String::new()); } fn equal_to_max_suggestion_highest_lines() { @@ -215,7 +215,7 @@ mod issue8239 { acc.push_str(&f); acc }) - .unwrap_or_default(); + .unwrap_or(String::new()); } fn less_than_max_suggestion_highest_lines() { @@ -226,7 +226,7 @@ mod issue8239 { acc.push_str(&f); acc }) - .unwrap_or_default(); + .unwrap_or(String::new()); } } @@ -257,4 +257,59 @@ mod issue8993 { } } +mod lazy { + use super::*; + + fn foo() { + struct Foo; + + impl Foo { + fn new() -> Foo { + Foo + } + } + + struct FakeDefault; + impl FakeDefault { + fn default() -> Self { + FakeDefault + } + } + + impl Default for FakeDefault { + fn default() -> Self { + FakeDefault + } + } + + let with_new = Some(vec![1]); + with_new.unwrap_or_default(); + + let with_default_trait = Some(1); + with_default_trait.unwrap_or_default(); + + let with_default_type = Some(1); + with_default_type.unwrap_or_default(); + + let real_default = None::; + real_default.unwrap_or_default(); + + let mut map = HashMap::::new(); + map.entry(42).or_default(); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_default(); + + let stringy = Some(String::new()); + let _ = stringy.unwrap_or_default(); + + // negative tests + let self_default = None::; + self_default.unwrap_or_else(::default); + + let without_default = Some(Foo); + without_default.unwrap_or_else(Foo::new); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index b05b33e6ee2..1f3987eb891 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -257,4 +257,59 @@ mod issue8993 { } } +mod lazy { + use super::*; + + fn foo() { + struct Foo; + + impl Foo { + fn new() -> Foo { + Foo + } + } + + struct FakeDefault; + impl FakeDefault { + fn default() -> Self { + FakeDefault + } + } + + impl Default for FakeDefault { + fn default() -> Self { + FakeDefault + } + } + + let with_new = Some(vec![1]); + with_new.unwrap_or_else(Vec::new); + + let with_default_trait = Some(1); + with_default_trait.unwrap_or_else(Default::default); + + let with_default_type = Some(1); + with_default_type.unwrap_or_else(u64::default); + + let real_default = None::; + real_default.unwrap_or_else(::default); + + let mut map = HashMap::::new(); + map.entry(42).or_insert_with(String::new); + + let mut btree = BTreeMap::::new(); + btree.entry(42).or_insert_with(String::new); + + let stringy = Some(String::new()); + let _ = stringy.unwrap_or_else(String::new); + + // negative tests + let self_default = None::; + self_default.unwrap_or_else(::default); + + let without_default = Some(Foo); + without_default.unwrap_or_else(Foo::new); + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 7342b0c2914..13d392461de 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -6,11 +6,13 @@ LL | with_constructor.unwrap_or(make()); | = note: `-D clippy::or-fun-call` implied by `-D warnings` -error: use of `unwrap_or` followed by a call to `new` +error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:56:14 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + | + = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:59:21 @@ -30,13 +32,13 @@ error: use of `unwrap_or` followed by a function call LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))` -error: use of `unwrap_or` followed by a call to `default` +error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:68:24 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `unwrap_or` followed by a call to `default` +error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:71:23 | LL | with_default_type.unwrap_or(u64::default()); @@ -48,13 +50,13 @@ error: use of `unwrap_or` followed by a function call LL | self_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(::default)` -error: use of `unwrap_or` followed by a call to `default` +error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:77:18 | LL | real_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `unwrap_or` followed by a call to `new` +error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:80:14 | LL | with_vec.unwrap_or(vec![]); @@ -66,31 +68,31 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)` -error: use of `or_insert` followed by a call to `new` +error: use of `or_insert` to construct default value --> $DIR/or_fun_call.rs:86:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` -error: use of `or_insert` followed by a call to `new` +error: use of `or_insert` to construct default value --> $DIR/or_fun_call.rs:89:23 | LL | map_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` -error: use of `or_insert` followed by a call to `new` +error: use of `or_insert` to construct default value --> $DIR/or_fun_call.rs:92:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` -error: use of `or_insert` followed by a call to `new` +error: use of `or_insert` to construct default value --> $DIR/or_fun_call.rs:95:25 | LL | btree_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` -error: use of `unwrap_or` followed by a call to `new` +error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:98:21 | LL | let _ = stringy.unwrap_or(String::new()); @@ -132,30 +134,6 @@ error: use of `unwrap_or` followed by a function call LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` -error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:193:14 - | -LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` - -error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:206:14 - | -LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` - -error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:218:14 - | -LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` - -error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:229:10 - | -LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` - error: use of `map_or` followed by a function call --> $DIR/or_fun_call.rs:254:25 | @@ -168,5 +146,47 @@ error: use of `map_or` followed by a function call LL | let _ = Some(4).map_or(g(), f); | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` -error: aborting due to 28 previous errors +error: use of `unwrap_or_else` to construct default value + --> $DIR/or_fun_call.rs:286:18 + | +LL | with_new.unwrap_or_else(Vec::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: use of `unwrap_or_else` to construct default value + --> $DIR/or_fun_call.rs:289:28 + | +LL | with_default_trait.unwrap_or_else(Default::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: use of `unwrap_or_else` to construct default value + --> $DIR/or_fun_call.rs:292:27 + | +LL | with_default_type.unwrap_or_else(u64::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: use of `unwrap_or_else` to construct default value + --> $DIR/or_fun_call.rs:295:22 + | +LL | real_default.unwrap_or_else(::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: use of `or_insert_with` to construct default value + --> $DIR/or_fun_call.rs:298:23 + | +LL | map.entry(42).or_insert_with(String::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` + +error: use of `or_insert_with` to construct default value + --> $DIR/or_fun_call.rs:301:25 + | +LL | btree.entry(42).or_insert_with(String::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` + +error: use of `unwrap_or_else` to construct default value + --> $DIR/or_fun_call.rs:304:25 + | +LL | let _ = stringy.unwrap_or_else(String::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: aborting due to 31 previous errors diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index e6b6ab359df..8c038c3647d 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -4,7 +4,7 @@ #![allow(dead_code)] #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] -/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint. +/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint. fn unwrap_or_else_default() { struct Foo; @@ -111,4 +111,21 @@ fn type_certainty(option: Option>) { option.unwrap_or_else(Vec::new).push(1); } +fn method_call_with_deref() { + use std::cell::RefCell; + use std::collections::HashMap; + + let cell = RefCell::new(HashMap::>::new()); + + let mut outer_map = cell.borrow_mut(); + + #[allow(unused_assignments)] + let mut option = None; + option = Some(0); + + let inner_map = outer_map.get_mut(&option.unwrap()).unwrap(); + + let _ = inner_map.entry(0).or_default(); +} + fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index 38fa2e4595d..47aadb68548 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -4,7 +4,7 @@ #![allow(dead_code)] #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] -/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint. +/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint. fn unwrap_or_else_default() { struct Foo; @@ -111,4 +111,21 @@ fn type_certainty(option: Option>) { option.unwrap_or_else(Vec::new).push(1); } +fn method_call_with_deref() { + use std::cell::RefCell; + use std::collections::HashMap; + + let cell = RefCell::new(HashMap::>::new()); + + let mut outer_map = cell.borrow_mut(); + + #[allow(unused_assignments)] + let mut option = None; + option = Some(0); + + let inner_map = outer_map.get_mut(&option.unwrap()).unwrap(); + + let _ = inner_map.entry(0).or_insert_with(Default::default); +} + fn main() {} diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index a6815e8f916..5486d82e8fa 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -1,88 +1,94 @@ -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:48:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:48:14 | LL | with_new.unwrap_or_else(Vec::new); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` | = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:62:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:62:23 | LL | with_real_default.unwrap_or_else(::default); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:65:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:65:24 | LL | with_default_trait.unwrap_or_else(Default::default); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:68:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:68:23 | LL | with_default_type.unwrap_or_else(u64::default); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:71:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:71:23 | LL | with_default_type.unwrap_or_else(Vec::new); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:74:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:74:18 | LL | empty_string.unwrap_or_else(|| "".to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:78:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:78:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:81:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:81:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:84:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:84:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:87:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:87:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:90:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:90:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:93:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:93:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:96:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:96:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: use of `.unwrap_or_else(..)` to construct default value - --> $DIR/unwrap_or_else_default.rs:99:5 +error: use of `unwrap_or_else` to construct default value + --> $DIR/unwrap_or_else_default.rs:99:12 | LL | option.unwrap_or_else(Vec::new).push(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `option.unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: aborting due to 14 previous errors +error: use of `or_insert_with` to construct default value + --> $DIR/unwrap_or_else_default.rs:128:32 + | +LL | let _ = inner_map.entry(0).or_insert_with(Default::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` + +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From e27977b84776b641ec48482f18c1dac7420a5830 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Wed, 19 Jul 2023 20:05:16 -0400 Subject: Rename `unwrap_or_else_default` to `unwrap_or_default` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 +- clippy_lints/src/methods/or_fun_call.rs | 4 +- clippy_lints/src/renamed_lints.rs | 1 + tests/ui/or_fun_call.stderr | 2 +- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 114 +++++++++++++++++--------------- tests/ui/unwrap_or_else_default.fixed | 2 +- tests/ui/unwrap_or_else_default.rs | 2 +- tests/ui/unwrap_or_else_default.stderr | 2 +- 12 files changed, 75 insertions(+), 63 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index acc9d8ffbf7..c50d28273bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5366,6 +5366,7 @@ Released 2018-09-13 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result +[`unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_default [`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default [`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used [`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 47995fea9f9..cb5fed5f109 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -422,7 +422,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, - crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO, + crate::methods::UNWRAP_OR_DEFAULT_INFO, crate::methods::UNWRAP_USED_INFO, crate::methods::USELESS_ASREF_INFO, crate::methods::VEC_RESIZE_TO_ZERO_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ac3055f04ee..1058289679b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -506,7 +506,7 @@ declare_clippy_lint! { /// map.entry(42).or_default(); /// ``` #[clippy::version = "1.56.0"] - pub UNWRAP_OR_ELSE_DEFAULT, + pub UNWRAP_OR_DEFAULT, style, "using `.unwrap_or`, etc. with an argument that constructs a default value" } @@ -3505,7 +3505,7 @@ impl_lint_pass!(Methods => [ SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, OK_EXPECT, - UNWRAP_OR_ELSE_DEFAULT, + UNWRAP_OR_DEFAULT, MAP_UNWRAP_OR, RESULT_MAP_OR_INTO_OPTION, OPTION_MAP_OR_NONE, diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 1a5a65dbece..d1899658b84 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -11,7 +11,7 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{self, sym, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; -use super::{OR_FUN_CALL, UNWRAP_OR_ELSE_DEFAULT}; +use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] @@ -80,7 +80,7 @@ pub(super) fn check<'tcx>( then { span_lint_and_sugg( cx, - UNWRAP_OR_ELSE_DEFAULT, + UNWRAP_OR_DEFAULT, method_span.with_hi(span.hi()), &format!("use of `{name}` to construct default value"), "try", diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index d24215c2292..13086f996ee 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::single_char_push_str", "clippy::single_char_add_str"), ("clippy::stutter", "clippy::module_name_repetitions"), ("clippy::to_string_in_display", "clippy::recursive_format_impl"), + ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), ("clippy::zero_width_space", "clippy::invisible_characters"), ("clippy::cast_ref_to_mut", "cast_ref_to_mut"), ("clippy::clone_double_ref", "suspicious_double_ref_op"), diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 13d392461de..519f0916562 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -12,7 +12,7 @@ error: use of `unwrap_or` to construct default value LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` | - = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` + = note: `-D clippy::unwrap-or-default` implied by `-D warnings` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:59:21 diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index cab02bb93c9..6936d526aeb 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -27,6 +27,7 @@ #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::recursive_format_impl)] +#![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] #![allow(cast_ref_to_mut)] #![allow(suspicious_double_ref_op)] @@ -78,6 +79,7 @@ #![warn(clippy::single_char_add_str)] #![warn(clippy::module_name_repetitions)] #![warn(clippy::recursive_format_impl)] +#![warn(clippy::unwrap_or_default)] #![warn(clippy::invisible_characters)] #![warn(cast_ref_to_mut)] #![warn(suspicious_double_ref_op)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index e5e31452149..626e5202025 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -27,6 +27,7 @@ #![allow(clippy::single_char_add_str)] #![allow(clippy::module_name_repetitions)] #![allow(clippy::recursive_format_impl)] +#![allow(clippy::unwrap_or_default)] #![allow(clippy::invisible_characters)] #![allow(cast_ref_to_mut)] #![allow(suspicious_double_ref_op)] @@ -78,6 +79,7 @@ #![warn(clippy::single_char_push_str)] #![warn(clippy::stutter)] #![warn(clippy::to_string_in_display)] +#![warn(clippy::unwrap_or_else_default)] #![warn(clippy::zero_width_space)] #![warn(clippy::cast_ref_to_mut)] #![warn(clippy::clone_double_ref)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 783608a0841..a0e0a66892e 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,316 +7,322 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` +error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` + --> $DIR/rename.rs:82:9 + | +LL | #![warn(clippy::unwrap_or_else_default)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` + error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `cast_ref_to_mut` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `cast_ref_to_mut` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> $DIR/rename.rs:97:9 + --> $DIR/rename.rs:99:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:98:9 + --> $DIR/rename.rs:100:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:99:9 + --> $DIR/rename.rs:101:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:100:9 + --> $DIR/rename.rs:102:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:101:9 + --> $DIR/rename.rs:103:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:102:9 + --> $DIR/rename.rs:104:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> $DIR/rename.rs:103:9 + --> $DIR/rename.rs:105:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:104:9 + --> $DIR/rename.rs:106:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:105:9 + --> $DIR/rename.rs:107:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 53 previous errors +error: aborting due to 54 previous errors diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 8c038c3647d..89a6b1395e5 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![warn(clippy::unwrap_or_else_default)] +#![warn(clippy::unwrap_or_default)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index 47aadb68548..e5ebf35adda 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![warn(clippy::unwrap_or_else_default)] +#![warn(clippy::unwrap_or_default)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index 5486d82e8fa..91e48375f18 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -4,7 +4,7 @@ error: use of `unwrap_or_else` to construct default value LL | with_new.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` | - = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` + = note: `-D clippy::unwrap-or-default` implied by `-D warnings` error: use of `unwrap_or_else` to construct default value --> $DIR/unwrap_or_else_default.rs:62:23 -- cgit 1.4.1-3-g733a5 From 99202a0b56e2ac801dfc8d6fe1a5ae539e6dbc15 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 22 Jul 2023 11:51:44 -0400 Subject: Start addressing review comments --- clippy_lints/src/methods/or_fun_call.rs | 53 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 27 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index d1899658b84..9fe863ecc0d 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -64,34 +64,33 @@ pub(super) fn check<'tcx>( } }; - if_chain! { - if let Some(sugg) = match (name, call_expr.is_some()) { - ("unwrap_or", true) | ("unwrap_or_else", false) => Some("unwrap_or_default"), - ("or_insert", true) | ("or_insert_with", false) => Some("or_default"), - _ => None, - }; - // needs to target Default::default in particular or be *::new and have a Default impl - // available - if (is_new(fun) && output_type_implements_default(fun)) - || match call_expr { - Some(call_expr) => is_default_equivalent(cx, call_expr), - None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun), - }; - then { - span_lint_and_sugg( - cx, - UNWRAP_OR_DEFAULT, - method_span.with_hi(span.hi()), - &format!("use of `{name}` to construct default value"), - "try", - format!("{sugg}()"), - Applicability::MachineApplicable, - ); + let sugg = match (name, call_expr.is_some()) { + ("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default", + ("or_insert", true) | ("or_insert_with", false) => "or_default", + _ => return false, + }; - true - } else { - false + // needs to target Default::default in particular or be *::new and have a Default impl + // available + if (is_new(fun) && output_type_implements_default(fun)) + || match call_expr { + Some(call_expr) => is_default_equivalent(cx, call_expr), + None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun), } + { + span_lint_and_sugg( + cx, + UNWRAP_OR_DEFAULT, + method_span.with_hi(span.hi()), + &format!("use of `{name}` to construct default value"), + "try", + format!("{sugg}()"), + Applicability::MachineApplicable, + ); + + true + } else { + false } } @@ -223,7 +222,7 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) if body.params.is_empty() && let hir::Expr{ kind, .. } = &body.value && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind - && ident == &symbol::Ident::from_str("to_string") + && ident.name == sym::to_string && let hir::Expr{ kind, .. } = self_arg && let hir::ExprKind::Lit(lit) = kind && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node -- cgit 1.4.1-3-g733a5 From 978b1daf99d8326718684381704902fdaaf71b18 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:56:52 -0500 Subject: New lint [`filter_map_bool_then`] --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/filter_map_bool_then.rs | 39 ++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 34 +++++++++++++++++++++ clippy_utils/src/paths.rs | 2 ++ tests/ui/filter_map_bool_then.fixed | 33 ++++++++++++++++++++ tests/ui/filter_map_bool_then.rs | 33 ++++++++++++++++++++ tests/ui/filter_map_bool_then.stderr | 28 +++++++++++++++++ 8 files changed, 171 insertions(+) create mode 100644 clippy_lints/src/methods/filter_map_bool_then.rs create mode 100644 tests/ui/filter_map_bool_then.fixed create mode 100644 tests/ui/filter_map_bool_then.rs create mode 100644 tests/ui/filter_map_bool_then.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 02d12d60e73..251f32d2e6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4844,6 +4844,7 @@ Released 2018-09-13 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map +[`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then [`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 9b99a255423..e084471433d 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -337,6 +337,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::EXPECT_USED_INFO, crate::methods::EXTEND_WITH_DRAIN_INFO, crate::methods::FILETYPE_IS_FILE_INFO, + crate::methods::FILTER_MAP_BOOL_THEN_INFO, crate::methods::FILTER_MAP_IDENTITY_INFO, crate::methods::FILTER_MAP_NEXT_INFO, crate::methods::FILTER_NEXT_INFO, diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs new file mode 100644 index 00000000000..e5d8be21f3d --- /dev/null +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::paths::BOOL_THEN; +use clippy_utils::source::snippet_opt; +use clippy_utils::{is_from_proc_macro, match_def_path, peel_blocks}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_span::Span; + +use super::FILTER_MAP_BOOL_THEN; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { + if !in_external_macro(cx.sess(), expr.span) + && let ExprKind::Closure(closure) = arg.kind + && let body = peel_blocks(cx.tcx.hir().body(closure.body).value) + && let ExprKind::MethodCall(_, recv, [then_arg], _) = body.kind + && let ExprKind::Closure(then_closure) = then_arg.kind + && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value) + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(body.hir_id) + && match_def_path(cx, def_id, &BOOL_THEN) + && !is_from_proc_macro(cx, expr) + && let Some(decl_snippet) = closure.fn_arg_span.and_then(|s| snippet_opt(cx, s)) + // NOTE: This will include the `()` (parenthesis) around it. Maybe there's some utils method + // to remove them? `unused_parens` will already take care of this but it may be nice. + && let Some(filter) = snippet_opt(cx, recv.span) + && let Some(map) = snippet_opt(cx, then_body.span) + { + span_lint_and_sugg( + cx, + FILTER_MAP_BOOL_THEN, + call_span, + "usage of `bool::then` in `filter_map`", + "use `filter` then `map` instead", + format!("filter({decl_snippet} {filter}).map({decl_snippet} {map})"), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1058289679b..e774450018e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -21,6 +21,7 @@ mod expect_used; mod extend_with_drain; mod filetype_is_file; mod filter_map; +mod filter_map_bool_then; mod filter_map_identity; mod filter_map_next; mod filter_next; @@ -3475,6 +3476,37 @@ declare_clippy_lint! { "disallows `.skip(0)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `bool::then` in `Iterator::filter_map`. + /// + /// ### Why is this bad? + /// This can be written with `filter` then `map` instead, which would reduce nesting and + /// separates the filtering from the transformation phase. This comes with no cost to + /// performance and is just cleaner. + /// + /// ### Limitations + /// Does not lint `bool::then_some`, as it eagerly evaluates its arguments rather than lazily. + /// This can create differing behavior, so better safe than sorry. + /// + /// ### Example + /// ```rust + /// # fn really_expensive_fn(i: i32) -> i32 { i } + /// # let v = vec![]; + /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i))); + /// ``` + /// Use instead: + /// ```rust + /// # fn really_expensive_fn(i: i32) -> i32 { i } + /// # let v = vec![]; + /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); + /// ``` + #[clippy::version = "1.72.0"] + pub FILTER_MAP_BOOL_THEN, + style, + "checks for usage of `bool::then` in `Iterator::filter_map`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3612,6 +3644,7 @@ impl_lint_pass!(Methods => [ FORMAT_COLLECT, STRING_LIT_CHARS_ANY, ITER_SKIP_ZERO, + FILTER_MAP_BOOL_THEN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3889,6 +3922,7 @@ impl Methods { }, ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg, name); + filter_map_bool_then::check(cx, expr, arg, call_span); filter_map_identity::check(cx, expr, arg, span); }, ("find_map", [arg]) => { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 8d96d3cfe50..914ea85ac28 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -163,3 +163,5 @@ pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"]; pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"]; pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"]; +#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so +pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed new file mode 100644 index 00000000000..0db0b0a8a28 --- /dev/null +++ b/tests/ui/filter_map_bool_then.fixed @@ -0,0 +1,33 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::clone_on_copy, clippy::unnecessary_lazy_evaluations, unused)] +#![warn(clippy::filter_map_bool_then)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().into_iter().filter(|i| (i % 2 == 0)).map(|i| i + 1); + v.clone() + .into_iter() + .filter(|i| (i % 2 == 0)).map(|i| i + 1); + v.clone() + .into_iter() + .filter(|&i| i != 1000) + .filter(|i| (i % 2 == 0)).map(|i| i + 1); + v.iter() + .copied() + .filter(|&i| i != 1000) + .filter(|i| (i.clone() % 2 == 0)).map(|i| i + 1); + // Do not lint + external! { + let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + } + with_span! { + span + let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + } +} diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs new file mode 100644 index 00000000000..764f9c4a85e --- /dev/null +++ b/tests/ui/filter_map_bool_then.rs @@ -0,0 +1,33 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::clone_on_copy, clippy::unnecessary_lazy_evaluations, unused)] +#![warn(clippy::filter_map_bool_then)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + v.clone() + .into_iter() + .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); + v.clone() + .into_iter() + .filter(|&i| i != 1000) + .filter_map(|i| (i % 2 == 0).then(|| i + 1)); + v.iter() + .copied() + .filter(|&i| i != 1000) + .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); + // Do not lint + external! { + let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + } + with_span! { + span + let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + } +} diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr new file mode 100644 index 00000000000..79bc7ba02f7 --- /dev/null +++ b/tests/ui/filter_map_bool_then.stderr @@ -0,0 +1,28 @@ +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:11:27 + | +LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i % 2 == 0)).map(|i| i + 1)` + | + = note: `-D clippy::filter-map-bool-then` implied by `-D warnings` + +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:14:10 + | +LL | .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i % 2 == 0)).map(|i| i + 1)` + +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:18:10 + | +LL | .filter_map(|i| (i % 2 == 0).then(|| i + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i % 2 == 0)).map(|i| i + 1)` + +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:22:10 + | +LL | .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i.clone() % 2 == 0)).map(|i| i + 1)` + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 3235d9d612909bc64550eea3a0d387e1187e93dd Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Sun, 16 Jul 2023 05:30:01 -0500 Subject: Only lint `Copy` types --- clippy_lints/src/methods/filter_map_bool_then.rs | 24 ++++++++++++++-------- tests/ui/filter_map_bool_then.fixed | 21 ++++++++++++++----- tests/ui/filter_map_bool_then.rs | 13 +++++++++++- tests/ui/filter_map_bool_then.stderr | 26 +++++++++++++++--------- 4 files changed, 59 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index e5d8be21f3d..4aee22a4afc 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,28 +1,34 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; use clippy_utils::source::snippet_opt; -use clippy_utils::{is_from_proc_macro, match_def_path, peel_blocks}; +use clippy_utils::ty::is_copy; +use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::FILTER_MAP_BOOL_THEN; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { if !in_external_macro(cx.sess(), expr.span) + && is_trait_method(cx, expr, sym::Iterator) && let ExprKind::Closure(closure) = arg.kind - && let body = peel_blocks(cx.tcx.hir().body(closure.body).value) - && let ExprKind::MethodCall(_, recv, [then_arg], _) = body.kind + && let body = cx.tcx.hir().body(closure.body) + && let value = peel_blocks(body.value) + // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both + // `inputs` and `params` here as we need both the type and the span + && let param_ty = closure.fn_decl.inputs[0] + && let param = body.params[0] + && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs()) + && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind && let ExprKind::Closure(then_closure) = then_arg.kind && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value) - && let Some(def_id) = cx.typeck_results().type_dependent_def_id(body.hir_id) + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) && match_def_path(cx, def_id, &BOOL_THEN) && !is_from_proc_macro(cx, expr) - && let Some(decl_snippet) = closure.fn_arg_span.and_then(|s| snippet_opt(cx, s)) - // NOTE: This will include the `()` (parenthesis) around it. Maybe there's some utils method - // to remove them? `unused_parens` will already take care of this but it may be nice. + && let Some(param_snippet) = snippet_opt(cx, param.span) && let Some(filter) = snippet_opt(cx, recv.span) && let Some(map) = snippet_opt(cx, then_body.span) { @@ -32,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & call_span, "usage of `bool::then` in `filter_map`", "use `filter` then `map` instead", - format!("filter({decl_snippet} {filter}).map({decl_snippet} {map})"), + format!("filter(|&{param_snippet}| {filter}).map(|{param_snippet}| {map})"), Applicability::MachineApplicable, ); } diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed index 0db0b0a8a28..3e72fee4b07 100644 --- a/tests/ui/filter_map_bool_then.fixed +++ b/tests/ui/filter_map_bool_then.fixed @@ -1,26 +1,37 @@ //@run-rustfix //@aux-build:proc_macros.rs:proc-macro -#![allow(clippy::clone_on_copy, clippy::unnecessary_lazy_evaluations, unused)] +#![allow( + clippy::clone_on_copy, + clippy::map_identity, + clippy::unnecessary_lazy_evaluations, + unused +)] #![warn(clippy::filter_map_bool_then)] #[macro_use] extern crate proc_macros; +#[derive(Clone, PartialEq)] +struct NonCopy; + fn main() { let v = vec![1, 2, 3, 4, 5, 6]; - v.clone().into_iter().filter(|i| (i % 2 == 0)).map(|i| i + 1); + v.clone().iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1); + v.clone().into_iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1); v.clone() .into_iter() - .filter(|i| (i % 2 == 0)).map(|i| i + 1); + .filter(|&i| (i % 2 == 0)).map(|i| i + 1); v.clone() .into_iter() .filter(|&i| i != 1000) - .filter(|i| (i % 2 == 0)).map(|i| i + 1); + .filter(|&i| (i % 2 == 0)).map(|i| i + 1); v.iter() .copied() .filter(|&i| i != 1000) - .filter(|i| (i.clone() % 2 == 0)).map(|i| i + 1); + .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1); // Do not lint + let v = vec![NonCopy, NonCopy]; + v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); external! { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs index 764f9c4a85e..38a04e57de4 100644 --- a/tests/ui/filter_map_bool_then.rs +++ b/tests/ui/filter_map_bool_then.rs @@ -1,13 +1,22 @@ //@run-rustfix //@aux-build:proc_macros.rs:proc-macro -#![allow(clippy::clone_on_copy, clippy::unnecessary_lazy_evaluations, unused)] +#![allow( + clippy::clone_on_copy, + clippy::map_identity, + clippy::unnecessary_lazy_evaluations, + unused +)] #![warn(clippy::filter_map_bool_then)] #[macro_use] extern crate proc_macros; +#[derive(Clone, PartialEq)] +struct NonCopy; + fn main() { let v = vec![1, 2, 3, 4, 5, 6]; + v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); v.clone() .into_iter() @@ -21,6 +30,8 @@ fn main() { .filter(|&i| i != 1000) .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); // Do not lint + let v = vec![NonCopy, NonCopy]; + v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); external! { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr index 79bc7ba02f7..b411cd83dfd 100644 --- a/tests/ui/filter_map_bool_then.stderr +++ b/tests/ui/filter_map_bool_then.stderr @@ -1,28 +1,34 @@ error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:11:27 + --> $DIR/filter_map_bool_then.rs:19:22 | -LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i % 2 == 0)).map(|i| i + 1)` +LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` | = note: `-D clippy::filter-map-bool-then` implied by `-D warnings` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:14:10 + --> $DIR/filter_map_bool_then.rs:20:27 + | +LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` + +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:23:10 | LL | .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i % 2 == 0)).map(|i| i + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:18:10 + --> $DIR/filter_map_bool_then.rs:27:10 | LL | .filter_map(|i| (i % 2 == 0).then(|| i + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i % 2 == 0)).map(|i| i + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:22:10 + --> $DIR/filter_map_bool_then.rs:31:10 | LL | .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|i| (i.clone() % 2 == 0)).map(|i| i + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From 136339f2d307cb819b61573c37e4bb5d155a6d9c Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 22 Jul 2023 02:17:51 +0200 Subject: new lint: [`readonly_write_lock`] --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 36 +++++++++++++++++ clippy_lints/src/methods/readonly_write_lock.rs | 51 +++++++++++++++++++++++++ tests/ui/readonly_write_lock.rs | 42 ++++++++++++++++++++ tests/ui/readonly_write_lock.stderr | 16 ++++++++ 6 files changed, 147 insertions(+) create mode 100644 clippy_lints/src/methods/readonly_write_lock.rs create mode 100644 tests/ui/readonly_write_lock.rs create mode 100644 tests/ui/readonly_write_lock.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 251f32d2e6e..2655d93599e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5181,6 +5181,7 @@ Released 2018-09-13 [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex [`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim [`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec +[`readonly_write_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#readonly_write_lock [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation [`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e084471433d..d4e0d286334 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -398,6 +398,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, + crate::methods::READONLY_WRITE_LOCK_INFO, crate::methods::READ_LINE_WITHOUT_TRIM_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e774450018e..0e02c6d8e1b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -76,6 +76,7 @@ mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; mod read_line_without_trim; +mod readonly_write_lock; mod repeat_once; mod search_is_some; mod seek_from_current; @@ -3507,6 +3508,37 @@ declare_clippy_lint! { "checks for usage of `bool::then` in `Iterator::filter_map`" } +declare_clippy_lint! { + /// ### What it does + /// Looks for calls to `RwLock::write` where the lock is only used for reading. + /// + /// ### Why is this bad? + /// The write portion of `RwLock` is exclusive, meaning that no other thread + /// can access the lock while this writer is active. + /// + /// ### Example + /// ```rust + /// use std::sync::RwLock; + /// fn assert_is_zero(lock: &RwLock) { + /// let num = lock.write().unwrap(); + /// assert_eq!(*num, 0); + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// use std::sync::RwLock; + /// fn assert_is_zero(lock: &RwLock) { + /// let num = lock.read().unwrap(); + /// assert_eq!(*num, 0); + /// } + /// ``` + #[clippy::version = "1.73.0"] + pub READONLY_WRITE_LOCK, + nursery, + "acquiring a writer lock when a reader lock would work" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3645,6 +3677,7 @@ impl_lint_pass!(Methods => [ STRING_LIT_CHARS_ANY, ITER_SKIP_ZERO, FILTER_MAP_BOOL_THEN, + READONLY_WRITE_LOCK ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4188,6 +4221,9 @@ impl Methods { range_zip_with_len::check(cx, expr, iter_recv, arg); } }, + ("write", []) => { + readonly_write_lock::check(cx, expr, recv); + } _ => {}, } } diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs new file mode 100644 index 00000000000..404ded2b013 --- /dev/null +++ b/clippy_lints/src/methods/readonly_write_lock.rs @@ -0,0 +1,51 @@ +use super::READONLY_WRITE_LOCK; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::mir::{enclosing_mir, visit_local_usage}; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Node}; +use rustc_lint::LateContext; +use rustc_middle::mir::{Location, START_BLOCK}; +use rustc_span::sym; + +fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let ExprKind::MethodCall(path, receiver, ..) = expr.kind + && path.ident.name == sym::unwrap + { + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result) + } else { + false + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock) + && let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id) + && is_unwrap_call(cx, unwrap_call_expr) + && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id) + && let Node::Local(local) = parent + && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) + && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| { + local.span.contains(decl.source_info.span) + }) + && let Some(usage) = visit_local_usage(&[local], mir, Location { + block: START_BLOCK, + statement_index: 0, + }) + { + let writer_never_mutated = usage[0].local_consume_or_mutate_locs.is_empty(); + + if writer_never_mutated { + span_lint_and_sugg( + cx, + READONLY_WRITE_LOCK, + expr.span, + "this write lock is used only for reading", + "consider using a read lock instead", + format!("{}.read()", snippet(cx, receiver.span, "")), + Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness + ); + } + } +} diff --git a/tests/ui/readonly_write_lock.rs b/tests/ui/readonly_write_lock.rs new file mode 100644 index 00000000000..656b45787e8 --- /dev/null +++ b/tests/ui/readonly_write_lock.rs @@ -0,0 +1,42 @@ +#![warn(clippy::readonly_write_lock)] + +use std::sync::RwLock; + +fn mutate_i32(x: &mut i32) { + *x += 1; +} + +fn accept_i32(_: i32) {} + +fn main() { + let lock = RwLock::new(42); + let lock2 = RwLock::new(1234); + + { + let writer = lock.write().unwrap(); + dbg!(&writer); + } + + { + let writer = lock.write().unwrap(); + accept_i32(*writer); + } + + { + let mut writer = lock.write().unwrap(); + mutate_i32(&mut writer); + dbg!(&writer); + } + + { + let mut writer = lock.write().unwrap(); + *writer += 1; + } + + { + let mut writer1 = lock.write().unwrap(); + let mut writer2 = lock2.write().unwrap(); + *writer2 += 1; + *writer1 = *writer2; + } +} diff --git a/tests/ui/readonly_write_lock.stderr b/tests/ui/readonly_write_lock.stderr new file mode 100644 index 00000000000..e3d8fce7b2c --- /dev/null +++ b/tests/ui/readonly_write_lock.stderr @@ -0,0 +1,16 @@ +error: this write lock is used only for reading + --> $DIR/readonly_write_lock.rs:16:22 + | +LL | let writer = lock.write().unwrap(); + | ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()` + | + = note: `-D clippy::readonly-write-lock` implied by `-D warnings` + +error: this write lock is used only for reading + --> $DIR/readonly_write_lock.rs:21:22 + | +LL | let writer = lock.write().unwrap(); + | ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 205a3741c1659b5157a5dfdaec2476c8a151ada2 Mon Sep 17 00:00:00 2001 From: Timo <30553356+y21@users.noreply.github.com> Date: Thu, 27 Jul 2023 20:37:15 +0200 Subject: make lint description more consistent (writer/reader -> write/read) Co-authored-by: Takayuki Nakata --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0e02c6d8e1b..bca2039860d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3536,7 +3536,7 @@ declare_clippy_lint! { #[clippy::version = "1.73.0"] pub READONLY_WRITE_LOCK, nursery, - "acquiring a writer lock when a reader lock would work" + "acquiring a write lock when a read lock would work" } pub struct Methods { -- cgit 1.4.1-3-g733a5 From 5e88003ddac563a8ffc912d6e69332d479a92cc3 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 28 Jul 2023 12:52:06 +0200 Subject: pattern match on local usage slice to avoid ICE --- clippy_lints/src/methods/readonly_write_lock.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs index 404ded2b013..e3ec921da0c 100644 --- a/clippy_lints/src/methods/readonly_write_lock.rs +++ b/clippy_lints/src/methods/readonly_write_lock.rs @@ -29,12 +29,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| { local.span.contains(decl.source_info.span) }) - && let Some(usage) = visit_local_usage(&[local], mir, Location { + && let Some(usages) = visit_local_usage(&[local], mir, Location { block: START_BLOCK, statement_index: 0, }) + && let [usage] = usages.as_slice() { - let writer_never_mutated = usage[0].local_consume_or_mutate_locs.is_empty(); + let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty(); if writer_never_mutated { span_lint_and_sugg( -- cgit 1.4.1-3-g733a5 From 71cc39e1f2f4cd7e8cd6fa09c65ecab06ce9cc80 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 30 Jul 2023 00:00:19 -0400 Subject: Add debug assertions to `implements_trait` Improve debug assertions for `make_projection` --- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/incorrect_impls.rs | 8 +- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 10 +- clippy_utils/src/ty.rs | 184 +++++++++++++++------------ 6 files changed, 117 insertions(+), 93 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index c343f248d06..ad7b3b27383 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -471,12 +471,12 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id); - if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []); + if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]); // If all of our fields implement `Eq`, we can implement `Eq` too if adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, [])); + .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[])); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs index bce010bb168..f4edb17ae80 100644 --- a/clippy_lints/src/incorrect_impls.rs +++ b/clippy_lints/src/incorrect_impls.rs @@ -189,12 +189,8 @@ impl LateLintPass<'_> for IncorrectImpls { .diagnostic_items(trait_impl.def_id.krate) .name_to_id .get(&sym::Ord) - && implements_trait( - cx, - hir_ty_to_ty(cx.tcx, imp.self_ty), - *ord_def_id, - trait_impl.args, - ) + && trait_impl.self_ty() == trait_impl.args.type_at(1) + && implements_trait(cx, hir_ty_to_ty(cx.tcx, imp.self_ty), *ord_def_id, &[]) { // If the `cmp` call likely needs to be fully qualified in the suggestion // (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index a84a0a6eeb8..7b8c88235a9 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -109,7 +109,7 @@ fn is_ref_iterable<'tcx>( && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output && let param_env = cx.tcx.param_env(fn_id) - && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, []) + && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[]) && let Some(into_iter_ty) = make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty]) && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 23039f2f3f1..8b2f57160af 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -57,7 +57,7 @@ pub(super) fn check<'tcx>( cx.tcx .get_diagnostic_item(sym::Default) .map_or(false, |default_trait_id| { - implements_trait(cx, output_ty, default_trait_id, args) + implements_trait(cx, output_ty, default_trait_id, &[]) }) } else { false diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5e26601537f..5ee26966fa7 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::ptr::get_spans; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ - implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item, + implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; @@ -182,7 +182,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !ty.is_mutable_ptr(); if !is_copy(cx, ty); if ty.is_sized(cx.tcx, cx.param_env); - if !allowed_traits.iter().any(|&t| implements_trait_with_env(cx.tcx, cx.param_env, ty, t, [None])); + if !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter( + cx.tcx, + cx.param_env, + ty, + t, + [Option::>::None], + )); if !implements_borrow_trait; if !all_borrowable_trait; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 44ec8813f19..dbb6b986952 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -3,6 +3,7 @@ #![allow(clippy::module_name_repetitions)] use core::ops::ControlFlow; +use itertools::Itertools; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -13,17 +14,19 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; +use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, IntTy, - List, ParamEnv, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - UintTy, VariantDef, VariantDiscr, + self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, + GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{Size, VariantIdx}; -use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; +use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::iter; use crate::{match_def_path, path_res, paths}; @@ -207,15 +210,9 @@ pub fn implements_trait<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, trait_id: DefId, - ty_params: &[GenericArg<'tcx>], + args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env( - cx.tcx, - cx.param_env, - ty, - trait_id, - ty_params.iter().map(|&arg| Some(arg)), - ) + implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. @@ -224,7 +221,18 @@ pub fn implements_trait_with_env<'tcx>( param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, - ty_params: impl IntoIterator>>, + args: &[GenericArg<'tcx>], +) -> bool { + implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, args.iter().map(|&x| Some(x))) +} + +/// Same as `implements_trait_from_env` but takes the arguments as an iterator. +pub fn implements_trait_with_env_from_iter<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + trait_id: DefId, + args: impl IntoIterator>>>, ) -> bool { // Clippy shouldn't have infer types assert!(!ty.has_infer()); @@ -233,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>( if ty.has_escaping_bound_vars() { return false; } + let infcx = tcx.infer_ctxt().build(); - let orig = TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: DUMMY_SP, - }; - let ty_params = tcx.mk_args_from_iter( - ty_params + let trait_ref = TraitRef::new( + tcx, + trait_id, + Some(GenericArg::from(ty)) .into_iter() - .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())), + .chain(args.into_iter().map(|arg| { + arg.into().unwrap_or_else(|| { + let orig = TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }; + infcx.next_ty_var(orig).into() + }) + })), ); + + debug_assert_eq!(tcx.def_kind(trait_id), DefKind::Trait); + #[cfg(debug_assertions)] + assert_generic_args_match(tcx, trait_id, trait_ref.args); + + let obligation = Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + }; infcx - .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env) - .must_apply_modulo_regions() + .evaluate_obligation(&obligation) + .is_ok_and(EvaluationResult::must_apply_modulo_regions) } /// Checks whether this type implements `Drop`. @@ -1014,12 +1040,60 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { } } +/// Asserts that the given arguments match the generic parameters of the given item. +#[allow(dead_code)] +fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) { + let g = tcx.generics_of(did); + let parent = g.parent.map(|did| tcx.generics_of(did)); + let count = g.parent_count + g.params.len(); + let params = parent + .map_or([].as_slice(), |p| p.params.as_slice()) + .iter() + .chain(&g.params) + .map(|x| &x.kind); + + assert!( + count == args.len(), + "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\ + note: the expected arguments are: `[{}]`\n\ + the given arguments are: `{args:#?}`", + args.len(), + params.clone().map(GenericParamDefKind::descr).format(", "), + ); + + if let Some((idx, (param, arg))) = + params + .clone() + .zip(args.iter().map(|&x| x.unpack())) + .enumerate() + .find(|(_, (param, arg))| match (param, arg) { + (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_)) + | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_)) + | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false, + ( + GenericParamDefKind::Lifetime + | GenericParamDefKind::Type { .. } + | GenericParamDefKind::Const { .. }, + _, + ) => true, + }) + { + panic!( + "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n\ + note: the expected arguments are `[{}]`\n\ + the given arguments are `{args:#?}`", + param.descr(), + params.clone().map(GenericParamDefKind::descr).format(", "), + ); + } +} + /// Makes the projection type for the named associated type in the given impl or trait impl. /// /// This function is for associated types which are "known" to exist, and as such, will only return /// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions /// enabled this will check that the named associated type exists, the correct number of -/// substitutions are given, and that the correct kinds of substitutions are given (lifetime, +/// arguments are given, and that the correct kinds of arguments are given (lifetime, /// constant or type). This will not check if type normalization would succeed. pub fn make_projection<'tcx>( tcx: TyCtxt<'tcx>, @@ -1043,49 +1117,7 @@ pub fn make_projection<'tcx>( return None; }; #[cfg(debug_assertions)] - { - let generics = tcx.generics_of(assoc_item.def_id); - let generic_count = generics.parent_count + generics.params.len(); - let params = generics - .parent - .map_or([].as_slice(), |id| &*tcx.generics_of(id).params) - .iter() - .chain(&generics.params) - .map(|x| &x.kind); - - debug_assert!( - generic_count == args.len(), - "wrong number of args for `{:?}`: found `{}` expected `{generic_count}`.\n\ - note: the expected parameters are: {:#?}\n\ - the given arguments are: `{args:#?}`", - assoc_item.def_id, - args.len(), - params.map(ty::GenericParamDefKind::descr).collect::>(), - ); - - if let Some((idx, (param, arg))) = params - .clone() - .zip(args.iter().map(GenericArg::unpack)) - .enumerate() - .find(|(_, (param, arg))| { - !matches!( - (param, arg), - (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_)) - | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_)) - | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) - ) - }) - { - debug_assert!( - false, - "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\ - note: the expected parameters are {:#?}\n\ - the given arguments are {args:#?}", - param.descr(), - params.map(ty::GenericParamDefKind::descr).collect::>() - ); - } - } + assert_generic_args_match(tcx, assoc_item.def_id, args); Some(tcx.mk_alias_ty(assoc_item.def_id, args)) } @@ -1100,7 +1132,7 @@ pub fn make_projection<'tcx>( /// Normalizes the named associated type in the given impl or trait impl. /// /// This function is for associated types which are "known" to be valid with the given -/// substitutions, and as such, will only return `None` when debug assertions are disabled in order +/// arguments, and as such, will only return `None` when debug assertions are disabled in order /// to prevent ICE's. With debug assertions enabled this will check that type normalization /// succeeds as well as everything checked by `make_projection`. pub fn make_normalized_projection<'tcx>( @@ -1112,17 +1144,12 @@ pub fn make_normalized_projection<'tcx>( ) -> Option> { fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { #[cfg(debug_assertions)] - if let Some((i, subst)) = ty - .args - .iter() - .enumerate() - .find(|(_, subst)| subst.has_late_bound_regions()) - { + if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) { debug_assert!( false, "args contain late-bound region at index `{i}` which can't be normalized.\n\ use `TyCtxt::erase_late_bound_regions`\n\ - note: subst is `{subst:#?}`", + note: arg is `{arg:#?}`", ); return None; } @@ -1190,17 +1217,12 @@ pub fn make_normalized_projection_with_regions<'tcx>( ) -> Option> { fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { #[cfg(debug_assertions)] - if let Some((i, subst)) = ty - .args - .iter() - .enumerate() - .find(|(_, subst)| subst.has_late_bound_regions()) - { + if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) { debug_assert!( false, "args contain late-bound region at index `{i}` which can't be normalized.\n\ use `TyCtxt::erase_late_bound_regions`\n\ - note: subst is `{subst:#?}`", + note: arg is `{arg:#?}`", ); return None; } -- cgit 1.4.1-3-g733a5 From 008746cae4976baab645a6ca2d49f8392ded68ae Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 30 Jul 2023 13:41:58 +0200 Subject: [`unnecessary_find_map`]: look for then_some --- clippy_lints/src/methods/unnecessary_filter_map.rs | 10 ++++++++++ tests/ui/unnecessary_find_map.rs | 4 ++++ tests/ui/unnecessary_find_map.stderr | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index cc64a2e7948..fabf3fa0c0c 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -77,6 +77,16 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } (true, true) }, + hir::ExprKind::MethodCall(segment, recv, [arg], _) => { + if segment.ident.name == sym!(then_some) + && cx.typeck_results().expr_ty(recv).is_bool() + && path_to_local_id(arg, arg_id) + { + (false, true) + } else { + (true, true) + } + }, hir::ExprKind::Block(block, _) => block .expr .as_ref() diff --git a/tests/ui/unnecessary_find_map.rs b/tests/ui/unnecessary_find_map.rs index a52390861b4..3be41b775aa 100644 --- a/tests/ui/unnecessary_find_map.rs +++ b/tests/ui/unnecessary_find_map.rs @@ -21,3 +21,7 @@ fn main() { fn find_map_none_changes_item_type() -> Option { "".chars().find_map(|_| None) } + +fn issue11260() { + let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); +} diff --git a/tests/ui/unnecessary_find_map.stderr b/tests/ui/unnecessary_find_map.stderr index fb33c122fe3..3d6ef4f44fd 100644 --- a/tests/ui/unnecessary_find_map.stderr +++ b/tests/ui/unnecessary_find_map.stderr @@ -34,5 +34,11 @@ error: this `.find_map` can be written more simply using `.map(..).next()` LL | let _ = (0..4).find_map(|x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: this `.find_map` can be written more simply using `.find` + --> $DIR/unnecessary_find_map.rs:26:14 + | +LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From 72074a0f002dd67aa87f2bd913e8811972dcc415 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 2 Aug 2023 13:38:59 +0800 Subject: Alphabetically order arms in methods/mod.rs match --- clippy_lints/src/methods/mod.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index dd694ce7393..62d565bcc5c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3881,6 +3881,13 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, + ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params + && let Some(("chars", recv, _, _, _)) = method_call(recv) => + { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + } ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); } @@ -3999,15 +4006,6 @@ impl Methods { unnecessary_join::check(cx, expr, recv, join_arg, span); } }, - ("skip", [arg]) => { - iter_skip_zero::check(cx, expr, arg); - - 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); - } - } - } ("last", []) => { if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { @@ -4060,13 +4058,6 @@ impl Methods { } } }, - ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params - && let Some(("chars", recv, _, _, _)) = method_call(recv) => - { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); - } ("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), @@ -4120,6 +4111,15 @@ impl Methods { seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } }, + ("skip", [arg]) => { + iter_skip_zero::check(cx, expr, arg); + + 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); + } + } + } ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, @@ -4214,6 +4214,9 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, + ("write", []) => { + readonly_write_lock::check(cx, expr, recv); + } ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter @@ -4221,9 +4224,6 @@ impl Methods { range_zip_with_len::check(cx, expr, iter_recv, arg); } }, - ("write", []) => { - readonly_write_lock::check(cx, expr, recv); - } _ => {}, } } -- cgit 1.4.1-3-g733a5 From 779e0f4021b591919c34126f623e3bc2383cb185 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Sat, 29 Jul 2023 00:06:08 -0500 Subject: Do not lint unwrapping on `!` or never-like enums --- clippy_lints/src/methods/expect_used.rs | 44 ------------- clippy_lints/src/methods/mod.rs | 39 ++++++++++-- clippy_lints/src/methods/unwrap_expect_used.rs | 87 ++++++++++++++++++++++++++ clippy_lints/src/methods/unwrap_used.rs | 53 ---------------- tests/ui/unwrap_expect_used.rs | 11 ++++ tests/ui/unwrap_expect_used.stderr | 12 ++-- 6 files changed, 137 insertions(+), 109 deletions(-) delete mode 100644 clippy_lints/src/methods/expect_used.rs create mode 100644 clippy_lints/src/methods/unwrap_expect_used.rs delete mode 100644 clippy_lints/src/methods/unwrap_used.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs deleted file mode 100644 index 614610335a1..00000000000 --- a/clippy_lints/src/methods/expect_used.rs +++ /dev/null @@ -1,44 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_span::sym; - -use super::EXPECT_USED; - -/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`. -pub(super) fn check( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - recv: &hir::Expr<'_>, - is_err: bool, - allow_expect_in_tests: bool, -) { - let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { - Some((EXPECT_USED, "an `Option`", "None", "")) - } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an ")) - } else { - None - }; - - let method = if is_err { "expect_err" } else { "expect" }; - - if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { - return; - } - - if let Some((lint, kind, none_value, none_prefix)) = mess { - span_lint_and_help( - cx, - lint, - expr.span, - &format!("used `{method}()` on {kind} value"), - None, - &format!("if this value is {none_prefix}`{none_value}`, it will panic"), - ); - } -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 62d565bcc5c..17483656cec 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -17,7 +17,6 @@ mod collapsible_str_replace; mod drain_collect; mod err_expect; mod expect_fun_call; -mod expect_used; mod extend_with_drain; mod filetype_is_file; mod filter_map; @@ -105,7 +104,7 @@ mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; mod unnecessary_sort_by; mod unnecessary_to_owned; -mod unwrap_used; +mod unwrap_expect_used; mod useless_asref; mod utils; mod vec_resize_to_zero; @@ -3948,13 +3947,27 @@ impl Methods { match method_call(recv) { 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), + _ => unwrap_expect_used::check( + cx, + expr, + recv, + false, + self.allow_expect_in_tests, + unwrap_expect_used::Variant::Expect, + ), } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("expect_err", [_]) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests); + unwrap_expect_used::check( + cx, + expr, + recv, + true, + self.allow_expect_in_tests, + unwrap_expect_used::Variant::Expect, + ); }, ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); @@ -4180,11 +4193,25 @@ impl Methods { _ => {}, } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); + unwrap_expect_used::check( + cx, + expr, + recv, + false, + self.allow_unwrap_in_tests, + unwrap_expect_used::Variant::Unwrap, + ); }, ("unwrap_err", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests); + unwrap_expect_used::check( + cx, + expr, + recv, + true, + self.allow_unwrap_in_tests, + unwrap_expect_used::Variant::Unwrap, + ); }, ("unwrap_or", [u_arg]) => { match method_call(recv) { diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs new file mode 100644 index 00000000000..9b93eda688d --- /dev/null +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -0,0 +1,87 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; +use rustc_hir::Expr; +use rustc_lint::{LateContext, Lint}; +use rustc_middle::ty; +use rustc_span::sym; + +use super::{EXPECT_USED, UNWRAP_USED}; + +#[derive(Clone, Copy, Eq, PartialEq)] +pub(super) enum Variant { + Unwrap, + Expect, +} + +impl Variant { + fn method_name(self, is_err: bool) -> &'static str { + match (self, is_err) { + (Variant::Unwrap, true) => "unwrap_err", + (Variant::Unwrap, false) => "unwrap", + (Variant::Expect, true) => "expect_err", + (Variant::Expect, false) => "expect", + } + } + + fn lint(self) -> &'static Lint { + match self { + Variant::Unwrap => UNWRAP_USED, + Variant::Expect => EXPECT_USED, + } + } +} + +/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + recv: &Expr<'_>, + is_err: bool, + allow_unwrap_in_tests: bool, + variant: Variant, +) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err { + ("an `Option`", "None", "") + } else if is_type_diagnostic_item(cx, ty, sym::Result) + && let ty::Adt(_, substs) = ty.kind() + && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type() + { + // Issue #11245: Do not lint `!` or never-like enums + if t_or_e_ty.is_never() + || (t_or_e_ty.is_enum() && t_or_e_ty.ty_adt_def().is_some_and(|def| def.variants().is_empty())) + { + return; + } + + ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ") + } else { + return; + }; + + let method_suffix = if is_err { "_err" } else { "" }; + + if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { + return; + } + + let help = if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { + format!( + "if you don't want to handle the `{none_value}` case gracefully, consider \ + using `expect{method_suffix}()` to provide a better panic message" + ) + } else { + format!("if this value is {none_prefix}`{none_value}`, it will panic") + }; + + span_lint_and_help( + cx, + variant.lint(), + expr.span, + &format!("used `{}()` on {kind} value", variant.method_name(is_err)), + None, + &help, + ); +} diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs deleted file mode 100644 index 5e4c3daee64..00000000000 --- a/clippy_lints/src/methods/unwrap_used.rs +++ /dev/null @@ -1,53 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_span::sym; - -use super::{EXPECT_USED, UNWRAP_USED}; - -/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`. -pub(super) fn check( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - recv: &hir::Expr<'_>, - is_err: bool, - allow_unwrap_in_tests: bool, -) { - let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { - Some((UNWRAP_USED, "an `Option`", "None", "")) - } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an ")) - } else { - None - }; - - let method_suffix = if is_err { "_err" } else { "" }; - - if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { - return; - } - - if let Some((lint, kind, none_value, none_prefix)) = mess { - let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { - format!( - "if you don't want to handle the `{none_value}` case gracefully, consider \ - using `expect{method_suffix}()` to provide a better panic message" - ) - } else { - format!("if this value is {none_prefix}`{none_value}`, it will panic") - }; - - span_lint_and_help( - cx, - lint, - expr.span, - &format!("used `unwrap{method_suffix}()` on {kind} value"), - None, - &help, - ); - } -} diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index 7f57efc53c9..26f92ccdefa 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -1,5 +1,8 @@ #![warn(clippy::unwrap_used, clippy::expect_used)] #![allow(clippy::unnecessary_literal_unwrap)] +#![feature(never_type)] + +use std::convert::Infallible; trait OptionExt { type Item; @@ -28,6 +31,14 @@ fn main() { Some(3).unwrap_err(); Some(3).expect_err("Hellow none!"); + // Issue #11245: The `Err` variant can never be constructed so do not lint this. + let x: Result<(), !> = Ok(()); + x.unwrap(); + x.expect("is `!` (never)"); + let x: Result<(), Infallible> = Ok(()); + x.unwrap(); + x.expect("is never-like (0 variants)"); + let a: Result = Ok(3); a.unwrap(); a.expect("Hello world!"); diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index 1a551ab5ab8..8cbde8bf946 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_expect_used.rs:24:5 + --> $DIR/unwrap_expect_used.rs:27:5 | LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | Some(3).unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `expect()` on an `Option` value - --> $DIR/unwrap_expect_used.rs:25:5 + --> $DIR/unwrap_expect_used.rs:28:5 | LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | Some(3).expect("Hello world!"); = note: `-D clippy::expect-used` implied by `-D warnings` error: used `unwrap()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:32:5 + --> $DIR/unwrap_expect_used.rs:43:5 | LL | a.unwrap(); | ^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | a.unwrap(); = help: if this value is an `Err`, it will panic error: used `expect()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:33:5 + --> $DIR/unwrap_expect_used.rs:44:5 | LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | a.expect("Hello world!"); = help: if this value is an `Err`, it will panic error: used `unwrap_err()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:34:5 + --> $DIR/unwrap_expect_used.rs:45:5 | LL | a.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | a.unwrap_err(); = help: if this value is an `Ok`, it will panic error: used `expect_err()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:35:5 + --> $DIR/unwrap_expect_used.rs:46:5 | LL | a.expect_err("Hello error!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 71c54137eadc730d01fe15c17df8bf3ba5d3b04b Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Wed, 2 Aug 2023 13:57:06 -0500 Subject: Extract never-like into `clippy_utils` --- clippy_lints/src/methods/unwrap_expect_used.rs | 34 ++++++++++------------ clippy_utils/src/ty.rs | 5 ++++ tests/ui-toml/expect_used/expect_used.stderr | 4 +-- tests/ui-toml/unwrap_used/unwrap_used.stderr | 39 +++++++++++++++++--------- tests/ui/expect.stderr | 6 ++-- tests/ui/get_unwrap.stderr | 39 +++++++++++++++++--------- tests/ui/unwrap.stderr | 9 ++++-- tests/ui/unwrap_expect_used.stderr | 12 ++++---- 8 files changed, 89 insertions(+), 59 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 9b93eda688d..7bd16b473ce 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -1,5 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::{is_never_like, is_type_diagnostic_item}; use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; use rustc_hir::Expr; use rustc_lint::{LateContext, Lint}; @@ -32,7 +32,8 @@ impl Variant { } } -/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`. +/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their +/// `expect` counterparts). pub(super) fn check( cx: &LateContext<'_>, expr: &Expr<'_>, @@ -49,10 +50,7 @@ pub(super) fn check( && let ty::Adt(_, substs) = ty.kind() && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type() { - // Issue #11245: Do not lint `!` or never-like enums - if t_or_e_ty.is_never() - || (t_or_e_ty.is_enum() && t_or_e_ty.ty_adt_def().is_some_and(|def| def.variants().is_empty())) - { + if is_never_like(t_or_e_ty) { return; } @@ -67,21 +65,19 @@ pub(super) fn check( return; } - let help = if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { - format!( - "if you don't want to handle the `{none_value}` case gracefully, consider \ - using `expect{method_suffix}()` to provide a better panic message" - ) - } else { - format!("if this value is {none_prefix}`{none_value}`, it will panic") - }; - - span_lint_and_help( + span_lint_and_then( cx, variant.lint(), expr.span, &format!("used `{}()` on {kind} value", variant.method_name(is_err)), - None, - &help, + |diag| { + diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic")); + + if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { + diag.help(format!( + "consider using `expect{method_suffix}()` to provide a better panic message" + )); + } + }, ); } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index d0e15aa8bb3..98e163abc58 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1093,6 +1093,11 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi } } +/// Returns whether `ty` is never-like; i.e., `!` (never) or an enum with zero variants. +pub fn is_never_like(ty: Ty<'_>) -> bool { + ty.is_never() || (ty.is_enum() && ty.ty_adt_def().is_some_and(|def| def.variants().is_empty())) +} + /// Makes the projection type for the named associated type in the given impl or trait impl. /// /// This function is for associated types which are "known" to exist, and as such, will only return diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index 9eef0e1bfaa..815d009350f 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | - = help: if this value is `None`, it will panic + = note: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` error: used `expect()` on a `Result` value @@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ | - = help: if this value is an `Err`, it will panic + = note: if this value is an `Err`, it will panic error: aborting due to 2 previous errors diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 4c9bdfa9dba..10219beaf97 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -12,7 +12,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise @@ -27,7 +28,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:40:17 @@ -41,7 +43,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:41:17 @@ -55,7 +58,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:42:17 @@ -69,7 +73,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:43:17 @@ -83,7 +88,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:47:21 @@ -97,7 +103,8 @@ error: used `unwrap()` on an `Option` value LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:52:9 @@ -111,7 +118,8 @@ error: used `unwrap()` on an `Option` value LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:53:9 @@ -125,7 +133,8 @@ error: used `unwrap()` on an `Option` value LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:54:9 @@ -139,7 +148,8 @@ error: used `unwrap()` on an `Option` value LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:55:9 @@ -153,7 +163,8 @@ error: used `unwrap()` on an `Option` value LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:67:17 @@ -167,7 +178,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:68:17 @@ -181,7 +193,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:75:13 diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index be340340d47..f787fa973a3 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | - = help: if this value is `None`, it will panic + = note: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` error: used `expect()` on a `Result` value @@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ | - = help: if this value is an `Err`, it will panic + = note: if this value is an `Err`, it will panic error: used `expect_err()` on a `Result` value --> $DIR/expect.rs:12:13 @@ -21,7 +21,7 @@ error: used `expect_err()` on a `Result` value LL | let _ = res.expect_err(""); | ^^^^^^^^^^^^^^^^^^ | - = help: if this value is an `Ok`, it will panic + = note: if this value is an `Ok`, it will panic error: aborting due to 3 previous errors diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index c567ed319b5..19dc9071fe7 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -16,7 +16,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise @@ -31,7 +32,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:40:17 @@ -45,7 +47,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:41:17 @@ -59,7 +62,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:42:17 @@ -73,7 +77,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:43:17 @@ -87,7 +92,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:47:21 @@ -101,7 +107,8 @@ error: used `unwrap()` on an `Option` value LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:52:9 @@ -115,7 +122,8 @@ error: used `unwrap()` on an `Option` value LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:53:9 @@ -129,7 +137,8 @@ error: used `unwrap()` on an `Option` value LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:54:9 @@ -143,7 +152,8 @@ error: used `unwrap()` on an `Option` value LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:55:9 @@ -157,7 +167,8 @@ error: used `unwrap()` on an `Option` value LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:67:17 @@ -171,7 +182,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:68:17 @@ -185,7 +197,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:78:24 diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index 3796d942ff9..41db819f6fb 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -4,7 +4,8 @@ error: used `unwrap()` on an `Option` value LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ | - = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `unwrap()` on a `Result` value @@ -13,7 +14,8 @@ error: used `unwrap()` on a `Result` value LL | let _ = res.unwrap(); | ^^^^^^^^^^^^ | - = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message + = note: if this value is an `Err`, it will panic + = help: consider using `expect()` to provide a better panic message error: used `unwrap_err()` on a `Result` value --> $DIR/unwrap.rs:12:13 @@ -21,7 +23,8 @@ error: used `unwrap_err()` on a `Result` value LL | let _ = res.unwrap_err(); | ^^^^^^^^^^^^^^^^ | - = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message + = note: if this value is an `Ok`, it will panic + = help: consider using `expect_err()` to provide a better panic message error: aborting due to 3 previous errors diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index 8cbde8bf946..f66e47612ad 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -4,7 +4,7 @@ error: used `unwrap()` on an `Option` value LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ | - = help: if this value is `None`, it will panic + = note: if this value is `None`, it will panic = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `expect()` on an `Option` value @@ -13,7 +13,7 @@ error: used `expect()` on an `Option` value LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if this value is `None`, it will panic + = note: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` error: used `unwrap()` on a `Result` value @@ -22,7 +22,7 @@ error: used `unwrap()` on a `Result` value LL | a.unwrap(); | ^^^^^^^^^^ | - = help: if this value is an `Err`, it will panic + = note: if this value is an `Err`, it will panic error: used `expect()` on a `Result` value --> $DIR/unwrap_expect_used.rs:44:5 @@ -30,7 +30,7 @@ error: used `expect()` on a `Result` value LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if this value is an `Err`, it will panic + = note: if this value is an `Err`, it will panic error: used `unwrap_err()` on a `Result` value --> $DIR/unwrap_expect_used.rs:45:5 @@ -38,7 +38,7 @@ error: used `unwrap_err()` on a `Result` value LL | a.unwrap_err(); | ^^^^^^^^^^^^^^ | - = help: if this value is an `Ok`, it will panic + = note: if this value is an `Ok`, it will panic error: used `expect_err()` on a `Result` value --> $DIR/unwrap_expect_used.rs:46:5 @@ -46,7 +46,7 @@ error: used `expect_err()` on a `Result` value LL | a.expect_err("Hello error!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if this value is an `Ok`, it will panic + = note: if this value is an `Ok`, it will panic error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From e5b0483c852ed801b18fd1a43afa471f13937a47 Mon Sep 17 00:00:00 2001 From: lengyijun Date: Sat, 5 Aug 2023 12:39:31 +0800 Subject: Small code style adjustments --- clippy_lints/src/methods/mod.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 17483656cec..42756b27d01 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4020,10 +4020,8 @@ impl Methods { } }, ("last", []) => { - 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); - } + if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } }, ("lock", []) => { @@ -4127,10 +4125,8 @@ impl Methods { ("skip", [arg]) => { iter_skip_zero::check(cx, expr, arg); - 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); - } + if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } } ("sort", []) => { @@ -4155,10 +4151,8 @@ 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 ("cloned", []) = (name2, args2) { - iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); - } + if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } }, ("take", []) => needless_option_take::check(cx, expr, recv), -- cgit 1.4.1-3-g733a5 From beb57f074eb83643dde6ad960edadd3dbe4e6109 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Thu, 10 Aug 2023 16:21:35 -0500 Subject: Don't ICE with late bound regions --- clippy_lints/src/methods/filter_map_bool_then.rs | 14 +++++++++++--- tests/ui/filter_map_bool_then.fixed | 12 +++++++++++- tests/ui/filter_map_bool_then.rs | 12 +++++++++++- tests/ui/filter_map_bool_then.stderr | 18 ++++++++++++------ 4 files changed, 45 insertions(+), 11 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 4aee22a4afc..fafc9709770 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,3 +1,4 @@ +use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; use clippy_utils::source::snippet_opt; @@ -7,10 +8,9 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Binder; use rustc_span::{sym, Span}; -use super::FILTER_MAP_BOOL_THEN; - pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { if !in_external_macro(cx.sess(), expr.span) && is_trait_method(cx, expr, sym::Iterator) @@ -21,7 +21,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & // `inputs` and `params` here as we need both the type and the span && let param_ty = closure.fn_decl.inputs[0] && let param = body.params[0] - && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs()) + // Issue #11309 + && let param_ty = cx.tcx.liberate_late_bound_regions( + closure.def_id.to_def_id(), + Binder::bind_with_vars( + cx.typeck_results().node_type(param_ty.hir_id), + cx.tcx.late_bound_vars(cx.tcx.hir().local_def_id_to_hir_id(closure.def_id)), + ), + ) + && is_copy(cx, param_ty) && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind && let ExprKind::Closure(then_closure) = then_arg.kind && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value) diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed index 3e72fee4b07..b85e3659a4c 100644 --- a/tests/ui/filter_map_bool_then.fixed +++ b/tests/ui/filter_map_bool_then.fixed @@ -4,6 +4,7 @@ clippy::clone_on_copy, clippy::map_identity, clippy::unnecessary_lazy_evaluations, + clippy::unnecessary_filter_map, unused )] #![warn(clippy::filter_map_bool_then)] @@ -29,9 +30,14 @@ fn main() { .copied() .filter(|&i| i != 1000) .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1); + // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`, + // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`), + // we can lint this and still get the same input type. + let v = vec![NonCopy, NonCopy]; + v.clone().iter().filter(|&i| (i == &NonCopy)).map(|i| i); // Do not lint let v = vec![NonCopy, NonCopy]; - v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i)); external! { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); @@ -42,3 +48,7 @@ fn main() { v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); } } + +fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str> { + iter.filter_map(|(_, s): (&str, _)| Some(s)).collect() +} diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs index 38a04e57de4..c009b4e6ebe 100644 --- a/tests/ui/filter_map_bool_then.rs +++ b/tests/ui/filter_map_bool_then.rs @@ -4,6 +4,7 @@ clippy::clone_on_copy, clippy::map_identity, clippy::unnecessary_lazy_evaluations, + clippy::unnecessary_filter_map, unused )] #![warn(clippy::filter_map_bool_then)] @@ -29,9 +30,14 @@ fn main() { .copied() .filter(|&i| i != 1000) .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); - // Do not lint + // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`, + // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`), + // we can lint this and still get the same input type. let v = vec![NonCopy, NonCopy]; v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + // Do not lint + let v = vec![NonCopy, NonCopy]; + v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i)); external! { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); @@ -42,3 +48,7 @@ fn main() { v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); } } + +fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str> { + iter.filter_map(|(_, s): (&str, _)| Some(s)).collect() +} diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr index b411cd83dfd..b47f8eac7f0 100644 --- a/tests/ui/filter_map_bool_then.stderr +++ b/tests/ui/filter_map_bool_then.stderr @@ -1,5 +1,5 @@ error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:19:22 + --> $DIR/filter_map_bool_then.rs:20:22 | LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` @@ -7,28 +7,34 @@ LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); = note: `-D clippy::filter-map-bool-then` implied by `-D warnings` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:20:27 + --> $DIR/filter_map_bool_then.rs:21:27 | LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:23:10 + --> $DIR/filter_map_bool_then.rs:24:10 | LL | .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:27:10 + --> $DIR/filter_map_bool_then.rs:28:10 | LL | .filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> $DIR/filter_map_bool_then.rs:31:10 + --> $DIR/filter_map_bool_then.rs:32:10 | LL | .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)` -error: aborting due to 5 previous errors +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:37:22 + | +LL | v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i == &NonCopy)).map(|i| i)` + +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From fc061890d6b1a2715d30e99e36ae4305f473c43c Mon Sep 17 00:00:00 2001 From: lengyijun Date: Thu, 3 Aug 2023 11:37:23 +0800 Subject: [`iter_overeager_cloned`]: detect .cloned().filter() and .cloned().find() Key idea: ``` // before iter.cloned().filter(|x| unimplemented!() ) // after iter.filter(|&x| unimplemented!() ).cloned() // before iter.cloned().filter( foo ) // after iter.filter(|&x| foo(x) ).cloned() ``` --- clippy_lints/src/methods/iter_overeager_cloned.rs | 53 ++++++++++++++---- clippy_lints/src/methods/mod.rs | 24 ++++++--- tests/ui/iter_overeager_cloned.fixed | 40 ++++++++++++-- tests/ui/iter_overeager_cloned.rs | 38 +++++++++++-- tests/ui/iter_overeager_cloned.stderr | 66 ++++++++++++++++++++++- 5 files changed, 193 insertions(+), 28 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index 9f7ec19aa59..4b1ca0d9b9c 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_copy}; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::sym; @@ -10,12 +10,28 @@ use rustc_span::sym; use super::ITER_OVEREAGER_CLONED; use crate::redundant_clone::REDUNDANT_CLONE; +#[derive(Clone, Copy)] +pub(super) enum Op<'a> { + // rm `.cloned()` + // e.g. `count` + RmCloned, + + // later `.cloned()` + // and add `&` to the parameter of closure parameter + // e.g. `find` `filter` + FixClosure(&'a str, &'a Expr<'a>), + + // later `.cloned()` + // e.g. `skip` `take` + LaterCloned, +} + pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, cloned_call: &'tcx Expr<'_>, cloned_recv: &'tcx Expr<'_>, - is_count: bool, + op: Op<'tcx>, needs_into_iter: bool, ) { let typeck = cx.typeck_results(); @@ -35,10 +51,9 @@ pub(super) fn check<'tcx>( return; } - let (lint, msg, trailing_clone) = if is_count { - (REDUNDANT_CLONE, "unneeded cloning of iterator items", "") - } else { - (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()") + let (lint, msg, trailing_clone) = match op { + Op::RmCloned => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), + Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"), }; span_lint_and_then( @@ -47,11 +62,27 @@ pub(super) fn check<'tcx>( expr.span, msg, |diag| { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(mut snip) = snippet_opt(cx, method_span) { - snip.push_str(trailing_clone); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); + match op { + Op::RmCloned | Op::LaterCloned => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(mut snip) = snippet_opt(cx, method_span) { + snip.push_str(trailing_clone); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); + } + } + Op::FixClosure(name, predicate_expr) => { + if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { + let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { + predicate.replacen('|', "|&", 1) + } else { + format!("|&x| {predicate}(x)") + }; + let snip = format!(".{name}({new_closure}).cloned()" ); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); + } + } } } ); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 42756b27d01..729eda37af6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3919,7 +3919,7 @@ impl Methods { } }, ("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(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned , false), Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { iter_count::check(cx, expr, recv2, name2); }, @@ -3973,6 +3973,13 @@ impl Methods { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, + (name @ ( "filter" | "find" ) , [arg]) => { + if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + // if `arg` has side-effect, the semantic will change + iter_overeager_cloned::check(cx, expr, recv, recv2, + iter_overeager_cloned::Op::FixClosure(name, arg), false); + } + } ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); @@ -3987,7 +3994,7 @@ impl Methods { }, ("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(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , true), _ => {}, }, ("fold", [init, acc]) => { @@ -4021,7 +4028,8 @@ impl Methods { }, ("last", []) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); + iter_overeager_cloned::check(cx, expr, recv, recv2, + iter_overeager_cloned::Op::LaterCloned , false); } }, ("lock", []) => { @@ -4058,7 +4066,7 @@ impl Methods { ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), + ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv), ("iter", []) => iter_next_slice::check(cx, expr, recv2), @@ -4071,7 +4079,7 @@ 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(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , 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), @@ -4126,7 +4134,8 @@ impl Methods { iter_skip_zero::check(cx, expr, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); + iter_overeager_cloned::check(cx, expr, recv, recv2, + iter_overeager_cloned::Op::LaterCloned , false); } } ("sort", []) => { @@ -4152,7 +4161,8 @@ impl Methods { ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [_arg]) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); + iter_overeager_cloned::check(cx, expr, recv, recv2, + iter_overeager_cloned::Op::LaterCloned, false); } }, ("take", []) => needless_option_take::check(cx, expr, recv), diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index ba26fe33d89..9605b449b40 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -20,8 +20,41 @@ fn main() { .iter() .flatten().cloned(); - // Not implemented yet - let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); + let _ = vec.iter().filter(|&x| x.starts_with('2')).cloned(); + + let _ = vec.iter().find(|&x| x == "2").cloned(); + + { + let f = |x: &String| x.starts_with('2'); + let _ = vec.iter().filter(|&x| f(x)).cloned(); + let _ = vec.iter().find(|&x| f(x)).cloned(); + } + + { + let vec: Vec<(String, String)> = vec![]; + let f = move |x: &(String, String)| x.0.starts_with('2'); + let _ = vec.iter().filter(|&x| f(x)).cloned(); + let _ = vec.iter().find(|&x| f(x)).cloned(); + } + + fn test_move<'a>( + iter: impl Iterator + 'a, + target: String, + ) -> impl Iterator + 'a { + iter.filter(move |&(&a, b)| a == 1 && b == &target).cloned() + } + + { + #[derive(Clone)] + struct S<'a> { + a: &'a u32, + b: String, + } + + fn bar<'a>(iter: impl Iterator> + 'a, target: String) -> impl Iterator> + 'a { + iter.filter(move |&S { a, b }| **a == 1 && b == &target).cloned() + } + } // Not implemented yet let _ = vec.iter().cloned().map(|x| x.len()); @@ -29,9 +62,6 @@ fn main() { // This would fail if changed. let _ = vec.iter().cloned().map(|x| x + "2"); - // Not implemented yet - let _ = vec.iter().cloned().find(|x| x == "2"); - // Not implemented yet let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 2d3c4ea7c20..8d75f039d44 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -21,18 +21,48 @@ fn main() { .cloned() .flatten(); - // Not implemented yet let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); + let _ = vec.iter().cloned().find(|x| x == "2"); + + { + let f = |x: &String| x.starts_with('2'); + let _ = vec.iter().cloned().filter(f); + let _ = vec.iter().cloned().find(f); + } + + { + let vec: Vec<(String, String)> = vec![]; + let f = move |x: &(String, String)| x.0.starts_with('2'); + let _ = vec.iter().cloned().filter(f); + let _ = vec.iter().cloned().find(f); + } + + fn test_move<'a>( + iter: impl Iterator + 'a, + target: String, + ) -> impl Iterator + 'a { + iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) + } + + { + #[derive(Clone)] + struct S<'a> { + a: &'a u32, + b: String, + } + + fn bar<'a>(iter: impl Iterator> + 'a, target: String) -> impl Iterator> + 'a { + iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) + } + } + // Not implemented yet let _ = vec.iter().cloned().map(|x| x.len()); // This would fail if changed. let _ = vec.iter().cloned().map(|x| x + "2"); - // Not implemented yet - let _ = vec.iter().cloned().find(|x| x == "2"); - // Not implemented yet let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index 2be2b7e07a4..bdbb04d7f08 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -66,5 +66,69 @@ LL ~ .iter() LL ~ .flatten().cloned(); | -error: aborting due to 7 previous errors +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:24:13 + | +LL | let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); + | ^^^^^^^^^^---------------------------------------- + | | + | help: try: `.filter(|&x| x.starts_with('2')).cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:26:13 + | +LL | let _ = vec.iter().cloned().find(|x| x == "2"); + | ^^^^^^^^^^---------------------------- + | | + | help: try: `.find(|&x| x == "2").cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:30:17 + | +LL | let _ = vec.iter().cloned().filter(f); + | ^^^^^^^^^^------------------- + | | + | help: try: `.filter(|&x| f(x)).cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:31:17 + | +LL | let _ = vec.iter().cloned().find(f); + | ^^^^^^^^^^----------------- + | | + | help: try: `.find(|&x| f(x)).cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:37:17 + | +LL | let _ = vec.iter().cloned().filter(f); + | ^^^^^^^^^^------------------- + | | + | help: try: `.filter(|&x| f(x)).cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:38:17 + | +LL | let _ = vec.iter().cloned().find(f); + | ^^^^^^^^^^----------------- + | | + | help: try: `.find(|&x| f(x)).cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:45:9 + | +LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) + | ^^^^------------------------------------------------------- + | | + | help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()` + +error: unnecessarily eager cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:56:13 + | +LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) + | ^^^^------------------------------------------------------------ + | | + | help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()` + +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From aa8995e589c7f4a433ae6fe27b319ff9898b523a Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Tue, 15 Aug 2023 09:41:15 +0800 Subject: allow calling `to_owned` with borrowed value for [`implicit_clone`] --- clippy_lints/src/methods/implicit_clone.rs | 1 + tests/ui/implicit_clone.fixed | 2 +- tests/ui/implicit_clone.stderr | 8 +------- 3 files changed, 3 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 043425300d8..e91ce64d8c8 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -17,6 +17,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv let return_type = cx.typeck_results().expr_ty(expr); let input_type = cx.typeck_results().expr_ty(recv); let (input_type, ref_count) = peel_mid_ty_refs(input_type); + if !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned)); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())); if return_type == input_type; if let Some(clone_trait) = cx.tcx.lang_items().clone_trait(); diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed index 04644b111bf..98556b4dd30 100644 --- a/tests/ui/implicit_clone.fixed +++ b/tests/ui/implicit_clone.fixed @@ -67,7 +67,7 @@ fn main() { let vec_ref = &vec; let _ = return_owned_from_slice(vec_ref); - let _ = vec_ref.clone(); + let _ = vec_ref.to_owned(); let _ = vec_ref.clone(); // we expect no lint for this diff --git a/tests/ui/implicit_clone.stderr b/tests/ui/implicit_clone.stderr index 0f412424190..59f000c06e2 100644 --- a/tests/ui/implicit_clone.stderr +++ b/tests/ui/implicit_clone.stderr @@ -12,12 +12,6 @@ error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type LL | let _ = vec.to_vec(); | ^^^^^^^^^^^^ help: consider using: `vec.clone()` -error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> $DIR/implicit_clone.rs:70:13 - | -LL | let _ = vec_ref.to_owned(); - | ^^^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()` - error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type --> $DIR/implicit_clone.rs:71:13 | @@ -72,5 +66,5 @@ error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenc LL | let _ = pathbuf_ref.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()` -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From 41570c1ee71b36a5a5ea887a3aee07121d1aa0b6 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 18 Aug 2023 17:07:43 +0200 Subject: Update version attribute for 1.72 lints --- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/endian_bytes.rs | 6 +++--- clippy_lints/src/excessive_nesting.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/redundant_type_annotations.rs | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d34de305f5d..88ffbb55486 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -418,7 +418,7 @@ declare_clippy_lint! { /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, pedantic, "casting using `as` from and to raw pointers to change constness when specialized methods apply" diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index dda14b4df53..affd0822120 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// let _x = 2i32.to_ne_bytes(); /// let _y = 2i64.to_ne_bytes(); /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub HOST_ENDIAN_BYTES, restriction, "disallows usage of the `to_ne_bytes` method" @@ -40,7 +40,7 @@ declare_clippy_lint! { /// let _x = 2i32.to_le_bytes(); /// let _y = 2i64.to_le_bytes(); /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub LITTLE_ENDIAN_BYTES, restriction, "disallows usage of the `to_le_bytes` method" @@ -59,7 +59,7 @@ declare_clippy_lint! { /// let _x = 2i32.to_be_bytes(); /// let _y = 2i64.to_be_bytes(); /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub BIG_ENDIAN_BYTES, restriction, "disallows usage of the `to_be_bytes` method" diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index 8911f1872c2..83480fc5eeb 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -56,7 +56,7 @@ declare_clippy_lint! { /// // lib.rs /// pub mod a; /// ``` - #[clippy::version = "1.70.0"] + #[clippy::version = "1.72.0"] pub EXCESSIVE_NESTING, complexity, "checks for blocks nested beyond a certain threshold" diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 7aa1446d53d..1d28d7dd0e7 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -72,7 +72,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub LARGE_STACK_FRAMES, nursery, "checks for functions that allocate a lot of stack space" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 729eda37af6..3a8af0248d8 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -301,7 +301,7 @@ declare_clippy_lint! { /// let val2 = 1; /// let val3 = 1; /// ``` - #[clippy::version = "1.69.0"] + #[clippy::version = "1.72.0"] pub UNNECESSARY_LITERAL_UNWRAP, complexity, "using `unwrap()` related calls on `Result` and `Option` constructors" @@ -3328,7 +3328,7 @@ declare_clippy_lint! { /// mem::take(v) /// } /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub DRAIN_COLLECT, perf, "calling `.drain(..).collect()` to move all elements into a new collection" diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 03bab86c6d7..0c1fe881fc1 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// println!("Check successful!"); /// } /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.72.0"] pub NEEDLESS_ELSE, style, "empty else branch" diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 3e963d79892..1d4fdb43a0b 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ```rust /// let foo = String::new(); /// ``` - #[clippy::version = "1.70.0"] + #[clippy::version = "1.72.0"] pub REDUNDANT_TYPE_ANNOTATIONS, restriction, "warns about needless / redundant type annotations." -- cgit 1.4.1-3-g733a5 From e440065a0f930b527925b61c3a6dd5f4207dd7b6 Mon Sep 17 00:00:00 2001 From: lengyijun Date: Sat, 5 Aug 2023 10:20:16 +0800 Subject: [`iter_overeager_cloned`]: detect .cloned().map() and .cloned().for_each() key idea: for `f` in `.map(f)` and `.for_each(f)`: 1. `f` must be a closure with one parameter 2. don't lint if mutable paramter in clsure `f`: `|mut x| ...` 3. don't lint if parameter is moved --- clippy_lints/src/methods/iter_overeager_cloned.rs | 77 ++++++++++++++++++++++- clippy_lints/src/methods/mod.rs | 14 +++-- tests/ui/iter_overeager_cloned.fixed | 6 +- tests/ui/iter_overeager_cloned.rs | 2 - tests/ui/iter_overeager_cloned.stderr | 18 +++++- 5 files changed, 102 insertions(+), 15 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index 4b1ca0d9b9c..ee405a3e30c 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -1,14 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_copy}; +use rustc_ast::BindingAnnotation; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Body, Expr, ExprKind, HirId, HirIdSet, PatKind}; +use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::mir::{FakeReadCause, Mutability}; +use rustc_middle::ty::{self, BorrowKind}; use rustc_span::sym; use super::ITER_OVEREAGER_CLONED; use crate::redundant_clone::REDUNDANT_CLONE; +use crate::rustc_trait_selection::infer::TyCtxtInferExt; #[derive(Clone, Copy)] pub(super) enum Op<'a> { @@ -16,6 +20,10 @@ pub(super) enum Op<'a> { // e.g. `count` RmCloned, + // rm `.cloned()` + // e.g. `map` `for_each` + NeedlessMove(&'a str, &'a Expr<'a>), + // later `.cloned()` // and add `&` to the parameter of closure parameter // e.g. `find` `filter` @@ -51,8 +59,46 @@ pub(super) fn check<'tcx>( return; } + if let Op::NeedlessMove(_, expr) = op { + let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ; + let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return }; + let mut delegate = MoveDelegate {used_move : HirIdSet::default()}; + let infcx = cx.tcx.infer_ctxt().build(); + + ExprUseVisitor::new( + &mut delegate, + &infcx, + closure.body.hir_id.owner.def_id, + cx.param_env, + cx.typeck_results(), + ) + .consume_body(body); + + let mut to_be_discarded = false; + + p.pat.walk(|it| { + if delegate.used_move.contains(&it.hir_id){ + to_be_discarded = true; + return false; + } + + match it.kind { + PatKind::Binding(BindingAnnotation(_, Mutability::Mut), _, _, _) + | PatKind::Ref(_, Mutability::Mut) => { + to_be_discarded = true; + false + } + _ => { true } + } + }); + + if to_be_discarded { + return; + } + } + let (lint, msg, trailing_clone) = match op { - Op::RmCloned => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), + Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"), }; @@ -83,8 +129,33 @@ pub(super) fn check<'tcx>( diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); } } + Op::NeedlessMove(_, _) => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(snip) = snippet_opt(cx, method_span) { + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); + } + } } } ); } } + +struct MoveDelegate { + used_move: HirIdSet, +} + +impl<'tcx> Delegate<'tcx> for MoveDelegate { + fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, _: HirId) { + if let PlaceBase::Local(l) = place_with_id.place.base { + self.used_move.insert(l); + } + } + + fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {} + + fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3a8af0248d8..5075137caa0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4001,9 +4001,11 @@ impl Methods { manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [_]) => { - if let Some(("inspect", _, [_], span2, _)) = method_call(recv) { - inspect_for_each::check(cx, expr, span2); + ("for_each", [arg]) => { + match method_call(recv) { + Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), + _ => {} } }, ("get", [arg]) => { @@ -4038,8 +4040,10 @@ 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) { - iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + match method_call(recv) { + Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => iter_kv_map::check(cx, map_name, expr, recv2, m_arg), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, m_arg), false), + _ => {} } } else { map_err_ignore::check(cx, expr, m_arg); diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index 9605b449b40..9dd046fec1f 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -56,14 +56,12 @@ fn main() { } } - // Not implemented yet - let _ = vec.iter().cloned().map(|x| x.len()); + let _ = vec.iter().map(|x| x.len()); // This would fail if changed. let _ = vec.iter().cloned().map(|x| x + "2"); - // Not implemented yet - let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); + let _ = vec.iter().for_each(|x| assert!(!x.is_empty())); // Not implemented yet let _ = vec.iter().cloned().all(|x| x.len() == 1); diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 8d75f039d44..3cab3669554 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -57,13 +57,11 @@ fn main() { } } - // Not implemented yet let _ = vec.iter().cloned().map(|x| x.len()); // This would fail if changed. let _ = vec.iter().cloned().map(|x| x + "2"); - // Not implemented yet let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); // Not implemented yet diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index bdbb04d7f08..4417a40a63b 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -130,5 +130,21 @@ LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target | | | help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()` -error: aborting due to 15 previous errors +error: unneeded cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:60:13 + | +LL | let _ = vec.iter().cloned().map(|x| x.len()); + | ^^^^^^^^^^-------------------------- + | | + | help: try: `.map(|x| x.len())` + +error: unneeded cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:65:13 + | +LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); + | ^^^^^^^^^^---------------------------------------------- + | | + | help: try: `.for_each(|x| assert!(!x.is_empty()))` + +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From 8f2d47ea72fdc754697b381441fb49953bf37b58 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 19 Aug 2023 18:06:46 +0000 Subject: Check that the suggested method exists in unwrap_or_default --- clippy_lints/src/methods/or_fun_call.rs | 19 +++++++++++++++++-- tests/ui/unwrap_or_else_default.fixed | 30 ++++++++++++++++++++++++++++++ tests/ui/unwrap_or_else_default.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 8b2f57160af..942f3bd79a6 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -65,11 +65,26 @@ pub(super) fn check<'tcx>( }; let sugg = match (name, call_expr.is_some()) { - ("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default", - ("or_insert", true) | ("or_insert_with", false) => "or_default", + ("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default), + ("or_insert", true) | ("or_insert_with", false) => sym!(or_default), _ => return false, }; + let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs(); + let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| { + cx.tcx + .inherent_impls(adt_def.did()) + .iter() + .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) + .any(|assoc| { + assoc.fn_has_self_parameter + && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 + }) + }); + if !has_suggested_method { + return false; + } + // needs to target Default::default in particular or be *::new and have a Default impl // available if (is_new(fun) && output_type_implements_default(fun)) diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 73d99907958..8d5d34175c5 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -130,4 +130,34 @@ fn method_call_with_deref() { let _ = inner_map.entry(0).or_default(); } +fn missing_suggested_method() { + #[derive(Copy, Clone)] + struct S(T); + + impl S { + fn or_insert_with(&mut self, default: impl FnOnce() -> T) -> &mut T { + &mut self.0 + } + + fn or_insert(&mut self, default: T) -> &mut T { + &mut self.0 + } + + fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T { + self.0 + } + + fn unwrap_or(self, default: T) -> T { + self.0 + } + } + + // Don't lint when or_default/unwrap_or_default do not exist on the type + let mut s = S(1); + s.or_insert_with(Default::default); + s.or_insert(Default::default()); + s.unwrap_or_else(Default::default); + s.unwrap_or(Default::default()); +} + fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index afacedf17c6..adbcb4b4465 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -130,4 +130,34 @@ fn method_call_with_deref() { let _ = inner_map.entry(0).or_insert_with(Default::default); } +fn missing_suggested_method() { + #[derive(Copy, Clone)] + struct S(T); + + impl S { + fn or_insert_with(&mut self, default: impl FnOnce() -> T) -> &mut T { + &mut self.0 + } + + fn or_insert(&mut self, default: T) -> &mut T { + &mut self.0 + } + + fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T { + self.0 + } + + fn unwrap_or(self, default: T) -> T { + self.0 + } + } + + // Don't lint when or_default/unwrap_or_default do not exist on the type + let mut s = S(1); + s.or_insert_with(Default::default); + s.or_insert(Default::default()); + s.unwrap_or_else(Default::default); + s.unwrap_or(Default::default()); +} + fn main() {} -- cgit 1.4.1-3-g733a5 From fb6fad20c87d8562c60ef1ad28f6cf471b76d3c2 Mon Sep 17 00:00:00 2001 From: lengyijun Date: Sun, 20 Aug 2023 09:14:52 +0800 Subject: [`iter_overeager_cloned`]: detect .cloned().all() and .cloned().any() --- clippy_lints/src/methods/iter_overeager_cloned.rs | 2 +- clippy_lints/src/methods/mod.rs | 22 ++++++++++++++++------ tests/ui/iter_overeager_cloned.fixed | 6 ++---- tests/ui/iter_overeager_cloned.rs | 2 -- tests/ui/iter_overeager_cloned.stderr | 18 +++++++++++++++++- 5 files changed, 36 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index ee405a3e30c..a49dd98db87 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -21,7 +21,7 @@ pub(super) enum Op<'a> { RmCloned, // rm `.cloned()` - // e.g. `map` `for_each` + // e.g. `map` `for_each` `all` `any` NeedlessMove(&'a str, &'a Expr<'a>), // later `.cloned()` diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5075137caa0..5fb0d9f0a57 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3873,6 +3873,12 @@ impl Methods { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); }, + ("all", [arg]) => { + if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { + iter_overeager_cloned::check(cx, expr, recv, recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), false); + } + } ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); @@ -3880,12 +3886,16 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, - ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params - && let Some(("chars", recv, _, _, _)) = method_call(recv) => - { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + ("any", [arg]) => { + match method_call(recv) { + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), + Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params => { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + } + _ => {} + } } ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index 9dd046fec1f..7d8a584b022 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -63,11 +63,9 @@ fn main() { let _ = vec.iter().for_each(|x| assert!(!x.is_empty())); - // Not implemented yet - let _ = vec.iter().cloned().all(|x| x.len() == 1); + let _ = vec.iter().all(|x| x.len() == 1); - // Not implemented yet - let _ = vec.iter().cloned().any(|x| x.len() == 1); + let _ = vec.iter().any(|x| x.len() == 1); // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 3cab3669554..58c374ab8cd 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -64,10 +64,8 @@ fn main() { let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); - // Not implemented yet let _ = vec.iter().cloned().all(|x| x.len() == 1); - // Not implemented yet let _ = vec.iter().cloned().any(|x| x.len() == 1); // Should probably stay as it is. diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index 4417a40a63b..1f4c9040f77 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -146,5 +146,21 @@ LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); | | | help: try: `.for_each(|x| assert!(!x.is_empty()))` -error: aborting due to 17 previous errors +error: unneeded cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:67:13 + | +LL | let _ = vec.iter().cloned().all(|x| x.len() == 1); + | ^^^^^^^^^^------------------------------- + | | + | help: try: `.all(|x| x.len() == 1)` + +error: unneeded cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:69:13 + | +LL | let _ = vec.iter().cloned().any(|x| x.len() == 1); + | ^^^^^^^^^^------------------------------- + | | + | help: try: `.any(|x| x.len() == 1)` + +error: aborting due to 19 previous errors -- cgit 1.4.1-3-g733a5 From 86b66443797bfa89dbc099722c20c9c2c5943217 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 24 Aug 2023 20:12:03 +0200 Subject: new lint: `iter_out_of_bounds` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/iter_out_of_bounds.rs | 91 ++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 32 ++++++++- clippy_utils/src/paths.rs | 2 + tests/ui/iter_out_of_bounds.rs | 44 +++++++++++++ tests/ui/iter_out_of_bounds.stderr | 71 ++++++++++++++++++++ tests/ui/iter_skip_zero.fixed | 2 +- tests/ui/iter_skip_zero.rs | 2 +- 9 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 clippy_lints/src/methods/iter_out_of_bounds.rs create mode 100644 tests/ui/iter_out_of_bounds.rs create mode 100644 tests/ui/iter_out_of_bounds.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e33cb7b457..43633b36925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5030,6 +5030,7 @@ Released 2018-09-13 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero [`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections [`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items +[`iter_out_of_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_out_of_bounds [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 1be9720fbbf..10cb8201306 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -364,6 +364,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_NTH_ZERO_INFO, crate::methods::ITER_ON_EMPTY_COLLECTIONS_INFO, crate::methods::ITER_ON_SINGLE_ITEMS_INFO, + crate::methods::ITER_OUT_OF_BOUNDS_INFO, crate::methods::ITER_OVEREAGER_CLONED_INFO, crate::methods::ITER_SKIP_NEXT_INFO, crate::methods::ITER_SKIP_ZERO_INFO, diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs new file mode 100644 index 00000000000..0a94700ae8e --- /dev/null +++ b/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -0,0 +1,91 @@ +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{is_trait_method, match_def_path, paths}; +use rustc_ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self}; +use rustc_span::sym; + +use super::ITER_OUT_OF_BOUNDS; + +/// Attempts to extract the length out of an iterator expression. +fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> Option { + let iter_ty = cx.typeck_results().expr_ty(iter); + + if let ty::Adt(adt, substs) = iter_ty.kind() { + let did = adt.did(); + + if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) { + // For array::IntoIter, the length is the second generic + // parameter. + substs + .const_at(1) + .try_eval_target_usize(cx.tcx, cx.param_env) + .map(u128::from) + } else if match_def_path(cx, did, &paths::SLICE_ITER) + && let ExprKind::MethodCall(_, recv, ..) = iter.kind + && let ExprKind::Array(array) = recv.peel_borrows().kind + { + // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..) + array.len().try_into().ok() + } else if match_def_path(cx, did, &paths::ITER_EMPTY) { + Some(0) + } else if match_def_path(cx, did, &paths::ITER_ONCE) { + Some(1) + } else { + None + } + } else { + None + } +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + arg: &'tcx Expr<'tcx>, + message: &'static str, + note: &'static str, +) { + if is_trait_method(cx, expr, sym::Iterator) + && let Some(len) = get_iterator_length(cx, recv) + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Int(skip, _) = lit.node + && skip > len + { + span_lint_and_note(cx, ITER_OUT_OF_BOUNDS, expr.span, message, None, note); + } +} + +pub(super) fn check_skip<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + arg: &'tcx Expr<'tcx>, +) { + check( + cx, + expr, + recv, + arg, + "this `.skip()` call skips more items than the iterator will produce", + "this operation is useless and will create an empty iterator", + ); +} + +pub(super) fn check_take<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + arg: &'tcx Expr<'tcx>, +) { + check( + cx, + expr, + recv, + arg, + "this `.take()` call takes more items than the iterator will produce", + "this operation is useless and the returned iterator will simply yield the same items", + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5075137caa0..5dbbd7f9618 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -43,6 +43,7 @@ mod iter_next_slice; mod iter_nth; mod iter_nth_zero; mod iter_on_single_or_empty_collections; +mod iter_out_of_bounds; mod iter_overeager_cloned; mod iter_skip_next; mod iter_skip_zero; @@ -3538,6 +3539,30 @@ declare_clippy_lint! { "acquiring a write lock when a read lock would work" } +declare_clippy_lint! { + /// ### What it does + /// Looks for iterator combinator calls such as `.take(x)` or `.skip(x)` + /// where `x` is greater than the amount of items that an iterator will produce. + /// + /// ### Why is this bad? + /// Taking or skipping more items than there are in an iterator either creates an iterator + /// with all items from the original iterator or an iterator with no items at all. + /// This is most likely not what the user intended to do. + /// + /// ### Example + /// ```rust + /// for _ in [1, 2, 3].iter().take(4) {} + /// ``` + /// Use instead: + /// ```rust + /// for _ in [1, 2, 3].iter() {} + /// ``` + #[clippy::version = "1.73.0"] + pub ITER_OUT_OF_BOUNDS, + suspicious, + "calls to `.take()` or `.skip()` that are out of bounds" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3676,7 +3701,8 @@ impl_lint_pass!(Methods => [ STRING_LIT_CHARS_ANY, ITER_SKIP_ZERO, FILTER_MAP_BOOL_THEN, - READONLY_WRITE_LOCK + READONLY_WRITE_LOCK, + ITER_OUT_OF_BOUNDS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4136,6 +4162,7 @@ impl Methods { }, ("skip", [arg]) => { iter_skip_zero::check(cx, expr, arg); + iter_out_of_bounds::check_skip(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check(cx, expr, recv, recv2, @@ -4163,7 +4190,8 @@ impl Methods { } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("take", [_arg]) => { + ("take", [arg]) => { + iter_out_of_bounds::check_take(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false); diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e72d063cfd9..61022ea0651 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -49,6 +49,7 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; +pub const ITER_ONCE: [&str; 5] = ["core", "iter", "sources", "once", "Once"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; @@ -166,3 +167,4 @@ pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"]; pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"]; #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; +pub const ARRAY_INTO_ITER: [&str; 4] = ["core", "array", "iter", "IntoIter"]; diff --git a/tests/ui/iter_out_of_bounds.rs b/tests/ui/iter_out_of_bounds.rs new file mode 100644 index 00000000000..07908f929cd --- /dev/null +++ b/tests/ui/iter_out_of_bounds.rs @@ -0,0 +1,44 @@ +#![deny(clippy::iter_out_of_bounds)] + +fn opaque_empty_iter() -> impl Iterator { + std::iter::empty() +} + +fn main() { + for _ in [1, 2, 3].iter().skip(4) { + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + unreachable!(); + } + for (i, _) in [1, 2, 3].iter().take(4).enumerate() { + //~^ ERROR: this `.take()` call takes more items than the iterator will produce + assert!(i <= 2); + } + + #[allow(clippy::needless_borrow)] + for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} + //~^ ERROR: this `.take()` call takes more items than the iterator will produce + + for _ in [1, 2, 3].iter().skip(4) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + + // Should not lint + for _ in opaque_empty_iter().skip(1) {} + + // Should not lint + let empty: [i8; 0] = []; + for _ in empty.iter().skip(1) {} + + let empty = std::iter::empty::; + + for _ in empty().skip(1) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + + for _ in empty().take(1) {} + //~^ ERROR: this `.take()` call takes more items than the iterator will produce + + for _ in std::iter::once(1).skip(2) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + + for _ in std::iter::once(1).take(2) {} + //~^ ERROR: this `.take()` call takes more items than the iterator will produce +} diff --git a/tests/ui/iter_out_of_bounds.stderr b/tests/ui/iter_out_of_bounds.stderr new file mode 100644 index 00000000000..c819ca3771f --- /dev/null +++ b/tests/ui/iter_out_of_bounds.stderr @@ -0,0 +1,71 @@ +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:8:14 + | +LL | for _ in [1, 2, 3].iter().skip(4) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator +note: the lint level is defined here + --> $DIR/iter_out_of_bounds.rs:1:9 + | +LL | #![deny(clippy::iter_out_of_bounds)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `.take()` call takes more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:12:19 + | +LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and the returned iterator will simply yield the same items + +error: this `.take()` call takes more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:18:14 + | +LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and the returned iterator will simply yield the same items + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:21:14 + | +LL | for _ in [1, 2, 3].iter().skip(4) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:33:14 + | +LL | for _ in empty().skip(1) {} + | ^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.take()` call takes more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:36:14 + | +LL | for _ in empty().take(1) {} + | ^^^^^^^^^^^^^^^ + | + = note: this operation is useless and the returned iterator will simply yield the same items + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:39:14 + | +LL | for _ in std::iter::once(1).skip(2) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.take()` call takes more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:42:14 + | +LL | for _ in std::iter::once(1).take(2) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and the returned iterator will simply yield the same items + +error: aborting due to 8 previous errors + diff --git a/tests/ui/iter_skip_zero.fixed b/tests/ui/iter_skip_zero.fixed index 62a83d5905b..447d07100e9 100644 --- a/tests/ui/iter_skip_zero.fixed +++ b/tests/ui/iter_skip_zero.fixed @@ -1,5 +1,5 @@ //@aux-build:proc_macros.rs -#![allow(clippy::useless_vec, unused)] +#![allow(clippy::useless_vec, clippy::iter_out_of_bounds, unused)] #![warn(clippy::iter_skip_zero)] #[macro_use] diff --git a/tests/ui/iter_skip_zero.rs b/tests/ui/iter_skip_zero.rs index c96696dde65..ba63c398180 100644 --- a/tests/ui/iter_skip_zero.rs +++ b/tests/ui/iter_skip_zero.rs @@ -1,5 +1,5 @@ //@aux-build:proc_macros.rs -#![allow(clippy::useless_vec, unused)] +#![allow(clippy::useless_vec, clippy::iter_out_of_bounds, unused)] #![warn(clippy::iter_skip_zero)] #[macro_use] -- cgit 1.4.1-3-g733a5 From 11072b51fa2b8fbcf68f8cf6a5f4140b19c16241 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 25 Aug 2023 01:13:35 +0200 Subject: lint vecs, version bump, more tests --- clippy_lints/src/methods/iter_out_of_bounds.rs | 65 ++++++++++++++++---------- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/iter_out_of_bounds.rs | 22 +++++++-- tests/ui/iter_out_of_bounds.stderr | 58 +++++++++++++++++++---- tests/ui/iter_skip_next.fixed | 1 + tests/ui/iter_skip_next.rs | 1 + tests/ui/iter_skip_next.stderr | 14 +++--- tests/ui/iter_skip_next_unfixable.rs | 2 +- 8 files changed, 119 insertions(+), 46 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs index 0a94700ae8e..79c6d63254b 100644 --- a/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::{is_trait_method, match_def_path, paths}; +use clippy_utils::higher::VecArgs; +use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -8,34 +9,49 @@ use rustc_span::sym; use super::ITER_OUT_OF_BOUNDS; +fn expr_as_u128(cx: &LateContext<'_>, e: &Expr<'_>) -> Option { + if let ExprKind::Lit(lit) = expr_or_init(cx, e).kind + && let LitKind::Int(n, _) = lit.node + { + Some(n) + } else { + None + } +} + /// Attempts to extract the length out of an iterator expression. fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> Option { - let iter_ty = cx.typeck_results().expr_ty(iter); - - if let ty::Adt(adt, substs) = iter_ty.kind() { - let did = adt.did(); + let ty::Adt(adt, substs) = cx.typeck_results().expr_ty(iter).kind() else { + return None; + }; + let did = adt.did(); - if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) { - // For array::IntoIter, the length is the second generic - // parameter. - substs - .const_at(1) - .try_eval_target_usize(cx.tcx, cx.param_env) - .map(u128::from) - } else if match_def_path(cx, did, &paths::SLICE_ITER) - && let ExprKind::MethodCall(_, recv, ..) = iter.kind - && let ExprKind::Array(array) = recv.peel_borrows().kind - { + if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) { + // For array::IntoIter, the length is the second generic + // parameter. + substs + .const_at(1) + .try_eval_target_usize(cx.tcx, cx.param_env) + .map(u128::from) + } else if match_def_path(cx, did, &paths::SLICE_ITER) + && let ExprKind::MethodCall(_, recv, ..) = iter.kind + { + if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..) - array.len().try_into().ok() - } else if match_def_path(cx, did, &paths::ITER_EMPTY) { - Some(0) - } else if match_def_path(cx, did, &paths::ITER_ONCE) { - Some(1) + len.try_eval_target_usize(cx.tcx, cx.param_env).map(u128::from) + } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) { + match args { + VecArgs::Vec(vec) => vec.len().try_into().ok(), + VecArgs::Repeat(_, len) => expr_as_u128(cx, len), + } } else { None } - } else { + } else if match_def_path(cx, did, &paths::ITER_EMPTY) { + Some(0) + } else if match_def_path(cx, did, &paths::ITER_ONCE) { + Some(1) + } else { None } } @@ -50,9 +66,8 @@ fn check<'tcx>( ) { if is_trait_method(cx, expr, sym::Iterator) && let Some(len) = get_iterator_length(cx, recv) - && let ExprKind::Lit(lit) = arg.kind - && let LitKind::Int(skip, _) = lit.node - && skip > len + && let Some(skipped) = expr_as_u128(cx, arg) + && skipped > len { span_lint_and_note(cx, ITER_OUT_OF_BOUNDS, expr.span, message, None, note); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5dbbd7f9618..76beb9380a9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3557,7 +3557,7 @@ declare_clippy_lint! { /// ```rust /// for _ in [1, 2, 3].iter() {} /// ``` - #[clippy::version = "1.73.0"] + #[clippy::version = "1.74.0"] pub ITER_OUT_OF_BOUNDS, suspicious, "calls to `.take()` or `.skip()` that are out of bounds" diff --git a/tests/ui/iter_out_of_bounds.rs b/tests/ui/iter_out_of_bounds.rs index 07908f929cd..a2c17b452d6 100644 --- a/tests/ui/iter_out_of_bounds.rs +++ b/tests/ui/iter_out_of_bounds.rs @@ -1,4 +1,7 @@ +//@no-rustfix + #![deny(clippy::iter_out_of_bounds)] +#![allow(clippy::useless_vec)] fn opaque_empty_iter() -> impl Iterator { std::iter::empty() @@ -21,12 +24,25 @@ fn main() { for _ in [1, 2, 3].iter().skip(4) {} //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + for _ in [1; 3].iter().skip(4) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + // Should not lint for _ in opaque_empty_iter().skip(1) {} - // Should not lint - let empty: [i8; 0] = []; - for _ in empty.iter().skip(1) {} + for _ in vec![1, 2, 3].iter().skip(4) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + + for _ in vec![1; 3].iter().skip(4) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + + let x = [1, 2, 3]; + for _ in x.iter().skip(4) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + + let n = 4; + for _ in x.iter().skip(n) {} + //~^ ERROR: this `.skip()` call skips more items than the iterator will produce let empty = std::iter::empty::; diff --git a/tests/ui/iter_out_of_bounds.stderr b/tests/ui/iter_out_of_bounds.stderr index c819ca3771f..d4b7b4355d0 100644 --- a/tests/ui/iter_out_of_bounds.stderr +++ b/tests/ui/iter_out_of_bounds.stderr @@ -1,18 +1,18 @@ error: this `.skip()` call skips more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:8:14 + --> $DIR/iter_out_of_bounds.rs:11:14 | LL | for _ in [1, 2, 3].iter().skip(4) { | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this operation is useless and will create an empty iterator note: the lint level is defined here - --> $DIR/iter_out_of_bounds.rs:1:9 + --> $DIR/iter_out_of_bounds.rs:3:9 | LL | #![deny(clippy::iter_out_of_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `.take()` call takes more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:12:19 + --> $DIR/iter_out_of_bounds.rs:15:19 | LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:18:14 + --> $DIR/iter_out_of_bounds.rs:21:14 | LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,23 +28,63 @@ LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:21:14 + --> $DIR/iter_out_of_bounds.rs:24:14 | LL | for _ in [1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this operation is useless and will create an empty iterator +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:27:14 + | +LL | for _ in [1; 3].iter().skip(4) {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + error: this `.skip()` call skips more items than the iterator will produce --> $DIR/iter_out_of_bounds.rs:33:14 | +LL | for _ in vec![1, 2, 3].iter().skip(4) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:36:14 + | +LL | for _ in vec![1; 3].iter().skip(4) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:40:14 + | +LL | for _ in x.iter().skip(4) {} + | ^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:44:14 + | +LL | for _ in x.iter().skip(n) {} + | ^^^^^^^^^^^^^^^^ + | + = note: this operation is useless and will create an empty iterator + +error: this `.skip()` call skips more items than the iterator will produce + --> $DIR/iter_out_of_bounds.rs:49:14 + | LL | for _ in empty().skip(1) {} | ^^^^^^^^^^^^^^^ | = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:36:14 + --> $DIR/iter_out_of_bounds.rs:52:14 | LL | for _ in empty().take(1) {} | ^^^^^^^^^^^^^^^ @@ -52,7 +92,7 @@ LL | for _ in empty().take(1) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:39:14 + --> $DIR/iter_out_of_bounds.rs:55:14 | LL | for _ in std::iter::once(1).skip(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,12 +100,12 @@ LL | for _ in std::iter::once(1).skip(2) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> $DIR/iter_out_of_bounds.rs:42:14 + --> $DIR/iter_out_of_bounds.rs:58:14 | LL | for _ in std::iter::once(1).take(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this operation is useless and the returned iterator will simply yield the same items -error: aborting due to 8 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index 310b24a9cde..3e41b363249 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -4,6 +4,7 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(clippy::useless_vec)] +#![allow(clippy::iter_out_of_bounds)] #![allow(unused_mut, dead_code)] extern crate option_helpers; diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 222d6a2a184..6d96441ca96 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -4,6 +4,7 @@ #![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(clippy::useless_vec)] +#![allow(clippy::iter_out_of_bounds)] #![allow(unused_mut, dead_code)] extern crate option_helpers; diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index ca6970b27f1..4ee26e088ce 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,5 +1,5 @@ error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:16:28 + --> $DIR/iter_skip_next.rs:17:28 | LL | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` @@ -7,37 +7,37 @@ LL | let _ = some_vec.iter().skip(42).next(); = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:17:36 + --> $DIR/iter_skip_next.rs:18:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:18:20 + --> $DIR/iter_skip_next.rs:19:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:19:33 + --> $DIR/iter_skip_next.rs:20:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:27:26 + --> $DIR/iter_skip_next.rs:28:26 | LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:29:29 + --> $DIR/iter_skip_next.rs:30:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:35:29 + --> $DIR/iter_skip_next.rs:36:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` diff --git a/tests/ui/iter_skip_next_unfixable.rs b/tests/ui/iter_skip_next_unfixable.rs index 9c224f4117d..6c98bdc8c88 100644 --- a/tests/ui/iter_skip_next_unfixable.rs +++ b/tests/ui/iter_skip_next_unfixable.rs @@ -1,5 +1,5 @@ #![warn(clippy::iter_skip_next)] -#![allow(dead_code)] +#![allow(dead_code, clippy::iter_out_of_bounds)] //@no-rustfix /// Checks implementation of `ITER_SKIP_NEXT` lint fn main() { -- cgit 1.4.1-3-g733a5 From 6eb7a46b8872af41e467d5ee96fd15c5741fec49 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Wed, 30 Aug 2023 13:36:37 +0200 Subject: Documentation Formatting --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5fb0d9f0a57..df44b1a676b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3054,12 +3054,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// vec!(1, 2, 3, 4, 5).resize(0, 5) + /// vec![1, 2, 3, 4, 5].resize(0, 5) /// ``` /// /// Use instead: /// ```rust - /// vec!(1, 2, 3, 4, 5).clear() + /// vec![1, 2, 3, 4, 5].clear() /// ``` #[clippy::version = "1.46.0"] pub VEC_RESIZE_TO_ZERO, -- cgit 1.4.1-3-g733a5 From c29de92d85f22bdc8814e87e4d4ee9f46d3c679e Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 1 Sep 2023 17:05:30 +0000 Subject: Return a value from find_format_args instead of using a callback --- clippy_lints/src/explicit_write.rs | 90 ++++++++++++------------- clippy_lints/src/format.rs | 14 ++-- clippy_lints/src/format_args.rs | 20 +++--- clippy_lints/src/format_impl.rs | 41 ++++++----- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 13 ++-- clippy_lints/src/utils/format_args_collector.rs | 28 ++++++-- clippy_lints/src/write.rs | 10 +-- clippy_utils/src/macros.rs | 37 +++++----- 9 files changed, 126 insertions(+), 129 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 4b9ca8c917e..b612cc00bf9 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -57,54 +57,52 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { } else { None } + && let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) { - find_format_args(cx, write_arg, ExpnId::root(), |format_args| { - let calling_macro = - // ordering is important here, since `writeln!` uses `write!` internally - if is_expn_of(write_call.span, "writeln").is_some() { - Some("writeln") - } else if is_expn_of(write_call.span, "write").is_some() { - Some("write") - } else { - None - }; - let prefix = if dest_name == "stderr" { - "e" - } else { - "" - }; + // ordering is important here, since `writeln!` uses `write!` internally + let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { + Some("writeln") + } else if is_expn_of(write_call.span, "write").is_some() { + Some("write") + } else { + None + }; + let prefix = if dest_name == "stderr" { + "e" + } else { + "" + }; - // We need to remove the last trailing newline from the string because the - // underlying `fmt::write` function doesn't know whether `println!` or `print!` was - // used. - let (used, sugg_mac) = if let Some(macro_name) = calling_macro { - ( - format!("{macro_name}!({dest_name}(), ...)"), - macro_name.replace("write", "print"), - ) - } else { - ( - format!("{dest_name}().write_fmt(...)"), - "print".into(), - ) - }; - let mut applicability = Applicability::MachineApplicable; - let inputs_snippet = snippet_with_applicability( - cx, - format_args_inputs_span(format_args), - "..", - &mut applicability, - ); - span_lint_and_sugg( - cx, - EXPLICIT_WRITE, - expr.span, - &format!("use of `{used}.unwrap()`"), - "try", - format!("{prefix}{sugg_mac}!({inputs_snippet})"), - applicability, - ); - }); + // We need to remove the last trailing newline from the string because the + // underlying `fmt::write` function doesn't know whether `println!` or `print!` was + // used. + let (used, sugg_mac) = if let Some(macro_name) = calling_macro { + ( + format!("{macro_name}!({dest_name}(), ...)"), + macro_name.replace("write", "print"), + ) + } else { + ( + format!("{dest_name}().write_fmt(...)"), + "print".into(), + ) + }; + let mut applicability = Applicability::MachineApplicable; + let inputs_snippet = snippet_with_applicability( + cx, + format_args_inputs_span(&format_args), + "..", + &mut applicability, + ); + span_lint_and_sugg( + cx, + EXPLICIT_WRITE, + expr.span, + &format!("use of `{used}.unwrap()`"), + "try", + format!("{prefix}{sugg_mac}!({inputs_snippet})"), + applicability, + ); } } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index f4f8bdc2c44..b748d329367 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -43,14 +43,10 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { - return; - }; - if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { - return; - } - - find_format_args(cx, expr, macro_call.expn, |format_args| { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) + && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) + { let mut applicability = Applicability::MachineApplicable; let call_site = macro_call.span; @@ -91,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { }, _ => {}, } - }); + } } } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 01c714c414b..39abf5c2def 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -186,15 +186,10 @@ impl FormatArgs { impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { - return; - }; - if !is_format_macro(cx, macro_call.def_id) { - return; - } - let name = cx.tcx.item_name(macro_call.def_id); - - find_format_args(cx, expr, macro_call.expn, |format_args| { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && is_format_macro(cx, macro_call.def_id) + && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) + { for piece in &format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece && let Ok(index) = placeholder.argument.index @@ -206,12 +201,13 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if placeholder.format_trait != FormatTrait::Display || placeholder.format_options != FormatOptions::default() - || is_aliased(format_args, index) + || is_aliased(&format_args, index) { continue; } if let Ok(arg_hir_expr) = arg_expr { + let name = cx.tcx.item_name(macro_call.def_id); check_format_in_format_args(cx, macro_call.span, name, arg_hir_expr); check_to_string_in_format_args(cx, name, arg_hir_expr); } @@ -219,9 +215,9 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { } if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { - check_uninlined_args(cx, format_args, macro_call.span, macro_call.def_id, self.ignore_mixed); + check_uninlined_args(cx, &format_args, macro_call.span, macro_call.def_id, self.ignore_mixed); } - }); + } } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 76369bccf9e..1d2f7cb7130 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -170,30 +170,29 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, if let Some(outer_macro) = root_macro_call_first_node(cx, expr) && let macro_def_id = outer_macro.def_id && is_format_macro(cx, macro_def_id) + && let Some(format_args) = find_format_args(cx, expr, outer_macro.expn) { - find_format_args(cx, expr, outer_macro.expn, |format_args| { - for piece in &format_args.template { - if let FormatArgsPiece::Placeholder(placeholder) = piece - && let trait_name = match placeholder.format_trait { - FormatTrait::Display => sym::Display, - FormatTrait::Debug => sym::Debug, - FormatTrait::LowerExp => sym!(LowerExp), - FormatTrait::UpperExp => sym!(UpperExp), - FormatTrait::Octal => sym!(Octal), - FormatTrait::Pointer => sym::Pointer, - FormatTrait::Binary => sym!(Binary), - FormatTrait::LowerHex => sym!(LowerHex), - FormatTrait::UpperHex => sym!(UpperHex), - } - && trait_name == impl_trait.name - && let Ok(index) = placeholder.argument.index - && let Some(arg) = format_args.arguments.all_args().get(index) - && let Ok(arg_expr) = find_format_arg_expr(expr, arg) - { - check_format_arg_self(cx, expr.span, arg_expr, impl_trait); + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let trait_name = match placeholder.format_trait { + FormatTrait::Display => sym::Display, + FormatTrait::Debug => sym::Debug, + FormatTrait::LowerExp => sym!(LowerExp), + FormatTrait::UpperExp => sym!(UpperExp), + FormatTrait::Octal => sym!(Octal), + FormatTrait::Pointer => sym::Pointer, + FormatTrait::Binary => sym!(Binary), + FormatTrait::LowerHex => sym!(LowerHex), + FormatTrait::UpperHex => sym!(UpperHex), } + && trait_name == impl_trait.name + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + && let Ok(arg_expr) = find_format_arg_expr(expr, arg) + { + check_format_arg_self(cx, expr.span, arg_expr, impl_trait); } - }); + } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f5035dcfeeb..3f6bdb2b62c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -609,7 +609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: .collect(), )) }); - store.register_early_pass(|| Box::new(utils::format_args_collector::FormatArgsCollector)); + store.register_early_pass(|| Box::::default()); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index d3e90e4bba3..40e487bf650 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -131,13 +131,12 @@ pub(super) fn check<'tcx>( let mut applicability = Applicability::MachineApplicable; - //Special handling for `format!` as arg_root + // Special handling for `format!` as arg_root if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) { - if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { - return; - } - find_format_args(cx, arg_root, macro_call.expn, |format_args| { - let span = format_args_inputs_span(format_args); + if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) + && let Some(format_args) = find_format_args(cx, arg_root, macro_call.expn) + { + let span = format_args_inputs_span(&format_args); let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); span_lint_and_sugg( cx, @@ -148,7 +147,7 @@ pub(super) fn check<'tcx>( format!("unwrap_or_else({closure_args} panic!({sugg}))"), applicability, ); - }); + } return; } diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 6d3493523e6..94a9a7c241b 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,12 +1,15 @@ -use clippy_utils::macros::collect_ast_format_args; +use clippy_utils::macros::AST_FORMAT_ARGS; use clippy_utils::source::snippet_opt; use itertools::Itertools; -use rustc_ast::{Expr, ExprKind, FormatArgs}; +use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; +use rustc_data_structures::fx::FxHashMap; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::hygiene; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{hygiene, Span}; use std::iter::once; +use std::mem; +use std::rc::Rc; declare_clippy_lint! { /// ### What it does @@ -17,7 +20,12 @@ declare_clippy_lint! { "collects `format_args` AST nodes for use in later lints" } -declare_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); +#[derive(Default)] +pub struct FormatArgsCollector { + format_args: FxHashMap>, +} + +impl_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); impl EarlyLintPass for FormatArgsCollector { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { @@ -26,9 +34,17 @@ impl EarlyLintPass for FormatArgsCollector { return; } - collect_ast_format_args(expr.span, args); + self.format_args + .insert(expr.span.with_parent(None), Rc::new((**args).clone())); } } + + fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) { + AST_FORMAT_ARGS.with(|ast_format_args| { + let result = ast_format_args.set(mem::take(&mut self.format_args)); + debug_assert!(result.is_ok()); + }); + } } /// Detects if the format string or an argument has its span set by a proc macro to something inside diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index a9957b18a53..da083fb14aa 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -304,7 +304,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { _ => return, } - find_format_args(cx, expr, macro_call.expn, |format_args| { + if let Some(format_args) = find_format_args(cx, expr, macro_call.expn) { // ignore `writeln!(w)` and `write!(v, some_macro!())` if format_args.span.from_expansion() { return; @@ -312,15 +312,15 @@ impl<'tcx> LateLintPass<'tcx> for Write { match diag_name { sym::print_macro | sym::eprint_macro | sym::write_macro => { - check_newline(cx, format_args, ¯o_call, name); + check_newline(cx, &format_args, ¯o_call, name); }, sym::println_macro | sym::eprintln_macro | sym::writeln_macro => { - check_empty_string(cx, format_args, ¯o_call, name); + check_empty_string(cx, &format_args, ¯o_call, name); }, _ => {}, } - check_literal(cx, format_args, name); + check_literal(cx, &format_args, name); if !self.in_debug_impl { for piece in &format_args.template { @@ -334,7 +334,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { } } } - }); + } } } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 98724fcbe96..82508bcdb85 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -10,8 +10,9 @@ use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; -use std::cell::RefCell; +use std::cell::OnceCell; use std::ops::ControlFlow; +use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ @@ -374,30 +375,21 @@ thread_local! { /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an /// assumption that the early pass that populates the map and the later late passes will all be /// running on the same thread. - static AST_FORMAT_ARGS: RefCell> = { + #[doc(hidden)] + pub static AST_FORMAT_ARGS: OnceCell>> = { static CALLED: AtomicBool = AtomicBool::new(false); debug_assert!( !CALLED.swap(true, Ordering::SeqCst), "incorrect assumption: `AST_FORMAT_ARGS` should only be accessed by a single thread", ); - RefCell::default() + OnceCell::new() }; } -/// Record [`rustc_ast::FormatArgs`] for use in late lint passes, this should only be called by -/// `FormatArgsCollector` -pub fn collect_ast_format_args(span: Span, format_args: &FormatArgs) { - AST_FORMAT_ARGS.with(|ast_format_args| { - ast_format_args - .borrow_mut() - .insert(span.with_parent(None), format_args.clone()); - }); -} - -/// Calls `callback` with an AST [`FormatArgs`] node if a `format_args` expansion is found as a -/// descendant of `expn_id` -pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId, callback: impl FnOnce(&FormatArgs)) { +/// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of +/// `expn_id` +pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option> { let format_args_expr = for_each_expr(start, |expr| { let ctxt = expr.span.ctxt(); if ctxt.outer_expn().is_descendant_of(expn_id) { @@ -412,13 +404,14 @@ pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId, } else { ControlFlow::Continue(Descend::No) } - }); + })?; - if let Some(expr) = format_args_expr { - AST_FORMAT_ARGS.with(|ast_format_args| { - ast_format_args.borrow().get(&expr.span.with_parent(None)).map(callback); - }); - } + AST_FORMAT_ARGS.with(|ast_format_args| { + ast_format_args + .get()? + .get(&format_args_expr.span.with_parent(None)) + .map(Rc::clone) + }) } /// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if -- cgit 1.4.1-3-g733a5 From c9b212d5ffa5dcfe36ed41658c71dcbcbf949dd8 Mon Sep 17 00:00:00 2001 From: mojave2 Date: Fri, 15 Sep 2023 14:23:58 +0800 Subject: fix filter_map_bool_then with a bool reference --- clippy_lints/src/methods/filter_map_bool_then.rs | 5 +++-- tests/ui/filter_map_bool_then.fixed | 5 +++++ tests/ui/filter_map_bool_then.rs | 5 +++++ tests/ui/filter_map_bool_then.stderr | 8 +++++++- 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index fafc9709770..ac5bff6fee0 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::Binder; +use rustc_middle::ty::{self, Binder}; use rustc_span::{sym, Span}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { @@ -36,6 +36,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) && match_def_path(cx, def_id, &BOOL_THEN) && !is_from_proc_macro(cx, expr) + && let ref_bool = matches!(cx.typeck_results().expr_ty(recv).kind(), ty::Ref(..)) && let Some(param_snippet) = snippet_opt(cx, param.span) && let Some(filter) = snippet_opt(cx, recv.span) && let Some(map) = snippet_opt(cx, then_body.span) @@ -46,7 +47,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & call_span, "usage of `bool::then` in `filter_map`", "use `filter` then `map` instead", - format!("filter(|&{param_snippet}| {filter}).map(|{param_snippet}| {map})"), + format!("filter(|&{param_snippet}| {}{filter}).map(|{param_snippet}| {map})", if ref_bool { "*" } else { "" }), Applicability::MachineApplicable, ); } diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed index 6de870a9289..67b984ce025 100644 --- a/tests/ui/filter_map_bool_then.fixed +++ b/tests/ui/filter_map_bool_then.fixed @@ -55,3 +55,8 @@ fn main() { fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str> { iter.filter_map(|(_, s): (&str, _)| Some(s)).collect() } + +fn issue11503() { + let bools: &[bool] = &[true, false, false, true]; + let _: Vec = bools.iter().enumerate().filter(|&(i, b)| *b).map(|(i, b)| i).collect(); +} diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs index 4108177e3a0..b716fd70fa0 100644 --- a/tests/ui/filter_map_bool_then.rs +++ b/tests/ui/filter_map_bool_then.rs @@ -55,3 +55,8 @@ fn main() { fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str> { iter.filter_map(|(_, s): (&str, _)| Some(s)).collect() } + +fn issue11503() { + let bools: &[bool] = &[true, false, false, true]; + let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); +} diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr index 86ef6edf8ee..1fee93afb36 100644 --- a/tests/ui/filter_map_bool_then.stderr +++ b/tests/ui/filter_map_bool_then.stderr @@ -37,5 +37,11 @@ error: usage of `bool::then` in `filter_map` LL | v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i == &NonCopy)).map(|i| i)` -error: aborting due to 6 previous errors +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:61:50 + | +LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| *b).map(|(i, b)| i)` + +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 981e96008b58d34e9c52b0aa3b318974c75b9d1d Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 11 Sep 2023 22:46:15 +0200 Subject: new lint: `path_ends_with_ext` --- CHANGELOG.md | 2 + book/src/lint_configuration.md | 10 ++++ clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 7 +++ clippy_lints/src/methods/mod.rs | 47 +++++++++++++++++++ clippy_lints/src/methods/path_ends_with_ext.rs | 53 ++++++++++++++++++++++ clippy_lints/src/utils/conf.rs | 5 ++ .../toml_unknown_key/conf_unknown_key.stderr | 2 + tests/ui/path_ends_with_ext.fixed | 36 +++++++++++++++ tests/ui/path_ends_with_ext.rs | 36 +++++++++++++++ tests/ui/path_ends_with_ext.stderr | 17 +++++++ 11 files changed, 216 insertions(+) create mode 100644 clippy_lints/src/methods/path_ends_with_ext.rs create mode 100644 tests/ui/path_ends_with_ext.fixed create mode 100644 tests/ui/path_ends_with_ext.rs create mode 100644 tests/ui/path_ends_with_ext.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aca13a6cf6..5e01e8d07bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5245,6 +5245,7 @@ Released 2018-09-13 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite +[`path_ends_with_ext`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters @@ -5575,5 +5576,6 @@ Released 2018-09-13 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings [`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments [`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates +[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 52c795e04fe..3aeb6206fca 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -751,6 +751,16 @@ Which crates to allow absolute paths from * [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) +## `allowed-dotfiles` +Additional dotfiles (files or directories starting with a dot) to allow + +**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) + +--- +**Affected lints:** +* [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) + + ## `enforce-iter-loop-reborrow` #### Example ``` diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ecf44e05920..4772f3d8037 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -399,6 +399,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OR_FUN_CALL_INFO, crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, + crate::methods::PATH_ENDS_WITH_EXT_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::READONLY_WRITE_LOCK_INFO, crate::methods::READ_LINE_WITHOUT_TRIM_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3f6bdb2b62c..8f603d5d988 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -662,12 +662,19 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const; store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv()))); + let allowed_dotfiles = conf + .allowed_dotfiles + .iter() + .cloned() + .chain(methods::DEFAULT_ALLOWED_DOTFILES.iter().copied().map(ToOwned::to_owned)) + .collect::>(); store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, msrv(), allow_expect_in_tests, allow_unwrap_in_tests, + allowed_dotfiles.clone(), )) }); store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv()))); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 81223fa8d95..f4682364806 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -74,6 +74,7 @@ mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; +mod path_ends_with_ext; mod range_zip_with_len; mod read_line_without_trim; mod readonly_write_lock; @@ -120,6 +121,8 @@ 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, peel_blocks, return_ty}; use if_chain::if_chain; +pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_hir_analysis::hir_ty_to_ty; @@ -3563,11 +3566,51 @@ declare_clippy_lint! { "calls to `.take()` or `.skip()` that are out of bounds" } +declare_clippy_lint! { + /// ### What it does + /// Looks for calls to `Path::ends_with` calls where the argument looks like a file extension. + /// + /// By default, Clippy has a short list of known filenames that start with a dot + /// but aren't necessarily file extensions (e.g. the `.git` folder), which are allowed by default. + /// The `allowed-dotfiles` configuration can be used to allow additional + /// file extensions that Clippy should not lint. + /// + /// ### Why is this bad? + /// This doesn't actually compare file extensions. Rather, `ends_with` compares the given argument + /// to the last **component** of the path and checks if it matches exactly. + /// + /// ### Known issues + /// File extensions are often at most three characters long, so this only lints in those cases + /// in an attempt to avoid false positives. + /// Any extension names longer than that are assumed to likely be real path components and are + /// therefore ignored. + /// + /// ### Example + /// ```rust + /// # use std::path::Path; + /// fn is_markdown(path: &Path) -> bool { + /// path.ends_with(".md") + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::path::Path; + /// fn is_markdown(path: &Path) -> bool { + /// path.extension().is_some_and(|ext| ext == "md") + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub PATH_ENDS_WITH_EXT, + suspicious, + "attempting to compare file extensions using `Path::ends_with`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, + allowed_dotfiles: FxHashSet, } impl Methods { @@ -3577,12 +3620,14 @@ impl Methods { msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, + allowed_dotfiles: FxHashSet, ) -> Self { Self { avoid_breaking_exported_api, msrv, allow_expect_in_tests, allow_unwrap_in_tests, + allowed_dotfiles, } } } @@ -3703,6 +3748,7 @@ impl_lint_pass!(Methods => [ FILTER_MAP_BOOL_THEN, READONLY_WRITE_LOCK, ITER_OUT_OF_BOUNDS, + PATH_ENDS_WITH_EXT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3978,6 +4024,7 @@ impl Methods { if let ExprKind::MethodCall(.., span) = expr.kind { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); } + path_ends_with_ext::check(cx, recv, arg, expr, &self.msrv, &self.allowed_dotfiles); }, ("expect", [_]) => { match method_call(recv) { diff --git a/clippy_lints/src/methods/path_ends_with_ext.rs b/clippy_lints/src/methods/path_ends_with_ext.rs new file mode 100644 index 00000000000..3347c8c1620 --- /dev/null +++ b/clippy_lints/src/methods/path_ends_with_ext.rs @@ -0,0 +1,53 @@ +use super::PATH_ENDS_WITH_EXT; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs; +use clippy_utils::msrvs::Msrv; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_ast::{LitKind, StrStyle}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; +use std::fmt::Write; + +pub const DEFAULT_ALLOWED_DOTFILES: &[&str] = &[ + "git", "svn", "gem", "npm", "vim", "env", "rnd", "ssh", "vnc", "smb", "nvm", "bin", +]; + +pub(super) fn check( + cx: &LateContext<'_>, + recv: &Expr<'_>, + path: &Expr<'_>, + expr: &Expr<'_>, + msrv: &Msrv, + allowed_dotfiles: &FxHashSet, +) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::Path) + && !path.span.from_expansion() + && let ExprKind::Lit(lit) = path.kind + && let LitKind::Str(path, StrStyle::Cooked) = lit.node + && let Some(path) = path.as_str().strip_prefix('.') + && (1..=3).contains(&path.len()) + && !allowed_dotfiles.contains(path) + && path.chars().all(char::is_alphanumeric) + { + let mut sugg = snippet(cx, recv.span, "..").into_owned(); + if msrv.meets(msrvs::OPTION_IS_SOME_AND) { + let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#); + } else { + let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#); + }; + + span_lint_and_sugg( + cx, + PATH_ENDS_WITH_EXT, + expr.span, + "this looks like a failed attempt at checking for the file extension", + "try", + sugg, + Applicability::MaybeIncorrect + ); + } +} diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 26889475522..e1280ef38ef 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -561,6 +561,11 @@ define_Conf! { /// Which crates to allow absolute paths from (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet = rustc_data_structures::fx::FxHashSet::default()), + /// Lint: PATH_ENDS_WITH_EXT. + /// + /// Additional dotfiles (files or directories starting with a dot) to allow + (allowed_dotfiles: rustc_data_structures::fx::FxHashSet = + rustc_data_structures::fx::FxHashSet::default()), /// Lint: EXPLICIT_ITER_LOOP /// /// Whether to recommend using implicit into iter for reborrowed values. diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index b97bb144468..4bed5c149f5 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -10,6 +10,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allowed-dotfiles allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed @@ -82,6 +83,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-print-in-tests allow-private-module-inception allow-unwrap-in-tests + allowed-dotfiles allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed diff --git a/tests/ui/path_ends_with_ext.fixed b/tests/ui/path_ends_with_ext.fixed new file mode 100644 index 00000000000..49767e242ce --- /dev/null +++ b/tests/ui/path_ends_with_ext.fixed @@ -0,0 +1,36 @@ +#![warn(clippy::path_ends_with_ext)] +use std::path::Path; + +macro_rules! arg { + () => { + ".md" + }; +} + +fn test(path: &Path) { + path.extension().is_some_and(|ext| ext == "md"); + //~^ ERROR: this looks like a failed attempt at checking for the file extension + + // some "extensions" are allowed by default + path.ends_with(".git"); + + // most legitimate "dotfiles" are longer than 3 chars, so we allow them as well + path.ends_with(".bashrc"); + + // argument from expn shouldn't trigger + path.ends_with(arg!()); + + path.ends_with(".."); + path.ends_with("./a"); + path.ends_with("."); + path.ends_with(""); +} + +// is_some_and was stabilized in 1.70, so suggest map_or(false, ..) if under that +#[clippy::msrv = "1.69"] +fn under_msv(path: &Path) -> bool { + path.extension().map_or(false, |ext| ext == "md") + //~^ ERROR: this looks like a failed attempt at checking for the file extension +} + +fn main() {} diff --git a/tests/ui/path_ends_with_ext.rs b/tests/ui/path_ends_with_ext.rs new file mode 100644 index 00000000000..2dfd046218a --- /dev/null +++ b/tests/ui/path_ends_with_ext.rs @@ -0,0 +1,36 @@ +#![warn(clippy::path_ends_with_ext)] +use std::path::Path; + +macro_rules! arg { + () => { + ".md" + }; +} + +fn test(path: &Path) { + path.ends_with(".md"); + //~^ ERROR: this looks like a failed attempt at checking for the file extension + + // some "extensions" are allowed by default + path.ends_with(".git"); + + // most legitimate "dotfiles" are longer than 3 chars, so we allow them as well + path.ends_with(".bashrc"); + + // argument from expn shouldn't trigger + path.ends_with(arg!()); + + path.ends_with(".."); + path.ends_with("./a"); + path.ends_with("."); + path.ends_with(""); +} + +// is_some_and was stabilized in 1.70, so suggest map_or(false, ..) if under that +#[clippy::msrv = "1.69"] +fn under_msv(path: &Path) -> bool { + path.ends_with(".md") + //~^ ERROR: this looks like a failed attempt at checking for the file extension +} + +fn main() {} diff --git a/tests/ui/path_ends_with_ext.stderr b/tests/ui/path_ends_with_ext.stderr new file mode 100644 index 00000000000..a73ab4d08e9 --- /dev/null +++ b/tests/ui/path_ends_with_ext.stderr @@ -0,0 +1,17 @@ +error: this looks like a failed attempt at checking for the file extension + --> $DIR/path_ends_with_ext.rs:11:5 + | +LL | path.ends_with(".md"); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `path.extension().is_some_and(|ext| ext == "md")` + | + = note: `-D clippy::path-ends-with-ext` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::path_ends_with_ext)]` + +error: this looks like a failed attempt at checking for the file extension + --> $DIR/path_ends_with_ext.rs:32:5 + | +LL | path.ends_with(".md") + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `path.extension().map_or(false, |ext| ext == "md")` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 860e800fa08734ff9d15a67115f8220e5fa2202e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:14:51 +0200 Subject: [`filter_map_bool_then`]: peel as many refs as needed --- clippy_lints/src/methods/filter_map_bool_then.rs | 15 +++++++++++---- tests/ui/filter_map_bool_then.fixed | 8 ++++++++ tests/ui/filter_map_bool_then.rs | 8 ++++++++ tests/ui/filter_map_bool_then.stderr | 14 +++++++++++++- 4 files changed, 40 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index ac5bff6fee0..dd4aa276663 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -2,13 +2,13 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::is_copy; +use clippy_utils::ty::{is_copy, peel_mid_ty_refs_is_mutable}; use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Binder}; +use rustc_middle::ty::Binder; use rustc_span::{sym, Span}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { @@ -36,7 +36,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) && match_def_path(cx, def_id, &BOOL_THEN) && !is_from_proc_macro(cx, expr) - && let ref_bool = matches!(cx.typeck_results().expr_ty(recv).kind(), ty::Ref(..)) + // Peel all refs (e.g. `&&&&mut &&&bool` -> `bool`) and get its count so we can suggest the exact + // amount of derefs to get to the bool in the filter. + // `peel_mid_ty_refs` alone doesn't handle mutable reference, so we use `_is_mutable` + // instead which counts them too and just ignore the resulting mutability + && let (_, needed_derefs, _) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv)) && let Some(param_snippet) = snippet_opt(cx, param.span) && let Some(filter) = snippet_opt(cx, recv.span) && let Some(map) = snippet_opt(cx, then_body.span) @@ -47,7 +51,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & call_span, "usage of `bool::then` in `filter_map`", "use `filter` then `map` instead", - format!("filter(|&{param_snippet}| {}{filter}).map(|{param_snippet}| {map})", if ref_bool { "*" } else { "" }), + format!( + "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", + derefs="*".repeat(needed_derefs) + ), Applicability::MachineApplicable, ); } diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed index 67b984ce025..d1c946585f5 100644 --- a/tests/ui/filter_map_bool_then.fixed +++ b/tests/ui/filter_map_bool_then.fixed @@ -59,4 +59,12 @@ fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str fn issue11503() { let bools: &[bool] = &[true, false, false, true]; let _: Vec = bools.iter().enumerate().filter(|&(i, b)| *b).map(|(i, b)| i).collect(); + + // Need to insert multiple derefs if there is more than one layer of references + let bools: &[&&bool] = &[&&true, &&false, &&false, &&true]; + let _: Vec = bools.iter().enumerate().filter(|&(i, b)| ***b).map(|(i, b)| i).collect(); + + // Should also suggest derefs when going through a mutable reference + let bools: &[&mut bool] = &[&mut true]; + let _: Vec = bools.iter().enumerate().filter(|&(i, b)| **b).map(|(i, b)| i).collect(); } diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs index b716fd70fa0..2d0ed282013 100644 --- a/tests/ui/filter_map_bool_then.rs +++ b/tests/ui/filter_map_bool_then.rs @@ -59,4 +59,12 @@ fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str fn issue11503() { let bools: &[bool] = &[true, false, false, true]; let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + + // Need to insert multiple derefs if there is more than one layer of references + let bools: &[&&bool] = &[&&true, &&false, &&false, &&true]; + let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + + // Should also suggest derefs when going through a mutable reference + let bools: &[&mut bool] = &[&mut true]; + let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); } diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr index 1fee93afb36..174786ff32e 100644 --- a/tests/ui/filter_map_bool_then.stderr +++ b/tests/ui/filter_map_bool_then.stderr @@ -43,5 +43,17 @@ error: usage of `bool::then` in `filter_map` LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| *b).map(|(i, b)| i)` -error: aborting due to 7 previous errors +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:65:50 + | +LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ***b).map(|(i, b)| i)` + +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:69:50 + | +LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| **b).map(|(i, b)| i)` + +error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From 2ec6f3b1ed22c3fa0b20eda5cf335c54f81b4462 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 16 Sep 2023 15:13:44 +0200 Subject: also count derefs through custom `Deref` impls --- clippy_lints/src/methods/filter_map_bool_then.rs | 13 +++++++------ tests/ui/filter_map_bool_then.fixed | 11 +++++++++++ tests/ui/filter_map_bool_then.rs | 11 +++++++++++ tests/ui/filter_map_bool_then.stderr | 8 +++++++- 4 files changed, 36 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index dd4aa276663..33657254965 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -2,12 +2,13 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{is_copy, peel_mid_ty_refs_is_mutable}; +use clippy_utils::ty::is_copy; use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::Binder; use rustc_span::{sym, Span}; @@ -36,11 +37,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) && match_def_path(cx, def_id, &BOOL_THEN) && !is_from_proc_macro(cx, expr) - // Peel all refs (e.g. `&&&&mut &&&bool` -> `bool`) and get its count so we can suggest the exact - // amount of derefs to get to the bool in the filter. - // `peel_mid_ty_refs` alone doesn't handle mutable reference, so we use `_is_mutable` - // instead which counts them too and just ignore the resulting mutability - && let (_, needed_derefs, _) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv)) + // Count the number of derefs needed to get to the bool because we need those in the suggestion + && let needed_derefs = cx.typeck_results().expr_adjustments(recv) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count() && let Some(param_snippet) = snippet_opt(cx, param.span) && let Some(filter) = snippet_opt(cx, recv.span) && let Some(map) = snippet_opt(cx, then_body.span) diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed index d1c946585f5..6a1b81fdbcb 100644 --- a/tests/ui/filter_map_bool_then.fixed +++ b/tests/ui/filter_map_bool_then.fixed @@ -67,4 +67,15 @@ fn issue11503() { // Should also suggest derefs when going through a mutable reference let bools: &[&mut bool] = &[&mut true]; let _: Vec = bools.iter().enumerate().filter(|&(i, b)| **b).map(|(i, b)| i).collect(); + + // Should also suggest derefs when going through a custom deref + struct DerefToBool; + impl std::ops::Deref for DerefToBool { + type Target = bool; + fn deref(&self) -> &Self::Target { + &true + } + } + let bools: &[&&DerefToBool] = &[&&DerefToBool]; + let _: Vec = bools.iter().enumerate().filter(|&(i, b)| ****b).map(|(i, b)| i).collect(); } diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs index 2d0ed282013..a41e88f8805 100644 --- a/tests/ui/filter_map_bool_then.rs +++ b/tests/ui/filter_map_bool_then.rs @@ -67,4 +67,15 @@ fn issue11503() { // Should also suggest derefs when going through a mutable reference let bools: &[&mut bool] = &[&mut true]; let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + + // Should also suggest derefs when going through a custom deref + struct DerefToBool; + impl std::ops::Deref for DerefToBool { + type Target = bool; + fn deref(&self) -> &Self::Target { + &true + } + } + let bools: &[&&DerefToBool] = &[&&DerefToBool]; + let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); } diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr index 174786ff32e..fab6987913a 100644 --- a/tests/ui/filter_map_bool_then.stderr +++ b/tests/ui/filter_map_bool_then.stderr @@ -55,5 +55,11 @@ error: usage of `bool::then` in `filter_map` LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| **b).map(|(i, b)| i)` -error: aborting due to 9 previous errors +error: usage of `bool::then` in `filter_map` + --> $DIR/filter_map_bool_then.rs:80:50 + | +LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ****b).map(|(i, b)| i)` + +error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 1c9f3bef8bb80dc8706e4595a262fe8825ccf74a Mon Sep 17 00:00:00 2001 From: Dev381 <49997896+Dev380@users.noreply.github.com> Date: Sun, 17 Sep 2023 17:50:45 -0400 Subject: Add redundant_as_str lint This lint checks for `as_str` on a `String` immediately followed by `as_bytes` or `is_empty` as those methods are available on `String` too. This could possibly also be extended to `&[u8]` in the future. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 29 ++++++++++++++++++++++++ clippy_lints/src/methods/redundant_as_str.rs | 34 ++++++++++++++++++++++++++++ tests/ui/redundant_as_str.fixed | 6 +++++ tests/ui/redundant_as_str.rs | 6 +++++ tests/ui/redundant_as_str.stderr | 17 ++++++++++++++ 7 files changed, 94 insertions(+) create mode 100644 clippy_lints/src/methods/redundant_as_str.rs create mode 100644 tests/ui/redundant_as_str.fixed create mode 100644 tests/ui/redundant_as_str.rs create mode 100644 tests/ui/redundant_as_str.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index a2484203e9e..8c9ab1e2402 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5281,6 +5281,7 @@ Released 2018-09-13 [`readonly_write_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#readonly_write_lock [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation +[`redundant_as_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_as_str [`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block [`redundant_at_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_at_rest_pattern [`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index b1ffc347812..aa2ca0e1149 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -403,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::RANGE_ZIP_WITH_LEN_INFO, crate::methods::READONLY_WRITE_LOCK_INFO, crate::methods::READ_LINE_WITHOUT_TRIM_INFO, + crate::methods::REDUNDANT_AS_STR_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, crate::methods::SEARCH_IS_SOME_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f4682364806..0b0a90bac0c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -78,6 +78,7 @@ mod path_ends_with_ext; mod range_zip_with_len; mod read_line_without_trim; mod readonly_write_lock; +mod redundant_as_str; mod repeat_once; mod search_is_some; mod seek_from_current; @@ -3605,6 +3606,32 @@ declare_clippy_lint! { "attempting to compare file extensions using `Path::ends_with`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself. + /// + /// ### Why is this bad? + /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. + /// + /// ### Example + /// ```rust + /// # #![allow(unused)] + /// let owned_string = "This is a string".to_owned(); + /// owned_string.as_str().as_bytes() + /// ``` + /// + /// Use instead: + /// ```rust + /// # #![allow(unused)] + /// let owned_string = "This is a string".to_owned(); + /// owned_string.as_bytes() + /// ``` + #[clippy::version = "1.74.0"] + pub REDUNDANT_AS_STR, + complexity, + "`as_str` used to call a method on `str` that is also available on `String`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3749,6 +3776,7 @@ impl_lint_pass!(Methods => [ READONLY_WRITE_LOCK, ITER_OUT_OF_BOUNDS, PATH_ENDS_WITH_EXT, + REDUNDANT_AS_STR, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3975,6 +4003,7 @@ impl Methods { ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, + ("as_bytes" | "is_empty", []) => if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); }, ("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), diff --git a/clippy_lints/src/methods/redundant_as_str.rs b/clippy_lints/src/methods/redundant_as_str.rs new file mode 100644 index 00000000000..98cd6afc2b7 --- /dev/null +++ b/clippy_lints/src/methods/redundant_as_str.rs @@ -0,0 +1,34 @@ +use super::REDUNDANT_AS_STR; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::query::Key; +use rustc_span::Span; + +pub(super) fn check( + cx: &LateContext<'_>, + _expr: &Expr<'_>, + recv: &Expr<'_>, + as_str_span: Span, + other_method_span: Span, +) { + if cx + .tcx + .lang_items() + .string() + .is_some_and(|id| Some(id) == cx.typeck_results().expr_ty(recv).ty_adt_id()) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + REDUNDANT_AS_STR, + as_str_span.to(other_method_span), + "this `as_str` is redundant and can be removed as the method immediately following exists on `String` too", + "try", + snippet_with_applicability(cx, other_method_span, "..", &mut applicability).into_owned(), + applicability, + ); + } +} diff --git a/tests/ui/redundant_as_str.fixed b/tests/ui/redundant_as_str.fixed new file mode 100644 index 00000000000..f339787e689 --- /dev/null +++ b/tests/ui/redundant_as_str.fixed @@ -0,0 +1,6 @@ +#![warn(clippy::redundant_as_str)] + +fn main() { + let _redundant = "Hello, world!".to_owned().as_bytes(); + let _redundant = "Hello, world!".to_owned().is_empty(); +} diff --git a/tests/ui/redundant_as_str.rs b/tests/ui/redundant_as_str.rs new file mode 100644 index 00000000000..66074df83a8 --- /dev/null +++ b/tests/ui/redundant_as_str.rs @@ -0,0 +1,6 @@ +#![warn(clippy::redundant_as_str)] + +fn main() { + let _redundant = "Hello, world!".to_owned().as_str().as_bytes(); + let _redundant = "Hello, world!".to_owned().as_str().is_empty(); +} diff --git a/tests/ui/redundant_as_str.stderr b/tests/ui/redundant_as_str.stderr new file mode 100644 index 00000000000..32b5232385d --- /dev/null +++ b/tests/ui/redundant_as_str.stderr @@ -0,0 +1,17 @@ +error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too + --> $DIR/redundant_as_str.rs:4:49 + | +LL | let _redundant = "Hello, world!".to_owned().as_str().as_bytes(); + | ^^^^^^^^^^^^^^^^^ help: try: `as_bytes` + | + = note: `-D clippy::redundant-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_as_str)]` + +error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too + --> $DIR/redundant_as_str.rs:5:49 + | +LL | let _redundant = "Hello, world!".to_owned().as_str().is_empty(); + | ^^^^^^^^^^^^^^^^^ help: try: `is_empty` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 01056c5aae63c546c3d988a0b46e502a3a2a7baf Mon Sep 17 00:00:00 2001 From: Dev381 <49997896+Dev380@users.noreply.github.com> Date: Sun, 17 Sep 2023 18:10:21 -0400 Subject: Fix missing semicolon in redundant_as_str docstring example --- clippy_lints/src/methods/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0b0a90bac0c..bd07e6cbf2e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3617,14 +3617,14 @@ declare_clippy_lint! { /// ```rust /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_str().as_bytes() + /// owned_string.as_str().as_bytes(); /// ``` /// /// Use instead: /// ```rust /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_bytes() + /// owned_string.as_bytes(); /// ``` #[clippy::version = "1.74.0"] pub REDUNDANT_AS_STR, -- cgit 1.4.1-3-g733a5 From 01c25a8eb63f8da0453d1aedca782f477342ef2d Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 20 Sep 2023 13:41:20 +0000 Subject: Remove most usage of `hir_ty_to_ty` --- clippy_lints/src/default_union_representation.rs | 22 ++++++++++++---------- clippy_lints/src/error_impl_error.rs | 8 ++++---- clippy_lints/src/large_const_arrays.rs | 5 ++--- clippy_lints/src/loops/utils.rs | 3 +-- clippy_lints/src/matches/needless_match.rs | 17 ++++++++++------- clippy_lints/src/methods/mod.rs | 13 +++++++------ clippy_lints/src/missing_const_for_fn.rs | 12 +++++------- clippy_lints/src/no_effect.rs | 11 ++++------- clippy_lints/src/non_canonical_impls.rs | 14 +++----------- clippy_lints/src/non_copy_const.rs | 15 +++++++-------- clippy_lints/src/ptr.rs | 21 +++++++-------------- .../src/utils/internal_lints/invalid_paths.rs | 18 ++++++------------ .../src/utils/internal_lints/msrv_attr_impl.rs | 15 ++++++--------- tests/ui/no_effect_return.rs | 1 + tests/ui/no_effect_return.stderr | 8 +++----- 15 files changed, 78 insertions(+), 105 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index bbce6e1dd8f..63ec8195020 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{self as hir, HirId, Item, ItemKind}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, FieldDef, GenericArg, List}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -52,7 +52,10 @@ declare_lint_pass!(DefaultUnionRepresentation => [DEFAULT_UNION_REPRESENTATION]) impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if is_union_with_two_non_zst_fields(cx, item) && !has_c_repr_attr(cx, item.hir_id()) { + if !item.span.from_expansion() + && is_union_with_two_non_zst_fields(cx, item) + && !has_c_repr_attr(cx, item.hir_id()) + { span_lint_and_help( cx, DEFAULT_UNION_REPRESENTATION, @@ -73,18 +76,17 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { /// if there is only one field left after ignoring ZST fields then the offset /// of that field does not matter either.) fn is_union_with_two_non_zst_fields(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Union(data, _) = &item.kind { - data.fields().iter().filter(|f| !is_zst(cx, f.ty)).count() >= 2 + if let ItemKind::Union(..) = &item.kind + && let ty::Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() + { + adt_def.all_fields().filter(|f| !is_zst(cx, f, args)).count() >= 2 } else { false } } -fn is_zst(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) -> bool { - if hir_ty.span.from_expansion() { - return false; - } - let ty = hir_ty_to_ty(cx.tcx, hir_ty); +fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: &'tcx List>) -> bool { + let ty = field.ty(cx.tcx, args); if let Ok(layout) = cx.layout_of(ty) { layout.is_zst() } else { diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index 379af9b2234..f24577c7382 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -3,7 +3,6 @@ use clippy_utils::path_res; use clippy_utils::ty::implements_trait; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{Item, ItemKind}; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Visibility; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -42,9 +41,10 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { }; match item.kind { - ItemKind::TyAlias(ty, _) if implements_trait(cx, hir_ty_to_ty(cx.tcx, ty), error_def_id, &[]) - && item.ident.name == sym::Error - && is_visible_outside_module(cx, item.owner_id.def_id) => + ItemKind::TyAlias(..) if item.ident.name == sym::Error + && is_visible_outside_module(cx, item.owner_id.def_id) + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && implements_trait(cx, ty, error_def_id, &[]) => { span_lint( cx, diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 9b26c3573e1..a4f3d498345 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; @@ -50,12 +49,12 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { if !item.span.from_expansion(); - if let ItemKind::Const(hir_ty, generics, _) = &item.kind; + if let ItemKind::Const(_, generics, _) = &item.kind; // Since static items may not have generics, skip generic const items. // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it // doesn't account for empty where-clauses that only consist of keyword `where` IINM. if generics.params.is_empty() && !generics.has_where_clause_predicates; - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); if let ty::Array(element_type, cst) = ty.kind(); if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); if let Ok(element_count) = element_count.try_to_target_usize(cx.tcx); diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 6edca2d55f6..0a2bd89eb3c 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -5,7 +5,6 @@ use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt}; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -150,7 +149,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { if l.pat.hir_id == self.var_id; if let PatKind::Binding(.., ident, _) = l.pat.kind; then { - let ty = l.ty.map(|ty| hir_ty_to_ty(self.cx.tcx, ty)); + let ty = l.ty.map(|_| self.cx.typeck_results().pat_ty(l.pat)); self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| { InitializeVisitorState::Initialized { diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index c4f6852aedc..44dc29c36a6 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -8,8 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, Guard, ItemKind, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -141,11 +140,15 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_> return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr)); }, // compare match_expr ty with RetTy in `fn foo() -> RetTy` - Node::Item(..) => { - if let Some(fn_decl) = p_node.fn_decl() { - if let FnRetTy::Return(ret_ty) = fn_decl.output { - return same_type_and_consts(hir_ty_to_ty(cx.tcx, ret_ty), cx.typeck_results().expr_ty(expr)); - } + Node::Item(item) => { + if let ItemKind::Fn(..) = item.kind { + let output = cx + .tcx + .fn_sig(item.owner_id) + .instantiate_identity() + .output() + .skip_binder(); + return same_type_and_consts(output, cx.typeck_results().expr_ty(expr)); } }, // check the parent expr for this whole block `{ match match_expr {..} }` diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bd07e6cbf2e..e7fcef9e9de 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -126,7 +126,6 @@ pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, 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}; @@ -3926,18 +3925,20 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if_chain! { if let TraitItemKind::Fn(ref sig, _) = item.kind; if sig.decl.implicit_self.has_implicit_self(); - if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); - + if let Some(first_arg_hir_ty) = sig.decl.inputs.first(); + if let Some(&first_arg_ty) = cx.tcx.fn_sig(item.owner_id) + .instantiate_identity() + .inputs() + .skip_binder() + .first(); then { - let first_arg_span = first_arg_ty.span; - let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); wrong_self_convention::check( cx, item.ident.name.as_str(), self_ty, first_arg_ty, - first_arg_span, + first_arg_hir_ty.span, false, true, ); diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 3b7eccad79d..f598a65d2e4 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -7,7 +7,6 @@ use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -124,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Method(_, sig, ..) => { if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) - || method_accepts_droppable(cx, sig.decl.inputs) + || method_accepts_droppable(cx, def_id) { return; } @@ -165,12 +164,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { /// Returns true if any of the method parameters is a type that implements `Drop`. The method /// can't be made const then, because `drop` can't be const-evaluated. -fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { +fn method_accepts_droppable(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + // If any of the params are droppable, return true - param_tys.iter().any(|hir_ty| { - let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty); - has_drop(cx, ty_ty) - }) + sig.inputs().iter().any(|&ty| has_drop(cx, ty)) } // We don't have to lint on something that's already `const` diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 5f2a324b05f..aee184252fb 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -5,10 +5,8 @@ use clippy_utils::{get_parent_node, is_lint_allowed, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, FnRetTy, ItemKind, Node, PatKind, Stmt, StmtKind, - UnsafeSource, + is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, ItemKind, Node, PatKind, Stmt, StmtKind, UnsafeSource, }; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -99,14 +97,13 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { |diag| { for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { if let Node::Item(item) = parent.1 - && let ItemKind::Fn(sig, ..) = item.kind - && let FnRetTy::Return(ret_ty) = sig.decl.output + && let ItemKind::Fn(..) = item.kind && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) && let [.., final_stmt] = block.stmts && final_stmt.hir_id == stmt.hir_id { let expr_ty = cx.typeck_results().expr_ty(expr); - let mut ret_ty = hir_ty_to_ty(cx.tcx, ret_ty); + let mut ret_ty = cx.tcx.fn_sig(item.owner_id).instantiate_identity().output().skip_binder(); // Remove `impl Future` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) && @@ -115,7 +112,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { ret_ty = true_ret_ty; } - if ret_ty == expr_ty { + if !ret_ty.is_unit() && ret_ty == expr_ty { diag.span_suggestion( stmt.span.shrink_to_lo(), "did you mean to return it?", diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index c390e6913ff..20b4b4f03ed 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -4,8 +4,7 @@ use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -123,9 +122,6 @@ impl LateLintPass<'_> for NonCanonicalImpls { if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) { return; } - let ItemKind::Impl(imp) = item.kind else { - return; - }; let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else { return; }; @@ -181,12 +177,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id) && impl_item.ident.name == sym::partial_cmp - && let Some(ord_def_id) = cx - .tcx - .diagnostic_items(trait_impl.def_id.krate) - .name_to_id - .get(&sym::Ord) - && implements_trait(cx, hir_ty_to_ty(cx.tcx, imp.self_ty), *ord_def_id, &[]) + && let Some(ord_def_id) = cx.tcx.get_diagnostic_item(sym::Ord) + && implements_trait(cx, trait_impl.self_ty(), ord_def_id, &[]) { // If the `cmp` call likely needs to be fully qualified in the suggestion // (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 243192385c2..e106a959165 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -13,7 +13,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::{ BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, }; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; @@ -297,8 +296,8 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(hir_ty, _generics, body_id) = it.kind { - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + if let ItemKind::Const(.., body_id) = it.kind { + let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { lint(cx, Source::Item { item: it.span }); } @@ -306,8 +305,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind { - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + if let TraitItemKind::Const(_, body_id_opt) = &trait_item.kind { + let ty = cx.tcx.type_of(trait_item.owner_id).instantiate_identity(); // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. @@ -333,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind { + if let ImplItemKind::Const(_, body_id) = &impl_item.kind { let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(item_def_id); @@ -366,7 +365,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // we should use here as a frozen variant is a potential to be frozen // similar to unknown layouts. // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); if is_unfrozen(cx, normalized); if is_value_unfrozen_poly(cx, *body_id, normalized); @@ -381,7 +380,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } }, ItemKind::Impl(Impl { of_trait: None, .. }) => { - let ty = hir_ty_to_ty(cx.tcx, hir_ty); + let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index bf031ac8454..7dabdcd58ec 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -16,7 +16,6 @@ use rustc_hir::{ ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety, }; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; @@ -172,13 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { for arg in check_fn_args( cx, - cx.tcx - .fn_sig(item.owner_id) - .instantiate_identity() - .skip_binder() - .inputs(), + cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder(), sig.decl.inputs, - &sig.decl.output, &[], ) .filter(|arg| arg.mutability() == Mutability::Not) @@ -237,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { let decl = sig.decl; let sig = cx.tcx.fn_sig(item_id).instantiate_identity().skip_binder(); - let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params) + let lint_args: Vec<_> = check_fn_args(cx, sig, decl.inputs, body.params) .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not) .collect(); let results = check_ptr_arg_usage(cx, body, &lint_args); @@ -443,12 +437,13 @@ impl<'tcx> DerefTy<'tcx> { #[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, - tys: &'tcx [Ty<'tcx>], + fn_sig: ty::FnSig<'tcx>, hir_tys: &'tcx [hir::Ty<'tcx>], - ret_ty: &'tcx FnRetTy<'tcx>, params: &'tcx [Param<'tcx>], ) -> impl Iterator> + 'cx { - tys.iter() + fn_sig + .inputs() + .iter() .zip(hir_tys.iter()) .enumerate() .filter_map(move |(i, (ty, hir_ty))| { @@ -494,9 +489,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( }) { if !lifetime.is_anonymous() - && let FnRetTy::Return(ret_ty) = ret_ty - && let ret_ty = hir_ty_to_ty(cx.tcx, ret_ty) - && ret_ty + && fn_sig.output() .walk() .filter_map(|arg| { arg.as_region().and_then(|lifetime| { diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 4ed985f54d0..25077223885 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -5,10 +5,9 @@ use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::Item; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{self, FloatTy}; +use rustc_middle::ty::FloatTy; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; @@ -34,25 +33,20 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { let mod_name = &cx.tcx.item_name(local_def_id.to_def_id()); if_chain! { if mod_name.as_str() == "paths"; - if let hir::ItemKind::Const(ty, _, body_id) = item.kind; - let ty = hir_ty_to_ty(cx.tcx, ty); - if let ty::Array(el_ty, _) = &ty.kind(); - if let ty::Ref(_, el_ty, _) = &el_ty.kind(); - if el_ty.is_str(); + if let hir::ItemKind::Const(.., body_id) = item.kind; let body = cx.tcx.hir().body(body_id); let typeck_results = cx.tcx.typeck_body(body_id); if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value); - let path: Vec<&str> = path + if let Some(path) = path .iter() .map(|x| { if let Constant::Str(s) = x { - s.as_str() + Some(s.as_str()) } else { - // We checked the type of the constant above - unreachable!() + None } }) - .collect(); + .collect::>>(); if !check_path(cx, &path[..]); then { span_lint(cx, INVALID_PATHS, item.span, "invalid path"); diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index bf835f89cfc..86b77a77f17 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -5,9 +5,8 @@ use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::{self, GenericArgKind}; +use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -25,16 +24,14 @@ impl LateLintPass<'_> for MsrvAttrImpl { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { if_chain! { if let hir::ItemKind::Impl(hir::Impl { - of_trait: Some(lint_pass_trait_ref), - self_ty, + of_trait: Some(_), items, .. }) = &item.kind; - if let Some(lint_pass_trait_def_id) = lint_pass_trait_ref.trait_def_id(); - let is_late_pass = match_def_path(cx, lint_pass_trait_def_id, &paths::LATE_LINT_PASS); - if is_late_pass || match_def_path(cx, lint_pass_trait_def_id, &paths::EARLY_LINT_PASS); - let self_ty = hir_ty_to_ty(cx.tcx, self_ty); - if let ty::Adt(self_ty_def, _) = self_ty.kind(); + if let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity); + let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS); + if is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS); + if let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind(); if self_ty_def.is_struct(); if self_ty_def.all_fields().any(|f| { cx.tcx diff --git a/tests/ui/no_effect_return.rs b/tests/ui/no_effect_return.rs index f6585aa30a6..e46c0d73518 100644 --- a/tests/ui/no_effect_return.rs +++ b/tests/ui/no_effect_return.rs @@ -76,6 +76,7 @@ fn h() -> Vec { fn i() -> () { { + // does not suggest on function with explicit unit return type (); //~^ ERROR: statement with no effect } diff --git a/tests/ui/no_effect_return.stderr b/tests/ui/no_effect_return.stderr index b036e634204..aed079f09b9 100644 --- a/tests/ui/no_effect_return.stderr +++ b/tests/ui/no_effect_return.stderr @@ -54,15 +54,13 @@ LL | ControlFlow::Break::<()>(()); | help: did you mean to return it?: `return` error: statement with no effect - --> $DIR/no_effect_return.rs:79:9 + --> $DIR/no_effect_return.rs:80:9 | LL | (); - | -^^ - | | - | help: did you mean to return it?: `return` + | ^^^ error: statement with no effect - --> $DIR/no_effect_return.rs:88:9 + --> $DIR/no_effect_return.rs:89:9 | LL | (); | ^^^ -- cgit 1.4.1-3-g733a5 From ad5653b296e8b3a001f15a3c02c5b17de8d13d57 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Fri, 29 Sep 2023 03:08:34 +0200 Subject: Add missing lint description headers --- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/methods/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index e1ef514edfd..e3f4cf79d31 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { + /// ### What it does /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// @@ -19,7 +20,6 @@ declare_clippy_lint! { /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// /// ### Why is this bad? - /// /// `#[expect]` attributes suppress the lint emission, but emit a warning, if /// the expectation is unfulfilled. This can be useful to be notified when the /// lint is no longer triggered. diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e7fcef9e9de..7b743382fa1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3368,6 +3368,7 @@ declare_clippy_lint! { } declare_clippy_lint! { + /// ### What it does /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input /// into a string, then later attempting to parse this string into a type without first trimming it, which will /// always fail because the string has a trailing newline in it. -- cgit 1.4.1-3-g733a5 From eab0a75ff942598a57c93f78000a8a9dbb3af9b7 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 4 Oct 2023 01:04:00 +0200 Subject: Update version attribute for 1.73 lints --- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 4 ++-- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 12 ++++++------ clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/non_canonical_impls.rs | 2 +- clippy_lints/src/operators/mod.rs | 4 ++-- clippy_lints/src/redundant_locals.rs | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index f24577c7382..6d429fbd035 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// impl std::error::Error for Error { ... } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ERROR_IMPL_ERROR, restriction, "exported types named `Error` that implement `Error`" diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 419c7734344..0ec52f89e71 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FOUR_FORWARD_SLASHES, suspicious, "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)" diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 88db7ae6aec..ed9189a1804 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// # let x = 1.0f32; /// if x.is_infinite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_INFINITE, style, "use dedicated method to check if a float is infinite" @@ -51,7 +51,7 @@ declare_clippy_lint! { /// if x.is_finite() {} /// if x.is_finite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_FINITE, style, "use dedicated method to check if a float is finite" diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 930386a60aa..a23000e5fe1 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -961,7 +961,7 @@ declare_clippy_lint! { /// _ => todo!(), /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_GUARDS, complexity, "checks for unnecessary guards in match expressions" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7b743382fa1..a935aea5075 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2970,7 +2970,7 @@ declare_clippy_lint! { /// assert_eq!((*any_box).type_id(), TypeId::of::()); /// // ^ dereference first, to call `type_id` on `dyn Any` /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub TYPE_ID_ON_BOX, suspicious, "calling `.type_id()` on `Box`" @@ -3391,7 +3391,7 @@ declare_clippy_lint! { /// // ^^^^^^^^^^^ remove the trailing newline /// assert_eq!(num, 42); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub READ_LINE_WITHOUT_TRIM, correctness, "calling `Stdin::read_line`, then trying to parse it without first trimming" @@ -3419,7 +3419,7 @@ declare_clippy_lint! { /// # let c = 'c'; /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub STRING_LIT_CHARS_ANY, restriction, "checks for `.chars().any(|i| i == c)`" @@ -3454,7 +3454,7 @@ declare_clippy_lint! { /// }) /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FORMAT_COLLECT, perf, "`format!`ing every element in a collection, then collecting the strings into a new `String`" @@ -3475,7 +3475,7 @@ declare_clippy_lint! { /// let y = v.iter().collect::>(); /// assert_eq!(x, y); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ITER_SKIP_ZERO, correctness, "disallows `.skip(0)`" @@ -3506,7 +3506,7 @@ declare_clippy_lint! { /// # let v = vec![]; /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FILTER_MAP_BOOL_THEN, style, "checks for usage of `bool::then` in `Iterator::filter_map`" diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 3ad9ae0301a..212d6234bdb 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -47,7 +47,7 @@ declare_clippy_lint! { /// 12 + *y /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NEEDLESS_PASS_BY_REF_MUT, nursery, "using a `&mut` argument when it's not mutated" diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 20b4b4f03ed..f159c261d11 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -103,7 +103,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NON_CANONICAL_PARTIAL_ORD_IMPL, suspicious, "non-canonical implementation of `PartialOrd` on an `Ord` type" diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 4635e1164cd..6b247cf5f6a 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -312,7 +312,7 @@ declare_clippy_lint! { /// # let status_code = 200; /// if status_code <= 400 && status_code > 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub IMPOSSIBLE_COMPARISONS, correctness, "double comparisons that will never evaluate to `true`" @@ -332,7 +332,7 @@ declare_clippy_lint! { /// # let status_code = 200; /// if status_code <= 400 && status_code < 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_COMPARISONS, correctness, "double comparisons where one of them can be removed" diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index a26bb98c5e2..7864ff3e8ff 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// // no redefinition with the same name /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_LOCALS, correctness, "redundant redefinition of a local binding" -- cgit 1.4.1-3-g733a5 From 31fd282732e15811e916d216d5badd0a56361dd3 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:07:54 +0200 Subject: [`get_first`]: lint on non-primitive types --- clippy_lints/src/methods/get_first.rs | 2 -- tests/ui/get_first.fixed | 13 ++++++++++--- tests/ui/get_first.rs | 13 ++++++++++--- tests/ui/get_first.stderr | 18 ++++++++++++------ 4 files changed, 32 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index ee063adac64..e7b4564c651 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_slice_of_primitives; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::LitKind; @@ -20,7 +19,6 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); if cx.tcx.type_of(impl_id).instantiate_identity().is_slice(); - if let Some(_) = is_slice_of_primitives(cx, recv); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { let mut app = Applicability::MachineApplicable; diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index b1a597fc4dd..a7cdd2a93ba 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -14,17 +14,20 @@ impl Bar { fn main() { let x = vec![2, 3, 5]; - let _ = x.first(); // Use x.first() + let _ = x.first(); + //~^ ERROR: accessing first element with `x.get(0)` let _ = x.get(1); let _ = x[0]; let y = [2, 3, 5]; - let _ = y.first(); // Use y.first() + let _ = y.first(); + //~^ ERROR: accessing first element with `y.get(0)` let _ = y.get(1); let _ = y[0]; let z = &[2, 3, 5]; - let _ = z.first(); // Use z.first() + let _ = z.first(); + //~^ ERROR: accessing first element with `z.get(0)` let _ = z.get(1); let _ = z[0]; @@ -37,4 +40,8 @@ fn main() { let bar = Bar { arr: [0, 1, 2] }; let _ = bar.get(0); // Do not lint, because Bar is struct. + + let non_primitives = [vec![1, 2], vec![3, 4]]; + let _ = non_primitives.first(); + //~^ ERROR: accessing first element with `non_primitives.get(0)` } diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index e27ee4be8c0..cca743c4bf5 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -14,17 +14,20 @@ impl Bar { fn main() { let x = vec![2, 3, 5]; - let _ = x.get(0); // Use x.first() + let _ = x.get(0); + //~^ ERROR: accessing first element with `x.get(0)` let _ = x.get(1); let _ = x[0]; let y = [2, 3, 5]; - let _ = y.get(0); // Use y.first() + let _ = y.get(0); + //~^ ERROR: accessing first element with `y.get(0)` let _ = y.get(1); let _ = y[0]; let z = &[2, 3, 5]; - let _ = z.get(0); // Use z.first() + let _ = z.get(0); + //~^ ERROR: accessing first element with `z.get(0)` let _ = z.get(1); let _ = z[0]; @@ -37,4 +40,8 @@ fn main() { let bar = Bar { arr: [0, 1, 2] }; let _ = bar.get(0); // Do not lint, because Bar is struct. + + let non_primitives = [vec![1, 2], vec![3, 4]]; + let _ = non_primitives.get(0); + //~^ ERROR: accessing first element with `non_primitives.get(0)` } diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr index 56b4c29a313..8ee66e33cc8 100644 --- a/tests/ui/get_first.stderr +++ b/tests/ui/get_first.stderr @@ -1,23 +1,29 @@ error: accessing first element with `x.get(0)` --> $DIR/get_first.rs:17:13 | -LL | let _ = x.get(0); // Use x.first() +LL | let _ = x.get(0); | ^^^^^^^^ help: try: `x.first()` | = note: `-D clippy::get-first` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::get_first)]` error: accessing first element with `y.get(0)` - --> $DIR/get_first.rs:22:13 + --> $DIR/get_first.rs:23:13 | -LL | let _ = y.get(0); // Use y.first() +LL | let _ = y.get(0); | ^^^^^^^^ help: try: `y.first()` error: accessing first element with `z.get(0)` - --> $DIR/get_first.rs:27:13 + --> $DIR/get_first.rs:29:13 | -LL | let _ = z.get(0); // Use z.first() +LL | let _ = z.get(0); | ^^^^^^^^ help: try: `z.first()` -error: aborting due to 3 previous errors +error: accessing first element with `non_primitives.get(0)` + --> $DIR/get_first.rs:45:13 + | +LL | let _ = non_primitives.get(0); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From e6f29f1900002d980dd06778a29e73637539d928 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:08:30 +0200 Subject: dogfood --- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/manual_bits.rs | 4 ++-- clippy_lints/src/methods/search_is_some.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/needless_continue.rs | 4 ++-- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/uninit_vec.rs | 2 +- clippy_lints/src/unnecessary_map_on_constructor.rs | 4 ++-- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/higher.rs | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index f7b3b2358a0..5fffb27cda2 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -185,7 +185,7 @@ fn get_vec_push<'tcx>( if let StmtKind::Semi(semi_stmt) = &stmt.kind; if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; // Figure out the parameters for the method call - if let Some(pushed_item) = args.get(0); + if let Some(pushed_item) = args.first(); // Check that the method being called is push() on a Vec if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 6c7c57ba1d6..552c57d5e02 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let QPath::Resolved(_, count_func_path) = count_func_qpath; - if let Some(segment_zero) = count_func_path.segments.get(0); + if let Some(segment_zero) = count_func_path.segments.first(); if let Some(args) = segment_zero.args; - if let Some(GenericArg::Type(real_ty)) = args.args.get(0); + if let Some(GenericArg::Type(real_ty)) = args.args.first(); if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id); diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index afdb8ce94ac..04ddaaa2f46 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( if search_method == "find"; if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind; let closure_body = cx.tcx.hir().body(body); - if let Some(closure_arg) = closure_body.params.get(0); + if let Some(closure_arg) = closure_body.params.first(); then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index f2773cad400..0629dee4f72 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -67,7 +67,7 @@ impl MissingDoc { if_chain! { if let Some(meta) = meta; if let MetaItemKind::List(list) = meta.kind; - if let Some(meta) = list.get(0); + if let Some(meta) = list.first(); if let Some(name) = meta.ident(); then { name.name == sym::include diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 38a75034cd3..377cbef7b99 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -189,7 +189,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) } fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool { - block.stmts.get(0).map_or(false, |stmt| match stmt.kind { + block.stmts.first().map_or(false, |stmt| match stmt.kind { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { if let ast::ExprKind::Continue(ref l) = e.kind { compare_labels(label, l.as_ref()) @@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String { } fn span_of_first_expr_in_block(block: &ast::Block) -> Option { - block.stmts.get(0).map(|stmt| stmt.span) + block.stmts.first().map(|stmt| stmt.span) } #[cfg(test)] diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 9db18c2976c..2278e41be37 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { - if let Some(s) = block.stmts.get(0) { + if let Some(s) = block.stmts.first() { self.visit_stmt(s); } diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 6756df8e716..72569e10f05 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt let expr = peel_hir_expr_while(expr, |e| { if let ExprKind::Block(block, _) = e.kind { // Extract the first statement/expression - match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) { + match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) { (None, Some(expr)) => Some(expr), (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr), _ => None, diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 5aa057580e9..894de0d85c1 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind && let hir::ExprKind::Path(constructor_path) = constructor.kind - && let Some(arg) = constructor_args.get(0) + && let Some(arg) = constructor_args.first() { if constructor.span.from_expansion() || arg.span.from_expansion() { return; @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { _ => return, } - if let Some(map_arg) = args.get(0) + if let Some(map_arg) = args.first() && let hir::ExprKind::Path(fun) = map_arg.kind { if map_arg.span.from_expansion() { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 0bae7056c4f..79c04c7c7f4 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -504,7 +504,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { }, (Some(Constant::Vec(vec)), _) => { if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) { - match vec.get(0) { + match vec.first() { Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), _ => None, diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 802adbd4d2d..7c1be625bd3 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -449,7 +449,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - } else if name.ident.name == symbol::kw::Default { return Some(VecInitKind::Default); } else if name.ident.name.as_str() == "with_capacity" { - let arg = args.get(0)?; + let arg = args.first()?; return match constant_simple(cx, cx.typeck_results(), arg) { Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)), _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)), -- cgit 1.4.1-3-g733a5 From bba155ea9dac4f320303696572f552e80042889c Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:39:16 +0200 Subject: move changed logic to into its own util function --- clippy_lints/src/methods/filter_map_identity.rs | 4 +- clippy_lints/src/methods/flat_map_identity.rs | 4 +- clippy_lints/src/methods/map_identity.rs | 4 +- clippy_utils/src/lib.rs | 71 +++++++++++++++---------- 4 files changed, 49 insertions(+), 34 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 3337b250c0e..20878f1e4df 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,7 +9,7 @@ use rustc_span::sym; use super::FILTER_MAP_IDENTITY; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) { span_lint_and_sugg( cx, FILTER_MAP_IDENTITY, diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 84a21de0ac8..8849a4f4942 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( flat_map_arg: &'tcx hir::Expr<'_>, flat_map_span: Span, ) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) { span_lint_and_sugg( cx, FLAT_MAP_IDENTITY, diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 7be1ce483f6..57581363cfa 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expr_identity_function, is_trait_method}; +use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -23,7 +23,7 @@ pub(super) fn check( if is_trait_method(cx, expr, sym::Iterator) || is_type_diagnostic_item(cx, caller_ty, sym::Result) || is_type_diagnostic_item(cx, caller_ty, sym::Option); - if is_expr_identity_function(cx, map_arg); + if is_expr_untyped_identity_function(cx, map_arg); if let Some(sugg_span) = expr.span.trim_start(caller.span); then { span_lint_and_sugg( diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e22bf11bb79..dc1b5a0a324 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2027,36 +2027,31 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use)) } -/// Checks if an expression represents the identity function -/// Only examines closures and `std::convert::identity` +/// Checks if a function's body represents the identity function. Looks for bodies of the form: +/// * `|x| x` +/// * `|x| return x` +/// * `|x| { return x }` +/// * `|x| { return x; }` /// -/// Closure bindings with type annotations and `std::convert::identity` with generic args -/// are not considered identity functions because they can guide type inference, -/// and removing it may lead to compile errors. -pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - /// Checks if a function's body represents the identity function. Looks for bodies of the form: - /// * `|x| x` - /// * `|x| return x` - /// * `|x| { return x }` - /// * `|x| { return x; }` - fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { - let id = if_chain! { - if let [param] = func.params; - if let PatKind::Binding(_, id, _, _) = param.pat.kind; - then { - id - } else { - return false; - } - }; +/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead. +fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { + let id = if_chain! { + if let [param] = func.params; + if let PatKind::Binding(_, id, _, _) = param.pat.kind; + then { + id + } else { + return false; + } + }; - let mut expr = func.value; - loop { - match expr.kind { - #[rustfmt::skip] + let mut expr = func.value; + loop { + match expr.kind { + #[rustfmt::skip] ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, ) | ExprKind::Ret(Some(e)) => expr = e, - #[rustfmt::skip] + #[rustfmt::skip] ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => { if_chain! { if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind; @@ -2068,11 +2063,16 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } } }, - _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(), - } + _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(), } } +} +/// This is the same as [`is_expr_identity_function`], but does not consider closures +/// with type annotations for its bindings (or similar) as identity functions: +/// * `|x: u8| x` +/// * `std::convert::identity::` +pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(&Closure { body, fn_decl, .. }) if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) => @@ -2089,6 +2089,21 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } } +/// Checks if an expression represents the identity function +/// Only examines closures and `std::convert::identity` +/// +/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want +/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't +/// have type annotations. This is important because removing a closure with bindings can +/// remove type information that helped type inference before, which can then lead to compile +/// errors. +pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), + _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), + } +} + /// Gets the node where an expression is either used, or it's type is unified with another branch. /// Returns both the node and the `HirId` of the closest child node. pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> { -- cgit 1.4.1-3-g733a5 From bb6516ace013a2ec33ca1276b029786dfbb46ee1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 16 Oct 2023 00:29:28 +0200 Subject: [`unnecessary_lazy_eval`]: don't emit autofix suggestion if closure has return type --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 12 ++- tests/ui/unnecessary_lazy_eval.fixed | 3 + tests/ui/unnecessary_lazy_eval.rs | 3 + tests/ui/unnecessary_lazy_eval.stderr | 94 +++++++++++++---------- tests/ui/unnecessary_lazy_eval_unfixable.rs | 5 ++ tests/ui/unnecessary_lazy_eval_unfixable.stderr | 10 ++- 6 files changed, 85 insertions(+), 42 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 47e2e744112..4a651396f14 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; +use hir::FnRetTy; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -27,7 +28,7 @@ pub(super) fn check<'tcx>( let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); if is_option || is_result || is_bool { - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { + if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind { let body = cx.tcx.hir().body(body); let body_expr = &body.value; @@ -48,7 +49,14 @@ pub(super) fn check<'tcx>( .iter() // bindings are checked to be unused above .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) - { + && matches!( + fn_decl.output, + FnRetTy::DefaultReturn(_) + | FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Infer, + .. + }) + ) { Applicability::MachineApplicable } else { // replacing the lambda may break type inference diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 304e7b7fd7f..4778eaefdbd 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -5,6 +5,7 @@ #![allow(clippy::map_identity)] #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unit_arg)] use std::ops::Deref; @@ -76,6 +77,8 @@ fn main() { let _ = opt.ok_or(2); let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); let _ = cond.then_some(astronomers_pi); + let _ = true.then_some({}); + let _ = true.then_some({}); // Should lint - Builtin deref let r = &1; diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index ddfa6bb3ef6..d4b7fd31b1b 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -5,6 +5,7 @@ #![allow(clippy::map_identity)] #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] +#![allow(clippy::unit_arg)] use std::ops::Deref; @@ -76,6 +77,8 @@ fn main() { let _ = opt.ok_or_else(|| 2); let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = cond.then(|| astronomers_pi); + let _ = true.then(|| -> _ {}); + let _ = true.then(|| {}); // Should lint - Builtin deref let r = &1; diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 4f1ca374872..1b0db4759bb 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:68:13 + --> $DIR/unnecessary_lazy_eval.rs:69:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -10,7 +10,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:70:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -18,7 +18,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:70:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -26,7 +26,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:72:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -34,7 +34,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:73:13 + --> $DIR/unnecessary_lazy_eval.rs:74:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -42,7 +42,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:74:13 + --> $DIR/unnecessary_lazy_eval.rs:75:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -50,7 +50,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:75:13 + --> $DIR/unnecessary_lazy_eval.rs:76:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -58,7 +58,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:76:13 + --> $DIR/unnecessary_lazy_eval.rs:77:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -66,7 +66,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:77:13 + --> $DIR/unnecessary_lazy_eval.rs:78:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -74,15 +74,31 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:78:13 + --> $DIR/unnecessary_lazy_eval.rs:79:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- | | | help: use `then_some(..)` instead: `then_some(astronomers_pi)` +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:80:13 + | +LL | let _ = true.then(|| -> _ {}); + | ^^^^^---------------- + | | + | help: use `then_some(..)` instead: `then_some({})` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:81:13 + | +LL | let _ = true.then(|| {}); + | ^^^^^----------- + | | + | help: use `then_some(..)` instead: `then_some({})` + error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:82:13 + --> $DIR/unnecessary_lazy_eval.rs:85:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); | ^^^^^^^^--------------------- @@ -90,7 +106,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *r); | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:84:13 + --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); | ^^^^^^^^--------------------- @@ -98,7 +114,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *b); | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:86:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | ^^^^^^^^^^^^^^^^^--------------------- @@ -106,7 +122,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:87:13 + --> $DIR/unnecessary_lazy_eval.rs:90:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | ^^^^^^^^^^^^^^^^^--------------------- @@ -114,7 +130,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:90:13 + --> $DIR/unnecessary_lazy_eval.rs:93:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -122,7 +138,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:91:13 + --> $DIR/unnecessary_lazy_eval.rs:94:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -130,7 +146,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:92:28 + --> $DIR/unnecessary_lazy_eval.rs:95:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -138,7 +154,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:93:13 + --> $DIR/unnecessary_lazy_eval.rs:96:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -146,7 +162,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:94:35 + --> $DIR/unnecessary_lazy_eval.rs:97:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -154,7 +170,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:95:28 + --> $DIR/unnecessary_lazy_eval.rs:98:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -162,7 +178,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:98:13 + --> $DIR/unnecessary_lazy_eval.rs:101:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -170,7 +186,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:99:13 + --> $DIR/unnecessary_lazy_eval.rs:102:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -178,7 +194,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:100:13 + --> $DIR/unnecessary_lazy_eval.rs:103:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -186,7 +202,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:101:13 + --> $DIR/unnecessary_lazy_eval.rs:104:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -194,7 +210,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:102:13 + --> $DIR/unnecessary_lazy_eval.rs:105:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -202,7 +218,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:132:28 + --> $DIR/unnecessary_lazy_eval.rs:135:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -210,7 +226,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:133:13 + --> $DIR/unnecessary_lazy_eval.rs:136:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -218,7 +234,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:134:13 + --> $DIR/unnecessary_lazy_eval.rs:137:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -226,7 +242,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:140:13 + --> $DIR/unnecessary_lazy_eval.rs:143:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -234,7 +250,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:141:13 + --> $DIR/unnecessary_lazy_eval.rs:144:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -242,7 +258,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:142:13 + --> $DIR/unnecessary_lazy_eval.rs:145:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -250,7 +266,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:164:35 + --> $DIR/unnecessary_lazy_eval.rs:167:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -258,7 +274,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:165:35 + --> $DIR/unnecessary_lazy_eval.rs:168:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -266,7 +282,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:166:35 + --> $DIR/unnecessary_lazy_eval.rs:169:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -274,7 +290,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:168:35 + --> $DIR/unnecessary_lazy_eval.rs:171:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -282,7 +298,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:169:35 + --> $DIR/unnecessary_lazy_eval.rs:172:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -290,7 +306,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:170:35 + --> $DIR/unnecessary_lazy_eval.rs:173:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -298,7 +314,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:171:35 + --> $DIR/unnecessary_lazy_eval.rs:174:35 | LL | let _: Result = res. | ___________________________________^ @@ -312,5 +328,5 @@ LL | | or_else(|_| Ok(ext_str.some_field)); | | | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 38 previous errors +error: aborting due to 40 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs index 33685bfb738..412d4aaafb4 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -25,3 +25,8 @@ fn main() { let arr = [(Some(1),)]; Some(&0).and_then(|&i| arr[i].0); } + +fn issue11672() { + // Return type annotation helps type inference and removing it can break code + let _ = true.then(|| -> &[u8] { &[] }); +} diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 27fa560d4d7..95b02be91ca 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -25,5 +25,13 @@ LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); | | | help: use `unwrap_or(..)` instead: `unwrap_or(2)` -error: aborting due to 3 previous errors +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:31:13 + | +LL | let _ = true.then(|| -> &[u8] { &[] }); + | ^^^^^------------------------- + | | + | help: use `then_some(..)` instead: `then_some({ &[] })` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 7347c1803fa9c151033eb30fd722ff6d6d08ee49 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 23 Oct 2023 13:49:18 +0000 Subject: Set existing doc-tests to `no_run` --- book/src/lint_configuration.md | 4 +- clippy_lints/src/absolute_paths.rs | 4 +- clippy_lints/src/almost_complete_range.rs | 4 +- clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/arc_with_non_send_sync.rs | 2 +- clippy_lints/src/async_yields_async.rs | 4 +- clippy_lints/src/attrs.rs | 42 +-- clippy_lints/src/await_holding_invalid.rs | 10 +- clippy_lints/src/blocks_in_if_conditions.rs | 4 +- clippy_lints/src/bool_assert_comparison.rs | 4 +- clippy_lints/src/bool_to_int_with_if.rs | 6 +- clippy_lints/src/borrow_deref_ref.rs | 6 +- clippy_lints/src/box_default.rs | 4 +- clippy_lints/src/casts/mod.rs | 70 ++-- clippy_lints/src/checked_conversions.rs | 4 +- clippy_lints/src/collapsible_if.rs | 4 +- clippy_lints/src/collection_is_never_read.rs | 4 +- clippy_lints/src/crate_in_macro_def.rs | 4 +- clippy_lints/src/default.rs | 8 +- .../src/default_constructed_unit_structs.rs | 4 +- clippy_lints/src/default_instead_of_iter_empty.rs | 4 +- clippy_lints/src/default_numeric_fallback.rs | 4 +- clippy_lints/src/default_union_representation.rs | 4 +- clippy_lints/src/dereference.rs | 16 +- clippy_lints/src/derivable_impls.rs | 4 +- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/disallowed_macros.rs | 2 +- clippy_lints/src/disallowed_names.rs | 2 +- clippy_lints/src/disallowed_script_idents.rs | 2 +- clippy_lints/src/doc.rs | 22 +- clippy_lints/src/double_parens.rs | 4 +- clippy_lints/src/drop_forget_ref.rs | 6 +- clippy_lints/src/else_if_without_else.rs | 4 +- clippy_lints/src/empty_drop.rs | 4 +- clippy_lints/src/empty_enum.rs | 4 +- clippy_lints/src/empty_structs_with_brackets.rs | 4 +- clippy_lints/src/entry.rs | 6 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/escape.rs | 4 +- clippy_lints/src/excessive_bools.rs | 4 +- clippy_lints/src/exhaustive_items.rs | 8 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/explicit_write.rs | 4 +- clippy_lints/src/extra_unused_type_parameters.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 4 +- clippy_lints/src/float_literal.rs | 8 +- clippy_lints/src/floating_point_arithmetic.rs | 8 +- clippy_lints/src/format.rs | 4 +- clippy_lints/src/format_args.rs | 20 +- clippy_lints/src/format_impl.rs | 8 +- clippy_lints/src/format_push_string.rs | 4 +- clippy_lints/src/formatting.rs | 4 +- clippy_lints/src/four_forward_slashes.rs | 4 +- clippy_lints/src/from_over_into.rs | 4 +- clippy_lints/src/from_raw_with_void_ptr.rs | 4 +- clippy_lints/src/functions/mod.rs | 24 +- clippy_lints/src/future_not_send.rs | 4 +- clippy_lints/src/if_not_else.rs | 4 +- clippy_lints/src/if_then_some_else_none.rs | 4 +- clippy_lints/src/ignored_unit_patterns.rs | 4 +- clippy_lints/src/implicit_hasher.rs | 4 +- clippy_lints/src/implicit_return.rs | 4 +- clippy_lints/src/implicit_saturating_add.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 4 +- clippy_lints/src/implied_bounds_in_impls.rs | 4 +- .../src/inconsistent_struct_constructor.rs | 6 +- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/indexing_slicing.rs | 4 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/inherent_impl.rs | 4 +- clippy_lints/src/inherent_to_string.rs | 8 +- clippy_lints/src/init_numbered_fields.rs | 2 +- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 8 +- clippy_lints/src/int_plus_one.rs | 4 +- clippy_lints/src/invalid_upcast_comparisons.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 12 +- clippy_lints/src/items_after_statements.rs | 4 +- clippy_lints/src/items_after_test_module.rs | 4 +- clippy_lints/src/iter_not_returning_iterator.rs | 4 +- clippy_lints/src/iter_without_into_iter.rs | 8 +- clippy_lints/src/large_enum_variant.rs | 4 +- clippy_lints/src/large_futures.rs | 4 +- clippy_lints/src/large_stack_frames.rs | 4 +- clippy_lints/src/let_underscore.rs | 10 +- clippy_lints/src/lifetimes.rs | 8 +- clippy_lints/src/lines_filter_map_ok.rs | 4 +- clippy_lints/src/literal_representation.rs | 12 +- clippy_lints/src/loops/mod.rs | 48 +-- clippy_lints/src/manual_assert.rs | 4 +- clippy_lints/src/manual_async_fn.rs | 4 +- clippy_lints/src/manual_bits.rs | 4 +- clippy_lints/src/manual_clamp.rs | 22 +- clippy_lints/src/manual_float_methods.rs | 8 +- clippy_lints/src/manual_hash_one.rs | 4 +- clippy_lints/src/manual_is_ascii_check.rs | 4 +- clippy_lints/src/manual_let_else.rs | 4 +- clippy_lints/src/manual_main_separator_str.rs | 4 +- clippy_lints/src/manual_non_exhaustive.rs | 4 +- clippy_lints/src/manual_range_patterns.rs | 4 +- clippy_lints/src/manual_rem_euclid.rs | 4 +- clippy_lints/src/manual_retain.rs | 4 +- clippy_lints/src/manual_slice_size_calculation.rs | 4 +- clippy_lints/src/manual_string_new.rs | 4 +- clippy_lints/src/manual_strip.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 8 +- clippy_lints/src/matches/mod.rs | 78 ++-- clippy_lints/src/mem_replace.rs | 10 +- clippy_lints/src/methods/mod.rs | 420 ++++++++++----------- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/misc.rs | 6 +- clippy_lints/src/misc_early/mod.rs | 32 +- clippy_lints/src/mismatching_type_param_order.rs | 4 +- clippy_lints/src/missing_assert_message.rs | 4 +- clippy_lints/src/missing_asserts_for_indexing.rs | 4 +- clippy_lints/src/missing_const_for_fn.rs | 6 +- clippy_lints/src/missing_fields_in_debug.rs | 4 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/missing_trait_methods.rs | 4 +- clippy_lints/src/mixed_read_write_in_expression.rs | 4 +- clippy_lints/src/multi_assignments.rs | 4 +- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 4 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mut_reference.rs | 4 +- clippy_lints/src/mutex_atomic.rs | 8 +- clippy_lints/src/needless_arbitrary_self_type.rs | 4 +- clippy_lints/src/needless_bool.rs | 4 +- clippy_lints/src/needless_borrowed_ref.rs | 4 +- .../src/needless_borrows_for_generic_args.rs | 4 +- clippy_lints/src/needless_continue.rs | 10 +- clippy_lints/src/needless_else.rs | 4 +- clippy_lints/src/needless_for_each.rs | 4 +- clippy_lints/src/needless_late_init.rs | 4 +- .../src/needless_parens_on_range_literals.rs | 4 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 4 +- clippy_lints/src/needless_pass_by_value.rs | 4 +- clippy_lints/src/needless_question_mark.rs | 4 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 4 +- clippy_lints/src/non_canonical_impls.rs | 4 +- clippy_lints/src/non_copy_const.rs | 8 +- clippy_lints/src/non_expressive_names.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 4 +- clippy_lints/src/octal_escapes.rs | 4 +- clippy_lints/src/only_used_in_recursion.rs | 6 +- clippy_lints/src/operators/mod.rs | 72 ++-- clippy_lints/src/option_if_let_else.rs | 4 +- clippy_lints/src/overflow_check_conditional.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 4 +- clippy_lints/src/partial_pub_fields.rs | 4 +- clippy_lints/src/partialeq_ne_impl.rs | 2 +- clippy_lints/src/partialeq_to_none.rs | 4 +- clippy_lints/src/pass_by_ref_or_value.rs | 8 +- clippy_lints/src/permissions_set_readonly_false.rs | 2 +- clippy_lints/src/ptr_offset_with_cast.rs | 4 +- clippy_lints/src/pub_use.rs | 4 +- clippy_lints/src/ranges.rs | 14 +- clippy_lints/src/raw_strings.rs | 8 +- clippy_lints/src/rc_clone_in_vec_init.rs | 4 +- clippy_lints/src/read_zero_byte_vec.rs | 4 +- clippy_lints/src/redundant_async_block.rs | 4 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 4 +- clippy_lints/src/redundant_else.rs | 4 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_locals.rs | 4 +- clippy_lints/src/redundant_pub_crate.rs | 4 +- clippy_lints/src/redundant_slicing.rs | 4 +- clippy_lints/src/redundant_type_annotations.rs | 4 +- clippy_lints/src/ref_patterns.rs | 4 +- clippy_lints/src/reserve_after_initialization.rs | 4 +- clippy_lints/src/return_self_not_must_use.rs | 4 +- clippy_lints/src/returns.rs | 8 +- clippy_lints/src/same_name_method.rs | 2 +- clippy_lints/src/semicolon_block.rs | 8 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 4 +- clippy_lints/src/shadow.rs | 12 +- clippy_lints/src/single_call_fn.rs | 4 +- clippy_lints/src/single_char_lifetime_names.rs | 4 +- clippy_lints/src/single_range_in_vec_init.rs | 4 +- clippy_lints/src/size_of_ref.rs | 4 +- clippy_lints/src/slow_vector_initialization.rs | 4 +- clippy_lints/src/std_instead_of_core.rs | 12 +- clippy_lints/src/strings.rs | 26 +- clippy_lints/src/suspicious_doc_comments.rs | 4 +- clippy_lints/src/suspicious_operation_groupings.rs | 4 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 4 +- clippy_lints/src/swap.rs | 8 +- clippy_lints/src/swap_ptr_to_ref.rs | 4 +- clippy_lints/src/tabs_in_doc_comments.rs | 4 +- clippy_lints/src/temporary_assignment.rs | 2 +- clippy_lints/src/tests_outside_test_module.rs | 4 +- clippy_lints/src/to_digit_is_some.rs | 4 +- clippy_lints/src/trailing_empty_array.rs | 4 +- clippy_lints/src/trait_bounds.rs | 16 +- clippy_lints/src/transmute/mod.rs | 36 +- clippy_lints/src/types/mod.rs | 16 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 8 +- clippy_lints/src/unicode.rs | 4 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/mod.rs | 8 +- clippy_lints/src/unnamed_address.rs | 2 +- clippy_lints/src/unnecessary_box_returns.rs | 4 +- clippy_lints/src/unnecessary_map_on_constructor.rs | 4 +- .../src/unnecessary_owned_empty_strings.rs | 4 +- clippy_lints/src/unnecessary_self_imports.rs | 4 +- .../src/unnecessary_struct_initialization.rs | 4 +- clippy_lints/src/unnecessary_wraps.rs | 4 +- clippy_lints/src/unnested_or_patterns.rs | 4 +- clippy_lints/src/unused_async.rs | 4 +- clippy_lints/src/unused_peekable.rs | 4 +- clippy_lints/src/unused_rounding.rs | 4 +- clippy_lints/src/unused_unit.rs | 4 +- clippy_lints/src/unwrap.rs | 6 +- clippy_lints/src/unwrap_in_result.rs | 4 +- clippy_lints/src/upper_case_acronyms.rs | 4 +- clippy_lints/src/use_self.rs | 4 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_lints/src/utils/conf.rs | 4 +- clippy_lints/src/vec.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 4 +- clippy_lints/src/wildcard_imports.rs | 4 +- clippy_lints/src/write.rs | 30 +- clippy_lints/src/zero_div_zero.rs | 4 +- clippy_lints/src/zero_sized_map_values.rs | 4 +- clippy_utils/src/lib.rs | 10 +- clippy_utils/src/source.rs | 2 +- clippy_utils/src/str_utils.rs | 18 +- declare_clippy_lint/src/lib.rs | 2 +- 232 files changed, 989 insertions(+), 989 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index c7eeed17954..cbdf8a3001d 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -774,7 +774,7 @@ Additional dotfiles (files or directories starting with a dot) to allow ## `enforce-iter-loop-reborrow` #### Example -``` +```no_run let mut vec = vec![1, 2, 3]; let rmvec = &mut vec; for _ in rmvec.iter() {} @@ -782,7 +782,7 @@ for _ in rmvec.iter_mut() {} ``` Use instead: -``` +```no_run let mut vec = vec![1, 2, 3]; let rmvec = &mut vec; for _ in &*rmvec {} diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 04417c4c460..582423603eb 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// using absolute paths is the proper way of referencing items in one. /// /// ### Example - /// ```rust + /// ```no_run /// let x = std::f64::consts::PI; /// ``` /// Use any of the below instead, or anything else: - /// ```rust + /// ```no_run /// use std::f64; /// use std::f64::consts; /// use std::f64::consts::PI; diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 32d80f42e7e..4afb3957aa1 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -17,11 +17,11 @@ declare_clippy_lint! { /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = 'a'..'z'; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = 'a'..='z'; /// ``` #[clippy::version = "1.68.0"] diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index ccf82f132f4..591c78cb246 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -24,12 +24,12 @@ declare_clippy_lint! { /// issue](https://github.com/rust-lang/rust/issues). /// /// ### Example - /// ```rust + /// ```no_run /// let x = 3.14; /// let y = 1_f64 / x; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = std::f32::consts::PI; /// let y = std::f64::consts::FRAC_1_PI; /// ``` diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 35a04b5e44a..40e8281b260 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # use std::sync::Arc; /// diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 56f56fff1e7..b27d0ec1f42 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// An await is likely missing. /// /// ### Example - /// ```rust + /// ```no_run /// async fn foo() {} /// /// fn bar() { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// async fn foo() {} /// /// fn bar() { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index db01ddbde04..8a918c13cfc 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -129,7 +129,7 @@ declare_clippy_lint! { /// a valid semver. Failing that, the contained information is useless. /// /// ### Example - /// ```rust + /// ```no_run /// #[deprecated(since = "forever")] /// fn something_else() { /* ... */ } /// ``` @@ -156,14 +156,14 @@ declare_clippy_lint! { /// currently works for basic cases but is not perfect. /// /// ### Example - /// ```rust + /// ```no_run /// #[allow(dead_code)] /// /// fn not_quite_good_code() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Good (as inner attribute) /// #![allow(dead_code)] /// @@ -198,25 +198,25 @@ declare_clippy_lint! { /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). /// /// ### Example - /// ```rust + /// ```no_run /// /// Some doc comment with a blank line after it. /// /// fn not_quite_good_code() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// /// Good (no blank line) /// fn this_is_fine() { } /// ``` /// - /// ```rust + /// ```no_run /// // Good (convert to a regular comment) /// /// fn this_is_fine_too() { } /// ``` /// - /// ```rust + /// ```no_run /// //! Good (convert to a comment on an inner attribute) /// /// fn this_is_fine_as_well() { } @@ -236,12 +236,12 @@ declare_clippy_lint! { /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. /// /// ### Example - /// ```rust + /// ```no_run /// #![deny(clippy::restriction)] /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![deny(clippy::as_conversions)] /// ``` #[clippy::version = "1.47.0"] @@ -265,13 +265,13 @@ declare_clippy_lint! { /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg_attr(rustfmt, rustfmt_skip)] /// fn main() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[rustfmt::skip] /// fn main() { } /// ``` @@ -290,13 +290,13 @@ declare_clippy_lint! { /// by the conditional compilation engine. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(linux)] /// fn conditional() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # mod hidden { /// #[cfg(target_os = "linux")] /// fn conditional() { } @@ -325,14 +325,14 @@ declare_clippy_lint! { /// ensure that others understand the reasoning /// /// ### Example - /// ```rust + /// ```no_run /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint)] /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![feature(lint_reasons)] /// /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] @@ -352,7 +352,7 @@ declare_clippy_lint! { /// panicking with the expected message, and not another unrelated panic. /// /// ### Example - /// ```rust + /// ```no_run /// fn random() -> i32 { 0 } /// /// #[should_panic] @@ -363,7 +363,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn random() -> i32 { 0 } /// /// #[should_panic = "attempt to divide by zero"] @@ -386,13 +386,13 @@ declare_clippy_lint! { /// If there is only one condition, no need to wrap it into `any` or `all` combinators. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(any(unix))] /// pub struct Bar; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(unix)] /// pub struct Bar; /// ``` @@ -412,13 +412,13 @@ declare_clippy_lint! { /// may cause conditional compilation not work quitely. /// /// ### Example - /// ```rust + /// ```no_run /// #[cfg(features = "some-feature")] /// fn conditional() { } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(feature = "some-feature")] /// fn conditional() { } /// ``` diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index ae8618dcaa0..494374e967b 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # async fn baz() {} /// async fn foo(x: &Mutex) { @@ -47,7 +47,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # async fn baz() {} /// async fn foo(x: &Mutex) { @@ -87,7 +87,7 @@ declare_clippy_lint! { /// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # async fn baz() {} /// async fn foo(x: &RefCell) { @@ -105,7 +105,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::cell::RefCell; /// # async fn baz() {} /// async fn foo(x: &RefCell) { @@ -151,7 +151,7 @@ declare_clippy_lint! { /// ] /// ``` /// - /// ```rust + /// ```no_run /// # async fn baz() {} /// struct CustomLockType; /// struct OtherCustomLockType; diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 1593d7b0fb3..04bf541a5bd 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Style, using blocks in the condition makes it hard to read. /// /// ### Examples - /// ```rust + /// ```no_run /// # fn somefunc() -> bool { true }; /// if { true } { /* ... */ } /// @@ -29,7 +29,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn somefunc() -> bool { true }; /// if true { /* ... */ } /// diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 4503597713a..665dbd6f708 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// It is shorter to use the equivalent. /// /// ### Example - /// ```rust + /// ```no_run /// assert_eq!("a".is_empty(), false); /// assert_ne!("a".is_empty(), true); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// assert!(!"a".is_empty()); /// ``` #[clippy::version = "1.53.0"] diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 1828dd65152..ca305d0c6e5 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E /// /// ### Example - /// ```rust + /// ```no_run /// # let condition = false; /// if condition { /// 1_i64 @@ -30,12 +30,12 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let condition = false; /// i64::from(condition); /// ``` /// or - /// ```rust + /// ```no_run /// # let condition = false; /// condition as i64; /// ``` diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index b3dbbb08f8e..739ce8f67c2 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// /// ### Known problems /// False negative on such code: - /// ``` + /// ```no_run /// let x = &12; /// let addr_x = &x as *const _ as usize; /// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered. @@ -28,14 +28,14 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// ```rust + /// ```no_run /// let s = &String::new(); /// /// let a: &String = &* s; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = &String::new(); /// let a: &String = s; /// ``` diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index cc9bd727937..47672cb5fb5 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). /// /// ### Example - /// ```rust + /// ```no_run /// let x: Box = Box::new(Default::default()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: Box = Box::default(); /// ``` #[clippy::version = "1.66.0"] diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index b00130ffd76..2edbc6db5c3 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// those places in the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = u64::MAX; /// x as f64; /// ``` @@ -67,7 +67,7 @@ declare_clippy_lint! { /// as a one-time check to see where numerical wrapping can arise. /// /// ### Example - /// ```rust + /// ```no_run /// let y: i8 = -1; /// y as u128; // will return 18446744073709551615 /// ``` @@ -90,13 +90,13 @@ declare_clippy_lint! { /// checks could be beneficial. /// /// ### Example - /// ```rust + /// ```no_run /// fn as_u8(x: u64) -> u8 { /// x as u8 /// } /// ``` /// Use instead: - /// ``` + /// ```no_run /// fn as_u8(x: u64) -> u8 { /// if let Ok(x) = u8::try_from(x) { /// x @@ -132,7 +132,7 @@ declare_clippy_lint! { /// example below. /// /// ### Example - /// ```rust + /// ```no_run /// u32::MAX as i32; // will yield a value of `-1` /// ``` #[clippy::version = "pre 1.29.0"] @@ -155,7 +155,7 @@ declare_clippy_lint! { /// people reading the code to know that the conversion is lossless. /// /// ### Example - /// ```rust + /// ```no_run /// fn as_u64(x: u8) -> u64 { /// x as u64 /// } @@ -163,7 +163,7 @@ declare_clippy_lint! { /// /// Using `::from` would look like this: /// - /// ```rust + /// ```no_run /// fn as_u64(x: u8) -> u64 { /// u64::from(x) /// } @@ -191,14 +191,14 @@ declare_clippy_lint! { /// intermediate references, raw pointers and trait objects may or may not work. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = 2i32 as i32; /// let _ = 0.5 as f32; /// ``` /// /// Better: /// - /// ```rust + /// ```no_run /// let _ = 2_i32; /// let _ = 0.5_f32; /// ``` @@ -223,7 +223,7 @@ declare_clippy_lint! { /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (&1u8 as *const u8) as *const u16; /// let _ = (&mut 1u8 as *mut u8) as *mut u16; /// @@ -249,13 +249,13 @@ declare_clippy_lint! { /// Casting to isize also doesn't make sense since there are no signed addresses. /// /// ### Example - /// ```rust + /// ```no_run /// fn fun() -> i32 { 1 } /// let _ = fun as i64; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn fun() -> i32 { 1 } /// let _ = fun as usize; /// ``` @@ -276,7 +276,7 @@ declare_clippy_lint! { /// a comment) to perform the truncation. /// /// ### Example - /// ```rust + /// ```no_run /// fn fn1() -> i16 { /// 1 /// }; @@ -284,7 +284,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Cast to usize first, then comment with the reason for the truncation /// fn fn1() -> i16 { /// 1 @@ -310,7 +310,7 @@ declare_clippy_lint! { /// pointer casts in your code. /// /// ### Example - /// ```rust + /// ```no_run /// // fn1 is cast as `usize` /// fn fn1() -> u16 { /// 1 @@ -319,7 +319,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // maybe you intended to call the function? /// fn fn2() -> u16 { /// 1 @@ -378,14 +378,14 @@ declare_clippy_lint! { /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; /// let _ = ptr as *const i32; /// let _ = mut_ptr as *mut i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr: *mut u32 = &mut 42_u32; /// let _ = ptr.cast::(); @@ -408,13 +408,13 @@ declare_clippy_lint! { /// type. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr as *mut u32; /// let ptr = mut_ptr as *const u32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); @@ -434,7 +434,7 @@ declare_clippy_lint! { /// The resulting integral value will not match the value of the variant it came from. /// /// ### Example - /// ```rust + /// ```no_run /// enum E { X = 256 }; /// let _ = E::X as u8; /// ``` @@ -457,7 +457,7 @@ declare_clippy_lint! { /// /// ### Example /// // Missing data - /// ```rust + /// ```no_run /// let a = [1_i32, 2, 3, 4]; /// let p = &a as *const [i32] as *const [u8]; /// unsafe { @@ -465,7 +465,7 @@ declare_clippy_lint! { /// } /// ``` /// // Undefined Behavior (note: also potential alignment issues) - /// ```rust + /// ```no_run /// let a = [1_u8, 2, 3, 4]; /// let p = &a as *const [u8] as *const [u32]; /// unsafe { @@ -473,7 +473,7 @@ declare_clippy_lint! { /// } /// ``` /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length - /// ```rust + /// ```no_run /// let a = [1_i32, 2, 3, 4]; /// let old_ptr = &a as *const [i32]; /// // The data pointer is cast to a pointer to the target `u8` not `[u8]` @@ -497,7 +497,7 @@ declare_clippy_lint! { /// The cast is easily confused with casting a c-like enum value to an integer. /// /// ### Example - /// ```rust + /// ```no_run /// enum E { X(i32) }; /// let _ = E::X as usize; /// ``` @@ -515,12 +515,12 @@ declare_clippy_lint! { /// The `unsigned_abs()` method avoids panic when called on the MIN value. /// /// ### Example - /// ```rust + /// ```no_run /// let x: i32 = -42; /// let y: u32 = x.abs() as u32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: i32 = -42; /// let y: u32 = x.unsigned_abs(); /// ``` @@ -541,13 +541,13 @@ declare_clippy_lint! { /// The lint is allowed by default as using `_` is less wordy than always specifying the type. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(n: usize) {} /// let n: u16 = 256; /// foo(n as _); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(n: usize) {} /// let n: u16 = 256; /// foo(n as usize); @@ -570,7 +570,7 @@ declare_clippy_lint! { /// Read the `ptr::addr_of` docs for more information. /// /// ### Example - /// ```rust + /// ```no_run /// let val = 1; /// let p = &val as *const i32; /// @@ -578,7 +578,7 @@ declare_clippy_lint! { /// let p_mut = &mut val_mut as *mut i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let val = 1; /// let p = std::ptr::addr_of!(val); /// @@ -627,13 +627,13 @@ declare_clippy_lint! { /// mutability is used, making it unlikely that having it as a mutable pointer is correct. /// /// ### Example - /// ```rust + /// ```no_run /// let mut vec = Vec::::with_capacity(1); /// let ptr = vec.as_ptr() as *mut u8; /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = Vec::::with_capacity(1); /// let ptr = vec.as_mut_ptr(); /// unsafe { ptr.write(4) }; @@ -675,12 +675,12 @@ declare_clippy_lint! { /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 0 as *const u32; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = std::ptr::null::(); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 9102a89e377..1cfd0d1157c 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -19,13 +19,13 @@ declare_clippy_lint! { /// Reduces the readability of statements & is error prone. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo: u32 = 5; /// foo <= i32::MAX as u32; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = 1; /// # #[allow(unused)] /// i32::try_from(foo).is_ok(); diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index b38e09dc09f..d21ef195d9b 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// makes code look more complex than it really is. /// /// ### Example - /// ```rust + /// ```no_run /// # let (x, y) = (true, true); /// if x { /// if y { @@ -42,7 +42,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let (x, y) = (true, true); /// if x && y { /// // … diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index ac5ac542cf9..1dfc2e251d9 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// instead. /// /// ### Example - /// ```rust + /// ```no_run /// # let samples = vec![3, 1, 2]; /// let mut sorted_samples = samples.clone(); /// sorted_samples.sort(); @@ -29,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let samples = vec![3, 1, 2]; /// let mut sorted_samples = samples.clone(); /// sorted_samples.sort(); diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 726674d88f1..a2005638d24 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene /// /// ### Example - /// ```rust + /// ```no_run /// #[macro_export] /// macro_rules! print_message { /// () => { @@ -28,7 +28,7 @@ declare_clippy_lint! { /// pub const MESSAGE: &str = "Hello!"; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[macro_export] /// macro_rules! print_message { /// () => { diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 5787f19cc6c..c74b2b8831e 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// generic `Default`. /// /// ### Example - /// ```rust + /// ```no_run /// let s: String = Default::default(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let s = String::default(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -49,7 +49,7 @@ declare_clippy_lint! { /// Assignments to patterns that are of tuple type are not linted. /// /// ### Example - /// ``` + /// ```no_run /// # #[derive(Default)] /// # struct A { i: i32 } /// let mut a: A = Default::default(); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// # #[derive(Default)] /// # struct A { i: i32 } /// let a = A { diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 0676777e796..bf070432ef9 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// This adds code complexity and an unnecessary function call. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::marker::PhantomData; /// #[derive(Default)] /// struct S { @@ -29,7 +29,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::marker::PhantomData; /// struct S { /// _marker: PhantomData diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 2d11fa6b647..77f8243c969 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -14,12 +14,12 @@ declare_clippy_lint! { /// ### Why is this bad? /// `std::iter::empty()` is the more idiomatic way. /// ### Example - /// ```rust + /// ```no_run /// let _ = std::iter::Empty::::default(); /// let iter: std::iter::Empty = std::iter::Empty::default(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = std::iter::empty::(); /// let iter: std::iter::Empty = std::iter::empty(); /// ``` diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index d09428dbc1f..b296ea20f9c 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -31,13 +31,13 @@ declare_clippy_lint! { /// This lint can only be allowed at the function level or above. /// /// ### Example - /// ```rust + /// ```no_run /// let i = 10; /// let f = 1.23; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let i = 10i32; /// let f = 1.23f64; /// ``` diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index 63ec8195020..8c6749a95fa 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// specified layout. These cases may lead to undefined behavior in unsafe blocks. /// /// ### Example - /// ```rust + /// ```no_run /// union Foo { /// a: i32, /// b: u32, @@ -30,7 +30,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// union Foo { /// a: i32, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index efe82036dc8..ca4913ce1d1 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// when not part of a method chain. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ops::Deref; /// let a: &mut String = &mut String::from("foo"); /// let b: &str = a.deref(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a: &mut String = &mut String::from("foo"); /// let b = &*a; /// ``` @@ -68,7 +68,7 @@ declare_clippy_lint! { /// in such a case can change the semantics of the code. /// /// ### Example - /// ```rust + /// ```no_run /// fn fun(_a: &i32) {} /// /// let x: &i32 = &&&&&&5; @@ -76,7 +76,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn fun(_a: &i32) {} /// let x: &i32 = &5; /// fun(x); @@ -95,7 +95,7 @@ declare_clippy_lint! { /// The address-of operator at the use site is clearer about the need for a reference. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(""); /// if let Some(ref x) = x { /// // use `x` here @@ -103,7 +103,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(""); /// if let Some(x) = x { /// // use `&x` here @@ -123,12 +123,12 @@ declare_clippy_lint! { /// This unnecessarily complicates the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = String::new(); /// let y: &str = &*x; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = String::new(); /// let y: &str = &x; /// ``` diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index d2bfc4f8e27..ca3f1acfc0c 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// It is less concise. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// bar: bool /// } @@ -36,7 +36,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[derive(Default)] /// struct Foo { /// bar: bool diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 2bdac1352dc..6aaa9e39b8b 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -173,7 +173,7 @@ declare_clippy_lint! { /// `Eq` themselves. /// /// ### Example - /// ```rust + /// ```no_run /// #[derive(PartialEq)] /// struct Foo { /// i_am_eq: i32, @@ -181,7 +181,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[derive(PartialEq, Eq)] /// struct Foo { /// i_am_eq: i32, diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 7469f813ef8..e4f2328bc1f 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// { path = "serde::Serialize", reason = "no serializing" }, /// ] /// ``` - /// ``` + /// ```no_run /// use serde::Serialize; /// /// // Example code where clippy issues a warning diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 04c2d44137a..5e46b29b639 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// avoided. /// /// ### Example - /// ```rust + /// ```no_run /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index c9fad98e437..96a7f0e4fde 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents /// /// ### Example - /// ```rust + /// ```no_run /// // Assuming that `clippy.toml` contains the following line: /// // allowed-scripts = ["Latin", "Cyrillic"] /// let counter = 10; // OK, latin is allowed. diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index fc9b381664a..a2e05e5ba8d 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -58,14 +58,14 @@ declare_clippy_lint! { /// would fail. /// /// ### Examples - /// ```rust + /// ```no_run /// /// Do something with the foo_bar parameter. See also /// /// that::other::module::foo. /// // ^ `foo_bar` and `that::other::module::foo` should be ticked. /// fn doit(foo_bar: usize) {} /// ``` /// - /// ```rust + /// ```no_run /// // Link text with `[]` brackets should be written as following: /// /// Consume the array and return the inner /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]. @@ -88,7 +88,7 @@ declare_clippy_lint! { /// preconditions, so that users can be sure they are using them safely. /// /// ### Examples - /// ```rust + /// ```no_run ///# type Universe = (); /// /// This function should really be documented /// pub unsafe fn start_apocalypse(u: &mut Universe) { @@ -98,7 +98,7 @@ declare_clippy_lint! { /// /// At least write a line about safety: /// - /// ```rust + /// ```no_run ///# type Universe = (); /// /// # Safety /// /// @@ -126,7 +126,7 @@ declare_clippy_lint! { /// Since the following function returns a `Result` it has an `# Errors` section in /// its doc comment: /// - /// ```rust + /// ```no_run ///# use std::io; /// /// # Errors /// /// @@ -155,7 +155,7 @@ declare_clippy_lint! { /// Since the following function may panic it has a `# Panics` section in /// its doc comment: /// - /// ```rust + /// ```no_run /// /// # Panics /// /// /// /// Will panic if y is 0 @@ -182,7 +182,7 @@ declare_clippy_lint! { /// if the `fn main()` is left implicit. /// /// ### Examples - /// ```rust + /// ```no_run /// /// An example of a doctest with a `main()` function /// /// /// /// # Examples @@ -210,12 +210,12 @@ declare_clippy_lint! { /// It is likely a typo when defining an intra-doc link /// /// ### Example - /// ```rust + /// ```no_run /// /// See also: ['foo'] /// fn bar() {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// /// See also: [`foo`] /// fn bar() {} /// ``` @@ -235,7 +235,7 @@ declare_clippy_lint! { /// need to describe safety preconditions that users are required to uphold. /// /// ### Examples - /// ```rust + /// ```no_run ///# type Universe = (); /// /// # Safety /// /// @@ -248,7 +248,7 @@ declare_clippy_lint! { /// The function is safe, so there shouldn't be any preconditions /// that have to be explained for safety reasons. /// - /// ```rust + /// ```no_run ///# type Universe = (); /// /// This function should really be documented /// pub fn start_apocalypse(u: &mut Universe) { diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 29425b2e554..63f32173b05 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// mistake. /// /// ### Example - /// ```rust + /// ```no_run /// fn simple_double_parens() -> i32 { /// ((0)) /// } @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn simple_no_parens() -> i32 { /// 0 /// } diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 14122abbf2c..63394ea5fa3 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// have been intended. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// let x = Foo; /// std::mem::drop(x); @@ -36,7 +36,7 @@ declare_clippy_lint! { /// have been intended. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// let x = Foo; /// std::mem::forget(x); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// destructor, possibly causing leaks. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::mem; /// # use std::rc::Rc; /// mem::forget(Rc::new(55)) diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index bf4488570ea..61db1c1abd1 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// /// ### Example - /// ```rust + /// ```no_run /// # fn a() {} /// # fn b() {} /// # let x: i32 = 1; @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// # fn a() {} /// # fn b() {} /// # let x: i32 = 1; diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 209fb66fa40..5fcdca7cf36 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// destructured, which might be the intention behind adding the implementation as a marker. /// /// ### Example - /// ```rust + /// ```no_run /// struct S; /// /// impl Drop for S { @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct S; /// ``` #[clippy::version = "1.62.0"] diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 1701d061128..a5699727b5b 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// /// /// ### Example - /// ```rust + /// ```no_run /// enum Test {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #![feature(never_type)] /// /// struct Test(!); diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index 282157181ab..3122c1c1757 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -15,11 +15,11 @@ declare_clippy_lint! { /// Empty brackets after a struct declaration can be omitted. /// /// ### Example - /// ```rust + /// ```no_run /// struct Cookie {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Cookie; /// ``` #[clippy::version = "1.62.0"] diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 70a467dde61..3e3c62e85d0 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// /// ### Known problems /// The suggestion may have type inference errors in some cases. e.g. - /// ```rust + /// ```no_run /// let mut map = std::collections::HashMap::new(); /// let _ = if !map.contains_key(&0) { /// map.insert(0, 0) @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); /// # let k = 1; @@ -43,7 +43,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # let mut map = HashMap::new(); /// # let k = 1; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 646767868e2..003b5fc7261 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// architectures, but works fine on 64 bit. /// /// ### Example - /// ```rust + /// ```no_run /// # #[cfg(target_pointer_width = "64")] /// #[repr(usize)] /// enum NonPortable { diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index dbe3453e7bf..47ffde61fb7 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -28,12 +28,12 @@ declare_clippy_lint! { /// into something. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: Box) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(x: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index aef2db38583..1b0b88896ea 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// readability and API. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { /// is_pending: bool, /// is_processing: bool, @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// enum S { /// Pending, /// Processing, diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 9fd13084dc9..f976cfd3f22 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -17,14 +17,14 @@ declare_clippy_lint! { /// disable them by default. /// /// ### Example - /// ```rust + /// ```no_run /// enum Foo { /// Bar, /// Baz /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// enum Foo { /// Bar, @@ -47,14 +47,14 @@ declare_clippy_lint! { /// disable them by default. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// bar: u8, /// baz: String, /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// struct Foo { /// bar: u8, diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 5ecd0ffadf3..e14b1c556ec 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// the main function. /// /// ### Example - /// ``` + /// ```no_run /// std::process::exit(0) /// ``` /// diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 6f6177340f4..595da886601 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// Using `(e)println! is clearer and more concise /// /// ### Example - /// ```rust + /// ```no_run /// # use std::io::Write; /// # let bar = "furchtbar"; /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); @@ -27,7 +27,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::io::Write; /// # let bar = "furchtbar"; /// eprintln!("foo: {:?}", bar); diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 0a885984abb..73034b94206 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -23,13 +23,13 @@ declare_clippy_lint! { /// requires using a turbofish, which serves no purpose but to satisfy the compiler. /// /// ### Example - /// ```rust + /// ```no_run /// fn unused_ty(x: u8) { /// // .. /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn no_unused_ty(x: u8) { /// // .. /// } diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 2ef547526d4..efb69476b94 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// `TryFrom` should be used if there's a possibility of failure. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo(i32); /// /// impl From for Foo { @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// struct Foo(i32); /// /// impl TryFrom for Foo { diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index d182bb62195..506a1191747 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// Rust will truncate the literal silently. /// /// ### Example - /// ```rust + /// ```no_run /// let v: f32 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let v: f64 = 0.123_456_789_9; /// println!("{}", v); // 0.123_456_789_9 /// ``` @@ -44,12 +44,12 @@ declare_clippy_lint! { /// conversion to a float. /// /// ### Example - /// ```rust + /// ```no_run /// let _: f32 = 16_777_217.0; // 16_777_216.0 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let _: f32 = 16_777_216.0; /// let _: f64 = 16_777_217.0; /// ``` diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 29e5315f88b..3d51dfc3497 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// Negatively impacts accuracy. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 3f32; /// let _ = a.powf(1.0 / 3.0); /// let _ = (1.0 + a).ln(); @@ -35,7 +35,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = 3f32; /// let _ = a.cbrt(); /// let _ = a.ln_1p(); @@ -57,7 +57,7 @@ declare_clippy_lint! { /// Negatively impacts accuracy and performance. /// /// ### Example - /// ```rust + /// ```no_run /// use std::f32::consts::E; /// /// let a = 3f32; @@ -83,7 +83,7 @@ declare_clippy_lint! { /// /// is better expressed as /// - /// ```rust + /// ```no_run /// use std::f32::consts::E; /// /// let a = 3f32; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index b748d329367..fd34c8cddc0 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -23,13 +23,13 @@ declare_clippy_lint! { /// if `foo: &str`. /// /// ### Examples - /// ```rust + /// ```no_run /// let foo = "foo"; /// format!("{}", foo); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo = "foo"; /// foo.to_owned(); /// ``` diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 39abf5c2def..e674e03f17b 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -35,12 +35,12 @@ declare_clippy_lint! { /// The recommended code is both shorter and avoids a temporary allocation. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: {}", format!("something failed at {}", Location::caller())); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` @@ -61,12 +61,12 @@ declare_clippy_lint! { /// unnecessary. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller().to_string()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::panic::Location; /// println!("error: something failed at {}", Location::caller()); /// ``` @@ -87,7 +87,7 @@ declare_clippy_lint! { /// The inlined syntax, where allowed, is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// # let var = 42; /// # let width = 1; /// # let prec = 2; @@ -98,7 +98,7 @@ declare_clippy_lint! { /// format!("{:.*}", prec, var); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let var = 42; /// # let width = 1; /// # let prec = 2; @@ -111,12 +111,12 @@ declare_clippy_lint! { /// /// If allow-mixed-uninlined-format-args is set to false in clippy.toml, /// the following code will also trigger the lint: - /// ```rust + /// ```no_run /// # let var = 42; /// format!("{} {}", var, 1+2); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let var = 42; /// format!("{var} {}", 1+2); /// ``` @@ -141,13 +141,13 @@ declare_clippy_lint! { /// an expected formatting operation such as adding padding isn't happening. /// /// ### Example - /// ```rust + /// ```no_run /// println!("{:.}", 1.0); /// /// println!("not padded: {:5}", format_args!("...")); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// println!("{}", 1.0); /// /// println!("not padded: {}", format_args!("...")); diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 1d2f7cb7130..08ee7032c09 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// use std::fmt; /// /// struct Structure(i32); @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// struct Structure(i32); @@ -59,7 +59,7 @@ declare_clippy_lint! { /// should write to the `Formatter`, not stdout/stderr. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt::{Display, Error, Formatter}; /// /// struct S; @@ -72,7 +72,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::{Display, Error, Formatter}; /// /// struct S; diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 45f67020c2d..858ec91412b 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer. /// /// ### Example - /// ```rust + /// ```no_run /// let mut s = String::new(); /// s += &format!("0x{:X}", 1024); /// s.push_str(&format!("0x{:X}", 1024)); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::Write as _; // import without risk of name clashing /// /// let mut s = String::new(); diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 4ebf0e9667d..10ddc3bda34 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// This is either a typo in the binary operator or confusing. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = true; /// # let bar = false; /// // &&! looks like a different operator @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = true; /// # let bar = false; /// if foo && !bar {} diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 0ec52f89e71..69bc0b726fc 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// comment. /// /// ### Example - /// ```rust + /// ```no_run /// //// My amazing data structure /// pub struct Foo { /// // ... @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// /// My amazing data structure /// pub struct Foo { /// // ... diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 2b899e21ef5..a100fd6c595 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. /// /// ### Example - /// ```rust + /// ```no_run /// struct StringWrapper(String); /// /// impl Into for String { @@ -34,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct StringWrapper(String); /// /// impl From for StringWrapper { diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 617c96b4fcb..b66746d08f8 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::ffi::c_void; /// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; /// let _ = unsafe { Box::from_raw(ptr) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::ffi::c_void; /// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; /// let _ = unsafe { Box::from_raw(ptr as *mut usize) }; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 716908483e9..3f5cceec70e 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// grouping some parameters into a new type. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Color; /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { /// // .. @@ -46,7 +46,7 @@ declare_clippy_lint! { /// multiple functions. /// /// ### Example - /// ```rust + /// ```no_run /// fn im_too_long() { /// println!(""); /// // ... 100 more LoC @@ -129,7 +129,7 @@ declare_clippy_lint! { /// a remnant of a refactoring that removed the return type. /// /// ### Examples - /// ```rust + /// ```no_run /// #[must_use] /// fn useless() { } /// ``` @@ -151,7 +151,7 @@ declare_clippy_lint! { /// attribute to improve the lint message. /// /// ### Examples - /// ```rust + /// ```no_run /// #[must_use] /// fn double_must_use() -> Result<(), ()> { /// unimplemented!(); @@ -183,7 +183,7 @@ declare_clippy_lint! { /// `#[must_use]`. /// /// ### Examples - /// ```rust + /// ```no_run /// // this could be annotated with `#[must_use]`. /// pub fn id(t: T) -> T { t } /// ``` @@ -211,7 +211,7 @@ declare_clippy_lint! { /// instead. /// /// ### Examples - /// ```rust + /// ```no_run /// pub fn read_u8() -> Result { Err(()) } /// ``` /// should become @@ -262,7 +262,7 @@ declare_clippy_lint! { /// The size determined by Clippy is platform-dependent. /// /// ### Examples - /// ```rust + /// ```no_run /// pub enum ParseError { /// UnparsedBytes([u8; 512]), /// UnexpectedEof, @@ -274,7 +274,7 @@ declare_clippy_lint! { /// } /// ``` /// should be - /// ``` + /// ```no_run /// pub enum ParseError { /// UnparsedBytes(Box<[u8; 512]>), /// UnexpectedEof, @@ -301,7 +301,7 @@ declare_clippy_lint! { /// /// ### Example - /// ```rust + /// ```no_run /// struct A { /// a: String, /// b: String, @@ -315,7 +315,7 @@ declare_clippy_lint! { /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct A { /// a: String, /// b: String, @@ -340,14 +340,14 @@ declare_clippy_lint! { /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. /// /// ### Example - /// ```rust + /// ```no_run /// trait MyTrait {} /// fn foo(a: impl MyTrait) { /// // [...] /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// trait MyTrait {} /// fn foo(a: T) { /// // [...] diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 621415c881c..eee5b7540ba 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -34,11 +34,11 @@ declare_clippy_lint! { /// produced. /// /// ### Example - /// ```rust + /// ```no_run /// async fn not_send(bytes: std::rc::Rc<[u8]>) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// async fn is_send(bytes: std::sync::Arc<[u8]>) {} /// ``` #[clippy::version = "1.44.0"] diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 640819890b9..cae561f7802 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// Negations reduce the readability of statements. /// /// ### Example - /// ```rust + /// ```no_run /// # let v: Vec = vec![]; /// # fn a() {} /// # fn b() {} @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let v: Vec = vec![]; /// # fn a() {} /// # fn b() {} diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index e2d19e24557..ebd529bd356 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// in comparison to `bool::then`. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = vec![0]; /// let a = if v.is_empty() { /// println!("true!"); @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let v = vec![0]; /// let a = v.is_empty().then(|| { /// println!("true!"); diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index ef2a66d4a20..0798f26d8f6 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// would detect a type change that `_` would ignore. /// /// ### Example - /// ```rust + /// ```no_run /// match std::fs::create_dir("tmp-work-dir") { /// Ok(_) => println!("Working directory created"), /// Err(s) => eprintln!("Could not create directory: {s}"), /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// match std::fs::create_dir("tmp-work-dir") { /// Ok(()) => println!("Working directory created"), /// Err(s) => eprintln!("Could not create directory: {s}"), diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 2b2ea156cd4..a1fcce18ff6 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// pieces of code, possibly including external crates. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; /// # trait Serialize {}; @@ -44,7 +44,7 @@ declare_clippy_lint! { /// pub fn foo(map: &mut HashMap) { } /// ``` /// could be rewritten as - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// # use std::hash::{Hash, BuildHasher}; /// # trait Serialize {}; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index a6b035d5106..c6bcf3ba40c 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -24,13 +24,13 @@ declare_clippy_lint! { /// corresponding statements. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// x /// } /// ``` /// add return - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// return x; /// } diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index ee7973b82ab..453797f1853 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// The built-in function is more readable and may be faster. /// /// ### Example - /// ```rust + /// ```no_run ///let mut u:u32 = 7000; /// /// if u != u32::MAX { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run ///let mut u:u32 = 7000; /// /// u = u.saturating_add(1); diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index b99d4544681..859404289d9 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Simplicity and readability. Instead we can easily use an builtin function. /// /// ### Example - /// ```rust + /// ```no_run /// # let end: u32 = 10; /// # let start: u32 = 5; /// let mut i: u32 = end - start; @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let end: u32 = 10; /// # let start: u32 = 5; /// let mut i: u32 = end - start; diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index ec9044bba5c..cbe2b9c1dd4 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`) /// /// ### Example - /// ```rust + /// ```no_run /// # use std::ops::{Deref,DerefMut}; /// fn f() -> impl Deref + DerefMut { /// // ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound @@ -37,7 +37,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::ops::{Deref,DerefMut}; /// fn f() -> impl DerefMut { /// Box::new(123) diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 1ad886f2cf3..a84f7351ad6 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// Since the order of fields in a constructor doesn't affect the /// resulted instance as the below example indicates, /// - /// ```rust + /// ```no_run /// #[derive(Debug, PartialEq, Eq)] /// struct Foo { /// x: i32, @@ -35,7 +35,7 @@ declare_clippy_lint! { /// inconsistent order can be confusing and decreases readability and consistency. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// x: i32, /// y: i32, @@ -47,7 +47,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct Foo { /// # x: i32, /// # y: i32, diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index f507f45d5bb..ab5e6a93300 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// patterns. /// /// ### Example - /// ```rust + /// ```no_run /// let slice: Option<&[u32]> = Some(&[1, 2, 3]); /// /// if let Some(slice) = slice { @@ -39,7 +39,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let slice: Option<&[u32]> = Some(&[1, 2, 3]); /// /// if let Some(&[first, ..]) = slice { diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 4f4f571773f..1ce7d85d382 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = [1, 2, 3, 4]; /// // Index within bounds /// @@ -65,7 +65,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #![allow(unused)] /// /// # let x = vec![0; 5]; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index fe28c526be3..e9c53671a93 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// this lint is not clever enough to analyze it. /// /// ### Example - /// ```rust + /// ```no_run /// let infinite_iter = 0..; /// # #[allow(unused)] /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 3d1113ff9cc..a61a6416193 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Splitting the implementation of a type makes the code harder to navigate. /// /// ### Example - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn one() {} @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn one() {} diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index bc4ec33b733..fe5eb5ccac5 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct A; /// /// impl A { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; @@ -51,7 +51,7 @@ declare_clippy_lint! { /// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; @@ -70,7 +70,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// /// pub struct A; diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index f95d2c2edb1..269311a67d6 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// benefit as opposed to tuple initializers /// /// ### Example - /// ```rust + /// ```no_run /// struct TupleStruct(u8, u16); /// /// let _ = TupleStruct { diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index d609a5ca4d4..899126565f7 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// The inline attribute is ignored for trait methods without bodies. /// /// ### Example - /// ```rust + /// ```no_run /// trait Animal { /// #[inline] /// fn name(&self) -> &'static str; diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index a1a115f6d79..cb01f7aac14 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// `prev_instant.elapsed()` also more clearly signals intention. /// /// ### Example - /// ```rust + /// ```no_run /// use std::time::Instant; /// let prev_instant = Instant::now(); /// let duration = Instant::now() - prev_instant; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::time::Instant; /// let prev_instant = Instant::now(); /// let duration = prev_instant.elapsed(); @@ -47,13 +47,13 @@ declare_clippy_lint! { /// unintentional panics. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now() - Duration::from_secs(5); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::time::{Instant, Duration}; /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5)); /// ``` diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 1b14e525d9a..9ffcee07d28 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -16,14 +16,14 @@ declare_clippy_lint! { /// Readability -- better to use `> y` instead of `>= y + 1`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 1; /// if x >= y + 1 {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 1; /// if x > y {} diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 6ea637412d5..de82935e66b 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// https://github.com/rust-lang/rust-clippy/issues/886 /// /// ### Example - /// ```rust + /// ```no_run /// let x: u8 = 1; /// (x as u32) > 300; /// ``` diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 8b4984da3dd..923d90187e9 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹` /// /// ### Example - /// ```rust + /// ```no_run /// enum Cake { /// BlackForestCake, /// HummingbirdCake, @@ -34,7 +34,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// enum Cake { /// BlackForest, /// Hummingbird, @@ -56,14 +56,14 @@ declare_clippy_lint! { /// It requires the user to type the module name twice. /// /// ### Example - /// ```rust + /// ```no_run /// mod cake { /// struct BlackForestCake; /// } /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// mod cake { /// struct BlackForest; /// } @@ -119,7 +119,7 @@ declare_clippy_lint! { /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹` /// /// ### Example - /// ```rust + /// ```no_run /// struct Cake { /// cake_sugar: u8, /// cake_flour: u8, @@ -127,7 +127,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Cake { /// sugar: u8, /// flour: u8, diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index a7ec57e2850..9605d76fbf0 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// it's hard to figure out which item is meant in a statement. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() { /// println!("cake"); /// } @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo() { /// println!("cake"); /// } diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 41477242bcc..fde6bff9417 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### Why is this bad? /// Having items declared after the testing module is confusing and may lead to bad test coverage. /// ### Example - /// ```rust + /// ```no_run /// #[cfg(test)] /// mod tests { /// // [...] @@ -25,7 +25,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn my_function() { /// // [...] /// } diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 066d2c4b787..505aadd1a11 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Methods named `iter` or `iter_mut` conventionally return an `Iterator`. /// /// ### Example - /// ```rust + /// ```no_run /// // `String` does not implement `Iterator` /// struct Data {} /// impl Data { @@ -25,7 +25,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::str::Chars; /// struct Data {} /// impl Data { diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 0ee291a4e9d..88042525c4f 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`. /// /// ### Example - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> MySlice<'a> { /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { @@ -29,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> MySlice<'a> { /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { @@ -62,7 +62,7 @@ declare_clippy_lint! { /// in case of ambiguity with another `IntoIterator` impl. /// /// ### Example - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> IntoIterator for &MySlice<'a> { /// type Item = &'a u8; @@ -73,7 +73,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct MySlice<'a>(&'a [u8]); /// impl<'a> MySlice<'a> { /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index b22b57a3006..79522db3718 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// this may lead to a false positive. /// /// ### Example - /// ```rust + /// ```no_run /// enum Test { /// A(i32), /// B([i32; 8000]), @@ -46,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// // Possibly better /// enum Test2 { /// A(i32), diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 90096f0f506..26a7278524e 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// large size of a `Future` may cause stack overflows. /// /// ### Example - /// ```rust + /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} /// /// pub async fn trigger() { @@ -26,7 +26,7 @@ declare_clippy_lint! { /// /// `Box::pin` the big future instead. /// - /// ```rust + /// ```no_run /// async fn large_future(_x: [u8; 16 * 1024]) {} /// /// pub async fn trigger() { diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 1d28d7dd0e7..33636eb687f 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { /// ### Example /// This function creates four 500 KB arrays on the stack. Quite big but just small enough to not trigger `large_stack_arrays`. /// However, looking at the function as a whole, it's clear that this uses a lot of stack space. - /// ```rust + /// ```no_run /// struct QuiteLargeType([u8; 500_000]); /// fn foo() { /// // ... some function that uses a lot of stack space ... @@ -62,7 +62,7 @@ declare_clippy_lint! { /// /// Instead of doing this, allocate the arrays on the heap. /// This currently requires going through a `Vec` first and then converting it to a `Box`: - /// ```rust + /// ```no_run /// struct NotSoLargeType(Box<[u8]>); /// /// fn foo() { diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index e7c875ab3a9..7a19b1c4273 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// expr /// /// ### Example - /// ```rust + /// ```no_run /// fn f() -> Result { /// Ok(0) /// } @@ -69,7 +69,7 @@ declare_clippy_lint! { /// and ignore the resulting value. /// /// ### Example - /// ```rust + /// ```no_run /// async fn foo() -> Result<(), ()> { /// Ok(()) /// } @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # async fn context() { /// async fn foo() -> Result<(), ()> { /// Ok(()) @@ -107,14 +107,14 @@ declare_clippy_lint! { /// lints. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> Result { /// Ok(123) /// } /// let _ = foo(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo() -> Result { /// Ok(123) /// } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 0004a150d51..35d7a9540af 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// are mentioned due to potential false positives. /// /// ### Example - /// ```rust + /// ```no_run /// // Unnecessary lifetime annotations /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { /// x @@ -46,7 +46,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn elided(x: &u8, y: u8) -> &u8 { /// x /// } @@ -69,7 +69,7 @@ declare_clippy_lint! { /// them leads to more readable code. /// /// ### Example - /// ```rust + /// ```no_run /// // unnecessary lifetimes /// fn unused_lifetime<'a>(x: u8) { /// // .. @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn no_lifetime(x: u8) { /// // ... /// } diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index ac949b67260..1304654efa6 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -34,7 +34,7 @@ declare_clippy_lint! { /// successful results, using `map_while()` would stop at the first error. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::{fs::File, io::{self, BufRead, BufReader}}; /// # let _ = || -> io::Result<()> { /// let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok); @@ -43,7 +43,7 @@ declare_clippy_lint! { /// # Ok(()) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::{fs::File, io::{self, BufRead, BufReader}}; /// # let _ = || -> io::Result<()> { /// let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok); diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 09ca0317337..2c14bb72a9e 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -23,14 +23,14 @@ declare_clippy_lint! { /// Reading long numbers is difficult without separators. /// /// ### Example - /// ```rust + /// ```no_run /// # let _: u64 = /// 61864918973511 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _: u64 = /// 61_864_918_973_511 /// # ; @@ -73,14 +73,14 @@ declare_clippy_lint! { /// grouped digits. /// /// ### Example - /// ```rust + /// ```no_run /// # let _: u64 = /// 618_64_9189_73_511 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _: u64 = /// 61_864_918_973_511 /// # ; @@ -100,7 +100,7 @@ declare_clippy_lint! { /// Negatively impacts readability. /// /// ### Example - /// ```rust + /// ```no_run /// let x: u32 = 0xFFF_FFF; /// let y: u8 = 0b01_011_101; /// ``` @@ -120,7 +120,7 @@ declare_clippy_lint! { /// Negatively impacts readability. /// /// ### Example - /// ```rust + /// ```no_run /// let x: u64 = 6186491_8973511; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 1fb16adad7a..747fc7eb40e 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// It is not as fast as a memcpy. /// /// ### Example - /// ```rust + /// ```no_run /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; /// for i in 0..src.len() { @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let src = vec![1]; /// # let mut dst = vec![0; 65]; /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]); @@ -67,7 +67,7 @@ declare_clippy_lint! { /// the bounds check that is done when indexing. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec!['a', 'b', 'c']; /// for i in 0..vec.len() { /// println!("{}", vec[i]); @@ -75,7 +75,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec!['a', 'b', 'c']; /// for i in vec { /// println!("{}", i); @@ -100,7 +100,7 @@ declare_clippy_lint! { /// types. /// /// ### Example - /// ```rust + /// ```no_run /// // with `y` a `Vec` or slice: /// # let y = vec![1]; /// for x in y.iter() { @@ -109,7 +109,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = vec![1]; /// for x in &y { /// // .. @@ -130,7 +130,7 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = vec![1]; /// // with `y` a `Vec` or slice: /// for x in y.into_iter() { @@ -138,7 +138,7 @@ declare_clippy_lint! { /// } /// ``` /// can be rewritten to - /// ```rust + /// ```no_run /// # let y = vec![1]; /// for x in y { /// // .. @@ -217,7 +217,7 @@ declare_clippy_lint! { /// declutters the code and may be faster in some instances. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} /// let mut i = 0; @@ -228,7 +228,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let v = vec![1]; /// # fn bar(bar: usize, baz: usize) {} /// for (i, item) in v.iter().enumerate() { bar(i, *item); } @@ -339,7 +339,7 @@ declare_clippy_lint! { /// code. /// /// ### Example - /// ```rust + /// ```no_run /// loop { /// ..; /// break; @@ -362,7 +362,7 @@ declare_clippy_lint! { /// False positive when mutation is followed by a `break`, but the `break` is not immediately /// after the mutation: /// - /// ```rust + /// ```no_run /// let mut x = 5; /// for _ in 0..x { /// x += 1; // x is a range bound that is mutated @@ -374,7 +374,7 @@ declare_clippy_lint! { /// False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072)) /// /// ### Example - /// ```rust + /// ```no_run /// let mut foo = 42; /// for i in 0..foo { /// foo -= 1; @@ -402,7 +402,7 @@ declare_clippy_lint! { /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger. /// /// ### Example - /// ```rust + /// ```no_run /// let i = 0; /// while i > 10 { /// println!("let me loop forever!"); @@ -425,7 +425,7 @@ declare_clippy_lint! { /// have better performance. /// /// ### Example - /// ```rust + /// ```no_run /// let item1 = 2; /// let item2 = 3; /// let mut vec: Vec = Vec::new(); @@ -438,7 +438,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let item1 = 2; /// let item2 = 3; /// let mut vec: Vec = vec![item1; 20]; @@ -459,7 +459,7 @@ declare_clippy_lint! { /// single element. /// /// ### Example - /// ```rust + /// ```no_run /// let item1 = 2; /// for item in &[item1] { /// println!("{}", item); @@ -467,7 +467,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let item1 = 2; /// let item = &item1; /// println!("{}", item); @@ -489,7 +489,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// let x = vec![Some(1), Some(2), Some(3)]; /// for n in x { /// if let Some(n) = n { @@ -498,7 +498,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![Some(1), Some(2), Some(3)]; /// for n in x.into_iter().flatten() { /// println!("{}", n); @@ -555,7 +555,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// fn example(arr: Vec) -> Option { /// for el in arr { /// if el == 1 { @@ -566,7 +566,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn example(arr: Vec) -> Option { /// arr.into_iter().find(|&el| el == 1) /// } @@ -587,7 +587,7 @@ declare_clippy_lint! { /// pattern matching on the return value of `Vec::pop()`. /// /// ### Example - /// ```rust + /// ```no_run /// let mut numbers = vec![1, 2, 3, 4, 5]; /// while !numbers.is_empty() { /// let number = numbers.pop().unwrap(); @@ -595,7 +595,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut numbers = vec![1, 2, 3, 4, 5]; /// while let Some(number) = numbers.pop() { /// // use `number` diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 45ea5aab4c2..044d99bc0f7 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -16,14 +16,14 @@ declare_clippy_lint! { /// `assert!` is simpler than `if`-then-`panic!`. /// /// ### Example - /// ```rust + /// ```no_run /// let sad_people: Vec<&str> = vec![]; /// if !sad_people.is_empty() { /// panic!("there are sad people: {:?}", sad_people); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let sad_people: Vec<&str> = vec![]; /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 5a87e75722d..f2c278f4747 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -20,13 +20,13 @@ declare_clippy_lint! { /// It's more idiomatic to use the dedicated syntax. /// /// ### Example - /// ```rust + /// ```no_run /// use std::future::Future; /// /// fn foo() -> impl Future { async { 42 } } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// async fn foo() -> i32 { 42 } /// ``` #[clippy::version = "1.45.0"] diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 552c57d5e02..2db4443e059 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// Can be written as the shorter `T::BITS`. /// /// ### Example - /// ```rust + /// ```no_run /// std::mem::size_of::() * 8; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// usize::BITS as usize; /// ``` #[clippy::version = "1.60.0"] diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index e75666e61f5..4afeb5eebc3 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613). /// /// ### Examples - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// if input > max { /// max @@ -50,13 +50,13 @@ declare_clippy_lint! { /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// input.max(min).min(max) /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// match input { /// x if x > max => max, @@ -66,14 +66,14 @@ declare_clippy_lint! { /// # ; /// ``` /// - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// let mut x = input; /// if x < min { x = min; } /// if x > max { x = max; } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let (input, min, max) = (0, -2, 1); /// input.clamp(min, max) /// # ; @@ -207,7 +207,7 @@ impl TypeClampability { /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// if input < min { @@ -256,7 +256,7 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min_value, max_value) = (0, -3, 12); /// /// input.max(min_value).min(max_value) @@ -287,7 +287,7 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min_value, max_value) = (0, -3, 12); /// # use std::cmp::{max, min}; /// min(max(input, min_value), max_value) @@ -369,7 +369,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// match input { @@ -428,7 +428,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (input, min, max) = (0, -3, 12); /// /// let mut x = input; @@ -485,7 +485,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> /// Targets patterns like /// -/// ``` +/// ```no_run /// # let (mut input, min, max) = (0, -3, 12); /// /// if input < min { diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index f0994695565..c27ce062338 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -17,12 +17,12 @@ declare_clippy_lint! { /// The method `is_infinite` is shorter and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x == f32::INFINITY || x == f32::NEG_INFINITY {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x.is_infinite() {} /// ``` @@ -40,13 +40,13 @@ declare_clippy_lint! { /// The method `is_finite` is shorter and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x != f32::INFINITY && x != f32::NEG_INFINITY {} /// if x.abs() < f32::INFINITY {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.0f32; /// if x.is_finite() {} /// if x.is_finite() {} diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index ea911335450..cbad700c99a 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// It is more concise to use the `hash_one` method. /// /// ### Example - /// ```rust + /// ```no_run /// use std::hash::{BuildHasher, Hash, Hasher}; /// use std::collections::hash_map::RandomState; /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// let hash = hasher.finish(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::hash::BuildHasher; /// use std::collections::hash_map::RandomState; /// diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 9da20a28fba..2474c672e18 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// clear that it's not a specific subset of characters, but all /// ASCII (lowercase|uppercase|digit|hexdigit) characters. /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// assert!(matches!('x', 'a'..='z')); /// assert!(matches!(b'X', b'A'..=b'Z')); @@ -37,7 +37,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// assert!('x'.is_ascii_lowercase()); /// assert!(b'X'.is_ascii_uppercase()); diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 86bbdb4ea19..fb8ddd8c2be 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -30,14 +30,14 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # let w = Some(0); /// let v = if let Some(v) = w { v } else { return }; /// ``` /// /// Could be written: /// - /// ```rust + /// ```no_run /// # fn main () { /// # let w = Some(0); /// let Some(v) = w else { return }; diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index c292bbe4e93..8bd62b080c4 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -19,11 +19,11 @@ declare_clippy_lint! { /// an extra memory allocation. /// /// ### Example - /// ```rust + /// ```no_run /// let s: &str = &std::path::MAIN_SEPARATOR.to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let s: &str = std::path::MAIN_SEPARATOR_STR; /// ``` #[clippy::version = "1.70.0"] diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index c12727c4a28..85ca8486315 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// and allows possible optimizations when applied to enums. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { /// pub a: i32, /// pub b: i32, @@ -39,7 +39,7 @@ declare_clippy_lint! { /// struct T(pub i32, pub i32, ()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[non_exhaustive] /// struct S { /// pub a: i32, diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 90557b55560..d24bfe18224 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// in order to support negative numbers. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 6; /// let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 6; /// let foo = matches!(x, 1..=10); /// ``` diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 0e89ca132ef..80b83aac413 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -18,12 +18,12 @@ declare_clippy_lint! { /// It's simpler and more readable. /// /// ### Example - /// ```rust + /// ```no_run /// let x: i32 = 24; /// let rem = ((x % 4) + 4) % 4; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x: i32 = 24; /// let rem = x.rem_euclid(4); /// ``` diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index f923413f434..bfce92c0251 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -35,13 +35,13 @@ declare_clippy_lint! { /// ### Why is this bad? /// `.retain()` is simpler and avoids needless allocation. /// ### Example - /// ```rust + /// ```no_run /// let mut vec = vec![0, 1, 2]; /// vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); /// vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = vec![0, 1, 2]; /// vec.retain(|x| x % 2 == 0); /// ``` diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index f97600b53e4..3b97d165998 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// * Less turbofishing /// /// ### Example - /// ```rust + /// ```no_run /// # let data : &[i32] = &[1, 2, 3]; /// let newlen = data.len() * std::mem::size_of::(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let data : &[i32] = &[1, 2, 3]; /// let newlen = std::mem::size_of_val(data); /// ``` diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index c20d7959fc4..726087d4562 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -19,12 +19,12 @@ declare_clippy_lint! { /// be confusing. /// /// ### Example - /// ```rust + /// ```no_run /// let a = "".to_string(); /// let b: String = "".into(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = String::new(); /// let b = String::new(); /// ``` diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 201bb56efcd..e653064dbde 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -27,14 +27,14 @@ declare_clippy_lint! { /// used by `str::{starts,ends}_with` and in the slicing. /// /// ### Example - /// ```rust + /// ```no_run /// let s = "hello, world!"; /// if s.starts_with("hello, ") { /// assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let s = "hello, world!"; /// if let Some(end) = s.strip_prefix("hello, ") { /// assert_eq!(end.to_uppercase(), "WORLD!"); diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index f0a0f482af2..766beb980a5 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// an if let statement /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff() -> Option { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option { Some(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn do_stuff() -> Option { Some(String::new()) } /// # fn log_err_msg(foo: String) -> Option { Some(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -63,7 +63,7 @@ declare_clippy_lint! { /// an if let statement /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff() -> Result { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result { Ok(foo) } /// # fn format_msg(foo: String) -> String { String::new() } @@ -75,7 +75,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn do_stuff() -> Result { Ok(String::new()) } /// # fn log_err_msg(foo: String) -> Result { Ok(foo) } /// # fn format_msg(foo: String) -> String { String::new() } diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index b5ab94b3a2f..8f1ad962276 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -48,7 +48,7 @@ declare_clippy_lint! { /// Just readability – `if let` nests less than a `match`. /// /// ### Example - /// ```rust + /// ```no_run /// # fn bar(stool: &str) {} /// # let x = Some("abc"); /// match x { @@ -58,7 +58,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn bar(stool: &str) {} /// # let x = Some("abc"); /// if let Some(ref foo) = x { @@ -85,7 +85,7 @@ declare_clippy_lint! { /// ### Example /// Using `match`: /// - /// ```rust + /// ```no_run /// # fn bar(foo: &usize) {} /// # let other_ref: usize = 1; /// # let x: Option<&usize> = Some(&1); @@ -97,7 +97,7 @@ declare_clippy_lint! { /// /// Using `if let` with `else`: /// - /// ```rust + /// ```no_run /// # fn bar(foo: &usize) {} /// # let other_ref: usize = 1; /// # let x: Option<&usize> = Some(&1); @@ -155,7 +155,7 @@ declare_clippy_lint! { /// It makes the code less readable. /// /// ### Example - /// ```rust + /// ```no_run /// # fn foo() {} /// # fn bar() {} /// let condition: bool = true; @@ -165,7 +165,7 @@ declare_clippy_lint! { /// } /// ``` /// Use if/else instead: - /// ```rust + /// ```no_run /// # fn foo() {} /// # fn bar() {} /// let condition: bool = true; @@ -190,7 +190,7 @@ declare_clippy_lint! { /// less obvious. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 5; /// match x { /// 1..=10 => println!("1 ... 10"), @@ -214,7 +214,7 @@ declare_clippy_lint! { /// catching all exceptions in java with `catch(Exception)` /// /// ### Example - /// ```rust + /// ```no_run /// let x: Result = Ok(3); /// match x { /// Ok(_) => println!("ok"), @@ -236,7 +236,7 @@ declare_clippy_lint! { /// Using `as_ref()` or `as_mut()` instead is shorter. /// /// ### Example - /// ```rust + /// ```no_run /// let x: Option<()> = None; /// /// let r: Option<&()> = match x { @@ -246,7 +246,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x: Option<()> = None; /// /// let r: Option<&()> = x.as_ref(); @@ -269,7 +269,7 @@ declare_clippy_lint! { /// variants, and also may not use correct path to enum if it's not present in the current scope. /// /// ### Example - /// ```rust + /// ```no_run /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { @@ -279,7 +279,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { @@ -305,7 +305,7 @@ declare_clippy_lint! { /// if it's not present in the current scope. /// /// ### Example - /// ```rust + /// ```no_run /// # enum Foo { A, B, C } /// # let x = Foo::B; /// match x { @@ -316,7 +316,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # enum Foo { A, B, C } /// # let x = Foo::B; /// match x { @@ -340,7 +340,7 @@ declare_clippy_lint! { /// It makes the code less readable, especially to spot wildcard pattern use in match arm. /// /// ### Example - /// ```rust + /// ```no_run /// # let s = "foo"; /// match s { /// "a" => {}, @@ -349,7 +349,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = "foo"; /// match s { /// "a" => {}, @@ -371,7 +371,7 @@ declare_clippy_lint! { /// Just readability – `let` doesn't nest, whereas a `match` does. /// /// ### Example - /// ```rust + /// ```no_run /// enum Wrapper { /// Data(i32), /// } @@ -384,7 +384,7 @@ declare_clippy_lint! { /// ``` /// /// The correct use would be: - /// ```rust + /// ```no_run /// enum Wrapper { /// Data(i32), /// } @@ -410,7 +410,7 @@ declare_clippy_lint! { /// is actually binding temporary value, bringing a 'dropped while borrowed' error. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// match (a, b) { @@ -421,7 +421,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// let (c, d) = (a, b); @@ -441,7 +441,7 @@ declare_clippy_lint! { /// matching all enum variants explicitly. /// /// ### Example - /// ```rust + /// ```no_run /// # struct A { a: i32 } /// let a = A { a: 5 }; /// @@ -452,7 +452,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct A { a: i32 } /// # let a = A { a: 5 }; /// match a { @@ -484,7 +484,7 @@ declare_clippy_lint! { /// drop order. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if let Ok(_) = Ok::(42) {} @@ -503,7 +503,7 @@ declare_clippy_lint! { /// /// The more idiomatic use would be: /// - /// ```rust + /// ```no_run /// # use std::task::Poll; /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if Ok::(42).is_ok() {} @@ -535,7 +535,7 @@ declare_clippy_lint! { /// `cfg` attributes that remove an arm evaluating to `false`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(5); /// /// let a = match x { @@ -551,7 +551,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(5); /// let a = matches!(x, Some(0)); /// ``` @@ -664,7 +664,7 @@ declare_clippy_lint! { /// It is unnecessarily verbose and complex. /// /// ### Example - /// ```rust + /// ```no_run /// fn func(opt: Option>) { /// let n = match opt { /// Some(n) => match n { @@ -676,7 +676,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn func(opt: Option>) { /// let n = match opt { /// Some(Ok(n)) => n, @@ -698,7 +698,7 @@ declare_clippy_lint! { /// Concise code helps focusing on behavior instead of boilerplate. /// /// ### Example - /// ```rust + /// ```no_run /// let foo: Option = None; /// match foo { /// Some(v) => v, @@ -707,7 +707,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo: Option = None; /// foo.unwrap_or(1); /// ``` @@ -761,7 +761,7 @@ declare_clippy_lint! { /// The arm is unreachable, which is likely a mistake /// /// ### Example - /// ```rust + /// ```no_run /// # let text = "Foo"; /// match &*text.to_ascii_lowercase() { /// "foo" => {}, @@ -770,7 +770,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let text = "Foo"; /// match &*text.to_ascii_lowercase() { /// "foo" => {}, @@ -823,7 +823,7 @@ declare_clippy_lint! { /// println!("All done!"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// # struct State {} /// # impl State { @@ -861,7 +861,7 @@ declare_clippy_lint! { /// always return), it is more clear to write `return Err(x)`. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(fail: bool) -> Result { /// if fail { /// Err("failed")?; @@ -871,7 +871,7 @@ declare_clippy_lint! { /// ``` /// Could be written: /// - /// ```rust + /// ```no_run /// fn foo(fail: bool) -> Result { /// if fail { /// return Err("failed".into()); @@ -893,14 +893,14 @@ declare_clippy_lint! { /// Using the `map` method is clearer and more concise. /// /// ### Example - /// ```rust + /// ```no_run /// match Some(0) { /// Some(x) => Some(x + 1), /// None => None, /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(0).map(|x| x + 1); /// ``` #[clippy::version = "1.52.0"] @@ -917,7 +917,7 @@ declare_clippy_lint! { /// Using the `filter` method is clearer and more concise. /// /// ### Example - /// ```rust + /// ```no_run /// match Some(0) { /// Some(x) => if x % 2 == 0 { /// Some(x) @@ -928,7 +928,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(0).filter(|&x| x % 2 == 0); /// ``` #[clippy::version = "1.66.0"] diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 8a921d4af16..645c26f39c4 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -25,14 +25,14 @@ declare_clippy_lint! { /// `None`. /// /// ### Example - /// ```rust + /// ```no_run /// use std::mem; /// /// let mut an_option = Some(0); /// let replaced = mem::replace(&mut an_option, None); /// ``` /// Is better expressed with: - /// ```rust + /// ```no_run /// let mut an_option = Some(0); /// let taken = an_option.take(); /// ``` @@ -53,7 +53,7 @@ declare_clippy_lint! { /// observed in the case of a panic. /// /// ### Example - /// ``` + /// ```no_run /// use std::mem; ///# fn may_panic(v: Vec) -> Vec { v } /// @@ -84,12 +84,12 @@ declare_clippy_lint! { /// take the current value and replace it with the default value of that type. /// /// ### Example - /// ```rust + /// ```no_run /// let mut text = String::from("foo"); /// let replaced = std::mem::replace(&mut text, String::default()); /// ``` /// Is better expressed with: - /// ```rust + /// ```no_run /// let mut text = String::from("foo"); /// let taken = std::mem::take(&mut text); /// ``` diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a935aea5075..6d937b8619d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -142,11 +142,11 @@ declare_clippy_lint! { /// implements `Copy`. /// /// ### Example - /// ```rust + /// ```no_run /// [1, 2, 3].iter().cloned(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// [1, 2, 3].iter().copied(); /// ``` #[clippy::version = "1.53.0"] @@ -165,14 +165,14 @@ declare_clippy_lint! { /// with repetitive code. /// /// ### Example - /// ```rust + /// ```no_run /// let hello = "hesuo worpd" /// .replace('s', "l") /// .replace("u", "l") /// .replace('p', "l"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l"); /// ``` #[clippy::version = "1.65.0"] @@ -194,14 +194,14 @@ declare_clippy_lint! { /// A code that relies on that side-effect could fail. /// /// ### Examples - /// ```rust + /// ```no_run /// # let vec = vec!["string".to_string()]; /// vec.iter().cloned().take(10); /// vec.iter().cloned().last(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec!["string".to_string()]; /// vec.iter().take(10).cloned(); /// vec.iter().last().cloned(); @@ -222,11 +222,11 @@ declare_clippy_lint! { /// `Option` is used to produce 0 or 1 items. /// /// ### Example - /// ```rust + /// ```no_run /// let nums: Vec = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); /// ``` #[clippy::version = "1.53.0"] @@ -254,7 +254,7 @@ declare_clippy_lint! { /// where they may get displayed. Activate this lint to do just that. /// /// ### Examples - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result = Ok(1); /// option.unwrap(); @@ -262,7 +262,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result = Ok(1); /// option.expect("more helpful message"); @@ -293,14 +293,14 @@ declare_clippy_lint! { /// It is better to write the value directly without the indirection. /// /// ### Examples - /// ```rust + /// ```no_run /// let val1 = Some(1).unwrap(); /// let val2 = Ok::<_, ()>(1).unwrap(); /// let val3 = Err::<(), _>(1).unwrap_err(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let val1 = 1; /// let val2 = 1; /// let val3 = 1; @@ -363,7 +363,7 @@ declare_clippy_lint! { /// them. /// /// ### Example - /// ```rust + /// ```no_run /// struct X; /// impl X { /// fn add(&self, other: &X) -> X { @@ -412,7 +412,7 @@ declare_clippy_lint! { /// mutable reference to a `as_..` function. /// /// ### Example - /// ```rust + /// ```no_run /// # struct X; /// impl X { /// fn as_str(self) -> &'static str { @@ -439,13 +439,13 @@ declare_clippy_lint! { /// The error type needs to implement `Debug` /// /// ### Example - /// ```rust + /// ```no_run /// # let x = Ok::<_, ()>(()); /// x.ok().expect("why did I do this again?"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = Ok::<_, ()>(()); /// x.expect("why did I do this again?"); /// ``` @@ -496,7 +496,7 @@ declare_clippy_lint! { /// heuristic to try to identify such cases. However, the heuristic can produce false negatives. /// /// ### Examples - /// ```rust + /// ```no_run /// # let x = Some(1); /// # let mut map = std::collections::HashMap::::new(); /// x.unwrap_or(Default::default()); @@ -504,7 +504,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = Some(1); /// # let mut map = std::collections::HashMap::::new(); /// x.unwrap_or_default(); @@ -529,7 +529,7 @@ declare_clippy_lint! { /// The order of the arguments is not in execution order /// /// ### Examples - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } @@ -539,7 +539,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let option = Some(1); /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } @@ -565,13 +565,13 @@ declare_clippy_lint! { /// The order of the arguments is not in execution order. /// /// ### Example - /// ```rust + /// ```no_run /// # let opt = Some(1); /// opt.map_or(None, |a| Some(a + 1)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let opt = Some(1); /// opt.and_then(|a| Some(a + 1)); /// ``` @@ -590,13 +590,13 @@ declare_clippy_lint! { /// `_.ok()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let r: Result = Ok(1); /// assert_eq!(Some(1), r.map_or(None, Some)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let r: Result = Ok(1); /// assert_eq!(Some(1), r.ok()); /// ``` @@ -616,7 +616,7 @@ declare_clippy_lint! { /// `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example - /// ```rust + /// ```no_run /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } /// let _ = opt().and_then(|s| Some(s.len())); @@ -626,7 +626,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// # fn opt() -> Option<&'static str> { Some("42") } /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } /// let _ = opt().map(|s| s.len()); @@ -648,13 +648,13 @@ declare_clippy_lint! { /// `_.find(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().filter(|x| **x == 0).next(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().find(|x| **x == 0); /// ``` @@ -673,13 +673,13 @@ declare_clippy_lint! { /// `_.find(!condition)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().skip_while(|x| **x == 0).next(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![1]; /// vec.iter().find(|x| **x != 0); /// ``` @@ -698,7 +698,7 @@ declare_clippy_lint! { /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option` /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![vec![1]]; /// let opt = Some(5); /// @@ -707,7 +707,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![vec![1]]; /// # let opt = Some(5); /// vec.iter().flat_map(|x| x.iter()); @@ -729,7 +729,7 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// (0_i32..10) /// .filter(|n| n.checked_add(1).is_some()) @@ -737,7 +737,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[allow(unused)] /// (0_i32..10).filter_map(|n| n.checked_add(1)); /// ``` @@ -757,14 +757,14 @@ declare_clippy_lint! { /// less performant. /// /// ### Example - /// ```rust + /// ```no_run /// (0_i32..10) /// .find(|n| n.checked_add(1).is_some()) /// .map(|n| n.checked_add(1).unwrap()); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// (0_i32..10).find_map(|n| n.checked_add(1)); /// ``` #[clippy::version = "1.51.0"] @@ -782,12 +782,12 @@ declare_clippy_lint! { /// `_.find_map(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next(); /// ``` /// Can be written as /// - /// ```rust + /// ```no_run /// (0..3).find_map(|x| if x == 2 { Some(x) } else { None }); /// ``` #[clippy::version = "1.36.0"] @@ -804,12 +804,12 @@ declare_clippy_lint! { /// Readability, this can be written more concisely by using `flatten`. /// /// ### Example - /// ```rust + /// ```no_run /// # let iter = vec![vec![0]].into_iter(); /// iter.flat_map(|x| x); /// ``` /// Can be written as - /// ```rust + /// ```no_run /// # let iter = vec![vec![0]].into_iter(); /// iter.flatten(); /// ``` @@ -830,7 +830,7 @@ declare_clippy_lint! { /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let vec = vec![1]; /// vec.iter().find(|x| **x == 0).is_some(); @@ -839,7 +839,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec![1]; /// vec.iter().any(|x| *x == 0); /// @@ -862,13 +862,13 @@ declare_clippy_lint! { /// `_.starts_with(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// let name = "foo"; /// if name.chars().next() == Some('_') {}; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let name = "foo"; /// if name.starts_with('_') {}; /// ``` @@ -897,13 +897,13 @@ declare_clippy_lint! { /// actually expensive to call or not. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// foo.unwrap_or(String::from("empty")); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// foo.unwrap_or_else(|| String::from("empty")); /// ``` @@ -921,7 +921,7 @@ declare_clippy_lint! { /// You should use `.unwrap_or(…)` instead for clarity. /// /// ### Example - /// ```rust + /// ```no_run /// # let fallback = "fallback"; /// // Result /// # type Error = &'static str; @@ -933,7 +933,7 @@ declare_clippy_lint! { /// let value = option.or(Some(fallback)).unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let fallback = "fallback"; /// // Result /// # let result: Result<&str, &str> = Err("error"); @@ -962,7 +962,7 @@ declare_clippy_lint! { /// change the semantics of the program, but you shouldn't rely on that anyway. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; @@ -975,7 +975,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let foo = Some(String::new()); /// # let err_code = "418"; /// # let err_msg = "I'm a teapot"; @@ -996,7 +996,7 @@ declare_clippy_lint! { /// generics, not for using the `clone` method on a concrete type. /// /// ### Example - /// ```rust + /// ```no_run /// 42u64.clone(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1017,7 +1017,7 @@ declare_clippy_lint! { /// data. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// let x = Rc::new(1); /// @@ -1025,7 +1025,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// # let x = Rc::new(1); /// Rc::clone(&x); @@ -1047,7 +1047,7 @@ declare_clippy_lint! { /// facilities. /// /// ### Example - /// ```rust + /// ```no_run /// // Generic implementation for `T: Display` is used (slow) /// ["foo", "bar"].iter().map(|s| s.to_string()); /// @@ -1070,7 +1070,7 @@ declare_clippy_lint! { /// /// ### Example /// In an impl block: - /// ```rust + /// ```no_run /// # struct Foo; /// # struct NotAFoo; /// impl Foo { @@ -1080,7 +1080,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// ```rust + /// ```no_run /// # struct Foo; /// struct Bar(Foo); /// impl Foo { @@ -1091,7 +1091,7 @@ declare_clippy_lint! { /// } /// ``` /// - /// ```rust + /// ```no_run /// # struct Foo; /// # struct FooError; /// impl Foo { @@ -1103,14 +1103,14 @@ declare_clippy_lint! { /// ``` /// /// Or in a trait definition: - /// ```rust + /// ```no_run /// pub trait Trait { /// // Bad. The type name must contain `Self` /// fn new(); /// } /// ``` /// - /// ```rust + /// ```no_run /// pub trait Trait { /// // Good. Return type contains `Self` /// fn new() -> Self; @@ -1178,11 +1178,11 @@ declare_clippy_lint! { /// automatically does this without suspicious-looking `unwrap` calls. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = std::iter::empty::>().filter(Option::is_some).map(Option::unwrap); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let _ = std::iter::empty::>().flatten(); /// ``` #[clippy::version = "1.53.0"] @@ -1201,7 +1201,7 @@ declare_clippy_lint! { /// but is more readable. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); @@ -1209,7 +1209,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// # let mut s = HashSet::new(); /// # s.insert(1); @@ -1231,13 +1231,13 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.get(3); /// let bad_slice = &some_vec[..].get(3); @@ -1256,13 +1256,13 @@ declare_clippy_lint! { /// `.nth(x)` is cleaner /// /// ### Example - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().skip(3).next(); /// let bad_slice = &some_vec[..].iter().skip(3).next(); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// let bad_vec = some_vec.iter().nth(3); /// let bad_slice = &some_vec[..].iter().nth(3); @@ -1281,13 +1281,13 @@ declare_clippy_lint! { /// `.into_iter()` is simpler with better performance. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// let mut foo = vec![0, 1, 2, 3]; /// let bar: HashSet = foo.drain(..).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// let foo = vec![0, 1, 2, 3]; /// let bar: HashSet = foo.into_iter().collect(); @@ -1315,13 +1315,13 @@ declare_clippy_lint! { /// `x.get(index).unwrap()` instead of `x[index]`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let last_element = x.get(x.len() - 1); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let last_element = x.last(); /// ``` @@ -1351,13 +1351,13 @@ declare_clippy_lint! { /// trait. /// /// ### Example - /// ```rust + /// ```no_run /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec.get(3).unwrap(); /// *some_vec.get_mut(0).unwrap() = 1; /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let mut some_vec = vec![0, 1, 2, 3]; /// let last = some_vec[3]; /// some_vec[0] = 1; @@ -1376,7 +1376,7 @@ declare_clippy_lint! { /// Using `append` instead of `extend` is more concise and faster /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// @@ -1384,7 +1384,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut a = vec![1, 2, 3]; /// let mut b = vec![4, 5, 6]; /// @@ -1405,7 +1405,7 @@ declare_clippy_lint! { /// `.push_str(s)` is clearer /// /// ### Example - /// ```rust + /// ```no_run /// let abc = "abc"; /// let def = String::from("def"); /// let mut s = String::new(); @@ -1413,7 +1413,7 @@ declare_clippy_lint! { /// s.extend(def.chars()); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let abc = "abc"; /// let def = String::from("def"); /// let mut s = String::new(); @@ -1435,12 +1435,12 @@ declare_clippy_lint! { /// `.to_vec()` is clearer /// /// ### Example - /// ```rust + /// ```no_run /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec = s[..].iter().cloned().collect(); /// ``` /// The better use would be: - /// ```rust + /// ```no_run /// let s = [1, 2, 3, 4, 5]; /// let s2: Vec = s.to_vec(); /// ``` @@ -1460,13 +1460,13 @@ declare_clippy_lint! { /// `_.ends_with(_)`. /// /// ### Example - /// ```rust + /// ```no_run /// # let name = "_"; /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let name = "_"; /// name.ends_with('_') || name.ends_with('-'); /// ``` @@ -1485,13 +1485,13 @@ declare_clippy_lint! { /// The call is unnecessary. /// /// ### Example - /// ```rust + /// ```no_run /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x.as_ref()); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// # fn do_stuff(x: &[i32]) {} /// let x: &[i32] = &[1, 2, 3, 4, 5]; /// do_stuff(x); @@ -1512,13 +1512,13 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # #[allow(unused)] /// (0..3).fold(false, |acc, x| acc || x > 2); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// (0..3).any(|x| x > 2); /// ``` #[clippy::version = "pre 1.29.0"] @@ -1538,14 +1538,14 @@ declare_clippy_lint! { /// operation is being performed. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); /// /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).filter(|&x| x > 2); /// ``` /// - /// ```rust + /// ```no_run /// let _ = (0..4).filter_map(|x| Some(x + 1)); /// /// // As there is no conditional check on the argument this could be written as: @@ -1568,14 +1568,14 @@ declare_clippy_lint! { /// operation is being performed. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None }); /// /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).find(|&x| x > 2); /// ``` /// - /// ```rust + /// ```no_run /// let _ = (0..4).find_map(|x| Some(x + 1)); /// /// // As there is no conditional check on the argument this could be written as: @@ -1598,13 +1598,13 @@ declare_clippy_lint! { /// `iter_mut` directly. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![3, 4, 5]; /// (&vec).into_iter(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let vec = vec![3, 4, 5]; /// (&vec).iter(); /// ``` @@ -1625,7 +1625,7 @@ declare_clippy_lint! { /// completion, you can just use `for_each` instead. /// /// ### Example - /// ```rust + /// ```no_run /// let _ = (0..3).map(|x| x + 2).count(); /// ``` #[clippy::version = "1.39.0"] @@ -1647,7 +1647,7 @@ declare_clippy_lint! { /// data, but those are not yet rigorously defined. /// /// ### Example - /// ```rust + /// ```no_run /// // Beware the UB /// use std::mem::MaybeUninit; /// @@ -1656,7 +1656,7 @@ declare_clippy_lint! { /// /// Note that the following is OK: /// - /// ```rust + /// ```no_run /// use std::mem::MaybeUninit; /// /// let _: [MaybeUninit; 5] = unsafe { @@ -1677,7 +1677,7 @@ declare_clippy_lint! { /// These can be written simply with `saturating_add/sub` methods. /// /// ### Example - /// ```rust + /// ```no_run /// # let y: u32 = 0; /// # let x: u32 = 100; /// let add = x.checked_add(y).unwrap_or(u32::MAX); @@ -1686,7 +1686,7 @@ declare_clippy_lint! { /// /// can be written using dedicated methods for saturating addition/subtraction as: /// - /// ```rust + /// ```no_run /// # let y: u32 = 0; /// # let x: u32 = 100; /// let add = x.saturating_add(y); @@ -1707,7 +1707,7 @@ declare_clippy_lint! { /// This is a no-op, and likely unintended /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { (&() as *const ()).offset(1) }; /// ``` #[clippy::version = "1.41.0"] @@ -1727,7 +1727,7 @@ declare_clippy_lint! { /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. /// /// ### Example - /// ```rust + /// ```no_run /// # || { /// let metadata = std::fs::metadata("foo.txt")?; /// let filetype = metadata.file_type(); @@ -1741,7 +1741,7 @@ declare_clippy_lint! { /// /// should be written as: /// - /// ```rust + /// ```no_run /// # || { /// let metadata = std::fs::metadata("foo.txt")?; /// let filetype = metadata.file_type(); @@ -1767,13 +1767,13 @@ declare_clippy_lint! { /// `_.as_deref()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let opt = Some("".to_string()); /// opt.as_ref().map(String::as_str) /// # ; /// ``` /// Can be written as - /// ```rust + /// ```no_run /// # let opt = Some("".to_string()); /// opt.as_deref() /// # ; @@ -1792,14 +1792,14 @@ declare_clippy_lint! { /// These can be shortened into `.get()` /// /// ### Example - /// ```rust + /// ```no_run /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; /// a[2..].iter().next(); /// b.iter().next(); /// ``` /// should be written as: - /// ```rust + /// ```no_run /// # let a = [1, 2, 3]; /// # let b = vec![1, 2, 3]; /// a.get(2); @@ -1820,14 +1820,14 @@ declare_clippy_lint! { /// It's less clear that we are pushing a single character. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut string = String::new(); /// string.insert_str(0, "R"); /// string.push_str("R"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut string = String::new(); /// string.insert(0, 'R'); /// string.push('R'); @@ -1860,14 +1860,14 @@ declare_clippy_lint! { /// side effects. Eagerly evaluating them can change the semantics of the program. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let opt: Option = None; /// /// opt.unwrap_or_else(|| 42); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let opt: Option = None; /// /// opt.unwrap_or(42); @@ -1886,11 +1886,11 @@ declare_clippy_lint! { /// Using `try_for_each` instead is more readable and idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// (0..3).map(|t| Err(t)).collect::>(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// (0..3).try_for_each(|t| Err(t)); /// ``` #[clippy::version = "1.49.0"] @@ -1909,7 +1909,7 @@ declare_clippy_lint! { /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) /// /// ### Example - /// ```rust + /// ```no_run /// let five_fives = std::iter::repeat(5).take(5); /// /// let v = Vec::from_iter(five_fives); @@ -1917,7 +1917,7 @@ declare_clippy_lint! { /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let five_fives = std::iter::repeat(5).take(5); /// /// let v: Vec = five_fives.collect(); @@ -1939,7 +1939,7 @@ declare_clippy_lint! { /// inside `inspect` at the beginning of the closure in `for_each`. /// /// ### Example - /// ```rust + /// ```no_run /// [1,2,3,4,5].iter() /// .inspect(|&x| println!("inspect the number: {}", x)) /// .for_each(|&x| { @@ -1947,7 +1947,7 @@ declare_clippy_lint! { /// }); /// ``` /// Can be written as - /// ```rust + /// ```no_run /// [1,2,3,4,5].iter() /// .for_each(|&x| { /// println!("inspect the number: {}", x); @@ -1968,12 +1968,12 @@ declare_clippy_lint! { /// Readability, this can be written more concisely by using `flatten`. /// /// ### Example - /// ```rust + /// ```no_run /// # let iter = vec![Some(1)].into_iter(); /// iter.filter_map(|x| x); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let iter = vec![Some(1)].into_iter(); /// iter.flatten(); /// ``` @@ -1991,12 +1991,12 @@ declare_clippy_lint! { /// It can be written more concisely without the call to `map`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = [1, 2, 3]; /// let y: Vec<_> = x.iter().map(|x| 2*x).collect(); /// ``` @@ -2015,13 +2015,13 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// # #[allow(unused)] /// "Hello".bytes().nth(3); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[allow(unused)] /// "Hello".as_bytes().get(3); /// ``` @@ -2040,13 +2040,13 @@ declare_clippy_lint! { /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. /// /// ### Example - /// ```rust + /// ```no_run /// let a = vec![1, 2, 3]; /// let b = a.to_vec(); /// let c = a.to_owned(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = vec![1, 2, 3]; /// let b = a.clone(); /// let c = a.clone(); @@ -2066,7 +2066,7 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let some_vec = vec![0, 1, 2, 3]; /// @@ -2075,7 +2075,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let some_vec = vec![0, 1, 2, 3]; /// /// some_vec.len(); @@ -2104,7 +2104,7 @@ declare_clippy_lint! { /// was the original intent, using `into_owned` instead. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2113,7 +2113,7 @@ declare_clippy_lint! { /// assert!(matches!(data, Cow::Borrowed(_))) /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2122,7 +2122,7 @@ declare_clippy_lint! { /// assert!(matches!(data, Cow::Borrowed(_))) /// ``` /// or - /// ```rust + /// ```no_run /// # use std::borrow::Cow; /// let s = "Hello world!"; /// let cow = Cow::Borrowed(s); @@ -2146,7 +2146,7 @@ declare_clippy_lint! { /// likely to be intended as a different number. /// /// ### Example - /// ```rust + /// ```no_run /// # let s = ""; /// for x in s.splitn(1, ":") { /// // .. @@ -2154,7 +2154,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let s = ""; /// for x in s.splitn(2, ":") { /// // .. @@ -2174,12 +2174,12 @@ declare_clippy_lint! { /// These are both harder to read, as well as less performant. /// /// ### Example - /// ```rust + /// ```no_run /// let x: String = std::iter::repeat('x').take(10).collect(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x: String = "x".repeat(10); /// ``` #[clippy::version = "1.54.0"] @@ -2231,13 +2231,13 @@ declare_clippy_lint! { /// The function `split` is simpler and there is no performance difference in these cases, considering /// that both functions return a lazy iterator. /// ### Example - /// ```rust + /// ```no_run /// let str = "key=value=add"; /// let _ = str.splitn(3, '=').next().unwrap(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let str = "key=value=add"; /// let _ = str.split('=').next().unwrap(); /// ``` @@ -2261,13 +2261,13 @@ declare_clippy_lint! { /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148). /// /// ### Example - /// ```rust + /// ```no_run /// let path = std::path::Path::new("x"); /// foo(&path.to_string_lossy().to_string()); /// fn foo(s: &str) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let path = std::path::Path::new("x"); /// foo(&path.to_string_lossy()); /// fn foo(s: &str) {} @@ -2286,13 +2286,13 @@ declare_clippy_lint! { /// `.collect::()` is more concise and might be more performant /// /// ### Example - /// ```rust + /// ```no_run /// let vector = vec!["hello", "world"]; /// let output = vector.iter().map(|item| item.to_uppercase()).collect::>().join(""); /// println!("{}", output); /// ``` /// The correct use would be: - /// ```rust + /// ```no_run /// let vector = vec!["hello", "world"]; /// let output = vector.iter().map(|item| item.to_uppercase()).collect::(); /// println!("{}", output); @@ -2319,13 +2319,13 @@ declare_clippy_lint! { /// Redundant code and improving readability. /// /// ### Example - /// ```rust + /// ```no_run /// let a = Some(&1); /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = Some(&1); /// let b = a; /// ``` @@ -2345,13 +2345,13 @@ declare_clippy_lint! { /// `is_digit(..)` is slower and requires specifying the radix. /// /// ### Example - /// ```rust + /// ```no_run /// let c: char = '6'; /// c.is_digit(10); /// c.is_digit(16); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let c: char = '6'; /// c.is_ascii_digit(); /// c.is_ascii_hexdigit(); @@ -2371,12 +2371,12 @@ declare_clippy_lint! { /// In this case the modification is useless as it's a temporary that cannot be read from afterwards. /// /// ### Example - /// ```rust + /// ```no_run /// let x = Some(3); /// x.as_ref().take(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = Some(3); /// x.as_ref(); /// ``` @@ -2394,7 +2394,7 @@ declare_clippy_lint! { /// It's either a mistake or confusing. /// /// ### Example - /// ```rust + /// ```no_run /// "1234".replace("12", "12"); /// "1234".replacen("12", "12", 1); /// ``` @@ -2417,12 +2417,12 @@ declare_clippy_lint! { /// to account for similar patterns. /// /// ### Example - /// ```rust + /// ```no_run /// let x = true; /// x.then_some("a").unwrap_or("b"); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = true; /// if x { "a" } else { "b" }; /// ``` @@ -2444,12 +2444,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// let a = [123].iter(); /// let b = Some(123).into_iter(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::iter; /// let a = iter::once(&123); /// let b = iter::once(123); @@ -2475,13 +2475,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// use std::{slice, option}; /// let a: slice::Iter = [].iter(); /// let f: option::IntoIter = None.into_iter(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::iter; /// let a: iter::Empty = iter::empty(); /// let b: iter::Empty = iter::empty(); @@ -2511,7 +2511,7 @@ declare_clippy_lint! { /// faster in those cases. /// /// ### Example - /// ```rust + /// ```no_run /// # let vec = vec![1_u8]; /// let count = vec.iter().filter(|x| **x == 0u8).count(); /// ``` @@ -2537,12 +2537,12 @@ declare_clippy_lint! { /// `str::len()`. /// /// ### Example - /// ```rust + /// ```no_run /// "hello".bytes().count(); /// String::from("hello").bytes().count(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// "hello".len(); /// String::from("hello").len(); /// ``` @@ -2561,13 +2561,13 @@ declare_clippy_lint! { /// `ends_with` is case-sensitive and may not detect files with a valid extension. /// /// ### Example - /// ```rust + /// ```no_run /// fn is_rust_file(filename: &str) -> bool { /// filename.ends_with(".rs") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn is_rust_file(filename: &str) -> bool { /// let filename = std::path::Path::new(filename); /// filename.extension() @@ -2590,13 +2590,13 @@ declare_clippy_lint! { /// result. /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let first_element = x.get(0); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = vec![2, 3, 5]; /// let first_element = x.first(); /// ``` @@ -2616,13 +2616,13 @@ declare_clippy_lint! { /// Concise code helps focusing on behavior instead of boilerplate. /// /// ### Examples - /// ```rust + /// ```no_run /// let foo: Option = None; /// foo.map_or(Err("error"), |v| Ok(v)); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let foo: Option = None; /// foo.ok_or("error"); /// ``` @@ -2642,7 +2642,7 @@ declare_clippy_lint! { /// Readability, this can be written more concisely /// /// ### Example - /// ```rust + /// ```no_run /// let x = vec![42, 43]; /// let y = x.iter(); /// let z = y.map(|i| *i); @@ -2650,7 +2650,7 @@ declare_clippy_lint! { /// /// The correct use would be: /// - /// ```rust + /// ```no_run /// let x = vec![42, 43]; /// let y = x.iter(); /// let z = y.cloned(); @@ -2670,7 +2670,7 @@ declare_clippy_lint! { /// /// ### Example /// Before: - /// ```rust + /// ```no_run /// use std::fmt; /// /// #[derive(Debug)] @@ -2772,7 +2772,7 @@ declare_clippy_lint! { /// guarantee. /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::{Arc, Mutex}; /// /// let mut value_rc = Arc::new(Mutex::new(42_u8)); @@ -2782,7 +2782,7 @@ declare_clippy_lint! { /// *value += 1; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::{Arc, Mutex}; /// /// let mut value_rc = Arc::new(Mutex::new(42_u8)); @@ -2807,7 +2807,7 @@ declare_clippy_lint! { /// necessary. I don't know the worst case. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fs::OpenOptions; /// /// OpenOptions::new().read(true).truncate(true); @@ -2828,7 +2828,7 @@ declare_clippy_lint! { /// previous defined path. /// /// ### Example - /// ```rust + /// ```no_run /// use std::path::PathBuf; /// /// let mut x = PathBuf::from("/foo"); @@ -2837,7 +2837,7 @@ declare_clippy_lint! { /// ``` /// Could be written: /// - /// ```rust + /// ```no_run /// use std::path::PathBuf; /// /// let mut x = PathBuf::from("/foo"); @@ -2859,13 +2859,13 @@ declare_clippy_lint! { /// The code is better expressed with `.enumerate()`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = vec![1]; /// let _ = x.iter().zip(0..x.len()); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = vec![1]; /// let _ = x.iter().enumerate(); /// ``` @@ -2890,13 +2890,13 @@ declare_clippy_lint! { /// the string is the intention behind this, `clone()` should be used. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// let x = String::from("hello world").repeat(1); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// let x = String::from("hello world").clone(); /// } @@ -2930,12 +2930,12 @@ declare_clippy_lint! { /// issue linked above. /// /// ### Example - /// ```rust + /// ```no_run /// let mut vec = vec![2, 1, 3]; /// vec.sort(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut vec = vec![2, 1, 3]; /// vec.sort_unstable(); /// ``` @@ -2963,7 +2963,7 @@ declare_clippy_lint! { /// assert_eq!(any_box.type_id(), TypeId::of::()); // ⚠️ this fails! /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::any::{Any, TypeId}; /// /// let any_box: Box = Box::new(42_i32); @@ -2984,7 +2984,7 @@ declare_clippy_lint! { /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::hash::Hash; /// # use std::collections::hash_map::DefaultHasher; /// # enum Foo { Empty, WithValue(u8) } @@ -2997,7 +2997,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::hash::Hash; /// # use std::collections::hash_map::DefaultHasher; /// # enum Foo { Empty, WithValue(u8) } @@ -3030,14 +3030,14 @@ declare_clippy_lint! { /// imported by a use statement, then it will need to be added manually. /// /// ### Example - /// ```rust + /// ```no_run /// # struct A; /// # impl A { fn foo(&self) {} } /// # let mut vec: Vec = Vec::new(); /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct A; /// # impl A { fn foo(&self) {} } /// # let mut vec: Vec = Vec::new(); @@ -3057,12 +3057,12 @@ declare_clippy_lint! { /// This is probably an argument inversion mistake. /// /// ### Example - /// ```rust + /// ```no_run /// vec![1, 2, 3, 4, 5].resize(0, 5) /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3, 4, 5].clear() /// ``` #[clippy::version = "1.46.0"] @@ -3111,14 +3111,14 @@ declare_clippy_lint! { /// /// ### Example /// - /// ``` + /// ```no_run /// # use std::collections::HashMap; /// let map: HashMap = HashMap::new(); /// let values = map.iter().map(|(_, value)| value).collect::>(); /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// # use std::collections::HashMap; /// let map: HashMap = HashMap::new(); /// let values = map.values().collect::>(); @@ -3184,14 +3184,14 @@ declare_clippy_lint! { /// this exact scenario. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::io; /// fn foo(t: &mut T) { /// t.seek(io::SeekFrom::Start(0)); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::io; /// fn foo(t: &mut T) { /// t.rewind(); @@ -3213,12 +3213,12 @@ declare_clippy_lint! { /// when this allocation may not be needed. /// /// ### Example - /// ```rust + /// ```no_run /// # let iterator = vec![1].into_iter(); /// let len = iterator.collect::>().len(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` @@ -3241,11 +3241,11 @@ declare_clippy_lint! { /// which is likely not what was intended. /// /// ### Example - /// ```rust + /// ```no_run /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); /// ``` #[clippy::version = "1.69.0"] @@ -3264,12 +3264,12 @@ declare_clippy_lint! { /// Calling `.clear()` also makes the intent clearer. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = vec![1, 2, 3]; /// v.drain(..); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut v = vec![1, 2, 3]; /// v.clear(); /// ``` @@ -3287,12 +3287,12 @@ declare_clippy_lint! { /// `.next_back()` is cleaner. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = [0; 10]; /// foo.iter().rev().next(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let foo = [0; 10]; /// foo.iter().next_back(); /// ``` @@ -3320,13 +3320,13 @@ declare_clippy_lint! { /// to keep the capacity on the original `Vec`. /// /// ### Example - /// ```rust + /// ```no_run /// fn remove_all(v: &mut Vec) -> Vec { /// v.drain(..).collect() /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::mem; /// fn remove_all(v: &mut Vec) -> Vec { /// mem::take(v) @@ -3354,11 +3354,11 @@ declare_clippy_lint! { /// desirable in those cases. /// /// ### Example - /// ```rust + /// ```no_run /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)); /// ``` #[clippy::version = "1.72.0"] @@ -3410,12 +3410,12 @@ declare_clippy_lint! { /// for situations where that additional performance is absolutely necessary. /// /// ### Example - /// ```rust + /// ```no_run /// # let c = 'c'; /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let c = 'c'; /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); /// ``` @@ -3439,13 +3439,13 @@ declare_clippy_lint! { /// so it can be safely ignored or unwrapped. /// /// ### Example - /// ```rust + /// ```no_run /// fn hex_encode(bytes: &[u8]) -> String { /// bytes.iter().map(|b| format!("{b:02X}")).collect() /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt::Write; /// fn hex_encode(bytes: &[u8]) -> String { /// bytes.iter().fold(String::new(), |mut output, b| { @@ -3469,7 +3469,7 @@ declare_clippy_lint! { /// nothing. If not, the call should be removed. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![1, 2, 3]; /// let x = v.iter().skip(0).collect::>(); /// let y = v.iter().collect::>(); @@ -3495,13 +3495,13 @@ declare_clippy_lint! { /// This can create differing behavior, so better safe than sorry. /// /// ### Example - /// ```rust + /// ```no_run /// # fn really_expensive_fn(i: i32) -> i32 { i } /// # let v = vec![]; /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i))); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn really_expensive_fn(i: i32) -> i32 { i } /// # let v = vec![]; /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); @@ -3521,7 +3521,7 @@ declare_clippy_lint! { /// can access the lock while this writer is active. /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::RwLock; /// fn assert_is_zero(lock: &RwLock) { /// let num = lock.write().unwrap(); @@ -3530,7 +3530,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::RwLock; /// fn assert_is_zero(lock: &RwLock) { /// let num = lock.read().unwrap(); @@ -3554,11 +3554,11 @@ declare_clippy_lint! { /// This is most likely not what the user intended to do. /// /// ### Example - /// ```rust + /// ```no_run /// for _ in [1, 2, 3].iter().take(4) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// for _ in [1, 2, 3].iter() {} /// ``` #[clippy::version = "1.74.0"] @@ -3587,14 +3587,14 @@ declare_clippy_lint! { /// therefore ignored. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::path::Path; /// fn is_markdown(path: &Path) -> bool { /// path.ends_with(".md") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::path::Path; /// fn is_markdown(path: &Path) -> bool { /// path.extension().is_some_and(|ext| ext == "md") @@ -3614,14 +3614,14 @@ declare_clippy_lint! { /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. /// /// ### Example - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); /// owned_string.as_str().as_bytes(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); /// owned_string.as_bytes(); diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 7016ad0a80f..5d4b0e53762 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -115,7 +115,7 @@ fn check_manual_split_once( /// checks for /// -/// ``` +/// ```no_run /// let mut iter = "a.b.c".splitn(2, '.'); /// let a = iter.next(); /// let b = iter.next(); diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 9c8b47fb303..a102b5dfde6 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -41,12 +41,12 @@ declare_clippy_lint! { /// dereferences, e.g., changing `*x` to `x` within the function. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(ref _x: u8) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(_x: &u8) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -70,7 +70,7 @@ declare_clippy_lint! { /// macro, it has been allowed in the mean time. /// /// ### Example - /// ```rust + /// ```no_run /// let _x = 0; /// let y = _x + 1; // Here we are using `_x`, even though it has a leading /// // underscore. We should rename `_x` to `x` diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index b226b878123..f758cbb47fc 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// the fields that are actually bound. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Foo { /// # a: i32, /// # b: i32, @@ -43,7 +43,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct Foo { /// # a: i32, /// # b: i32, @@ -71,12 +71,12 @@ declare_clippy_lint! { /// It affects code readability. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(a: i32, _a: i32) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn bar(a: i32, _b: i32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -94,7 +94,7 @@ declare_clippy_lint! { /// decremented. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = 3; /// --x; /// ``` @@ -113,14 +113,14 @@ declare_clippy_lint! { /// It looks confusing. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 0x1a9BAcD /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 0x1A9BACD /// # ; @@ -142,14 +142,14 @@ declare_clippy_lint! { /// Suffix style should be consistent. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 123832i32 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 123832_i32 /// # ; @@ -170,14 +170,14 @@ declare_clippy_lint! { /// Suffix style should be consistent. /// /// ### Example - /// ```rust + /// ```no_run /// # let _ = /// 123832_i32 /// # ; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let _ = /// 123832i32 /// # ; @@ -202,7 +202,7 @@ declare_clippy_lint! { /// ### Example /// /// In Rust: - /// ```rust + /// ```no_run /// fn main() { /// let a = 0123; /// println!("{}", a); @@ -258,7 +258,7 @@ declare_clippy_lint! { /// bindings. /// /// ### Example - /// ```rust + /// ```no_run /// # let v = Some("abc"); /// match v { /// Some(x) => (), @@ -267,7 +267,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let v = Some("abc"); /// match v { /// Some(x) => (), @@ -295,7 +295,7 @@ declare_clippy_lint! { /// can match that element as well. /// /// ### Example - /// ```rust + /// ```no_run /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// match t { @@ -305,7 +305,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// match t { diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 28e041dee0d..0d79ece087f 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ignored. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// x: A, /// y: B, @@ -33,7 +33,7 @@ declare_clippy_lint! { /// impl Foo {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Foo { /// x: A, /// y: B, diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 136947a2c8c..4e00215c5cb 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -27,14 +27,14 @@ declare_clippy_lint! { /// don't provide any extra information. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Service { ready: bool } /// fn call(service: Service) { /// assert!(service.ready); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct Service { ready: bool } /// fn call(service: Service) { /// assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests"); diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 08fec2b8ec8..094939f862e 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -43,14 +43,14 @@ declare_clippy_lint! { /// about the length of a slice, but this lint will not detect that. /// /// ### Example - /// ```rust + /// ```no_run /// fn sum(v: &[u8]) -> u8 { /// // 4 bounds checks /// v[0] + v[1] + v[2] + v[3] /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn sum(v: &[u8]) -> u8 { /// assert!(v.len() > 4); /// // no bounds checks diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index f598a65d2e4..b39f1de0b41 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// Also, the lint only runs one pass over the code. Consider these two non-const functions: /// - /// ```rust + /// ```no_run /// fn a() -> i32 { /// 0 /// } @@ -42,7 +42,7 @@ declare_clippy_lint! { /// /// If you are marking a public function with `const`, removing it again will break API compatibility. /// ### Example - /// ```rust + /// ```no_run /// # struct Foo { /// # random_number: usize, /// # } @@ -55,7 +55,7 @@ declare_clippy_lint! { /// /// Could be a const fn: /// - /// ```rust + /// ```no_run /// # struct Foo { /// # random_number: usize, /// # } diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index d205237a591..95f9df4e42a 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// making it much less likely to accidentally forget to update the `Debug` impl when adding a new variant. /// /// ### Example - /// ```rust + /// ```no_run /// use std::fmt; /// struct Foo { /// data: String, @@ -57,7 +57,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::fmt; /// struct Foo { /// data: String, diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 93f6025c71d..0346d80c676 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// then opt out for specific methods where this might not make sense. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn foo() {} // missing #[inline] /// fn ok() {} // ok /// #[inline] pub fn bar() {} // ok diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 1adecd2caac..ad5f45a3280 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Indicates that a method is missing. /// /// ### Example - /// ```rust + /// ```no_run /// trait Trait { /// fn required(); /// @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// trait Trait { /// fn required(); /// diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index e87aea263d4..215161b04c7 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// order, or which is correct for any evaluation order. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = 0; /// /// let a = { @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut x = 0; /// let tmp = { /// x = 1; diff --git a/clippy_lints/src/multi_assignments.rs b/clippy_lints/src/multi_assignments.rs index 81eb1a085ae..b42dce7a13a 100644 --- a/clippy_lints/src/multi_assignments.rs +++ b/clippy_lints/src/multi_assignments.rs @@ -13,12 +13,12 @@ declare_clippy_lint! { /// where such assignments return a copy of the assigned value. /// /// ### Example - /// ```rust + /// ```no_run ///# let (a, b); /// a = b = 42; /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# let (a, b); /// b = 42; /// a = b; diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 2c42a7a3676..d4f8008aece 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// elimination of unnecessary unsafe blocks through refactoring. /// /// ### Example - /// ```rust + /// ```no_run /// /// Reads a `char` from the given pointer. /// /// /// /// # Safety @@ -36,7 +36,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// /// Reads a `char` from the given pointer. /// /// /// /// # Safety diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 5878f899541..683ff859d37 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -47,7 +47,7 @@ declare_clippy_lint! { /// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745). /// /// ### Example - /// ```rust + /// ```no_run /// use std::cmp::{PartialEq, Eq}; /// use std::collections::HashSet; /// use std::hash::{Hash, Hasher}; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 64d8333a093..6989504a4a9 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// misunderstanding of references. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut y = 1; /// let x = &mut &mut y; /// ``` diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 01b850cdb11..4f8e244222d 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// the value. Also the code misleads about the intent of the call site. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut vec = Vec::new(); /// # let mut value = 5; /// vec.push(&mut value); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let mut vec = Vec::new(); /// # let value = 5; /// vec.push(&value); diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 99394b9e5fb..9d8c06cd077 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -29,14 +29,14 @@ declare_clippy_lint! { /// for waiting before a critical section. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = true; /// # use std::sync::Mutex; /// let x = Mutex::new(&y); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = true; /// # use std::sync::atomic::AtomicBool; /// let x = AtomicBool::new(y); @@ -62,13 +62,13 @@ declare_clippy_lint! { /// for waiting before a critical section. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::atomic::AtomicUsize; /// let x = AtomicUsize::new(0usize); /// ``` diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 5457eeec4ea..97e8f1c030a 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// Increases the amount and decreases the readability of code /// /// ### Example - /// ```rust + /// ```no_run /// enum ValType { /// I32, /// I64, @@ -35,7 +35,7 @@ declare_clippy_lint! { /// /// Could be rewritten as /// - /// ```rust + /// ```no_run /// enum ValType { /// I32, /// I64, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index f6b87b071b9..025eba2d166 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// shorter code. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = true; /// if x { /// false @@ -43,7 +43,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = true; /// !x /// # ; diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 11bf9e9ca17..fdb91f0dc0d 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// This pattern has no effect in almost all cases. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = Vec::::new(); /// v.iter_mut().filter(|&ref a| a.is_empty()); /// @@ -21,7 +21,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut v = Vec::::new(); /// v.iter_mut().filter(|a| a.is_empty()); /// diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index d55c77a92b1..542b81f3a12 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// in such a case can change the semantics of the code. /// /// ### Example - /// ```rust + /// ```no_run /// fn f(_: impl AsRef) {} /// /// let x = "foo"; @@ -44,7 +44,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn f(_: impl AsRef) {} /// /// let x = "foo"; diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 377cbef7b99..cb2738947d4 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -55,7 +55,7 @@ declare_clippy_lint! { /// statement within the THEN block and omitting the else block completely. /// /// ### Example - /// ```rust + /// ```no_run /// # fn condition() -> bool { false } /// # fn update_condition() {} /// # let x = false; @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// Could be rewritten as /// - /// ```rust + /// ```no_run /// # fn condition() -> bool { false } /// # fn update_condition() {} /// # let x = false; @@ -87,7 +87,7 @@ declare_clippy_lint! { /// /// As another example, the following code /// - /// ```rust + /// ```no_run /// # fn waiting() -> bool { false } /// loop { /// if waiting() { @@ -100,7 +100,7 @@ declare_clippy_lint! { /// ``` /// Could be rewritten as /// - /// ```rust + /// ```no_run /// # fn waiting() -> bool { false } /// loop { /// if waiting() { @@ -408,7 +408,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { /// till a non-whitespace character is found. e.g., the string. If no closing `}` is present, the /// string will be preserved. /// -/// ```rust +/// ```no_run /// { /// let x = 5; /// } diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 0c1fe881fc1..d881c13f84a 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// An empty else branch does nothing and can be removed. /// /// ### Example - /// ```rust + /// ```no_run ///# fn check() -> bool { true } /// if check() { /// println!("Check successful!"); @@ -21,7 +21,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# fn check() -> bool { true } /// if check() { /// println!("Check successful!"); diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 98bf122fab7..086c8e6fffe 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -25,14 +25,14 @@ declare_clippy_lint! { /// But when none of these apply, a simple `for` loop is more idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![0, 1, 2]; /// v.iter().for_each(|elem| { /// println!("{}", elem); /// }) /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let v = vec![0, 1, 2]; /// for elem in v.iter() { /// println!("{}", elem); diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 948454d13ae..c8888c744b6 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// Assigning in the `let` statement is less repetitive. /// /// ### Example - /// ```rust + /// ```no_run /// let a; /// a = 1; /// @@ -41,7 +41,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = 1; /// /// let b = match 3 { diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index d17a383e882..15589680220 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// for i in (0)..10 { /// println!("{i}"); /// } @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// for i in 0..10 { /// println!("{i}"); /// } diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 1d5874f6fea..efb218cd316 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -37,13 +37,13 @@ declare_clippy_lint! { /// opportunities for parallelization. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(y: &mut i32) -> i32 { /// 12 + *y /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(y: &i32) -> i32 { /// 12 + *y /// } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index f3c0d616473..8fa461ac12c 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -43,13 +43,13 @@ declare_clippy_lint! { /// (by using `Borrow` trait, for example), depending on how the function is used. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(v: Vec) { /// assert_eq!(v.len(), 42); /// } /// ``` /// should be - /// ```rust + /// ```no_run /// fn foo(v: &[i32]) { /// assert_eq!(v.len(), 42); /// } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index ed279a3813d..b783edd346a 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// /// ### Example - /// ```rust + /// ```no_run /// struct TO { /// magic: Option, /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct TO { /// magic: Option, /// } diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 0bd29d1776b..f8888d36878 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// somewhere), and make the code less readable. /// /// ### Example - /// ```rust + /// ```no_run /// # struct Point { /// # x: i32, /// # y: i32, diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index a022fc156fc..56c67406d6f 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// especially easy to miss if the operator based comparison result is negated. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 1.0; /// let b = f64::NAN; /// @@ -26,7 +26,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::cmp::Ordering; /// # let a = 1.0; /// # let b = f64::NAN; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index aee184252fb..60b40aecafa 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// readable. /// /// ### Example - /// ```rust + /// ```no_run /// 0; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index 8fd9ae351a0..f2a7debc930 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -18,13 +18,13 @@ declare_clippy_lint! { /// Rust ABI can break this at any point. /// /// ### Example - /// ```rust + /// ```no_run /// #[no_mangle] /// fn example(arg_one: u32, arg_two: usize) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[no_mangle] /// extern "C" fn example(arg_one: u32, arg_two: usize) {} /// ``` diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 0e4b6aa1b7d..427e636bdf8 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { /// in `Some`. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); @@ -84,7 +84,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 613afa46a91..54cec066ba1 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -58,7 +58,7 @@ declare_clippy_lint! { /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); @@ -67,7 +67,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); /// STATIC_ATOM.store(9, SeqCst); @@ -105,7 +105,7 @@ declare_clippy_lint! { /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// ### Example - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// @@ -114,7 +114,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index d562047cbf1..182d3747f78 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -63,7 +63,7 @@ declare_clippy_lint! { /// descriptive name. /// /// ### Example - /// ```rust + /// ```no_run /// let _1 = 1; /// let ___1 = 1; /// let __1___2 = 11; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index bd194b93584..35d06897eb4 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -23,11 +23,11 @@ declare_clippy_lint! { /// doesn't give you a semicolon in item position, which can be unexpected. /// /// ### Example - /// ```rust + /// ```no_run /// vec!{1, 2, 3}; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec![1, 2, 3]; /// ``` #[clippy::version = "1.55.0"] diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 6d3865080a6..0faf4ce3d3e 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -32,13 +32,13 @@ declare_clippy_lint! { /// can see it. /// /// ### Example - /// ```rust + /// ```no_run /// let one = "\033[1m Bold? \033[0m"; // \033 intended as escape /// let two = "\033\0"; // \033 intended as null-3-3 /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let one = "\x1b[1mWill this be bold?\x1b[0m"; /// let two = "\x0033\x00"; /// ``` diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index f0f8d510c7e..abc8927909b 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// /// In some cases, this would not catch all useless arguments. /// - /// ```rust + /// ```no_run /// fn foo(a: usize, b: usize) -> usize { /// let f = |x| x + 1; /// @@ -53,7 +53,7 @@ declare_clippy_lint! { /// Also, when you recurse the function name with path segments, it is not possible to detect. /// /// ### Example - /// ```rust + /// ```no_run /// fn f(a: usize, b: usize) -> usize { /// if a == 0 { /// 1 @@ -66,7 +66,7 @@ declare_clippy_lint! { /// # } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn f(a: usize) -> usize { /// if a == 0 { /// 1 diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 6b247cf5f6a..ee79ea27689 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -48,7 +48,7 @@ declare_clippy_lint! { /// like `#[cfg(target_pointer_width = "64")] ..` instead. /// /// ### Example - /// ```rust + /// ```no_run /// let vec: Vec = Vec::new(); /// if vec.len() <= 0 {} /// if 100 > i32::MAX {} @@ -76,7 +76,7 @@ declare_clippy_lint! { /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. /// /// #### Example - /// ```rust + /// ```no_run /// // `n` can be any number, including `i32::MAX`. /// fn foo(n: i32) -> i32 { /// n + 1 @@ -105,7 +105,7 @@ declare_clippy_lint! { /// can be useful to rule out floating-point numbers. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 0.0; /// a + 1.0; /// ``` @@ -128,7 +128,7 @@ declare_clippy_lint! { /// implementations that differ from the regular `Op` impl. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 0; /// // ... @@ -137,7 +137,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 0; /// // ... @@ -165,7 +165,7 @@ declare_clippy_lint! { /// written as `a = a op a op b` as it's less confusing. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 5; /// let b = 2; /// // ... @@ -205,7 +205,7 @@ declare_clippy_lint! { /// test-case for this lint. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if (x & 1 == 2) { } /// ``` @@ -238,7 +238,7 @@ declare_clippy_lint! { /// uncommon). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if (x | 1 > 3) { } /// ``` @@ -261,7 +261,7 @@ declare_clippy_lint! { /// llvm generates better code for `x & 15 == 0` on x86 /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if x & 0b1111 == 0 { } /// ``` @@ -280,7 +280,7 @@ declare_clippy_lint! { /// Readability. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 2; /// if x == y || x < y {} @@ -288,7 +288,7 @@ declare_clippy_lint! { /// /// Use instead: /// - /// ```rust + /// ```no_run /// # let x = 1; /// # let y = 2; /// if x <= y {} @@ -308,7 +308,7 @@ declare_clippy_lint! { /// which is probably not the programmer's intention /// /// ### Example - /// ```rust + /// ```no_run /// # let status_code = 200; /// if status_code <= 400 && status_code > 500 {} /// ``` @@ -328,7 +328,7 @@ declare_clippy_lint! { /// different value entirely. /// /// ### Example - /// ```rust + /// ```no_run /// # let status_code = 200; /// if status_code <= 400 && status_code < 500 {} /// ``` @@ -348,7 +348,7 @@ declare_clippy_lint! { /// `Duration::subsec_millis()` than to calculate them. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::time::Duration; /// # let duration = Duration::new(5, 0); /// let micros = duration.subsec_nanos() / 1_000; @@ -356,7 +356,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::time::Duration; /// # let duration = Duration::new(5, 0); /// let micros = duration.subsec_micros(); @@ -384,7 +384,7 @@ declare_clippy_lint! { /// calls. We may introduce a list of known pure functions in the future. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// if x + 1 == x + 1 {} /// @@ -434,7 +434,7 @@ declare_clippy_lint! { /// corrected /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1; /// 0 / x; /// 0 * x; @@ -462,13 +462,13 @@ declare_clippy_lint! { /// with an allow. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { /// (a - b) < f32::EPSILON /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { /// (a - b).abs() < f32::EPSILON /// } @@ -488,7 +488,7 @@ declare_clippy_lint! { /// meaning. So it just obscures what's going on. Delete it mercilessly. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// x / 1 + 0 * 1 - 0 | 0; /// ``` @@ -508,13 +508,13 @@ declare_clippy_lint! { /// remainder. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 3 / 2; /// println!("{}", x); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = 3f32 / 2f32; /// println!("{}", x); /// ``` @@ -535,14 +535,14 @@ declare_clippy_lint! { /// needlessly consuming code and heap space. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = "foo"; /// # let y = String::from("foo"); /// if x.to_owned() == y {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = "foo"; /// # let y = String::from("foo"); /// if x == y {} @@ -566,7 +566,7 @@ declare_clippy_lint! { /// guide](http://www.floating-point-gui.de/errors/comparison). /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1.2331f64; /// let y = 1.2332f64; /// @@ -575,7 +575,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1.2331f64; /// # let y = 1.2332f64; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison @@ -603,7 +603,7 @@ declare_clippy_lint! { /// guide](http://www.floating-point-gui.de/errors/comparison). /// /// ### Example - /// ```rust + /// ```no_run /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; /// @@ -611,7 +611,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x: f64 = 1.0; /// # const ONE: f64 = 1.00; /// let error_margin = f64::EPSILON; // Use an epsilon for comparison @@ -638,7 +638,7 @@ declare_clippy_lint! { /// contest, it's probably a bad idea. Use something more underhanded. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// let a = x % 1; /// let a = x % -1; @@ -662,7 +662,7 @@ declare_clippy_lint! { /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = -17 % 3; /// ``` #[clippy::version = "1.42.0"] @@ -685,12 +685,12 @@ declare_clippy_lint! { /// determination is quite conservative. /// /// ### Example - /// ```rust + /// ```no_run /// let (x,y) = (true, false); /// if x & !y {} // where both x and y are booleans /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let (x,y) = (true, false); /// if x && !y {} /// ``` @@ -710,14 +710,14 @@ declare_clippy_lint! { /// comparing the values they point to. /// /// ### Example - /// ```rust + /// ```no_run /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; /// /// assert!(a as *const _ as usize == b as *const _ as usize); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = &[1, 2, 3]; /// let b = &[1, 2, 3]; /// @@ -742,7 +742,7 @@ declare_clippy_lint! { /// indexing operations they are assumed not to have any side effects. /// /// ### Example - /// ```rust + /// ```no_run /// struct Event { /// x: i32, /// } @@ -753,7 +753,7 @@ declare_clippy_lint! { /// ``` /// /// Should be: - /// ```rust + /// ```no_run /// struct Event { /// x: i32, /// } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index a7a7f4fd8fa..022053f5e7d 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// this lint will not be raised. /// /// ### Example - /// ```rust + /// ```no_run /// # let optional: Option = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = if let Some(foo) = optional { @@ -54,7 +54,7 @@ declare_clippy_lint! { /// /// should be /// - /// ```rust + /// ```no_run /// # let optional: Option = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = optional.map_or(5, |foo| foo); diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 6dabbd48031..38cd5043adc 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. /// /// ### Example - /// ```rust + /// ```no_run /// # let a = 1; /// # let b = 2; /// a + b < a; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index a049427d85d..6a760f9fe64 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -22,14 +22,14 @@ declare_clippy_lint! { /// Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. /// /// ### Example - /// ```rust + /// ```no_run /// fn result_with_panic() -> Result /// { /// panic!("error"); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn result_without_panic() -> Result { /// Err(String::from("error")) /// } diff --git a/clippy_lints/src/partial_pub_fields.rs b/clippy_lints/src/partial_pub_fields.rs index f60d9d65b12..99ba55b6b31 100644 --- a/clippy_lints/src/partial_pub_fields.rs +++ b/clippy_lints/src/partial_pub_fields.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// * Data: relatively simple objects which group a bunch of related attributes together. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct Color { /// pub r: u8, /// pub g: u8, @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub struct Color { /// pub r: u8, /// pub g: u8, diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index a8c4823fe53..68d3d00ac16 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// re-implement it. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// /// impl PartialEq for Foo { diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index d9f5d1642d7..11e9a2bc394 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// way relies on `T: PartialEq` to do the comparison, which is unneeded. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(f: Option) -> &'static str { /// if f != None { "yay" } else { "nay" } /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(f: Option) -> &'static str { /// if f.is_some() { "yay" } else { "nay" } /// } diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 41513647f05..4814b3cd661 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -58,12 +58,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// fn foo(v: &u32) {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn foo(v: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] @@ -86,7 +86,7 @@ declare_clippy_lint! { /// `memcpy`, which can be expensive. /// /// ### Example - /// ```rust + /// ```no_run /// #[derive(Clone, Copy)] /// struct TooLarge([u8; 2048]); /// @@ -94,7 +94,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # #[derive(Clone, Copy)] /// # struct TooLarge([u8; 2048]); /// fn foo(v: &TooLarge) {} diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index f3089d716ff..bca8d0b6be8 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// On Unix platforms this results in the file being world writable, /// equivalent to `chmod a+w `. /// ### Example - /// ```rust + /// ```no_run /// use std::fs::File; /// let f = File::create("foo.txt").unwrap(); /// let metadata = f.metadata().unwrap(); diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 20e032d4b01..66d869bc45a 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// cast by using the `add` method instead. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); /// let offset = 1_usize; @@ -29,7 +29,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// let vec = vec![b'a', b'b', b'c']; /// let ptr = vec.as_ptr(); /// let offset = 1_usize; diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs index 9d2b0cedb60..a967b19b838 100644 --- a/clippy_lints/src/pub_use.rs +++ b/clippy_lints/src/pub_use.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// unintentional exports or to encourage placing exported items directly in public modules /// /// ### Example - /// ```rust + /// ```no_run /// pub mod outer { /// mod inner { /// pub struct Test {} @@ -25,7 +25,7 @@ declare_clippy_lint! { /// use outer::Test; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub mod outer { /// pub struct Test {} /// } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 3287675a82d..4a5c6b33298 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..(y+1) { @@ -48,7 +48,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..=y { @@ -77,7 +77,7 @@ declare_clippy_lint! { /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..=(y-1) { @@ -86,7 +86,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 0; /// # let y = 1; /// for i in x..y { @@ -118,7 +118,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// (0..=10).rev().for_each(|x| println!("{}", x)); /// @@ -142,14 +142,14 @@ declare_clippy_lint! { /// failure modes (such as fencepost errors or using `||` instead of `&&`). /// /// ### Example - /// ```rust + /// ```no_run /// // given /// let x = 6; /// /// assert!(x >= 3 && x < 8); /// ``` /// Use instead: - /// ```rust + /// ```no_run ///# let x = 6; /// assert!((3..8).contains(&x)); /// ``` diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index c951d9a4a09..391c77dbf90 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// idiomatic than a string literal, so it's opt-in. /// /// ### Example - /// ```rust + /// ```no_run /// let r = r"Hello, world!"; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let r = "Hello, world!"; /// ``` #[clippy::version = "1.72.0"] @@ -41,11 +41,11 @@ declare_clippy_lint! { /// necessary. /// /// ### Example - /// ```rust + /// ```no_run /// let r = r###"Hello, "world"!"###; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let r = r#"Hello, "world"!"#; /// ``` #[clippy::version = "1.72.0"] diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index bd0ca66b761..59ce289e7d2 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// than different instances. /// /// ### Example - /// ```rust + /// ```no_run /// let v = vec![std::sync::Arc::new("some data".to_string()); 100]; /// // or /// let v = vec![std::rc::Rc::new("some data".to_string()); 100]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // Initialize each value separately: /// let mut data = Vec::with_capacity(100); /// for _ in 0..100 { diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 2bf90815caa..71261ad275c 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// a zero-byte read would allocate a `Vec` for it. /// /// ### Example - /// ```rust + /// ```no_run /// use std::io; /// fn foo(mut f: F) { /// let mut data = Vec::with_capacity(100); @@ -32,7 +32,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::io; /// fn foo(mut f: F) { /// let mut data = Vec::with_capacity(100); diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 2e895d5f236..d97a32b749e 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// It is simpler and more efficient to use the future directly. /// /// ### Example - /// ```rust + /// ```no_run /// let f = async { /// 1 + 2 /// }; @@ -28,7 +28,7 @@ declare_clippy_lint! { /// }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let f = async { /// 1 + 2 /// }; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 2c0086b0981..ef14e68967e 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -37,7 +37,7 @@ declare_clippy_lint! { /// False-negatives: analysis performed by this lint is conservative and limited. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::path::Path; /// # #[derive(Clone)] /// # struct Foo; diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index c18237e887d..be57ed05e78 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -23,12 +23,12 @@ declare_clippy_lint! { /// complexity. /// /// ### Example - /// ```rust + /// ```no_run /// let a = (|| 42)(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let a = 42; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 73088ce1a87..221aa317e5d 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// Some may prefer to keep the `else` block for clarity. /// /// ### Example - /// ```rust + /// ```no_run /// fn my_func(count: u32) { /// if count == 0 { /// print!("Nothing to do"); @@ -27,7 +27,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn my_func(count: u32) { /// if count == 0 { /// print!("Nothing to do"); diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 61bff4a0e38..6bf512a0e2d 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// the field name is redundant. /// /// ### Example - /// ```rust + /// ```no_run /// let bar: u8 = 123; /// /// struct Foo { diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index a1a0e8f3520..6bc0d06183f 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation. /// /// ### Example - /// ```rust + /// ```no_run /// let a = 0; /// let a = a; /// @@ -29,7 +29,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let a = 0; /// // no redefinition with the same name /// diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index c2a8db7df03..03673eb27f8 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -18,14 +18,14 @@ declare_clippy_lint! { /// module's visibility. /// /// ### Example - /// ```rust + /// ```no_run /// mod internal { /// pub(crate) fn internal_fn() { } /// } /// ``` /// This function is not visible outside the module and it can be declared with `pub` or /// private visibility - /// ```rust + /// ```no_run /// mod internal { /// pub fn internal_fn() { } /// } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 4abfa0fc35c..7adbd67912c 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -51,12 +51,12 @@ declare_clippy_lint! { /// Some people may prefer to dereference rather than slice. /// /// ### Example - /// ```rust + /// ```no_run /// let vec = vec![1, 2, 3]; /// let slice = &vec[..]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let vec = vec![1, 2, 3]; /// let slice = &*vec; /// ``` diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 1d4fdb43a0b..5a3bee1caad 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -24,11 +24,11 @@ declare_clippy_lint! { /// - `Path` to anything else than a primitive type. /// /// ### Example - /// ```rust + /// ```no_run /// let foo: String = String::new(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let foo = String::new(); /// ``` #[clippy::version = "1.72.0"] diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index b1530eed1c1..ce4ca7b06e9 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -10,12 +10,12 @@ declare_clippy_lint! { /// The `ref` keyword can be confusing for people unfamiliar with it, and often /// it is more concise to use `&` instead. /// ### Example - /// ```rust + /// ```no_run /// let opt = Some(5); /// if let Some(ref foo) = opt {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let opt = Some(5); /// if let Some(foo) = &opt {} /// ``` diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index 0c8c904e374..f1ef3709514 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -18,12 +18,12 @@ declare_clippy_lint! { /// The `Vec::with_capacity` constructor is less complex. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v: Vec = vec![]; /// v.reserve(10); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let mut v: Vec = Vec::with_capacity(10); /// ``` #[clippy::version = "1.73.0"] diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index bccf421e8f3..245029a066d 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// if it was added on constructors for example. /// /// ### Example - /// ```rust + /// ```no_run /// pub struct Bar; /// impl Bar { /// // Missing attribute @@ -37,7 +37,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # { /// // It's better to have the `#[must_use]` attribute on the method like this: /// pub struct Bar; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index d6b9a49d2fe..11acc3c2d62 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -34,14 +34,14 @@ declare_clippy_lint! { /// bound without first assigning it to a let-binding. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> String { /// let x = String::new(); /// x /// } /// ``` /// instead, use - /// ``` + /// ```no_run /// fn foo() -> String { /// String::new() /// } @@ -61,13 +61,13 @@ declare_clippy_lint! { /// more rusty. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// return x; /// } /// ``` /// simplify to - /// ```rust + /// ```no_run /// fn foo(x: usize) -> usize { /// x /// } diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 45433b2adf0..d7fd3163801 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// Confusing. /// /// ### Example - /// ```rust + /// ```no_run /// trait T { /// fn foo(&self) {} /// } diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 88f295c72eb..b0601bba4af 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -19,13 +19,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } @@ -48,13 +48,13 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index c9547cd95dc..ccf8b997705 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -17,13 +17,13 @@ declare_clippy_lint! { /// code, it doesn't require a change in previous last line. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// println!("Hello world") /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// println!("Hello world"); /// } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 78418b22392..41c10b34a42 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -21,13 +21,13 @@ declare_clippy_lint! { /// lint to `Warn`. /// /// ### Example - /// ```rust + /// ```no_run /// # let x = 1; /// let x = &x; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let x = 1; /// let y = &x; // use different variable name /// ``` @@ -49,12 +49,12 @@ declare_clippy_lint! { /// the code. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 2; /// let x = x + 1; /// ``` /// use different variable name: - /// ```rust + /// ```no_run /// let x = 2; /// let y = x + 1; /// ``` @@ -77,7 +77,7 @@ declare_clippy_lint! { /// names to bindings or introducing more scopes to contain the bindings. /// /// ### Example - /// ```rust + /// ```no_run /// # let y = 1; /// # let z = 2; /// let x = y; @@ -85,7 +85,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let y = 1; /// # let z = 2; /// let x = y; diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index 7bbe98e0a7f..ae81e1198af 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// Note: If this lint is used, prepare to allow this a lot. /// /// ### Example - /// ```rust + /// ```no_run /// pub fn a(t: &T) /// where /// T: AsRef, @@ -37,7 +37,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// pub fn a(t: &T) /// where /// T: AsRef, diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 3dc995e2fa5..74ee8ce2de7 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -22,13 +22,13 @@ declare_clippy_lint! { /// be obvious or, rarely, expressible in one character. /// /// ### Example - /// ```rust + /// ```no_run /// struct DiagnosticCtx<'a> { /// source: &'a str, /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct DiagnosticCtx<'src> { /// source: &'src str, /// } diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 321c8988988..099743d229d 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -21,11 +21,11 @@ declare_clippy_lint! { /// the end of the range to be the length instead. /// /// ### Example - /// ```rust + /// ```no_run /// let x = [0..200]; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // If it was intended to include every element in the range... /// let x = (0..200).collect::>(); /// // ...Or if 200 was meant to be the len diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 89ac8cd8ca9..7de029b7b94 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// the reference. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo { /// buffer: [u8], /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct Foo { /// buffer: [u8], /// } diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 2278e41be37..2244eab96ca 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// The `resize` call first allocates memory (since `Vec::new()` did not), and only *then* zero-initializes it. /// /// ### Example - /// ```rust + /// ```no_run /// # use core::iter::repeat; /// # let len = 4; /// let mut vec1 = Vec::new(); @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # let len = 4; /// let mut vec1 = vec![0; len]; /// let mut vec2 = vec![0; len]; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index b7396535eed..a50ba0c0c7e 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -22,11 +22,11 @@ declare_clippy_lint! { /// migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// use std::hash::Hasher; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use core::hash::Hasher; /// ``` #[clippy::version = "1.64.0"] @@ -47,11 +47,11 @@ declare_clippy_lint! { /// for crates migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// use std::vec::Vec; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # extern crate alloc; /// use alloc::vec::Vec; /// ``` @@ -73,12 +73,12 @@ declare_clippy_lint! { /// is also useful for crates migrating to become `no_std` compatible. /// /// ### Example - /// ```rust + /// ```no_run /// # extern crate alloc; /// use alloc::slice::from_ref; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use core::slice::from_ref; /// ``` #[clippy::version = "1.64.0"] diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 76f463fff7d..a44adc93855 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// `.push_str(_)` method is more readable. /// /// ### Example - /// ```rust + /// ```no_run /// let mut x = "Hello".to_owned(); /// x = x + ", World"; /// @@ -58,13 +58,13 @@ declare_clippy_lint! { /// particular lint `allow` by default. /// /// ### Example - /// ```rust + /// ```no_run /// let x = "Hello".to_owned(); /// x + ", World"; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let mut x = "Hello".to_owned(); /// x.push_str(", World"); /// ``` @@ -106,12 +106,12 @@ declare_clippy_lint! { /// more readable than a function call. /// /// ### Example - /// ```rust + /// ```no_run /// let bstr = "a byte string".as_bytes(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let bstr = b"a byte string"; /// ``` #[clippy::version = "pre 1.29.0"] @@ -231,12 +231,12 @@ declare_clippy_lint! { /// It's unnecessary, the string can be used directly. /// /// ### Example - /// ```rust + /// ```no_run /// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// &"Hello World!"[6..11]; /// ``` #[clippy::version = "1.50.0"] @@ -387,12 +387,12 @@ declare_clippy_lint! { /// expressed with `.to_owned()`. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let _ = "str".to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// let _ = "str".to_owned(); /// ``` @@ -435,13 +435,13 @@ declare_clippy_lint! { /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. /// /// ### Example - /// ```rust + /// ```no_run /// // example code where clippy issues a warning /// let msg = String::from("Hello World"); /// let _ = msg.to_string(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// // example code which does not raise clippy warning /// let msg = String::from("Hello World"); /// let _ = msg.clone(); @@ -483,11 +483,11 @@ declare_clippy_lint! { /// `split_whitespace` already ignores leading and trailing whitespace. /// /// ### Example - /// ```rust + /// ```no_run /// " A B C ".trim().split_whitespace(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// " A B C ".split_whitespace(); /// ``` #[clippy::version = "1.62.0"] diff --git a/clippy_lints/src/suspicious_doc_comments.rs b/clippy_lints/src/suspicious_doc_comments.rs index 8be4ec3dc64..0abc199da16 100644 --- a/clippy_lints/src/suspicious_doc_comments.rs +++ b/clippy_lints/src/suspicious_doc_comments.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// /// ### Example /// In this example, the doc comment is attached to the *function*, rather than the *module*. - /// ```rust + /// ```no_run /// pub mod util { /// ///! This module contains utility functions. /// @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// pub mod util { /// //! This module contains utility functions. /// diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index d10f10ef87e..356156d699c 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// unusual that happens to look like a typo. /// /// ### Example - /// ```rust + /// ```no_run /// struct Vec3 { /// x: f64, /// y: f64, @@ -45,7 +45,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # struct Vec3 { /// # x: f64, /// # y: f64, diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 39cd289b67a..42cf034f22a 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -14,11 +14,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// It's most probably a typo and may lead to unexpected behaviours. /// ### Example - /// ```rust + /// ```no_run /// let x = 3_i32 ^ 4_i32; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 3_i32.pow(4); /// ``` #[clippy::version = "1.67.0"] diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 548fabb8b73..b24252a90d9 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// without deinitializing or copying either variable. /// /// ### Example - /// ```rust + /// ```no_run /// let mut a = 42; /// let mut b = 1337; /// @@ -34,7 +34,7 @@ declare_clippy_lint! { /// a = t; /// ``` /// Use std::mem::swap(): - /// ```rust + /// ```no_run /// let mut a = 1; /// let mut b = 2; /// std::mem::swap(&mut a, &mut b); @@ -53,14 +53,14 @@ declare_clippy_lint! { /// This looks like a failed attempt to swap. /// /// ### Example - /// ```rust + /// ```no_run /// # let mut a = 1; /// # let mut b = 2; /// a = b; /// b = a; /// ``` /// If swapping is intended, use `swap()` instead: - /// ```rust + /// ```no_run /// # let mut a = 1; /// # let mut b = 2; /// std::mem::swap(&mut a, &mut b); diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 4bfbe3bf37e..1667b74da7f 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// other. This would then lead to undefined behavior. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { /// for (&x, &y) in x.iter().zip(y) { /// core::mem::swap(&mut *x, &mut *y); @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { /// for (&x, &y) in x.iter().zip(y) { /// core::ptr::swap(x, y); diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index e223aea297f..71b6fef16ba 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// display settings of the author and reader differ. /// /// ### Example - /// ```rust + /// ```no_run /// /// /// /// Struct to hold two strings: /// /// - first one @@ -34,7 +34,7 @@ declare_clippy_lint! { /// ``` /// /// Will be converted to: - /// ```rust + /// ```no_run /// /// /// /// Struct to hold two strings: /// /// - first one diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index b6b653f6610..c717ccc35a6 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// updated, why not write the structure you want in the first place? /// /// ### Example - /// ```rust + /// ```no_run /// (0, 0).0 = 1 /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index b356666d852..0cfb1c1253c 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), /// having test functions outside of this module is confusing and may lead to them being "hidden". /// ### Example - /// ```rust + /// ```no_run /// #[test] /// fn my_cool_test() { /// // [...] @@ -28,7 +28,7 @@ declare_clippy_lint! { /// /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[cfg(test)] /// mod tests { /// #[test] diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index f1b703fde0e..a171d225f1e 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -17,13 +17,13 @@ declare_clippy_lint! { /// more straight forward to use the dedicated `is_digit` method. /// /// ### Example - /// ```rust + /// ```no_run /// # let c = 'c'; /// # let radix = 10; /// let is_digit = c.to_digit(radix).is_some(); /// ``` /// can be written as: - /// ``` + /// ```no_run /// # let c = 'c'; /// # let radix = 10; /// let is_digit = c.is_digit(radix); diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index bb9da3a2047..87181adc24b 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed. /// /// ### Example - /// ```rust + /// ```no_run /// struct RarelyUseful { /// some_field: u32, /// last: [u32; 0], @@ -21,7 +21,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// struct MoreOftenUseful { /// some_field: usize, diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 6db330dfa61..42b7b8645d4 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -27,12 +27,12 @@ declare_clippy_lint! { /// less readable than combining the bounds /// /// ### Example - /// ```rust + /// ```no_run /// pub fn foo(t: T) where T: Copy, T: Clone {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// pub fn foo(t: T) where T: Copy + Clone {} /// ``` #[clippy::version = "1.38.0"] @@ -51,12 +51,12 @@ declare_clippy_lint! { /// less readable than specifying them only once. /// /// ### Example - /// ```rust + /// ```no_run /// fn func(arg: T) where T: Clone + Default {} /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # mod hidden { /// fn func(arg: T) {} /// # } @@ -66,19 +66,19 @@ declare_clippy_lint! { /// fn func(arg: T) where T: Clone + Default {} /// ``` /// - /// ```rust + /// ```no_run /// fn foo(bar: T) {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(bar: T) {} /// ``` /// - /// ```rust + /// ```no_run /// fn foo(bar: T) where T: Default + Default {} /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo(bar: T) where T: Default {} /// ``` #[clippy::version = "1.47.0"] diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 0dc30f7a935..a6231ceb658 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -78,12 +78,12 @@ declare_clippy_lint! { /// /// ### Example /// - /// ```rust + /// ```no_run /// # let p: *const [i32] = &[]; /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # let p: *const [i32] = &[]; /// p as *const [u16]; /// ``` @@ -159,7 +159,7 @@ declare_clippy_lint! { /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1_u32; /// unsafe { /// let _: char = std::mem::transmute(x); // where x: u32 @@ -193,7 +193,7 @@ declare_clippy_lint! { /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html /// /// ### Example - /// ```rust + /// ```no_run /// let b: &[u8] = &[1_u8, 2_u8]; /// unsafe { /// let _: &str = std::mem::transmute(b); // where b: &[u8] @@ -216,7 +216,7 @@ declare_clippy_lint! { /// This might result in an invalid in-memory representation of a `bool`. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1_u8; /// unsafe { /// let _: bool = std::mem::transmute(x); // where x: u8 @@ -240,7 +240,7 @@ declare_clippy_lint! { /// and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let _: f32 = std::mem::transmute(1_u32); // where x: u32 /// } @@ -264,12 +264,12 @@ declare_clippy_lint! { /// elsewhere. `new_unchecked` only works for the appropriate types instead. /// /// ### Example - /// ```rust + /// ```no_run /// # use core::num::NonZeroU32; /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use core::num::NonZeroU32; /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) }; /// ``` @@ -288,7 +288,7 @@ declare_clippy_lint! { /// and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let _: u32 = std::mem::transmute(1f32); /// } @@ -311,7 +311,7 @@ declare_clippy_lint! { /// is intuitive and safe. /// /// ### Example - /// ```rust + /// ```no_run /// unsafe { /// let x: [u8; 8] = std::mem::transmute(1i64); /// } @@ -335,7 +335,7 @@ declare_clippy_lint! { /// written as casts. /// /// ### Example - /// ```rust + /// ```no_run /// let ptr = &1u32 as *const u32; /// unsafe { /// // pointer-to-pointer transmute @@ -366,7 +366,7 @@ declare_clippy_lint! { /// collection, so we just lint the ones that come with `std`. /// /// ### Example - /// ```rust + /// ```no_run /// // different size, therefore likely out-of-bounds memory access /// // You absolutely do not want this in your code! /// unsafe { @@ -376,7 +376,7 @@ declare_clippy_lint! { /// /// You must always iterate, map and collect the values: /// - /// ```rust + /// ```no_run /// vec![2_u16].into_iter().map(u32::from).collect::>(); /// ``` #[clippy::version = "1.40.0"] @@ -398,12 +398,12 @@ declare_clippy_lint! { /// [#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details. /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo(u32, T); /// let _ = unsafe { core::mem::transmute::, Foo>(Foo(0u32, 0u32)) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// #[repr(C)] /// struct Foo(u32, T); /// let _ = unsafe { core::mem::transmute::, Foo>(Foo(0u32, 0u32)) }; @@ -427,7 +427,7 @@ declare_clippy_lint! { /// call, aren't detectable yet. /// /// ### Example - /// ```rust + /// ```no_run /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; /// ``` #[clippy::version = "1.35.0"] @@ -451,11 +451,11 @@ declare_clippy_lint! { /// call, aren't detectable yet. /// /// ### Example - /// ```rust + /// ```no_run /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let null_fn: Option = None; /// ``` #[clippy::version = "1.68.0"] diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 788678a63b7..781e0aa22ed 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { /// 1st comment). /// /// ### Example - /// ```rust + /// ```no_run /// struct X { /// values: Vec>, /// } @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```no_run /// struct X { /// values: Vec, /// } @@ -97,7 +97,7 @@ declare_clippy_lint! { /// consider a custom `enum` instead, with clear names for each case. /// /// ### Example - /// ```rust + /// ```no_run /// fn get_data() -> Option> { /// None /// } @@ -105,7 +105,7 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```no_run /// pub enum Contents { /// Data(Vec), // Was Some(Some(Vec)) /// NotYetFetched, // Was Some(None) @@ -152,7 +152,7 @@ declare_clippy_lint! { /// `LinkedList` makes sense are few and far between, but they can still happen. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::LinkedList; /// let x: LinkedList = LinkedList::new(); /// ``` @@ -197,14 +197,14 @@ declare_clippy_lint! { /// `Arc>`, `Arc>`, `Box<&T>`, `Box>`, `Box>`, `Box>`, add an unnecessary level of indirection. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// fn foo(bar: Rc<&usize>) {} /// ``` /// /// Better: /// - /// ```rust + /// ```no_run /// fn foo(bar: &usize) {} /// ``` #[clippy::version = "1.44.0"] @@ -258,7 +258,7 @@ declare_clippy_lint! { /// using a `type` definition to simplify them. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::rc::Rc; /// struct Foo { /// inner: Rc>>>, diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 6193fdeb433..4d0b548d0a2 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -44,14 +44,14 @@ declare_clippy_lint! { /// and bugs. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// /// let ptr = unsafe { NonNull::new_unchecked(a) }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -72,7 +72,7 @@ declare_clippy_lint! { /// describe safety invariants. /// /// ### Example - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// @@ -80,7 +80,7 @@ declare_clippy_lint! { /// let ptr = NonNull::new(a).unwrap(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::ptr::NonNull; /// let a = &mut 42; /// diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index e275bfd37b0..37bf2a35251 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -39,12 +39,12 @@ declare_clippy_lint! { /// requirements, activating this lint could be useful. /// /// ### Example - /// ```rust + /// ```no_run /// let x = String::from("€"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let x = String::from("\u{20ac}"); /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index de4b8738e35..e76cc65fd46 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// way of specifying this without triggering needless_return lint /// /// ### Example - /// ```rust + /// ```no_run /// let mut twins = vec![(1, 1), (2, 2)]; /// twins.sort_by_key(|x| { x.1; }); /// ``` diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 546242ebd9a..884c6ca4d31 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// binding one is kind of pointless. /// /// ### Example - /// ```rust + /// ```no_run /// let x = { /// 1; /// }; @@ -38,7 +38,7 @@ declare_clippy_lint! { /// adds semicolons at the end of the operands. /// /// ### Example - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// # fn baz() {}; @@ -51,7 +51,7 @@ declare_clippy_lint! { /// } /// ``` /// is equal to - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// # fn baz() {}; @@ -63,7 +63,7 @@ declare_clippy_lint! { /// ``` /// /// For asserts: - /// ```rust + /// ```no_run /// # fn foo() {}; /// # fn bar() {}; /// assert_eq!({ foo(); }, { bar(); }); diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 996e7edf557..e7355f92304 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// the same address after being merged together. /// /// ### Example - /// ```rust + /// ```no_run /// type F = fn(); /// fn a() {} /// let f: F = a; diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index ed2ef506381..ca159eb4d5f 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -22,13 +22,13 @@ declare_clippy_lint! { /// `Box` been dropped. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo() -> Box { /// Box::new(String::from("Hello, world!")) /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn foo() -> String { /// String::from("Hello, world!") /// } diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 894de0d85c1..f9d9650db04 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -16,11 +16,11 @@ declare_clippy_lint! { /// construct the Option or Result from the output. /// /// ### Example - /// ```rust + /// ```no_run /// Some(4).map(i32::swap_bytes); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// Some(i32::swap_bytes(4)); /// ``` #[clippy::version = "1.73.0"] diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 57a4a429e12..28ea02e4d9a 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// This results in longer and less readable code /// /// ### Example - /// ```rust + /// ```no_run /// vec!["1", "2", "3"].join(&String::new()); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// vec!["1", "2", "3"].join(""); /// ``` #[clippy::version = "1.62.0"] diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 397633f533b..a1083a0a68e 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -19,11 +19,11 @@ declare_clippy_lint! { /// to detect this scenario and that is why it is a restriction lint. /// /// ### Example - /// ```rust + /// ```no_run /// use std::io::{self}; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// use std::io; /// ``` #[clippy::version = "1.53.0"] diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index f4111186c64..b75df0dec9a 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -15,14 +15,14 @@ declare_clippy_lint! { /// Readability suffers from unnecessary struct building. /// /// ### Example - /// ```rust + /// ```no_run /// struct S { s: String } /// /// let a = S { s: String::from("Hello, world!") }; /// let b = S { ..a }; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct S { s: String } /// /// let a = S { s: String::from("Hello, world!") }; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index f34f8d0e353..ab8de17b091 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// fit some external requirement. /// /// ### Example - /// ```rust + /// ```no_run /// fn get_cool_number(a: bool, b: bool) -> Option { /// if a && b { /// return Some(50); @@ -39,7 +39,7 @@ declare_clippy_lint! { /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn get_cool_number(a: bool, b: bool) -> i32 { /// if a && b { /// return 50; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 766a5481451..e8ec22831c3 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -29,13 +29,13 @@ declare_clippy_lint! { /// In the example above, `Some` is repeated, which unnecessarily complicates the pattern. /// /// ### Example - /// ```rust + /// ```no_run /// fn main() { /// if let Some(0) | Some(2) = Some(0) {} /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// fn main() { /// if let Some(0 | 2) = Some(0) {} /// } diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 3649f8792ae..aea72c798be 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -19,7 +19,7 @@ declare_clippy_lint! { /// causes runtime overhead and hassle for the caller. /// /// ### Example - /// ```rust + /// ```no_run /// async fn get_random_number() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } @@ -27,7 +27,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// fn get_random_number_improved() -> i64 { /// 4 // Chosen by fair dice roll. Guaranteed to be random. /// } diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index db91beec0ef..66b52dc94c2 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// or just a leftover after a refactor. /// /// ### Example - /// ```rust + /// ```no_run /// let collection = vec![1, 2, 3]; /// let iter = collection.iter().peekable(); /// @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let collection = vec![1, 2, 3]; /// let iter = collection.iter(); /// diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 097568cd1f7..de43c5cbae4 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -16,11 +16,11 @@ declare_clippy_lint! { /// This is unnecessary and confusing to the reader. Doing this is probably a mistake. /// /// ### Example - /// ```rust + /// ```no_run /// let x = 1f32.ceil(); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let x = 1f32; /// ``` #[clippy::version = "1.63.0"] diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 95e74718d80..ae844673b15 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -19,13 +19,13 @@ declare_clippy_lint! { /// statement look like a function call. /// /// ### Example - /// ```rust + /// ```no_run /// fn return_unit() -> () { /// () /// } /// ``` /// is equivalent to - /// ```rust + /// ```no_run /// fn return_unit() {} /// ``` #[clippy::version = "1.31.0"] diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 9a0d83d83f1..e52cfb29fe5 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// Using `if let` or `match` is more idiomatic. /// /// ### Example - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if option.is_some() { @@ -36,7 +36,7 @@ declare_clippy_lint! { /// /// Could be written: /// - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if let Some(value) = option { @@ -61,7 +61,7 @@ declare_clippy_lint! { /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized. /// /// ### Example - /// ```rust + /// ```no_run /// # let option = Some(0); /// # fn do_something_with(_x: usize) {} /// if option.is_none() { diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 3a1845425a2..21592abbf16 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// /// ### Example /// Before: - /// ```rust + /// ```no_run /// fn divisible_by_3(i_str: String) -> Result<(), String> { /// let i = i_str /// .parse::() @@ -37,7 +37,7 @@ declare_clippy_lint! { /// ``` /// /// After: - /// ```rust + /// ```no_run /// fn divisible_by_3(i_str: String) -> Result<(), String> { /// let i = i_str /// .parse::() diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 4df1e3299ed..de6a75b79fc 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -26,11 +26,11 @@ declare_clippy_lint! { /// the letters in the second acronym. /// /// ### Example - /// ```rust + /// ```no_run /// struct HTTPResponse; /// ``` /// Use instead: - /// ```rust + /// ```no_run /// struct HttpResponse; /// ``` #[clippy::version = "1.51.0"] diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f10ed4b3d41..0f57c5def21 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// - Unaddressed false negative in fn bodies of trait implementations /// /// ### Example - /// ```rust + /// ```no_run /// struct Foo; /// impl Foo { /// fn new() -> Foo { @@ -40,7 +40,7 @@ declare_clippy_lint! { /// } /// ``` /// could be - /// ```rust + /// ```no_run /// struct Foo; /// impl Foo { /// fn new() -> Self { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 3cc91838c00..edb5935f606 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -26,13 +26,13 @@ declare_clippy_lint! { /// Redundant code. /// /// ### Example - /// ```rust + /// ```no_run /// // format!() returns a `String` /// let s: String = format!("hello").into(); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let s: String = format!("hello"); /// ``` #[clippy::version = "1.45.0"] diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 8829f188fe7..e5409328b4d 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -549,7 +549,7 @@ define_Conf! { /// Whether to recommend using implicit into iter for reborrowed values. /// /// #### Example - /// ``` + /// ```no_run /// let mut vec = vec![1, 2, 3]; /// let rmvec = &mut vec; /// for _ in rmvec.iter() {} @@ -557,7 +557,7 @@ define_Conf! { /// ``` /// /// Use instead: - /// ``` + /// ```no_run /// let mut vec = vec![1, 2, 3]; /// let rmvec = &mut vec; /// for _ in &*rmvec {} diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index fc17e7c6d5a..42a69fa1133 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -33,14 +33,14 @@ declare_clippy_lint! { /// This is less efficient. /// /// ### Example - /// ```rust + /// ```no_run /// fn foo(_x: &[u8]) {} /// /// foo(&vec![1, 2]); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # fn foo(_x: &[u8]) {} /// foo(&[1, 2]); /// ``` diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 3fa51216c77..f0ae4e2a3ec 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -30,12 +30,12 @@ declare_clippy_lint! { /// multiple `push` calls. /// /// ### Example - /// ```rust + /// ```no_run /// let mut v = Vec::new(); /// v.push(0); /// ``` /// Use instead: - /// ```rust + /// ```no_run /// let v = vec![0]; /// ``` #[clippy::version = "1.51.0"] diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 70b83149ce1..d88ede76398 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// still around. /// /// ### Example - /// ```rust + /// ```no_run /// use std::cmp::Ordering::*; /// /// # fn foo(_: std::cmp::Ordering) {} @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// use std::cmp::Ordering; /// /// # fn foo(_: Ordering) {} diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 855aefa70cb..ea22be24a0d 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -22,12 +22,12 @@ declare_clippy_lint! { /// You should use `println!()`, which is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// println!(""); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// println!(); /// ``` #[clippy::version = "pre 1.29.0"] @@ -46,12 +46,12 @@ declare_clippy_lint! { /// newline. /// /// ### Example - /// ```rust + /// ```no_run /// # let name = "World"; /// print!("Hello {}!\n", name); /// ``` /// use println!() instead - /// ```rust + /// ```no_run /// # let name = "World"; /// println!("Hello {}!", name); /// ``` @@ -74,7 +74,7 @@ declare_clippy_lint! { /// Only catches `print!` and `println!` calls. /// /// ### Example - /// ```rust + /// ```no_run /// println!("Hello world!"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -96,7 +96,7 @@ declare_clippy_lint! { /// Only catches `eprint!` and `eprintln!` calls. /// /// ### Example - /// ```rust + /// ```no_run /// eprintln!("Hello world!"); /// ``` #[clippy::version = "1.50.0"] @@ -115,7 +115,7 @@ declare_clippy_lint! { /// debugging Rust code. It should not be used in user-facing output. /// /// ### Example - /// ```rust + /// ```no_run /// # let foo = "bar"; /// println!("{:?}", foo); /// ``` @@ -135,11 +135,11 @@ declare_clippy_lint! { /// (i.e., just put the literal in the format string) /// /// ### Example - /// ```rust + /// ```no_run /// println!("{}", "foo"); /// ``` /// use the literal without formatting: - /// ```rust + /// ```no_run /// println!("foo"); /// ``` #[clippy::version = "pre 1.29.0"] @@ -157,14 +157,14 @@ declare_clippy_lint! { /// You should use `writeln!(buf)`, which is simpler. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, ""); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf); @@ -186,7 +186,7 @@ declare_clippy_lint! { /// newline. /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; @@ -194,7 +194,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; @@ -216,14 +216,14 @@ declare_clippy_lint! { /// (i.e., just put the literal in the format string) /// /// ### Example - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, "{}", "foo"); /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// # use std::fmt::Write; /// # let mut buf = String::new(); /// writeln!(buf, "foo"); diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 9b3de35dbd3..f2f0699ef48 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -13,12 +13,12 @@ declare_clippy_lint! { /// It's less readable than `f32::NAN` or `f64::NAN`. /// /// ### Example - /// ```rust + /// ```no_run /// let nan = 0.0f32 / 0.0; /// ``` /// /// Use instead: - /// ```rust + /// ```no_run /// let nan = f32::NAN; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 002304f8840..fee100fe1ea 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -23,14 +23,14 @@ declare_clippy_lint! { /// * This lints the signature of public items /// /// ### Example - /// ```rust + /// ```no_run /// # use std::collections::HashMap; /// fn unique_words(text: &str) -> HashMap<&str, ()> { /// todo!(); /// } /// ``` /// Use instead: - /// ```rust + /// ```no_run /// # use std::collections::HashSet; /// fn unique_words(text: &str) -> HashSet<&str> { /// todo!(); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b4099bed5fc..9fed6130a28 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -144,7 +144,7 @@ macro_rules! extract_msrv_attr { /// instead. /// /// Examples: -/// ``` +/// ```no_run /// let abc = 1; /// // ^ output /// let def = abc; @@ -699,7 +699,7 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option { /// /// Use this if you want to find the `TraitRef` of the `Add` trait in this example: /// -/// ```rust +/// ```no_run /// struct Point(isize, isize); /// /// impl std::ops::Add for Point { @@ -895,7 +895,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: & /// /// For example, given the following function: /// -/// ``` +/// ```no_run /// fn f<'a>(iter: &mut impl Iterator) { /// for item in iter { /// let s = item.1; @@ -1609,7 +1609,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option { /// Returns the pre-expansion span if the span directly comes from an expansion /// of the macro `name`. /// The difference with [`is_expn_of`] is that in -/// ```rust +/// ```no_run /// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } } /// # macro_rules! bar { ($e:expr) => { $e } } /// foo!(bar!(42)); @@ -2204,7 +2204,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { /// Check if parent of a hir node is a trait implementation block. /// For example, `f` in -/// ```rust +/// ```no_run /// # struct S; /// # trait Trait { fn f(); } /// impl Trait for S { diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index bb9cdbbcaeb..916f7892944 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -108,7 +108,7 @@ fn first_char_in_first_line(cx: &T, span: Span) -> Option StrIndex { /// Returns index of the first camel-case component of `s`. /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_start, StrIndex}; /// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); /// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); @@ -73,7 +73,7 @@ pub fn camel_case_start(s: &str) -> StrIndex { /// Returns `StrIndex` of the last camel-case component of `s[idx..]`. /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex}; /// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0)); /// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3)); @@ -122,7 +122,7 @@ pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> StrIndex { /// Get the indexes of camel case components of a string `s` /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_indices, StrIndex}; /// assert_eq!( /// camel_case_indices("AbcDef"), @@ -149,7 +149,7 @@ pub fn camel_case_indices(s: &str) -> Vec { /// Split camel case string into a vector of its components /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{camel_case_split, StrIndex}; /// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); /// ``` @@ -181,7 +181,7 @@ impl StrCount { /// Returns the number of chars that match from the start /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{count_match_start, StrCount}; /// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6)); /// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0)); @@ -207,7 +207,7 @@ pub fn count_match_start(str1: &str, str2: &str) -> StrCount { /// Returns the number of chars and bytes that match from the end /// -/// ``` +/// ```no_run /// # use clippy_utils::str_utils::{count_match_end, StrCount}; /// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4)); /// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0)); @@ -237,7 +237,7 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount { } /// Returns a `snake_case` version of the input -/// ``` +/// ```no_run /// use clippy_utils::str_utils::to_snake_case; /// assert_eq!(to_snake_case("AbcDef"), "abc_def"); /// assert_eq!(to_snake_case("ABCD"), "a_b_c_d"); @@ -260,7 +260,7 @@ pub fn to_snake_case(name: &str) -> String { s } /// Returns a `CamelCase` version of the input -/// ``` +/// ```no_run /// use clippy_utils::str_utils::to_camel_case; /// assert_eq!(to_camel_case("abc_def"), "AbcDef"); /// assert_eq!(to_camel_case("a_b_c_d"), "ABCD"); diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index 0057256f659..ad8f77662ee 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -94,7 +94,7 @@ impl Parse for ClippyLint { /// /// # Example /// -/// ``` +/// ```ignore /// use rustc_session::declare_tool_lint; /// /// declare_clippy_lint! { -- cgit 1.4.1-3-g733a5 From 4622203c9b19e0d93bb70acca15c9895d749b8dc Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 19 Oct 2023 14:59:44 +0000 Subject: Move configuration to new `clippy_config` crate --- Cargo.toml | 5 +- book/src/lint_configuration.md | 26 +- clippy_config/Cargo.toml | 19 + clippy_config/src/conf.rs | 775 ++++++++++++++++++++ clippy_config/src/lib.rs | 16 + clippy_config/src/metadata.rs | 112 +++ clippy_config/src/msrvs.rs | 138 ++++ clippy_config/src/types.rs | 119 +++ clippy_lints/Cargo.toml | 3 +- clippy_lints/src/almost_complete_range.rs | 2 +- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 3 +- clippy_lints/src/casts/cast_abs_to_unsigned.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- .../src/casts/cast_slice_different_sizes.rs | 2 +- .../src/casts/cast_slice_from_raw_parts.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/casts/ptr_cast_constness.rs | 4 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/disallowed_macros.rs | 7 +- clippy_lints/src/disallowed_methods.rs | 8 +- clippy_lints/src/disallowed_types.rs | 11 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/manual_let_else.rs | 12 +- clippy_lints/src/manual_main_separator_str.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/mem_replace.rs | 2 +- .../src/methods/cloned_instead_of_copied.rs | 2 +- clippy_lints/src/methods/err_expect.rs | 2 +- clippy_lints/src/methods/filter_map_next.rs | 2 +- clippy_lints/src/methods/is_digit_ascii_radix.rs | 2 +- clippy_lints/src/methods/manual_try_fold.rs | 4 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/option_as_ref_deref.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/path_ends_with_ext.rs | 3 +- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/methods/string_lit_chars_any.rs | 4 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_enforced_import_rename.rs | 4 +- .../src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 85 +-- clippy_lints/src/question_mark.rs | 5 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/conf.rs | 812 --------------------- clippy_lints/src/utils/format_args_collector.rs | 15 +- .../src/utils/internal_lints/metadata_collector.rs | 14 +- clippy_lints/src/utils/mod.rs | 110 --- clippy_lints/src/vec.rs | 2 +- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/lib.rs | 1 - clippy_utils/src/msrvs.rs | 130 ---- clippy_utils/src/paths.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- src/driver.rs | 4 +- tests/compile-test.rs | 1 + tests/dogfood.rs | 11 +- tests/ui-internal/invalid_msrv_attr_impl.fixed | 2 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 2 +- tests/ui/min_rust_version_invalid_attr.rs | 5 +- tests/ui/min_rust_version_invalid_attr.stderr | 24 +- tests/versioncheck.rs | 1 + 91 files changed, 1309 insertions(+), 1300 deletions(-) create mode 100644 clippy_config/Cargo.toml create mode 100644 clippy_config/src/conf.rs create mode 100644 clippy_config/src/lib.rs create mode 100644 clippy_config/src/metadata.rs create mode 100644 clippy_config/src/msrvs.rs create mode 100644 clippy_config/src/types.rs delete mode 100644 clippy_lints/src/utils/conf.rs delete mode 100644 clippy_utils/src/msrvs.rs (limited to 'clippy_lints/src/methods') diff --git a/Cargo.toml b/Cargo.toml index 2c50addfd7d..28f006957cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,11 +21,12 @@ name = "clippy-driver" path = "src/driver.rs" [dependencies] +clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" -color-print = "0.3.4" # Sync version with Cargo +color-print = "0.3.4" anstream = "0.5.0" [dev-dependencies] @@ -54,7 +55,7 @@ rustc_tools_util = "0.3.0" [features] deny-warnings = ["clippy_lints/deny-warnings"] integration = ["tempfile"] -internal = ["clippy_lints/internal", "tempfile"] +internal = ["clippy_config/internal", "clippy_lints/internal", "tempfile"] [package.metadata.rust-analyzer] # This package uses #[feature(rustc_private)] diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index cbdf8a3001d..6b1a7ba54c6 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -26,7 +26,7 @@ arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) +**Default Value:** `{}` (`FxHashSet`) --- **Affected lints:** @@ -65,7 +65,7 @@ Suppress checking of the passed type names in unary operations like "negation" ( arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] ``` -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) +**Default Value:** `{}` (`FxHashSet`) --- **Affected lints:** @@ -100,7 +100,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat ## `msrv` The minimum rust version that the project supports -**Default Value:** `Msrv { stack: [] }` (`crate::Msrv`) +**Default Value:** `Msrv { stack: [] }` (`Msrv`) --- **Affected lints:** @@ -417,7 +417,7 @@ Whether to allow certain wildcard imports (prelude, super in tests). ## `disallowed-macros` The list of disallowed macros, written as fully qualified paths. -**Default Value:** `[]` (`Vec`) +**Default Value:** `[]` (`Vec`) --- **Affected lints:** @@ -427,7 +427,7 @@ The list of disallowed macros, written as fully qualified paths. ## `disallowed-methods` The list of disallowed methods, written as fully qualified paths. -**Default Value:** `[]` (`Vec`) +**Default Value:** `[]` (`Vec`) --- **Affected lints:** @@ -437,7 +437,7 @@ The list of disallowed methods, written as fully qualified paths. ## `disallowed-types` The list of disallowed types, written as fully qualified paths. -**Default Value:** `[]` (`Vec`) +**Default Value:** `[]` (`Vec`) --- **Affected lints:** @@ -468,7 +468,7 @@ Enables verbose mode. Triggers if there is more than one uppercase char next to Whether the matches should be considered by the lint, and whether there should be filtering for common types. -**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`) +**Default Value:** `WellKnownTypes` (`MatchLintBehaviour`) --- **Affected lints:** @@ -492,7 +492,7 @@ A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If could be used with a full path two `MacroMatcher`s have to be added one with the full path `crate_name::macro_name` and one with just the macro name. -**Default Value:** `[]` (`Vec`) +**Default Value:** `[]` (`Vec`) --- **Affected lints:** @@ -502,7 +502,7 @@ could be used with a full path two `MacroMatcher`s have to be added one with the ## `enforced-import-renames` The list of imports to always rename, a fully qualified path followed by the rename. -**Default Value:** `[]` (`Vec`) +**Default Value:** `[]` (`Vec`) --- **Affected lints:** @@ -544,7 +544,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. ## `await-holding-invalid-types` -**Default Value:** `[]` (`Vec`) +**Default Value:** `[]` (`Vec`) --- **Affected lints:** @@ -694,7 +694,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used the list to indicate, that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `{"j", "z", "i", "y", "n", "x", "w"}` (`rustc_data_structures::fx::FxHashSet`) +**Default Value:** `{"j", "z", "i", "y", "n", "x", "w"}` (`FxHashSet`) --- **Affected lints:** @@ -755,7 +755,7 @@ be linted. ## `absolute-paths-allowed-crates` Which crates to allow absolute paths from -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) +**Default Value:** `{}` (`FxHashSet`) --- **Affected lints:** @@ -765,7 +765,7 @@ Which crates to allow absolute paths from ## `allowed-dotfiles` Additional dotfiles (files or directories starting with a dot) to allow -**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) +**Default Value:** `{}` (`FxHashSet`) --- **Affected lints:** diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml new file mode 100644 index 00000000000..55f67b585e2 --- /dev/null +++ b/clippy_config/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "clippy_config" +version = "0.1.75" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustc-semver = "1.1" +serde = { version = "1.0", features = ["derive"] } +toml = "0.7.3" + +[features] +deny-warnings = [] +internal = [] + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)] +rustc_private = true diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs new file mode 100644 index 00000000000..d010dd5f42a --- /dev/null +++ b/clippy_config/src/conf.rs @@ -0,0 +1,775 @@ +use crate::msrvs::Msrv; +use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename}; +use crate::ClippyConfiguration; +use rustc_data_structures::fx::FxHashSet; +use rustc_session::Session; +use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; +use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor}; +use serde::Deserialize; +use std::fmt::{Debug, Display, Formatter}; +use std::ops::Range; +use std::path::PathBuf; +use std::str::FromStr; +use std::sync::OnceLock; +use std::{cmp, env, fmt, fs, io}; + +#[rustfmt::skip] +const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ + "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "DirectX", + "ECMAScript", + "GPLv2", "GPLv3", + "GitHub", "GitLab", + "IPv4", "IPv6", + "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", + "WebAssembly", + "NaN", "NaNs", + "OAuth", "GraphQL", + "OCaml", + "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", + "WebGL", + "TensorFlow", + "TrueType", + "iOS", "macOS", "FreeBSD", + "TeX", "LaTeX", "BibTeX", "BibLaTeX", + "MinGW", + "CamelCase", +]; +const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; +const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; + +/// Conf with parse errors +#[derive(Default)] +pub struct TryConf { + pub conf: Conf, + pub errors: Vec, + pub warnings: Vec, +} + +impl TryConf { + fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self { + Self { + conf: Conf::default(), + errors: vec![ConfError::from_toml(file, error)], + warnings: vec![], + } + } +} + +#[derive(Debug)] +pub struct ConfError { + pub message: String, + pub span: Span, +} + +impl ConfError { + fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self { + let span = error.span().unwrap_or(0..file.source_len.0 as usize); + Self::spanned(file, error.message(), span) + } + + fn spanned(file: &SourceFile, message: impl Into, span: Range) -> Self { + Self { + message: message.into(), + span: Span::new( + file.start_pos + BytePos::from_usize(span.start), + file.start_pos + BytePos::from_usize(span.end), + SyntaxContext::root(), + None, + ), + } + } +} + +macro_rules! define_Conf { + ($( + $(#[doc = $doc:literal])+ + $(#[conf_deprecated($dep:literal, $new_conf:ident)])? + ($name:ident: $ty:ty = $default:expr), + )*) => { + /// Clippy lint configuration + pub struct Conf { + $($(#[doc = $doc])+ pub $name: $ty,)* + } + + mod defaults { + use super::*; + $(pub fn $name() -> $ty { $default })* + } + + impl Default for Conf { + fn default() -> Self { + Self { $($name: defaults::$name(),)* } + } + } + + #[derive(Deserialize)] + #[serde(field_identifier, rename_all = "kebab-case")] + #[allow(non_camel_case_types)] + enum Field { $($name,)* third_party, } + + struct ConfVisitor<'a>(&'a SourceFile); + + impl<'de> Visitor<'de> for ConfVisitor<'_> { + type Value = TryConf; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("Conf") + } + + fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de> { + let mut errors = Vec::new(); + let mut warnings = Vec::new(); + $(let mut $name = None;)* + // could get `Field` here directly, but get `String` first for diagnostics + while let Some(name) = map.next_key::>()? { + match Field::deserialize(name.get_ref().as_str().into_deserializer()) { + Err(e) => { + let e: FieldError = e; + errors.push(ConfError::spanned(self.0, e.0, name.span())); + } + $(Ok(Field::$name) => { + $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), name.span()));)? + let raw_value = map.next_value::>()?; + let value_span = raw_value.span(); + match <$ty>::deserialize(raw_value.into_inner()) { + Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), value_span)), + Ok(value) => match $name { + Some(_) => errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), name.span())), + None => { + $name = Some(value); + // $new_conf is the same as one of the defined `$name`s, so + // this variable is defined in line 2 of this function. + $(match $new_conf { + Some(_) => errors.push(ConfError::spanned(self.0, concat!( + "duplicate field `", stringify!($new_conf), + "` (provided as `", stringify!($name), "`)" + ), name.span())), + None => $new_conf = $name.clone(), + })? + }, + } + } + })* + // ignore contents of the third_party key + Ok(Field::third_party) => drop(map.next_value::()) + } + } + let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; + Ok(TryConf { conf, errors, warnings }) + } + } + + macro_rules! wrap_option { + () => (None); + ($x:literal) => (Some($x)); + } + + pub fn get_configuration_metadata() -> Vec { + vec![ + $( + { + let deprecation_reason = wrap_option!($($dep)?); + + ClippyConfiguration::new( + stringify!($name), + stringify!($ty), + format!("{:?}", defaults::$name()), + concat!($($doc, '\n',)*), + deprecation_reason, + ) + }, + )+ + ] + } + }; +} + +define_Conf! { + /// Lint: ARITHMETIC_SIDE_EFFECTS. + /// + /// Suppress checking of the passed type names in all types of operations. + /// + /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. + /// + /// #### Example + /// + /// ```toml + /// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] + /// ``` + /// + /// #### Noteworthy + /// + /// A type, say `SomeType`, listed in this configuration has the same behavior of + /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. + (arithmetic_side_effects_allowed: FxHashSet = <_>::default()), + /// Lint: ARITHMETIC_SIDE_EFFECTS. + /// + /// Suppress checking of the passed type pair names in binary operations like addition or + /// multiplication. + /// + /// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless + /// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`. + /// + /// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as + /// `["AnotherType", "SomeType"]`. + /// + /// #### Example + /// + /// ```toml + /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] + /// ``` + (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()), + /// Lint: ARITHMETIC_SIDE_EFFECTS. + /// + /// Suppress checking of the passed type names in unary operations like "negation" (`-`). + /// + /// #### Example + /// + /// ```toml + /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] + /// ``` + (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. + /// + /// Suppress lints whenever the suggested change would cause breakage for other crates. + (avoid_breaking_exported_api: bool = true), + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. + /// + /// The minimum rust version that the project supports + (msrv: Msrv = Msrv::empty()), + /// DEPRECATED LINT: BLACKLISTED_NAME. + /// + /// Use the Disallowed Names lint instead + #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] + (blacklisted_names: Vec = Vec::new()), + /// Lint: COGNITIVE_COMPLEXITY. + /// + /// The maximum cognitive complexity a function can have + (cognitive_complexity_threshold: u64 = 25), + /// Lint: EXCESSIVE_NESTING. + /// + /// The maximum amount of nesting a block can reside in + (excessive_nesting_threshold: u64 = 0), + /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. + /// + /// Use the Cognitive Complexity lint instead. + #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] + (cyclomatic_complexity_threshold: u64 = 25), + /// Lint: DISALLOWED_NAMES. + /// + /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value + /// `".."` can be used as part of the list to indicate that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value. + (disallowed_names: Vec = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), + /// Lint: SEMICOLON_INSIDE_BLOCK. + /// + /// Whether to lint only if it's multiline. + (semicolon_inside_block_ignore_singleline: bool = false), + /// Lint: SEMICOLON_OUTSIDE_BLOCK. + /// + /// Whether to lint only if it's singleline. + (semicolon_outside_block_ignore_multiline: bool = false), + /// Lint: DOC_MARKDOWN. + /// + /// The list of words this lint should not consider as identifiers needing ticks. The value + /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value. For example: + /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. + /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. + /// + /// Default list: + (doc_valid_idents: Vec = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + /// Lint: TOO_MANY_ARGUMENTS. + /// + /// The maximum number of argument a function or method can have + (too_many_arguments_threshold: u64 = 7), + /// Lint: TYPE_COMPLEXITY. + /// + /// The maximum complexity a type can have + (type_complexity_threshold: u64 = 250), + /// Lint: MANY_SINGLE_CHAR_NAMES. + /// + /// The maximum number of single char bindings a scope may have + (single_char_binding_names_threshold: u64 = 4), + /// Lint: BOXED_LOCAL, USELESS_VEC. + /// + /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap + (too_large_for_stack: u64 = 200), + /// Lint: ENUM_VARIANT_NAMES. + /// + /// The minimum number of enum variants for the lints about variant names to trigger + (enum_variant_name_threshold: u64 = 3), + /// Lint: STRUCT_VARIANT_NAMES. + /// + /// The minimum number of struct fields for the lints about field names to trigger + (struct_field_name_threshold: u64 = 3), + /// Lint: LARGE_ENUM_VARIANT. + /// + /// The maximum size of an enum's variant to avoid box suggestion + (enum_variant_size_threshold: u64 = 200), + /// Lint: VERBOSE_BIT_MASK. + /// + /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' + (verbose_bit_mask_threshold: u64 = 1), + /// Lint: DECIMAL_LITERAL_REPRESENTATION. + /// + /// The lower bound for linting decimal literals + (literal_representation_threshold: u64 = 16384), + /// Lint: TRIVIALLY_COPY_PASS_BY_REF. + /// + /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. + (trivial_copy_size_limit: Option = None), + /// Lint: LARGE_TYPES_PASSED_BY_VALUE. + /// + /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. + (pass_by_value_size_limit: u64 = 256), + /// Lint: TOO_MANY_LINES. + /// + /// The maximum number of lines a function or method can have + (too_many_lines_threshold: u64 = 100), + /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. + /// + /// The maximum allowed size for arrays on the stack + (array_size_threshold: u64 = 512_000), + /// Lint: LARGE_STACK_FRAMES. + /// + /// The maximum allowed stack size for functions in bytes + (stack_size_threshold: u64 = 512_000), + /// Lint: VEC_BOX. + /// + /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed + (vec_box_size_threshold: u64 = 4096), + /// Lint: TYPE_REPETITION_IN_BOUNDS. + /// + /// The maximum number of bounds a trait can have to be linted + (max_trait_bounds: u64 = 3), + /// Lint: STRUCT_EXCESSIVE_BOOLS. + /// + /// The maximum number of bool fields a struct can have + (max_struct_bools: u64 = 3), + /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. + /// + /// The maximum number of bool parameters a function can have + (max_fn_params_bools: u64 = 3), + /// Lint: WILDCARD_IMPORTS. + /// + /// Whether to allow certain wildcard imports (prelude, super in tests). + (warn_on_all_wildcard_imports: bool = false), + /// Lint: DISALLOWED_MACROS. + /// + /// The list of disallowed macros, written as fully qualified paths. + (disallowed_macros: Vec = Vec::new()), + /// Lint: DISALLOWED_METHODS. + /// + /// The list of disallowed methods, written as fully qualified paths. + (disallowed_methods: Vec = Vec::new()), + /// Lint: DISALLOWED_TYPES. + /// + /// The list of disallowed types, written as fully qualified paths. + (disallowed_types: Vec = Vec::new()), + /// Lint: UNREADABLE_LITERAL. + /// + /// Should the fraction of a decimal be linted to include separators. + (unreadable_literal_lint_fractions: bool = true), + /// Lint: UPPER_CASE_ACRONYMS. + /// + /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other + (upper_case_acronyms_aggressive: bool = false), + /// Lint: MANUAL_LET_ELSE. + /// + /// Whether the matches should be considered by the lint, and whether there should + /// be filtering for common types. + (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes), + /// Lint: _CARGO_COMMON_METADATA. + /// + /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. + (cargo_ignore_publish: bool = false), + /// Lint: NONSTANDARD_MACRO_BRACES. + /// + /// Enforce the named macros always use the braces specified. + /// + /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro + /// could be used with a full path two `MacroMatcher`s have to be added one with the full path + /// `crate_name::macro_name` and one with just the macro name. + (standard_macro_braces: Vec = Vec::new()), + /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. + /// + /// The list of imports to always rename, a fully qualified path followed by the rename. + (enforced_import_renames: Vec = Vec::new()), + /// Lint: DISALLOWED_SCRIPT_IDENTS. + /// + /// The list of unicode scripts allowed to be used in the scope. + (allowed_scripts: Vec = vec!["Latin".to_string()]), + /// Lint: NON_SEND_FIELDS_IN_SEND_TY. + /// + /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. + (enable_raw_pointer_heuristic_for_send: bool = true), + /// Lint: INDEX_REFUTABLE_SLICE. + /// + /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in + /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. + /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. + (max_suggested_slice_pattern_length: u64 = 3), + /// Lint: AWAIT_HOLDING_INVALID_TYPE. + (await_holding_invalid_types: Vec = Vec::new()), + /// Lint: LARGE_INCLUDE_FILE. + /// + /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes + (max_include_file_size: u64 = 1_000_000), + /// Lint: EXPECT_USED. + /// + /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` + (allow_expect_in_tests: bool = false), + /// Lint: UNWRAP_USED. + /// + /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` + (allow_unwrap_in_tests: bool = false), + /// Lint: DBG_MACRO. + /// + /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` + (allow_dbg_in_tests: bool = false), + /// Lint: PRINT_STDOUT, PRINT_STDERR. + /// + /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` + (allow_print_in_tests: bool = false), + /// Lint: RESULT_LARGE_ERR. + /// + /// The maximum size of the `Err`-variant in a `Result` returned from a function + (large_error_threshold: u64 = 128), + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. + /// + /// A list of paths to types that should be treated like `Arc`, i.e. ignored but + /// for the generic parameters for determining interior mutability + (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), + /// Lint: UNINLINED_FORMAT_ARGS. + /// + /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` + (allow_mixed_uninlined_format_args: bool = true), + /// Lint: INDEXING_SLICING. + /// + /// Whether to suppress a restriction lint in constant code. In same + /// cases the restructured operation might not be unavoidable, as the + /// suggested counterparts are unavailable in constant code. This + /// configuration will cause restriction lints to trigger even + /// if no suggestion can be made. + (suppress_restriction_lint_in_const: bool = false), + /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. + /// + /// Whether to **only** check for missing documentation in items visible within the current + /// crate. For example, `pub(crate)` items. + (missing_docs_in_crate_items: bool = false), + /// Lint: LARGE_FUTURES. + /// + /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + (future_size_threshold: u64 = 16 * 1024), + /// Lint: UNNECESSARY_BOX_RETURNS. + /// + /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint + (unnecessary_box_size: u64 = 128), + /// Lint: MODULE_INCEPTION. + /// + /// Whether to allow module inception if it's not public. + (allow_private_module_inception: bool = false), + /// Lint: MIN_IDENT_CHARS. + /// + /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of + /// the list to indicate, that the configured values should be appended to the default + /// configuration of Clippy. By default, any configuration will replace the default value. + (allowed_idents_below_min_chars: FxHashSet = + DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), + /// Lint: MIN_IDENT_CHARS. + /// + /// Minimum chars an ident can have, anything below or equal to this will be linted. + (min_ident_chars_threshold: u64 = 1), + /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. + /// + /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block + (accept_comment_above_statement: bool = true), + /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. + /// + /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block + (accept_comment_above_attributes: bool = true), + /// Lint: UNNECESSARY_RAW_STRING_HASHES. + /// + /// Whether to allow `r#""#` when `r""` can be used + (allow_one_hash_in_raw_strings: bool = false), + /// Lint: ABSOLUTE_PATHS. + /// + /// The maximum number of segments a path can have before being linted, anything above this will + /// be linted. + (absolute_paths_max_segments: u64 = 2), + /// Lint: ABSOLUTE_PATHS. + /// + /// Which crates to allow absolute paths from + (absolute_paths_allowed_crates: FxHashSet = FxHashSet::default()), + /// Lint: PATH_ENDS_WITH_EXT. + /// + /// Additional dotfiles (files or directories starting with a dot) to allow + (allowed_dotfiles: FxHashSet = FxHashSet::default()), + /// Lint: EXPLICIT_ITER_LOOP + /// + /// Whether to recommend using implicit into iter for reborrowed values. + /// + /// #### Example + /// ```no_run + /// let mut vec = vec![1, 2, 3]; + /// let rmvec = &mut vec; + /// for _ in rmvec.iter() {} + /// for _ in rmvec.iter_mut() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// let mut vec = vec![1, 2, 3]; + /// let rmvec = &mut vec; + /// for _ in &*rmvec {} + /// for _ in &mut *rmvec {} + /// ``` + (enforce_iter_loop_reborrow: bool = false), +} + +/// Search for the configuration file. +/// +/// # Errors +/// +/// Returns any unexpected filesystem error encountered when searching for the config file +pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { + /// Possible filename to search for. + const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"]; + + // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR. + // If neither of those exist, use ".". (Update documentation if this priority changes) + let mut current = env::var_os("CLIPPY_CONF_DIR") + .or_else(|| env::var_os("CARGO_MANIFEST_DIR")) + .map_or_else(|| PathBuf::from("."), PathBuf::from) + .canonicalize()?; + + let mut found_config: Option = None; + let mut warnings = vec![]; + + loop { + for config_file_name in &CONFIG_FILE_NAMES { + if let Ok(config_file) = current.join(config_file_name).canonicalize() { + match fs::metadata(&config_file) { + Err(e) if e.kind() == io::ErrorKind::NotFound => {}, + Err(e) => return Err(e), + Ok(md) if md.is_dir() => {}, + Ok(_) => { + // warn if we happen to find two config files #8323 + if let Some(ref found_config) = found_config { + warnings.push(format!( + "using config file `{}`, `{}` will be ignored", + found_config.display(), + config_file.display() + )); + } else { + found_config = Some(config_file); + } + }, + } + } + } + + if found_config.is_some() { + return Ok((found_config, warnings)); + } + + // If the current directory has no parent, we're done searching. + if !current.pop() { + return Ok((None, warnings)); + } + } +} + +fn deserialize(file: &SourceFile) -> TryConf { + match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { + Ok(mut conf) => { + extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); + extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); + // TODO: THIS SHOULD BE TESTED, this comment will be gone soon + if conf.conf.allowed_idents_below_min_chars.contains(&"..".to_owned()) { + conf.conf + .allowed_idents_below_min_chars + .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); + } + + conf + }, + Err(e) => TryConf::from_toml_error(file, &e), + } +} + +fn extend_vec_if_indicator_present(vec: &mut Vec, default: &[&str]) { + if vec.contains(&"..".to_string()) { + vec.extend(default.iter().map(ToString::to_string)); + } +} + +impl Conf { + pub fn read(sess: &Session, path: &io::Result<(Option, Vec)>) -> &'static Conf { + static CONF: OnceLock = OnceLock::new(); + CONF.get_or_init(|| Conf::read_inner(sess, path)) + } + + fn read_inner(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { + match path { + Ok((_, warnings)) => { + for warning in warnings { + sess.warn(warning.clone()); + } + }, + Err(error) => { + sess.err(format!("error finding Clippy's configuration file: {error}")); + }, + } + + let TryConf { + mut conf, + errors, + warnings, + } = match path { + Ok((Some(path), _)) => match sess.source_map().load_file(path) { + Ok(file) => deserialize(&file), + Err(error) => { + sess.err(format!("failed to read `{}`: {error}", path.display())); + TryConf::default() + }, + }, + _ => TryConf::default(), + }; + + conf.msrv.read_cargo(sess); + + // all conf errors are non-fatal, we just use the default conf in case of error + for error in errors { + sess.span_err( + error.span, + format!("error reading Clippy's configuration file: {}", error.message), + ); + } + + for warning in warnings { + sess.span_warn( + warning.span, + format!("error reading Clippy's configuration file: {}", warning.message), + ); + } + + conf + } +} + +const SEPARATOR_WIDTH: usize = 4; + +#[derive(Debug)] +struct FieldError(String); + +impl std::error::Error for FieldError {} + +impl Display for FieldError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.pad(&self.0) + } +} + +impl serde::de::Error for FieldError { + fn custom(msg: T) -> Self { + Self(msg.to_string()) + } + + fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { + // List the available fields sorted and at least one per line, more if `CLIPPY_TERMINAL_WIDTH` is + // set and allows it. + use fmt::Write; + + let mut expected = expected.to_vec(); + expected.sort_unstable(); + + let (rows, column_widths) = calculate_dimensions(&expected); + + let mut msg = format!("unknown field `{field}`, expected one of"); + for row in 0..rows { + writeln!(msg).unwrap(); + for (column, column_width) in column_widths.iter().copied().enumerate() { + let index = column * rows + row; + let field = expected.get(index).copied().unwrap_or_default(); + write!(msg, "{:SEPARATOR_WIDTH$}{field:column_width$}", " ").unwrap(); + } + } + Self(msg) + } +} + +fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { + let columns = env::var("CLIPPY_TERMINAL_WIDTH") + .ok() + .and_then(|s| ::from_str(&s).ok()) + .map_or(1, |terminal_width| { + let max_field_width = fields.iter().map(|field| field.len()).max().unwrap(); + cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) + }); + + let rows = (fields.len() + (columns - 1)) / columns; + + let column_widths = (0..columns) + .map(|column| { + if column < columns - 1 { + (0..rows) + .map(|row| { + let index = column * rows + row; + let field = fields.get(index).copied().unwrap_or_default(); + field.len() + }) + .max() + .unwrap() + } else { + // Avoid adding extra space to the last column. + 0 + } + }) + .collect::>(); + + (rows, column_widths) +} + +#[cfg(test)] +mod tests { + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + use serde::de::IgnoredAny; + use std::fs; + use walkdir::WalkDir; + + #[test] + fn configs_are_tested() { + let mut names: FxHashSet = super::metadata::get_configuration_metadata() + .into_iter() + .map(|meta| meta.name.replace('_', "-")) + .collect(); + + let toml_files = WalkDir::new("../tests") + .into_iter() + .map(Result::unwrap) + .filter(|entry| entry.file_name() == "clippy.toml"); + + for entry in toml_files { + let file = fs::read_to_string(entry.path()).unwrap(); + #[allow(clippy::zero_sized_map_values)] + if let Ok(map) = toml::from_str::>(&file) { + for name in map.keys() { + names.remove(name.as_str()); + } + } + } + + assert!( + names.remove("allow-one-hash-in-raw-strings"), + "remove this when #11481 is fixed" + ); + + assert!( + names.is_empty(), + "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`" + ); + } +} diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs new file mode 100644 index 00000000000..44bbeb17209 --- /dev/null +++ b/clippy_config/src/lib.rs @@ -0,0 +1,16 @@ +#![feature(rustc_private, let_chains)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![warn(rust_2018_idioms, unused_lifetimes)] + +extern crate rustc_ast; +extern crate rustc_data_structures; +extern crate rustc_session; +extern crate rustc_span; + +mod conf; +mod metadata; +pub mod msrvs; +pub mod types; + +pub use conf::{get_configuration_metadata, lookup_conf_file, Conf}; +pub use metadata::ClippyConfiguration; diff --git a/clippy_config/src/metadata.rs b/clippy_config/src/metadata.rs new file mode 100644 index 00000000000..c40cbd6330f --- /dev/null +++ b/clippy_config/src/metadata.rs @@ -0,0 +1,112 @@ +use std::fmt; + +#[derive(Debug, Clone, Default)] +pub struct ClippyConfiguration { + pub name: String, + config_type: &'static str, + pub default: String, + pub lints: Vec, + pub doc: String, + #[allow(dead_code)] + pub deprecation_reason: Option<&'static str>, +} + +impl fmt::Display for ClippyConfiguration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!( + f, + "* `{}`: `{}`(defaults to `{}`): {}", + self.name, self.config_type, self.default, self.doc + ) + } +} + +impl ClippyConfiguration { + pub fn new( + name: &'static str, + config_type: &'static str, + default: String, + doc_comment: &'static str, + deprecation_reason: Option<&'static str>, + ) -> Self { + let (lints, doc) = parse_config_field_doc(doc_comment) + .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + + Self { + name: to_kebab(name), + lints, + doc, + config_type, + default, + deprecation_reason, + } + } + + #[cfg(feature = "internal")] + pub fn to_markdown_paragraph(&self) -> String { + format!( + "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n", + self.name, + self.doc + .lines() + .map(|line| line.strip_prefix(" ").unwrap_or(line)) + .collect::>() + .join("\n"), + self.default, + self.config_type, + self.lints + .iter() + .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) + .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) + .collect::>() + .join("\n"), + ) + } + + #[cfg(feature = "internal")] + pub fn to_markdown_link(&self) -> String { + const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html"; + format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) + } +} + +/// This parses the field documentation of the config struct. +/// +/// ```rust, ignore +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") +/// ``` +/// +/// Would yield: +/// ```rust, ignore +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") +/// ``` +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec, String)> { + const DOC_START: &str = " Lint: "; + if doc_comment.starts_with(DOC_START) + && let Some(split_pos) = doc_comment.find('.') + { + let mut doc_comment = doc_comment.to_string(); + let mut documentation = doc_comment.split_off(split_pos); + + // Extract lints + doc_comment.make_ascii_lowercase(); + let lints: Vec = doc_comment + .split_off(DOC_START.len()) + .split(", ") + .map(str::to_string) + .collect(); + + // Format documentation correctly + // split off leading `.` from lint name list and indent for correct formatting + documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); + + Some((lints, documentation)) + } else { + None + } +} + +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` +fn to_kebab(config_name: &str) -> String { + config_name.replace('_', "-") +} diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs new file mode 100644 index 00000000000..2cdfa6b42f9 --- /dev/null +++ b/clippy_config/src/msrvs.rs @@ -0,0 +1,138 @@ +use rustc_ast::Attribute; +use rustc_semver::RustcVersion; +use rustc_session::Session; +use rustc_span::{sym, Symbol}; +use serde::Deserialize; + +macro_rules! msrv_aliases { + ($($major:literal,$minor:literal,$patch:literal { + $($name:ident),* $(,)? + })*) => { + $($( + pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch); + )*)* + }; +} + +// names may refer to stabilized feature flags or library items +msrv_aliases! { + 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } + 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } + 1,68,0 { PATH_MAIN_SEPARATOR_STR } + 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } + 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } + 1,55,0 { SEEK_REWIND } + 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } + 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } + 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } + 1,50,0 { BOOL_THEN, CLAMP } + 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } + 1,46,0 { CONST_IF_MATCH } + 1,45,0 { STR_STRIP_PREFIX } + 1,43,0 { LOG2_10, LOG10_2 } + 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS } + 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } + 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } + 1,38,0 { POINTER_CAST, REM_EUCLID } + 1,37,0 { TYPE_ALIAS_ENUM_VARIANTS } + 1,36,0 { ITERATOR_COPIED } + 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } + 1,34,0 { TRY_FROM } + 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } + 1,28,0 { FROM_BOOL } + 1,27,0 { ITERATOR_TRY_FOLD } + 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } + 1,24,0 { IS_ASCII_DIGIT } + 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } + 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } + 1,16,0 { STR_REPEAT } + 1,15,0 { MAYBE_BOUND_IN_WHERE } +} + +/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` +#[derive(Debug, Clone)] +pub struct Msrv { + stack: Vec, +} + +impl<'de> Deserialize<'de> for Msrv { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let v = String::deserialize(deserializer)?; + RustcVersion::parse(&v) + .map(|v| Msrv { stack: vec![v] }) + .map_err(|_| serde::de::Error::custom("not a valid Rust version")) + } +} + +impl Msrv { + pub fn empty() -> Msrv { + Msrv { stack: Vec::new() } + } + + pub fn read_cargo(&mut self, sess: &Session) { + let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") + .ok() + .and_then(|v| RustcVersion::parse(&v).ok()); + + match (self.current(), cargo_msrv) { + (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv], + (Some(clippy_msrv), Some(cargo_msrv)) => { + if clippy_msrv != cargo_msrv { + sess.warn(format!( + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" + )); + } + }, + _ => {}, + } + } + + pub fn current(&self) -> Option { + self.stack.last().copied() + } + + pub fn meets(&self, required: RustcVersion) -> bool { + self.current().map_or(true, |version| version.meets(required)) + } + + fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option { + let sym_msrv = Symbol::intern("msrv"); + let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); + + if let Some(msrv_attr) = msrv_attrs.next() { + if let Some(duplicate) = msrv_attrs.last() { + sess.struct_span_err(duplicate.span, format!("`clippy::msrv` is defined multiple times")) + .span_note(msrv_attr.span, "first definition found here") + .emit(); + } + + if let Some(msrv) = msrv_attr.value_str() { + if let Ok(version) = RustcVersion::parse(msrv.as_str()) { + return Some(version); + } + + sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version")); + } else { + sess.span_err(msrv_attr.span, "bad clippy attribute"); + } + } + + None + } + + pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { + if let Some(version) = Self::parse_attr(sess, attrs) { + self.stack.push(version); + } + } + + pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { + if Self::parse_attr(sess, attrs).is_some() { + self.stack.pop(); + } + } +} diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs new file mode 100644 index 00000000000..d179f6baab7 --- /dev/null +++ b/clippy_config/src/types.rs @@ -0,0 +1,119 @@ +use serde::de::{self, Deserializer, Visitor}; +use serde::Deserialize; +use std::fmt; +use std::hash::{Hash, Hasher}; + +#[derive(Clone, Debug, Deserialize)] +pub struct Rename { + pub path: String, + pub rename: String, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub enum DisallowedPath { + Simple(String), + WithReason { path: String, reason: Option }, +} + +impl DisallowedPath { + pub fn path(&self) -> &str { + let (Self::Simple(path) | Self::WithReason { path, .. }) = self; + + path + } + + pub fn reason(&self) -> Option { + match self { + Self::WithReason { + reason: Some(reason), .. + } => Some(format!("{reason} (from clippy.toml)")), + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)] +pub enum MatchLintBehaviour { + AllTypes, + WellKnownTypes, + Never, +} + +#[derive(Clone, Debug)] +pub struct MacroMatcher { + pub name: String, + pub braces: (String, String), +} + +impl Hash for MacroMatcher { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl PartialEq for MacroMatcher { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} +impl Eq for MacroMatcher {} + +impl<'de> Deserialize<'de> for MacroMatcher { + fn deserialize(deser: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Name, + Brace, + } + struct MacVisitor; + impl<'de> Visitor<'de> for MacVisitor { + type Value = MacroMatcher; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("struct MacroMatcher") + } + + fn visit_map(self, mut map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mut name = None; + let mut brace: Option = None; + while let Some(key) = map.next_key()? { + match key { + Field::Name => { + if name.is_some() { + return Err(de::Error::duplicate_field("name")); + } + name = Some(map.next_value()?); + }, + Field::Brace => { + if brace.is_some() { + return Err(de::Error::duplicate_field("brace")); + } + brace = Some(map.next_value()?); + }, + } + } + let name = name.ok_or_else(|| de::Error::missing_field("name"))?; + let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?; + Ok(MacroMatcher { + name, + braces: [("(", ")"), ("{", "}"), ("[", "]")] + .into_iter() + .find(|b| b.0 == brace) + .map(|(o, c)| (o.to_owned(), c.to_owned())) + .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, + }) + } + } + + const FIELDS: &[&str] = &["name", "brace"]; + deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor) + } +} diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 4d5b3bf8a94..54f67c59761 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" [dependencies] arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.15.3" +clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } if_chain = "1.0" @@ -34,7 +35,7 @@ walkdir = "2.3" [features] deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default -internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"] +internal = ["clippy_config/internal", "clippy_utils/internal", "serde_json", "tempfile", "regex"] [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 4afb3957aa1..82c6712506d 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 591c78cb246..b4f778f12b9 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 8a918c13cfc..c720eba11b1 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,9 +1,9 @@ //! checks for attributes +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_from_proc_macro; use clippy_utils::macros::{is_panic, macro_backtrace}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use if_chain::if_chain; use rustc_ast::token::{Token, TokenKind}; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 494374e967b..dbeca372b4d 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,3 +1,4 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; @@ -8,8 +9,6 @@ use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use crate::utils::conf::DisallowedPath; - declare_clippy_lint! { /// ### What it does /// Checks for calls to await while holding a non-async-aware MutexGuard. diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 44226298333..c1663348321 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index c586b572be9..fe2455f4b23 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_constant; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 4d9cc4cacc3..d1410402913 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source; use if_chain::if_chain; use rustc_ast::Mutability; diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index eb0f75b2f60..badadf2c9f6 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 2edbc6db5c3..49a90a2f3c2 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -22,8 +22,8 @@ mod unnecessary_cast; mod utils; mod zero_ptr; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::is_hir_ty_cfg_dependant; -use clippy_utils::msrvs::{self, Msrv}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 181dbcf6e9a..0c555c1acc5 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index ce1ab10910c..0172e933649 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -18,7 +18,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if_chain! { - if msrv.meets(POINTER_CAST_CONSTNESS); + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS); if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind(); if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind(); if matches!((from_mutbl, to_mutbl), diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1cfd0d1157c..d31c2268a65 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,7 +1,7 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; use if_chain::if_chain; diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index ca3f1acfc0c..a450becc647 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index e4f2328bc1f..324b5e0798e 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -1,3 +1,4 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -8,8 +9,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{ExpnId, Span}; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured macros in clippy.toml @@ -55,13 +54,13 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec, + conf_disallowed: Vec, disallowed: DefIdMap, seen: FxHashSet, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 95d3f7547b4..d23aeebb5a8 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,13 +1,11 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; - use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured methods and functions in clippy.toml @@ -59,12 +57,12 @@ declare_clippy_lint! { #[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec, + conf_disallowed: Vec, disallowed: DefIdMap, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { conf_disallowed, disallowed: DefIdMap::default(), diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 1f56d0118a4..3578fb640fc 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -1,5 +1,5 @@ +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; - use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; @@ -8,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; -use crate::utils::conf; - declare_clippy_lint! { /// ### What it does /// Denies the configured types in clippy.toml. @@ -50,15 +48,16 @@ declare_clippy_lint! { style, "use of disallowed types" } + #[derive(Clone, Debug)] pub struct DisallowedTypes { - conf_disallowed: Vec, + conf_disallowed: Vec, def_ids: FxHashMap, prim_tys: FxHashMap, } impl DisallowedTypes { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { conf_disallowed, def_ids: FxHashMap::default(), @@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { } } -fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) { +fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) { span_lint_and_then( cx, DISALLOWED_TYPES, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index e674e03f17b..7d60fdd1b03 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,11 @@ use arrayvec::ArrayVec; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, }; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index a100fd6c595..948d709ce3f 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::path_def_id; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index ebd529bd356..55dab10ac88 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index ab5e6a93300..c2f1f18e39d 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -1,7 +1,7 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use if_chain::if_chain; diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index cb01f7aac14..32b2cb4385f 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{self, span_lint_and_sugg}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a70a38ee08b..a64efbca74f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -50,7 +50,6 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; -use clippy_utils::msrvs::Msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; use rustc_session::Session; @@ -358,9 +357,8 @@ mod zero_div_zero; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` -use crate::utils::conf::metadata::get_configuration_metadata; -pub use crate::utils::conf::{lookup_conf_file, Conf}; use crate::utils::FindAll; +use clippy_config::{get_configuration_metadata, Conf}; /// Register all pre expansion lints /// diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 6ab256ef001..92ee033df47 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,6 +1,6 @@ use super::EXPLICIT_ITER_LOOP; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{ implements_trait, implements_trait_with_env, is_copy, make_normalized_projection, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 747fc7eb40e..575a84c8c63 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -19,8 +19,8 @@ mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; +use clippy_config::msrvs::Msrv; use clippy_utils::higher; -use clippy_utils::msrvs::Msrv; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 2db4443e059..cd614c8951c 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 4afeb5eebc3..ec87ff3ef6a 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index cbad700c99a..19f2e1dc42c 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 2474c672e18..17415b58d9e 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::root_macro_call; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, in_constant}; use rustc_ast::ast::RangeLimits; diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index fb8ddd8c2be..7888fc10a0b 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,10 +1,12 @@ use crate::question_mark::{QuestionMark, QUESTION_MARK}; +use clippy_config::msrvs; +use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Descend, Visitable}; -use clippy_utils::{is_lint_allowed, msrvs, pat_and_expr_can_be_question_mark, peel_blocks}; +use clippy_utils::{is_lint_allowed, pat_and_expr_can_be_question_mark, peel_blocks}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -14,7 +16,6 @@ use rustc_middle::lint::in_external_macro; use rustc_session::declare_tool_lint; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use serde::Deserialize; use std::ops::ControlFlow; use std::slice; @@ -477,10 +478,3 @@ fn expr_simple_identity_map<'a, 'hir>( } Some(ident_map) } - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)] -pub enum MatchLintBehaviour { - AllTypes, - WellKnownTypes, - Never, -} diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 8bd62b080c4..8f5e7982242 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 85ca8486315..4c44ac7fa11 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::attr; diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 80b83aac413..b435fcf61df 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::{in_constant, path_to_local}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index bfce92c0251..f902b48fa81 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index e653064dbde..9a9e6af5084 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; use clippy_utils::{eq_expr_value, higher, match_def_path, paths}; diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 8f1ad962276..dea46d4d360 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -24,7 +24,7 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 645c26f39c4..c6a1b45a9fa 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index 4e6ec61f6a8..fcafa162236 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{get_iterator_item_ty, is_copy}; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 3d82441c0e6..a8d4dd5e4f3 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -1,6 +1,6 @@ use super::ERR_EXPECT; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; use rustc_errors::Applicability; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs index 3f89e593148..f94fe221833 100644 --- a/clippy_lints/src/methods/filter_map_next.rs +++ b/clippy_lints/src/methods/filter_map_next.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::is_trait_method; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index 120f3d5f42c..e963950960a 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,9 +1,9 @@ //! Lint for `c.is_digit(10)` use super::IS_DIGIT_ASCII_RADIX; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index dabed0affcf..5fc968f793f 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; -use clippy_utils::msrvs::{Msrv, ITERATOR_TRY_FOLD}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if !in_external_macro(cx.sess(), fold_span) - && msrv.meets(ITERATOR_TRY_FOLD) + && msrv.meets(msrvs::ITERATOR_TRY_FOLD) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() && implements_trait(cx, init_ty, try_trait, &[]) diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 880efe60c1a..e0f8cb1b955 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use clippy_utils::{is_diag_trait_item, peel_blocks}; diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index e70a1bc9879..cb81b3919bf 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::mutated_variables; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6d937b8619d..373d8606b1d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -116,9 +116,9 @@ mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -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, peel_blocks, return_ty}; use if_chain::if_chain; diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index d0c27f9631f..7b81d4571b2 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks}; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index fcbe005fb28..ebb0a7b562d 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/methods/path_ends_with_ext.rs b/clippy_lints/src/methods/path_ends_with_ext.rs index 3347c8c1620..9ec0ef0ea39 100644 --- a/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/clippy_lints/src/methods/path_ends_with_ext.rs @@ -1,7 +1,6 @@ use super::PATH_ENDS_WITH_EXT; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs; -use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 5d4b0e53762..6e00e0fd1fb 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 70da6ad58bd..fb8075e2362 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{Msrv, MATCHES_MACRO}; use clippy_utils::source::snippet_opt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( body: &Expr<'_>, msrv: &Msrv, ) { - if msrv.meets(MATCHES_MACRO) + if msrv.meets(msrvs::MATCHES_MACRO) && is_trait_method(cx, expr, sym::Iterator) && let PatKind::Binding(_, arg, _, _) = param.pat.kind && let ExprKind::Lit(lit_kind) = recv.kind diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 50d6f3b7e55..78d4bae60e5 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,7 +1,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index b39f1de0b41..97522cbe6ce 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index fc088710e42..16ff98a5922 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,6 +1,6 @@ +use clippy_config::types::Rename; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; - use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -10,8 +10,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; -use crate::utils::conf::Rename; - declare_clippy_lint! { /// ### What it does /// Checks for imports that do not rename the item as specified diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 542b81f3a12..53f449f2d43 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_copy; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 35d06897eb4..11c3a5417b5 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,6 +1,4 @@ -use std::fmt; -use std::hash::{Hash, Hasher}; - +use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use if_chain::if_chain; @@ -12,7 +10,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; -use serde::{de, Deserialize}; declare_clippy_lint! { /// ### What it does @@ -36,8 +33,6 @@ declare_clippy_lint! { "check consistent use of braces in macro" } -const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")]; - /// The (callsite span, (open brace, close brace), source snippet) type MacroInfo<'a> = (Span, &'a (String, String), String); @@ -195,81 +190,3 @@ macro_rules! macro_matcher { }; } pub(crate) use macro_matcher; - -#[derive(Clone, Debug)] -pub struct MacroMatcher { - name: String, - braces: (String, String), -} - -impl Hash for MacroMatcher { - fn hash(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl PartialEq for MacroMatcher { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} -impl Eq for MacroMatcher {} - -impl<'de> Deserialize<'de> for MacroMatcher { - fn deserialize(deser: D) -> Result - where - D: de::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(field_identifier, rename_all = "lowercase")] - enum Field { - Name, - Brace, - } - struct MacVisitor; - impl<'de> de::Visitor<'de> for MacVisitor { - type Value = MacroMatcher; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("struct MacroMatcher") - } - - fn visit_map(self, mut map: V) -> Result - where - V: de::MapAccess<'de>, - { - let mut name = None; - let mut brace: Option = None; - while let Some(key) = map.next_key()? { - match key { - Field::Name => { - if name.is_some() { - return Err(de::Error::duplicate_field("name")); - } - name = Some(map.next_value()?); - }, - Field::Brace => { - if brace.is_some() { - return Err(de::Error::duplicate_field("brace")); - } - brace = Some(map.next_value()?); - }, - } - } - let name = name.ok_or_else(|| de::Error::missing_field("name"))?; - let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?; - Ok(MacroMatcher { - name, - braces: BRACES - .iter() - .find(|b| b.0 == brace) - .map(|(o, c)| ((*o).to_owned(), (*c).to_owned())) - .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?, - }) - } - } - - const FIELDS: &[&str] = &["name", "brace"]; - deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor) - } -} diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 734ca2914f5..4305792873c 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,7 +1,8 @@ -use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE}; +use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; +use clippy_config::msrvs::Msrv; +use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 4a5c6b33298..ffd49de3820 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 6bf512a0e2d..b8e606df737 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index ed42a422b4b..a70b831a80c 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 42b7b8645d4..f065d215e48 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index a6231ceb658..6eec40cb529 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -17,8 +17,8 @@ mod useless_transmute; mod utils; mod wrong_transmute; +use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; -use clippy_utils::msrvs::Msrv; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 6bdb9aa5a26..4ab3afbe714 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_PTR_TO_REF; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg; use rustc_errors::Applicability; diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index c12519d723c..642e39e8270 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -1,5 +1,5 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{is_from_proc_macro, path_to_local}; use itertools::Itertools; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index e8ec22831c3..8ff088a208f 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,8 +1,8 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::over; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 0f57c5def21..c3fe16ad5c3 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,6 +1,6 @@ +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::same_type_and_consts; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs deleted file mode 100644 index e5409328b4d..00000000000 --- a/clippy_lints/src/utils/conf.rs +++ /dev/null @@ -1,812 +0,0 @@ -//! Read configurations files. - -#![allow(clippy::module_name_repetitions)] - -use rustc_session::Session; -use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; -use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor}; -use serde::Deserialize; -use std::fmt::{Debug, Display, Formatter}; -use std::ops::Range; -use std::path::PathBuf; -use std::str::FromStr; -use std::sync::OnceLock; -use std::{cmp, env, fmt, fs, io}; - -#[rustfmt::skip] -const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ - "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", - "DirectX", - "ECMAScript", - "GPLv2", "GPLv3", - "GitHub", "GitLab", - "IPv4", "IPv6", - "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", - "WebAssembly", - "NaN", "NaNs", - "OAuth", "GraphQL", - "OCaml", - "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", - "WebGL", - "TensorFlow", - "TrueType", - "iOS", "macOS", "FreeBSD", - "TeX", "LaTeX", "BibTeX", "BibLaTeX", - "MinGW", - "CamelCase", -]; -const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; -const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; - -/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. -#[derive(Clone, Debug, Deserialize)] -pub struct Rename { - pub path: String, - pub rename: String, -} - -#[derive(Clone, Debug, Deserialize)] -#[serde(untagged)] -pub enum DisallowedPath { - Simple(String), - WithReason { path: String, reason: Option }, -} - -impl DisallowedPath { - pub fn path(&self) -> &str { - let (Self::Simple(path) | Self::WithReason { path, .. }) = self; - - path - } - - pub fn reason(&self) -> Option { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, - } - } -} - -/// Conf with parse errors -#[derive(Default)] -pub struct TryConf { - pub conf: Conf, - pub errors: Vec, - pub warnings: Vec, -} - -impl TryConf { - fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self { - Self { - conf: Conf::default(), - errors: vec![ConfError::from_toml(file, error)], - warnings: vec![], - } - } -} - -#[derive(Debug)] -pub struct ConfError { - pub message: String, - pub span: Span, -} - -impl ConfError { - fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self { - let span = error.span().unwrap_or(0..file.source_len.0 as usize); - Self::spanned(file, error.message(), span) - } - - fn spanned(file: &SourceFile, message: impl Into, span: Range) -> Self { - Self { - message: message.into(), - span: Span::new( - file.start_pos + BytePos::from_usize(span.start), - file.start_pos + BytePos::from_usize(span.end), - SyntaxContext::root(), - None, - ), - } - } -} - -macro_rules! define_Conf { - ($( - $(#[doc = $doc:literal])+ - $(#[conf_deprecated($dep:literal, $new_conf:ident)])? - ($name:ident: $ty:ty = $default:expr), - )*) => { - /// Clippy lint configuration - pub struct Conf { - $($(#[doc = $doc])+ pub $name: $ty,)* - } - - mod defaults { - $(pub fn $name() -> $ty { $default })* - } - - impl Default for Conf { - fn default() -> Self { - Self { $($name: defaults::$name(),)* } - } - } - - #[derive(Deserialize)] - #[serde(field_identifier, rename_all = "kebab-case")] - #[allow(non_camel_case_types)] - enum Field { $($name,)* third_party, } - - struct ConfVisitor<'a>(&'a SourceFile); - - impl<'de> Visitor<'de> for ConfVisitor<'_> { - type Value = TryConf; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("Conf") - } - - fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de> { - let mut errors = Vec::new(); - let mut warnings = Vec::new(); - $(let mut $name = None;)* - // could get `Field` here directly, but get `String` first for diagnostics - while let Some(name) = map.next_key::>()? { - match Field::deserialize(name.get_ref().as_str().into_deserializer()) { - Err(e) => { - let e: FieldError = e; - errors.push(ConfError::spanned(self.0, e.0, name.span())); - } - $(Ok(Field::$name) => { - $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), name.span()));)? - let raw_value = map.next_value::>()?; - let value_span = raw_value.span(); - match <$ty>::deserialize(raw_value.into_inner()) { - Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), value_span)), - Ok(value) => match $name { - Some(_) => errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), name.span())), - None => { - $name = Some(value); - // $new_conf is the same as one of the defined `$name`s, so - // this variable is defined in line 2 of this function. - $(match $new_conf { - Some(_) => errors.push(ConfError::spanned(self.0, concat!( - "duplicate field `", stringify!($new_conf), - "` (provided as `", stringify!($name), "`)" - ), name.span())), - None => $new_conf = $name.clone(), - })? - }, - } - } - })* - // ignore contents of the third_party key - Ok(Field::third_party) => drop(map.next_value::()) - } - } - let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; - Ok(TryConf { conf, errors, warnings }) - } - } - - pub mod metadata { - use crate::utils::ClippyConfiguration; - - macro_rules! wrap_option { - () => (None); - ($x:literal) => (Some($x)); - } - - pub fn get_configuration_metadata() -> Vec { - vec![ - $( - { - let deprecation_reason = wrap_option!($($dep)?); - - ClippyConfiguration::new( - stringify!($name), - stringify!($ty), - format!("{:?}", super::defaults::$name()), - concat!($($doc, '\n',)*), - deprecation_reason, - ) - }, - )+ - ] - } - } - }; -} - -define_Conf! { - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// - /// Suppress checking of the passed type names in all types of operations. - /// - /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. - /// - /// #### Example - /// - /// ```toml - /// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] - /// ``` - /// - /// #### Noteworthy - /// - /// A type, say `SomeType`, listed in this configuration has the same behavior of - /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet = <_>::default()), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// - /// Suppress checking of the passed type pair names in binary operations like addition or - /// multiplication. - /// - /// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless - /// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`. - /// - /// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as - /// `["AnotherType", "SomeType"]`. - /// - /// #### Example - /// - /// ```toml - /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] - /// ``` - (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// - /// Suppress checking of the passed type names in unary operations like "negation" (`-`). - /// - /// #### Example - /// - /// ```toml - /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] - /// ``` - (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. - /// - /// Suppress lints whenever the suggested change would cause breakage for other crates. - (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. - /// - /// The minimum rust version that the project supports - (msrv: crate::Msrv = crate::Msrv::empty()), - /// DEPRECATED LINT: BLACKLISTED_NAME. - /// - /// Use the Disallowed Names lint instead - #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] - (blacklisted_names: Vec = Vec::new()), - /// Lint: COGNITIVE_COMPLEXITY. - /// - /// The maximum cognitive complexity a function can have - (cognitive_complexity_threshold: u64 = 25), - /// Lint: EXCESSIVE_NESTING. - /// - /// The maximum amount of nesting a block can reside in - (excessive_nesting_threshold: u64 = 0), - /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. - /// - /// Use the Cognitive Complexity lint instead. - #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] - (cyclomatic_complexity_threshold: u64 = 25), - /// Lint: DISALLOWED_NAMES. - /// - /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate that the configured values should be appended to the - /// default configuration of Clippy. By default, any configuration will replace the default value. - (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), - /// Lint: SEMICOLON_INSIDE_BLOCK. - /// - /// Whether to lint only if it's multiline. - (semicolon_inside_block_ignore_singleline: bool = false), - /// Lint: SEMICOLON_OUTSIDE_BLOCK. - /// - /// Whether to lint only if it's singleline. - (semicolon_outside_block_ignore_multiline: bool = false), - /// Lint: DOC_MARKDOWN. - /// - /// The list of words this lint should not consider as identifiers needing ticks. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default, any configuration will replace the default value. For example: - /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. - /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - /// - /// Default list: - (doc_valid_idents: Vec = super::DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), - /// Lint: TOO_MANY_ARGUMENTS. - /// - /// The maximum number of argument a function or method can have - (too_many_arguments_threshold: u64 = 7), - /// Lint: TYPE_COMPLEXITY. - /// - /// The maximum complexity a type can have - (type_complexity_threshold: u64 = 250), - /// Lint: MANY_SINGLE_CHAR_NAMES. - /// - /// The maximum number of single char bindings a scope may have - (single_char_binding_names_threshold: u64 = 4), - /// Lint: BOXED_LOCAL, USELESS_VEC. - /// - /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap - (too_large_for_stack: u64 = 200), - /// Lint: ENUM_VARIANT_NAMES. - /// - /// The minimum number of enum variants for the lints about variant names to trigger - (enum_variant_name_threshold: u64 = 3), - /// Lint: STRUCT_VARIANT_NAMES. - /// - /// The minimum number of struct fields for the lints about field names to trigger - (struct_field_name_threshold: u64 = 3), - /// Lint: LARGE_ENUM_VARIANT. - /// - /// The maximum size of an enum's variant to avoid box suggestion - (enum_variant_size_threshold: u64 = 200), - /// Lint: VERBOSE_BIT_MASK. - /// - /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' - (verbose_bit_mask_threshold: u64 = 1), - /// Lint: DECIMAL_LITERAL_REPRESENTATION. - /// - /// The lower bound for linting decimal literals - (literal_representation_threshold: u64 = 16384), - /// Lint: TRIVIALLY_COPY_PASS_BY_REF. - /// - /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. - (trivial_copy_size_limit: Option = None), - /// Lint: LARGE_TYPES_PASSED_BY_VALUE. - /// - /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. - (pass_by_value_size_limit: u64 = 256), - /// Lint: TOO_MANY_LINES. - /// - /// The maximum number of lines a function or method can have - (too_many_lines_threshold: u64 = 100), - /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. - /// - /// The maximum allowed size for arrays on the stack - (array_size_threshold: u64 = 512_000), - /// Lint: LARGE_STACK_FRAMES. - /// - /// The maximum allowed stack size for functions in bytes - (stack_size_threshold: u64 = 512_000), - /// Lint: VEC_BOX. - /// - /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed - (vec_box_size_threshold: u64 = 4096), - /// Lint: TYPE_REPETITION_IN_BOUNDS. - /// - /// The maximum number of bounds a trait can have to be linted - (max_trait_bounds: u64 = 3), - /// Lint: STRUCT_EXCESSIVE_BOOLS. - /// - /// The maximum number of bool fields a struct can have - (max_struct_bools: u64 = 3), - /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. - /// - /// The maximum number of bool parameters a function can have - (max_fn_params_bools: u64 = 3), - /// Lint: WILDCARD_IMPORTS. - /// - /// Whether to allow certain wildcard imports (prelude, super in tests). - (warn_on_all_wildcard_imports: bool = false), - /// Lint: DISALLOWED_MACROS. - /// - /// The list of disallowed macros, written as fully qualified paths. - (disallowed_macros: Vec = Vec::new()), - /// Lint: DISALLOWED_METHODS. - /// - /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec = Vec::new()), - /// Lint: DISALLOWED_TYPES. - /// - /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec = Vec::new()), - /// Lint: UNREADABLE_LITERAL. - /// - /// Should the fraction of a decimal be linted to include separators. - (unreadable_literal_lint_fractions: bool = true), - /// Lint: UPPER_CASE_ACRONYMS. - /// - /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other - (upper_case_acronyms_aggressive: bool = false), - /// Lint: MANUAL_LET_ELSE. - /// - /// Whether the matches should be considered by the lint, and whether there should - /// be filtering for common types. - (matches_for_let_else: crate::manual_let_else::MatchLintBehaviour = - crate::manual_let_else::MatchLintBehaviour::WellKnownTypes), - /// Lint: _CARGO_COMMON_METADATA. - /// - /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. - (cargo_ignore_publish: bool = false), - /// Lint: NONSTANDARD_MACRO_BRACES. - /// - /// Enforce the named macros always use the braces specified. - /// - /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro - /// could be used with a full path two `MacroMatcher`s have to be added one with the full path - /// `crate_name::macro_name` and one with just the macro name. - (standard_macro_braces: Vec = Vec::new()), - /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. - /// - /// The list of imports to always rename, a fully qualified path followed by the rename. - (enforced_import_renames: Vec = Vec::new()), - /// Lint: DISALLOWED_SCRIPT_IDENTS. - /// - /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec = vec!["Latin".to_string()]), - /// Lint: NON_SEND_FIELDS_IN_SEND_TY. - /// - /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. - (enable_raw_pointer_heuristic_for_send: bool = true), - /// Lint: INDEX_REFUTABLE_SLICE. - /// - /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in - /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. - /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. - (max_suggested_slice_pattern_length: u64 = 3), - /// Lint: AWAIT_HOLDING_INVALID_TYPE. - (await_holding_invalid_types: Vec = Vec::new()), - /// Lint: LARGE_INCLUDE_FILE. - /// - /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes - (max_include_file_size: u64 = 1_000_000), - /// Lint: EXPECT_USED. - /// - /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` - (allow_expect_in_tests: bool = false), - /// Lint: UNWRAP_USED. - /// - /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` - (allow_unwrap_in_tests: bool = false), - /// Lint: DBG_MACRO. - /// - /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` - (allow_dbg_in_tests: bool = false), - /// Lint: PRINT_STDOUT, PRINT_STDERR. - /// - /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` - (allow_print_in_tests: bool = false), - /// Lint: RESULT_LARGE_ERR. - /// - /// The maximum size of the `Err`-variant in a `Result` returned from a function - (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. - /// - /// A list of paths to types that should be treated like `Arc`, i.e. ignored but - /// for the generic parameters for determining interior mutability - (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), - /// Lint: UNINLINED_FORMAT_ARGS. - /// - /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` - (allow_mixed_uninlined_format_args: bool = true), - /// Lint: INDEXING_SLICING. - /// - /// Whether to suppress a restriction lint in constant code. In same - /// cases the restructured operation might not be unavoidable, as the - /// suggested counterparts are unavailable in constant code. This - /// configuration will cause restriction lints to trigger even - /// if no suggestion can be made. - (suppress_restriction_lint_in_const: bool = false), - /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. - /// - /// Whether to **only** check for missing documentation in items visible within the current - /// crate. For example, `pub(crate)` items. - (missing_docs_in_crate_items: bool = false), - /// Lint: LARGE_FUTURES. - /// - /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint - (future_size_threshold: u64 = 16 * 1024), - /// Lint: UNNECESSARY_BOX_RETURNS. - /// - /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint - (unnecessary_box_size: u64 = 128), - /// Lint: MODULE_INCEPTION. - /// - /// Whether to allow module inception if it's not public. - (allow_private_module_inception: bool = false), - /// Lint: MIN_IDENT_CHARS. - /// - /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of - /// the list to indicate, that the configured values should be appended to the default - /// configuration of Clippy. By default, any configuration will replace the default value. - (allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet = - super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), - /// Lint: MIN_IDENT_CHARS. - /// - /// Minimum chars an ident can have, anything below or equal to this will be linted. - (min_ident_chars_threshold: u64 = 1), - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// - /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block - (accept_comment_above_statement: bool = true), - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// - /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block - (accept_comment_above_attributes: bool = true), - /// Lint: UNNECESSARY_RAW_STRING_HASHES. - /// - /// Whether to allow `r#""#` when `r""` can be used - (allow_one_hash_in_raw_strings: bool = false), - /// Lint: ABSOLUTE_PATHS. - /// - /// The maximum number of segments a path can have before being linted, anything above this will - /// be linted. - (absolute_paths_max_segments: u64 = 2), - /// Lint: ABSOLUTE_PATHS. - /// - /// Which crates to allow absolute paths from - (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet = - rustc_data_structures::fx::FxHashSet::default()), - /// Lint: PATH_ENDS_WITH_EXT. - /// - /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: rustc_data_structures::fx::FxHashSet = - rustc_data_structures::fx::FxHashSet::default()), - /// Lint: EXPLICIT_ITER_LOOP - /// - /// Whether to recommend using implicit into iter for reborrowed values. - /// - /// #### Example - /// ```no_run - /// let mut vec = vec![1, 2, 3]; - /// let rmvec = &mut vec; - /// for _ in rmvec.iter() {} - /// for _ in rmvec.iter_mut() {} - /// ``` - /// - /// Use instead: - /// ```no_run - /// let mut vec = vec![1, 2, 3]; - /// let rmvec = &mut vec; - /// for _ in &*rmvec {} - /// for _ in &mut *rmvec {} - /// ``` - (enforce_iter_loop_reborrow: bool = false), -} - -/// Search for the configuration file. -/// -/// # Errors -/// -/// Returns any unexpected filesystem error encountered when searching for the config file -pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { - /// Possible filename to search for. - const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"]; - - // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR. - // If neither of those exist, use ".". (Update documentation if this priority changes) - let mut current = env::var_os("CLIPPY_CONF_DIR") - .or_else(|| env::var_os("CARGO_MANIFEST_DIR")) - .map_or_else(|| PathBuf::from("."), PathBuf::from) - .canonicalize()?; - - let mut found_config: Option = None; - let mut warnings = vec![]; - - loop { - for config_file_name in &CONFIG_FILE_NAMES { - if let Ok(config_file) = current.join(config_file_name).canonicalize() { - match fs::metadata(&config_file) { - Err(e) if e.kind() == io::ErrorKind::NotFound => {}, - Err(e) => return Err(e), - Ok(md) if md.is_dir() => {}, - Ok(_) => { - // warn if we happen to find two config files #8323 - if let Some(ref found_config) = found_config { - warnings.push(format!( - "using config file `{}`, `{}` will be ignored", - found_config.display(), - config_file.display() - )); - } else { - found_config = Some(config_file); - } - }, - } - } - } - - if found_config.is_some() { - return Ok((found_config, warnings)); - } - - // If the current directory has no parent, we're done searching. - if !current.pop() { - return Ok((None, warnings)); - } - } -} - -fn deserialize(file: &SourceFile) -> TryConf { - match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { - Ok(mut conf) => { - extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); - extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); - // TODO: THIS SHOULD BE TESTED, this comment will be gone soon - if conf.conf.allowed_idents_below_min_chars.contains(&"..".to_owned()) { - conf.conf - .allowed_idents_below_min_chars - .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); - } - - conf - }, - Err(e) => TryConf::from_toml_error(file, &e), - } -} - -fn extend_vec_if_indicator_present(vec: &mut Vec, default: &[&str]) { - if vec.contains(&"..".to_string()) { - vec.extend(default.iter().map(ToString::to_string)); - } -} - -impl Conf { - pub fn read(sess: &Session, path: &io::Result<(Option, Vec)>) -> &'static Conf { - static CONF: OnceLock = OnceLock::new(); - CONF.get_or_init(|| Conf::read_inner(sess, path)) - } - - fn read_inner(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { - match path { - Ok((_, warnings)) => { - for warning in warnings { - sess.warn(warning.clone()); - } - }, - Err(error) => { - sess.err(format!("error finding Clippy's configuration file: {error}")); - }, - } - - let TryConf { - mut conf, - errors, - warnings, - } = match path { - Ok((Some(path), _)) => match sess.source_map().load_file(path) { - Ok(file) => deserialize(&file), - Err(error) => { - sess.err(format!("failed to read `{}`: {error}", path.display())); - TryConf::default() - }, - }, - _ => TryConf::default(), - }; - - conf.msrv.read_cargo(sess); - - // all conf errors are non-fatal, we just use the default conf in case of error - for error in errors { - sess.span_err( - error.span, - format!("error reading Clippy's configuration file: {}", error.message), - ); - } - - for warning in warnings { - sess.span_warn( - warning.span, - format!("error reading Clippy's configuration file: {}", warning.message), - ); - } - - conf - } -} - -const SEPARATOR_WIDTH: usize = 4; - -#[derive(Debug)] -struct FieldError(String); - -impl std::error::Error for FieldError {} - -impl Display for FieldError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.pad(&self.0) - } -} - -impl serde::de::Error for FieldError { - fn custom(msg: T) -> Self { - Self(msg.to_string()) - } - - fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { - // List the available fields sorted and at least one per line, more if `CLIPPY_TERMINAL_WIDTH` is - // set and allows it. - use fmt::Write; - - let mut expected = expected.to_vec(); - expected.sort_unstable(); - - let (rows, column_widths) = calculate_dimensions(&expected); - - let mut msg = format!("unknown field `{field}`, expected one of"); - for row in 0..rows { - writeln!(msg).unwrap(); - for (column, column_width) in column_widths.iter().copied().enumerate() { - let index = column * rows + row; - let field = expected.get(index).copied().unwrap_or_default(); - write!(msg, "{:SEPARATOR_WIDTH$}{field:column_width$}", " ").unwrap(); - } - } - Self(msg) - } -} - -fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { - let columns = env::var("CLIPPY_TERMINAL_WIDTH") - .ok() - .and_then(|s| ::from_str(&s).ok()) - .map_or(1, |terminal_width| { - let max_field_width = fields.iter().map(|field| field.len()).max().unwrap(); - cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) - }); - - let rows = (fields.len() + (columns - 1)) / columns; - - let column_widths = (0..columns) - .map(|column| { - if column < columns - 1 { - (0..rows) - .map(|row| { - let index = column * rows + row; - let field = fields.get(index).copied().unwrap_or_default(); - field.len() - }) - .max() - .unwrap() - } else { - // Avoid adding extra space to the last column. - 0 - } - }) - .collect::>(); - - (rows, column_widths) -} - -#[cfg(test)] -mod tests { - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - use serde::de::IgnoredAny; - use std::fs; - use walkdir::WalkDir; - - #[test] - fn configs_are_tested() { - let mut names: FxHashSet = super::metadata::get_configuration_metadata() - .into_iter() - .map(|meta| meta.name.replace('_', "-")) - .collect(); - - let toml_files = WalkDir::new("../tests") - .into_iter() - .map(Result::unwrap) - .filter(|entry| entry.file_name() == "clippy.toml"); - - for entry in toml_files { - let file = fs::read_to_string(entry.path()).unwrap(); - #[allow(clippy::zero_sized_map_values)] - if let Ok(map) = toml::from_str::>(&file) { - for name in map.keys() { - names.remove(name.as_str()); - } - } - } - - assert!( - names.remove("allow-one-hash-in-raw-strings"), - "remove this when #11481 is fixed" - ); - - assert!( - names.is_empty(), - "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`" - ); - } -} diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 94a9a7c241b..58e66c9f9b9 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -5,27 +5,20 @@ use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{hygiene, Span}; use std::iter::once; use std::mem; use std::rc::Rc; -declare_clippy_lint! { - /// ### What it does - /// Collects [`rustc_ast::FormatArgs`] so that future late passes can call - /// [`clippy_utils::macros::find_format_args`] - pub FORMAT_ARGS_COLLECTOR, - internal_warn, - "collects `format_args` AST nodes for use in later lints" -} - +/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call +/// [`clippy_utils::macros::find_format_args`] #[derive(Default)] pub struct FormatArgsCollector { format_args: FxHashMap>, } -impl_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); +impl_lint_pass!(FormatArgsCollector => []); impl EarlyLintPass for FormatArgsCollector { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c8600badf18..01929e1ba10 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -9,7 +9,7 @@ use crate::renamed_lints::RENAMED_LINTS; use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; -use crate::utils::{collect_configs, ClippyConfiguration}; +use clippy_config::{get_configuration_metadata, ClippyConfiguration}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -155,7 +155,7 @@ impl MetadataCollector { Self { lints: BinaryHeap::::default(), applicability_info: FxHashMap::::default(), - config: collect_configs(), + config: get_configuration_metadata(), clippy_project_root: std::env::current_dir() .expect("failed to get current dir") .ancestors() @@ -528,16 +528,6 @@ impl Serialize for ApplicabilityInfo { } } -impl fmt::Display for ClippyConfiguration { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { - writeln!( - f, - "* `{}`: `{}`(defaults to `{}`): {}", - self.name, self.config_type, self.default, self.doc - ) - } -} - // ================================================================== // Lint pass // ================================================================== diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 4fef8c0717d..78096092a0e 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,122 +1,12 @@ pub mod author; -pub mod conf; pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] pub mod internal_lints; -#[cfg(feature = "internal")] -use itertools::Itertools; - -/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` -fn to_kebab(config_name: &str) -> String { - config_name.replace('_', "-") -} - -#[cfg(feature = "internal")] -const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html"; // ================================================================== // Configuration // ================================================================== -#[derive(Debug, Clone, Default)] -pub struct ClippyConfiguration { - pub name: String, - #[allow(dead_code)] - config_type: &'static str, - pub default: String, - pub lints: Vec, - pub doc: String, - #[allow(dead_code)] - deprecation_reason: Option<&'static str>, -} - -impl ClippyConfiguration { - pub fn new( - name: &'static str, - config_type: &'static str, - default: String, - doc_comment: &'static str, - deprecation_reason: Option<&'static str>, - ) -> Self { - let (lints, doc) = parse_config_field_doc(doc_comment) - .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); - - Self { - name: to_kebab(name), - lints, - doc, - config_type, - default, - deprecation_reason, - } - } - - #[cfg(feature = "internal")] - fn to_markdown_paragraph(&self) -> String { - format!( - "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n", - self.name, - self.doc - .lines() - .map(|line| line.strip_prefix(" ").unwrap_or(line)) - .join("\n"), - self.default, - self.config_type, - self.lints - .iter() - .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) - .join("\n"), - ) - } - #[cfg(feature = "internal")] - fn to_markdown_link(&self) -> String { - format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) - } -} - -#[cfg(feature = "internal")] -fn collect_configs() -> Vec { - crate::utils::conf::metadata::get_configuration_metadata() -} - -/// This parses the field documentation of the config struct. -/// -/// ```rust, ignore -/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") -/// ``` -/// -/// Would yield: -/// ```rust, ignore -/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") -/// ``` -fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec, String)> { - const DOC_START: &str = " Lint: "; - if_chain! { - if doc_comment.starts_with(DOC_START); - if let Some(split_pos) = doc_comment.find('.'); - then { - let mut doc_comment = doc_comment.to_string(); - let mut documentation = doc_comment.split_off(split_pos); - - // Extract lints - doc_comment.make_ascii_lowercase(); - let lints: Vec = doc_comment - .split_off(DOC_START.len()) - .split(", ") - .map(str::to_string) - .collect(); - - // Format documentation correctly - // split off leading `.` from lint name list and indent for correct formatting - documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); - - Some((lints, documentation)) - } else { - None - } - } -} // Shamelessly stolen from find_all (https://github.com/nectariner/find_all) pub trait FindAll: Iterator + Sized { diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 42a69fa1133..17294450acf 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,8 +1,8 @@ use std::ops::ControlFlow; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 90091ca927a..8c9cfbbd8fc 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -5,11 +5,11 @@ edition = "2021" publish = false [dependencies] +clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } if_chain = "1.0" itertools = "0.10.1" rustc-semver = "1.1" -serde = { version = "1.0" } [features] deny-warnings = [] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9fed6130a28..11467138a58 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -54,7 +54,6 @@ pub mod higher; mod hir_utils; pub mod macros; pub mod mir; -pub mod msrvs; pub mod numeric_literal; pub mod paths; pub mod ptr; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs deleted file mode 100644 index c6a48874e09..00000000000 --- a/clippy_utils/src/msrvs.rs +++ /dev/null @@ -1,130 +0,0 @@ -use rustc_ast::Attribute; -use rustc_semver::RustcVersion; -use rustc_session::Session; -use serde::Deserialize; - -use crate::attrs::get_unique_attr; - -macro_rules! msrv_aliases { - ($($major:literal,$minor:literal,$patch:literal { - $($name:ident),* $(,)? - })*) => { - $($( - pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch); - )*)* - }; -} - -// names may refer to stabilized feature flags or library items -msrv_aliases! { - 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } - 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } - 1,68,0 { PATH_MAIN_SEPARATOR_STR } - 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } - 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } - 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } - 1,55,0 { SEEK_REWIND } - 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } - 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } - 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } - 1,50,0 { BOOL_THEN, CLAMP } - 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } - 1,46,0 { CONST_IF_MATCH } - 1,45,0 { STR_STRIP_PREFIX } - 1,43,0 { LOG2_10, LOG10_2 } - 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS } - 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } - 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } - 1,38,0 { POINTER_CAST, REM_EUCLID } - 1,37,0 { TYPE_ALIAS_ENUM_VARIANTS } - 1,36,0 { ITERATOR_COPIED } - 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } - 1,34,0 { TRY_FROM } - 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } - 1,28,0 { FROM_BOOL } - 1,27,0 { ITERATOR_TRY_FOLD } - 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } - 1,24,0 { IS_ASCII_DIGIT } - 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } - 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } - 1,16,0 { STR_REPEAT } - 1,15,0 { MAYBE_BOUND_IN_WHERE } -} - -/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` -#[derive(Debug, Clone)] -pub struct Msrv { - stack: Vec, -} - -impl<'de> Deserialize<'de> for Msrv { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let v = String::deserialize(deserializer)?; - RustcVersion::parse(&v) - .map(|v| Msrv { stack: vec![v] }) - .map_err(|_| serde::de::Error::custom("not a valid Rust version")) - } -} - -impl Msrv { - pub fn empty() -> Msrv { - Msrv { stack: Vec::new() } - } - - pub fn read_cargo(&mut self, sess: &Session) { - let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") - .ok() - .and_then(|v| RustcVersion::parse(&v).ok()); - - match (self.current(), cargo_msrv) { - (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv], - (Some(clippy_msrv), Some(cargo_msrv)) => { - if clippy_msrv != cargo_msrv { - sess.warn(format!( - "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" - )); - } - }, - _ => {}, - } - } - - pub fn current(&self) -> Option { - self.stack.last().copied() - } - - pub fn meets(&self, required: RustcVersion) -> bool { - self.current().map_or(true, |version| version.meets(required)) - } - - fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option { - if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") { - if let Some(msrv) = msrv_attr.value_str() { - if let Ok(version) = RustcVersion::parse(msrv.as_str()) { - return Some(version); - } - - sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version")); - } else { - sess.span_err(msrv_attr.span, "bad clippy attribute"); - } - } - - None - } - - pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { - if let Some(version) = Self::parse_attr(sess, attrs) { - self.stack.push(version); - } - } - - pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) { - if Self::parse_attr(sess, attrs).is_some() { - self.stack.pop(); - } - } -} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 4a20399e364..0b0e8cdc9f4 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -53,7 +53,7 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; #[cfg(feature = "internal")] -pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; +pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index f6096ea546d..6cfd621d7f0 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -3,7 +3,7 @@ // of terminologies might not be relevant in the context of Clippy. Note that its behavior might // differ from the time of `rustc` even if the name stays the same. -use crate::msrvs::Msrv; +use clippy_config::msrvs::Msrv; use hir::LangItem; use rustc_const_eval::transform::check_consts::ConstCx; use rustc_hir as hir; diff --git a/src/driver.rs b/src/driver.rs index 0e81419f1fa..17d57c30f08 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -126,7 +126,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // JUSTIFICATION: necessary in clippy driver to set `mir_opt_level` #[allow(rustc::bad_opt_access)] fn config(&mut self, config: &mut interface::Config) { - let conf_path = clippy_lints::lookup_conf_file(); + let conf_path = clippy_config::lookup_conf_file(); let previous = config.register_lints.take(); let clippy_args_var = self.clippy_args_var.take(); config.parse_sess_created = Some(Box::new(move |parse_sess| { @@ -147,7 +147,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { (previous)(sess, lint_store); } - let conf = clippy_lints::Conf::read(sess, &conf_path); + let conf = clippy_config::Conf::read(sess, &conf_path); clippy_lints::register_plugins(lint_store, sess, conf); clippy_lints::register_pre_expansion_lints(lint_store, conf); clippy_lints::register_renamed(lint_store); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 1494c7d3179..3b7c974b65b 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -30,6 +30,7 @@ mod test_utils; /// All crates used in UI tests are listed here static TEST_DEPENDENCIES: &[&str] = &[ + "clippy_config", "clippy_lints", "clippy_utils", "futures", diff --git a/tests/dogfood.rs b/tests/dogfood.rs index afde31face1..59c7c53000b 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -56,7 +56,10 @@ fn run_metadata_collection_lint() { // Run collection as is std::env::set_var("ENABLE_METADATA_COLLECTION", "1"); - run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]); + assert!(run_clippy_for_package( + "clippy_lints", + &["-A", "unfulfilled_lint_expectations"] + )); // Check if cargo caching got in the way if let Ok(file) = File::open(metadata_output_path) { @@ -79,9 +82,13 @@ fn run_metadata_collection_lint() { .unwrap(); // Running the collection again - run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]); + assert!(run_clippy_for_package( + "clippy_lints", + &["-A", "unfulfilled_lint_expectations"] + )); } +#[must_use] fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 928596d0809..9b5bf736f13 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -8,8 +8,8 @@ extern crate rustc_lint; extern crate rustc_middle; #[macro_use] extern crate rustc_session; +use clippy_config::msrvs::Msrv; use clippy_utils::extract_msrv_attr; -use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index 50b28648ccc..c5bde47e4ce 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -8,8 +8,8 @@ extern crate rustc_lint; extern crate rustc_middle; #[macro_use] extern crate rustc_session; +use clippy_config::msrvs::Msrv; use clippy_utils::extract_msrv_attr; -use clippy_utils::msrvs::Msrv; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs index c8a0d664167..3917bb9e03d 100644 --- a/tests/ui/min_rust_version_invalid_attr.rs +++ b/tests/ui/min_rust_version_invalid_attr.rs @@ -11,13 +11,12 @@ fn outer_attr() {} mod multiple { #![clippy::msrv = "1.40"] #![clippy::msrv = "=1.35.0"] - //~^ ERROR: `msrv` is defined multiple times #![clippy::msrv = "1.10.1"] - //~^ ERROR: `msrv` is defined multiple times + //~^ ERROR: `clippy::msrv` is defined multiple times mod foo { #![clippy::msrv = "1"] #![clippy::msrv = "1.0.0"] - //~^ ERROR: `msrv` is defined multiple times + //~^ ERROR: `clippy::msrv` is defined multiple times } } diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr index 8d4071e258e..cf8392f0316 100644 --- a/tests/ui/min_rust_version_invalid_attr.stderr +++ b/tests/ui/min_rust_version_invalid_attr.stderr @@ -10,20 +10,8 @@ error: `invalid.version` is not a valid Rust version LL | #[clippy::msrv = "invalid.version"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `msrv` is defined multiple times - --> $DIR/min_rust_version_invalid_attr.rs:13:5 - | -LL | #![clippy::msrv = "=1.35.0"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: first definition found here - --> $DIR/min_rust_version_invalid_attr.rs:12:5 - | -LL | #![clippy::msrv = "1.40"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `msrv` is defined multiple times - --> $DIR/min_rust_version_invalid_attr.rs:15:5 +error: `clippy::msrv` is defined multiple times + --> $DIR/min_rust_version_invalid_attr.rs:14:5 | LL | #![clippy::msrv = "1.10.1"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,17 +22,17 @@ note: first definition found here LL | #![clippy::msrv = "1.40"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `msrv` is defined multiple times - --> $DIR/min_rust_version_invalid_attr.rs:20:9 +error: `clippy::msrv` is defined multiple times + --> $DIR/min_rust_version_invalid_attr.rs:19:9 | LL | #![clippy::msrv = "1.0.0"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first definition found here - --> $DIR/min_rust_version_invalid_attr.rs:19:9 + --> $DIR/min_rust_version_invalid_attr.rs:18:9 | LL | #![clippy::msrv = "1"] | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index c721e9969c9..eba5405e67e 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -26,6 +26,7 @@ fn consistent_clippy_crate_versions() { let paths = [ "declare_clippy_lint/Cargo.toml", + "clippy_config/Cargo.toml", "clippy_lints/Cargo.toml", "clippy_utils/Cargo.toml", ]; -- cgit 1.4.1-3-g733a5 From f8790963d9dd9fd4fd22456eef1cbfe2fb8cb12a Mon Sep 17 00:00:00 2001 From: Benoît du Garreau Date: Mon, 23 Oct 2023 14:41:10 +0200 Subject: Add a lint to check needless `Waker` clones --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 27 ++++++++++++++++++++++ clippy_lints/src/methods/waker_clone_wake.rs | 34 ++++++++++++++++++++++++++++ clippy_utils/src/paths.rs | 1 + tests/ui/waker_clone_wake.fixed | 22 ++++++++++++++++++ tests/ui/waker_clone_wake.rs | 22 ++++++++++++++++++ tests/ui/waker_clone_wake.stderr | 11 +++++++++ 8 files changed, 119 insertions(+) create mode 100644 clippy_lints/src/methods/waker_clone_wake.rs create mode 100644 tests/ui/waker_clone_wake.fixed create mode 100644 tests/ui/waker_clone_wake.rs create mode 100644 tests/ui/waker_clone_wake.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c9877dbff..b28075d8eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5589,6 +5589,7 @@ Released 2018-09-13 [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons +[`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 77438b27f90..9de4a8598b4 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -441,6 +441,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::USELESS_ASREF_INFO, crate::methods::VEC_RESIZE_TO_ZERO_INFO, crate::methods::VERBOSE_FILE_READS_INFO, + crate::methods::WAKER_CLONE_WAKE_INFO, crate::methods::WRONG_SELF_CONVENTION_INFO, crate::methods::ZST_OFFSET_INFO, crate::min_ident_chars::MIN_IDENT_CHARS_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a935aea5075..9c8d2711c3d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -112,6 +112,7 @@ mod useless_asref; mod utils; mod vec_resize_to_zero; mod verbose_file_reads; +mod waker_clone_wake; mod wrong_self_convention; mod zst_offset; @@ -3632,6 +3633,28 @@ declare_clippy_lint! { "`as_str` used to call a method on `str` that is also available on `String`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `waker.clone().wake()` + /// + /// ### Why is this bad? + /// Cloning the waker is not necessary, `wake_by_ref()` enables the same operation + /// without extra cloning/dropping. + /// + /// ### Example + /// ```rust,ignore + /// waker.clone().wake(); + /// ``` + /// Should be written + /// ```rust,ignore + /// waker.wake_by_ref(); + /// ``` + #[clippy::version = "1.75.0"] + pub WAKER_CLONE_WAKE, + perf, + "cloning a `Waker` only to wake it" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3777,6 +3800,7 @@ impl_lint_pass!(Methods => [ ITER_OUT_OF_BOUNDS, PATH_ENDS_WITH_EXT, REDUNDANT_AS_STR, + WAKER_CLONE_WAKE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4365,6 +4389,9 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, + ("wake", []) => { + waker_clone_wake::check(cx, expr, recv); + } ("write", []) => { readonly_write_lock::check(cx, expr, recv); } diff --git a/clippy_lints/src/methods/waker_clone_wake.rs b/clippy_lints/src/methods/waker_clone_wake.rs new file mode 100644 index 00000000000..db13266db80 --- /dev/null +++ b/clippy_lints/src/methods/waker_clone_wake.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::WAKER_CLONE_WAKE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + let ty = cx.typeck_results().expr_ty(recv); + + if let Some(did) = ty.ty_adt_def() + && match_def_path(cx, did.did(), &paths::WAKER) + && let ExprKind::MethodCall(func, waker_ref, &[], _) = recv.kind + && func.ident.name == sym::clone + { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + WAKER_CLONE_WAKE, + expr.span, + "cloning a `Waker` only to wake it", + "replace with", + format!( + "{}.wake_by_ref()", + snippet_with_applicability(cx, waker_ref.span, "..", &mut applicability) + ), + applicability, + ); + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 4a20399e364..2cf7e2cde96 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -112,6 +112,7 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; +pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so diff --git a/tests/ui/waker_clone_wake.fixed b/tests/ui/waker_clone_wake.fixed new file mode 100644 index 00000000000..2df52f57d65 --- /dev/null +++ b/tests/ui/waker_clone_wake.fixed @@ -0,0 +1,22 @@ +#[derive(Clone)] +pub struct Custom; + +impl Custom { + pub fn wake(self) {} +} + +pub fn wake(cx: &mut std::task::Context) { + cx.waker().wake_by_ref(); + + // We don't do that for now + let w = cx.waker().clone(); + w.wake(); + + cx.waker().clone().wake_by_ref(); +} + +pub fn no_lint(c: &Custom) { + c.clone().wake() +} + +fn main() {} diff --git a/tests/ui/waker_clone_wake.rs b/tests/ui/waker_clone_wake.rs new file mode 100644 index 00000000000..4fe354b0ef1 --- /dev/null +++ b/tests/ui/waker_clone_wake.rs @@ -0,0 +1,22 @@ +#[derive(Clone)] +pub struct Custom; + +impl Custom { + pub fn wake(self) {} +} + +pub fn wake(cx: &mut std::task::Context) { + cx.waker().clone().wake(); + + // We don't do that for now + let w = cx.waker().clone(); + w.wake(); + + cx.waker().clone().wake_by_ref(); +} + +pub fn no_lint(c: &Custom) { + c.clone().wake() +} + +fn main() {} diff --git a/tests/ui/waker_clone_wake.stderr b/tests/ui/waker_clone_wake.stderr new file mode 100644 index 00000000000..426a577e620 --- /dev/null +++ b/tests/ui/waker_clone_wake.stderr @@ -0,0 +1,11 @@ +error: cloning a `Waker` only to wake it + --> $DIR/waker_clone_wake.rs:9:5 + | +LL | cx.waker().clone().wake(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `cx.waker().wake_by_ref()` + | + = note: `-D clippy::waker-clone-wake` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::waker_clone_wake)]` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From ebf6667b571568e88e4b8934013515cb69db74e8 Mon Sep 17 00:00:00 2001 From: Benoît du Garreau Date: Wed, 25 Oct 2023 15:15:29 +0200 Subject: Apply suggestions --- clippy_lints/src/methods/waker_clone_wake.rs | 12 +++++------- tests/ui/waker_clone_wake.fixed | 17 ++++++++++++----- tests/ui/waker_clone_wake.rs | 17 ++++++++++++----- tests/ui/waker_clone_wake.stderr | 10 ++++++++-- 4 files changed, 37 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/waker_clone_wake.rs b/clippy_lints/src/methods/waker_clone_wake.rs index db13266db80..da66632d55f 100644 --- a/clippy_lints/src/methods/waker_clone_wake.rs +++ b/clippy_lints/src/methods/waker_clone_wake.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{match_def_path, paths}; +use clippy_utils::{is_trait_method, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -13,10 +13,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' if let Some(did) = ty.ty_adt_def() && match_def_path(cx, did.did(), &paths::WAKER) - && let ExprKind::MethodCall(func, waker_ref, &[], _) = recv.kind - && func.ident.name == sym::clone + && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind + && is_trait_method(cx, recv, sym::Clone) { let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, waker_ref.span.source_callsite(), "..", &mut applicability); span_lint_and_sugg( cx, @@ -24,10 +25,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' expr.span, "cloning a `Waker` only to wake it", "replace with", - format!( - "{}.wake_by_ref()", - snippet_with_applicability(cx, waker_ref.span, "..", &mut applicability) - ), + format!("{snippet}.wake_by_ref()"), applicability, ); } diff --git a/tests/ui/waker_clone_wake.fixed b/tests/ui/waker_clone_wake.fixed index 2df52f57d65..9c02b9a90fd 100644 --- a/tests/ui/waker_clone_wake.fixed +++ b/tests/ui/waker_clone_wake.fixed @@ -5,18 +5,25 @@ impl Custom { pub fn wake(self) {} } +macro_rules! mac { + ($cx:ident) => { + $cx.waker() + }; +} + pub fn wake(cx: &mut std::task::Context) { cx.waker().wake_by_ref(); - // We don't do that for now + mac!(cx).wake_by_ref(); +} + +pub fn no_lint(cx: &mut std::task::Context, c: &Custom) { + c.clone().wake(); + let w = cx.waker().clone(); w.wake(); cx.waker().clone().wake_by_ref(); } -pub fn no_lint(c: &Custom) { - c.clone().wake() -} - fn main() {} diff --git a/tests/ui/waker_clone_wake.rs b/tests/ui/waker_clone_wake.rs index 4fe354b0ef1..edc3bbd8fc0 100644 --- a/tests/ui/waker_clone_wake.rs +++ b/tests/ui/waker_clone_wake.rs @@ -5,18 +5,25 @@ impl Custom { pub fn wake(self) {} } +macro_rules! mac { + ($cx:ident) => { + $cx.waker() + }; +} + pub fn wake(cx: &mut std::task::Context) { cx.waker().clone().wake(); - // We don't do that for now + mac!(cx).clone().wake(); +} + +pub fn no_lint(cx: &mut std::task::Context, c: &Custom) { + c.clone().wake(); + let w = cx.waker().clone(); w.wake(); cx.waker().clone().wake_by_ref(); } -pub fn no_lint(c: &Custom) { - c.clone().wake() -} - fn main() {} diff --git a/tests/ui/waker_clone_wake.stderr b/tests/ui/waker_clone_wake.stderr index 426a577e620..f1abf4d9cb0 100644 --- a/tests/ui/waker_clone_wake.stderr +++ b/tests/ui/waker_clone_wake.stderr @@ -1,5 +1,5 @@ error: cloning a `Waker` only to wake it - --> $DIR/waker_clone_wake.rs:9:5 + --> $DIR/waker_clone_wake.rs:15:5 | LL | cx.waker().clone().wake(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `cx.waker().wake_by_ref()` @@ -7,5 +7,11 @@ LL | cx.waker().clone().wake(); = note: `-D clippy::waker-clone-wake` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::waker_clone_wake)]` -error: aborting due to previous error +error: cloning a `Waker` only to wake it + --> $DIR/waker_clone_wake.rs:17:5 + | +LL | mac!(cx).clone().wake(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `mac!(cx).wake_by_ref()` + +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 69c3b9c2523290f07713efdbfb4dc4a0369416b1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 15 Oct 2023 00:57:33 +0200 Subject: new lint: `unnecessary_fallible_conversions` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/implicit_saturating_add.rs | 24 ++--- clippy_lints/src/methods/mod.rs | 33 ++++++ .../methods/unnecessary_fallible_conversions.rs | 119 +++++++++++++++++++++ tests/ui/manual_string_new.fixed | 1 + tests/ui/manual_string_new.rs | 1 + tests/ui/manual_string_new.stderr | 18 ++-- tests/ui/unnecessary_fallible_conversions.fixed | 6 ++ tests/ui/unnecessary_fallible_conversions.rs | 6 ++ tests/ui/unnecessary_fallible_conversions.stderr | 17 +++ .../unnecessary_fallible_conversions_unfixable.rs | 43 ++++++++ ...necessary_fallible_conversions_unfixable.stderr | 41 +++++++ tests/ui/useless_conversion_try.rs | 2 +- 14 files changed, 291 insertions(+), 22 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_fallible_conversions.rs create mode 100644 tests/ui/unnecessary_fallible_conversions.fixed create mode 100644 tests/ui/unnecessary_fallible_conversions.rs create mode 100644 tests/ui/unnecessary_fallible_conversions.stderr create mode 100644 tests/ui/unnecessary_fallible_conversions_unfixable.rs create mode 100644 tests/ui/unnecessary_fallible_conversions_unfixable.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index b28075d8eb3..993406b692c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5528,6 +5528,7 @@ Released 2018-09-13 [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints [`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast +[`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 8a341513303..d9c97a8cc97 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -430,6 +430,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::TYPE_ID_ON_BOX_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, crate::methods::UNIT_HASH_INFO, + crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, crate::methods::UNNECESSARY_FOLD_INFO, diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index 453797f1853..24f62490f96 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -82,18 +82,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { fn get_int_max(ty: Ty<'_>) -> Option { match ty.peel_refs().kind() { - Int(IntTy::I8) => i8::max_value().try_into().ok(), - Int(IntTy::I16) => i16::max_value().try_into().ok(), - Int(IntTy::I32) => i32::max_value().try_into().ok(), - Int(IntTy::I64) => i64::max_value().try_into().ok(), - Int(IntTy::I128) => i128::max_value().try_into().ok(), - Int(IntTy::Isize) => isize::max_value().try_into().ok(), - Uint(UintTy::U8) => u8::max_value().try_into().ok(), - Uint(UintTy::U16) => u16::max_value().try_into().ok(), - Uint(UintTy::U32) => u32::max_value().try_into().ok(), - Uint(UintTy::U64) => u64::max_value().try_into().ok(), - Uint(UintTy::U128) => Some(u128::max_value()), - Uint(UintTy::Usize) => usize::max_value().try_into().ok(), + Int(IntTy::I8) => i8::MAX.try_into().ok(), + Int(IntTy::I16) => i16::MAX.try_into().ok(), + Int(IntTy::I32) => i32::MAX.try_into().ok(), + Int(IntTy::I64) => i64::MAX.try_into().ok(), + Int(IntTy::I128) => i128::MAX.try_into().ok(), + Int(IntTy::Isize) => isize::MAX.try_into().ok(), + Uint(UintTy::U8) => Some(u8::MAX.into()), + Uint(UintTy::U16) => Some(u16::MAX.into()), + Uint(UintTy::U32) => Some(u32::MAX.into()), + Uint(UintTy::U64) => Some(u64::MAX.into()), + Uint(UintTy::U128) => Some(u128::MAX), + Uint(UintTy::Usize) => usize::MAX.try_into().ok(), _ => None, } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e1a14e29358..90f6bc5e3d3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -99,6 +99,7 @@ mod suspicious_to_owned; mod type_id_on_box; mod uninit_assumed_init; mod unit_hash; +mod unnecessary_fallible_conversions; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; @@ -3655,6 +3656,33 @@ declare_clippy_lint! { "cloning a `Waker` only to wake it" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `TryInto::try_into` and `TryFrom::try_from` when their infallible counterparts + /// could be used. + /// + /// ### Why is this bad? + /// In those cases, the `TryInto` and `TryFrom` trait implementation is a blanket impl that forwards + /// to `Into` or `From`, which always succeeds. + /// The returned `Result<_, Infallible>` requires error handling to get the contained value + /// even though the conversion can never fail. + /// + /// ### Example + /// ```rust + /// let _: Result = 1i32.try_into(); + /// let _: Result = <_>::try_from(1i32); + /// ``` + /// Use `from`/`into` instead: + /// ```rust + /// let _: i64 = 1i32.into(); + /// let _: i64 = <_>::from(1i32); + /// ``` + #[clippy::version = "1.75.0"] + pub UNNECESSARY_FALLIBLE_CONVERSIONS, + style, + "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3801,6 +3829,7 @@ impl_lint_pass!(Methods => [ PATH_ENDS_WITH_EXT, REDUNDANT_AS_STR, WAKER_CLONE_WAKE, + UNNECESSARY_FALLIBLE_CONVERSIONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3827,6 +3856,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); + unnecessary_fallible_conversions::check_function(cx, expr, func); }, hir::ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; @@ -4316,6 +4346,9 @@ impl Methods { } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, + ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { + unnecessary_fallible_conversions::check_method(cx, expr); + } ("to_owned", []) => { if !suspicious_to_owned::check(cx, expr, recv) { implicit_clone::check(cx, name, expr, recv); diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs new file mode 100644 index 00000000000..6660ad215d8 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -0,0 +1,119 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::UNNECESSARY_FALLIBLE_CONVERSIONS; + +/// What function is being called and whether that call is written as a method call or a function +/// call +#[derive(Copy, Clone)] +#[expect(clippy::enum_variant_names)] +enum FunctionKind { + /// `T::try_from(U)` + TryFromFunction, + /// `t.try_into()` + TryIntoMethod, + /// `U::try_into(t)` + TryIntoFunction, +} + +fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'_>, + node_args: ty::GenericArgsRef<'tcx>, + kind: FunctionKind, + primary_span: Span, +) { + if let &[self_ty, other_ty] = node_args.as_slice() + // useless_conversion already warns `T::try_from(T)`, so ignore it here + && self_ty != other_ty + && let Some(self_ty) = self_ty.as_type() + && let Some(from_into_trait) = cx.tcx.get_diagnostic_item(match kind { + FunctionKind::TryFromFunction => sym::From, + FunctionKind::TryIntoMethod | FunctionKind::TryIntoFunction => sym::Into, + }) + // If `T: TryFrom` and `T: From` both exist, then that means that the `TryFrom` + // _must_ be from the blanket impl and cannot have been manually implemented + // (else there would be conflicting impls, even with #![feature(spec)]), so we don't even need to check + // what `>::Error` is: it's always `Infallible` + && implements_trait(cx, self_ty, from_into_trait, &[other_ty]) + { + let parent_unwrap_call = get_parent_expr(cx, expr) + .and_then(|parent| { + if let ExprKind::MethodCall(path, .., span) = parent.kind + && let sym::unwrap | sym::expect = path.ident.name + { + Some(span) + } else { + None + } + }); + + let (sugg, span, applicability) = match kind { + FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => { + // Extend the span to include the unwrap/expect call: + // `foo.try_into().expect("..")` + // ^^^^^^^^^^^^^^^^^^^^^^^ + // + // `try_into().unwrap()` specifically can be trivially replaced with just `into()`, + // so that can be machine-applicable + + ("into()", primary_span.with_hi(unwrap_span.hi()), Applicability::MachineApplicable) + } + FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified), + FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified), + FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified), + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FALLIBLE_CONVERSIONS, + span, + "use of a fallible conversion when an infallible one could be used", + "use", + sugg.into(), + applicability + ); + } +} + +/// Checks method call exprs: +/// - `0i32.try_into()` +pub(super) fn check_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(path, ..) = expr.kind { + check( + cx, + expr, + cx.typeck_results().node_args(expr.hir_id), + FunctionKind::TryIntoMethod, + path.ident.span, + ); + } +} + +/// Checks function call exprs: +/// - `>::try_from(0i32)` +/// - `<_ as TryInto>::try_into(0i32)` +pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Expr<'_>) { + if let ExprKind::Path(ref qpath) = callee.kind + && let Some(item_def_id) = cx.qpath_res(qpath, callee.hir_id).opt_def_id() + && let Some(trait_def_id) = cx.tcx.trait_of_item(item_def_id) + { + check( + cx, + expr, + cx.typeck_results().node_args(callee.hir_id), + match cx.tcx.get_diagnostic_name(trait_def_id) { + Some(sym::TryFrom) => FunctionKind::TryFromFunction, + Some(sym::TryInto) => FunctionKind::TryIntoFunction, + _ => return, + }, + callee.span, + ); + } +} diff --git a/tests/ui/manual_string_new.fixed b/tests/ui/manual_string_new.fixed index 273be4e0fd2..2d4c5a02915 100644 --- a/tests/ui/manual_string_new.fixed +++ b/tests/ui/manual_string_new.fixed @@ -1,4 +1,5 @@ #![warn(clippy::manual_string_new)] +#![allow(clippy::unnecessary_fallible_conversions)] macro_rules! create_strings_from_macro { // When inside a macro, nothing should warn to prevent false positives. diff --git a/tests/ui/manual_string_new.rs b/tests/ui/manual_string_new.rs index 0d5514fc893..20f0be6aaf9 100644 --- a/tests/ui/manual_string_new.rs +++ b/tests/ui/manual_string_new.rs @@ -1,4 +1,5 @@ #![warn(clippy::manual_string_new)] +#![allow(clippy::unnecessary_fallible_conversions)] macro_rules! create_strings_from_macro { // When inside a macro, nothing should warn to prevent false positives. diff --git a/tests/ui/manual_string_new.stderr b/tests/ui/manual_string_new.stderr index 399652d3fec..cb2d78c39ed 100644 --- a/tests/ui/manual_string_new.stderr +++ b/tests/ui/manual_string_new.stderr @@ -1,5 +1,5 @@ error: empty String is being created manually - --> $DIR/manual_string_new.rs:13:13 + --> $DIR/manual_string_new.rs:14:13 | LL | let _ = "".to_string(); | ^^^^^^^^^^^^^^ help: consider using: `String::new()` @@ -8,49 +8,49 @@ LL | let _ = "".to_string(); = help: to override `-D warnings` add `#[allow(clippy::manual_string_new)]` error: empty String is being created manually - --> $DIR/manual_string_new.rs:16:13 + --> $DIR/manual_string_new.rs:17:13 | LL | let _ = "".to_owned(); | ^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:19:21 + --> $DIR/manual_string_new.rs:20:21 | LL | let _: String = "".into(); | ^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:26:13 + --> $DIR/manual_string_new.rs:27:13 | LL | let _ = String::from(""); | ^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:27:13 + --> $DIR/manual_string_new.rs:28:13 | LL | let _ = ::from(""); | ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:32:13 + --> $DIR/manual_string_new.rs:33:13 | LL | let _ = String::try_from("").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:38:21 + --> $DIR/manual_string_new.rs:39:21 | LL | let _: String = From::from(""); | ^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:43:21 + --> $DIR/manual_string_new.rs:44:21 | LL | let _: String = TryFrom::try_from("").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> $DIR/manual_string_new.rs:46:21 + --> $DIR/manual_string_new.rs:47:21 | LL | let _: String = TryFrom::try_from("").expect("this should warn"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` diff --git a/tests/ui/unnecessary_fallible_conversions.fixed b/tests/ui/unnecessary_fallible_conversions.fixed new file mode 100644 index 00000000000..9668a6b99bf --- /dev/null +++ b/tests/ui/unnecessary_fallible_conversions.fixed @@ -0,0 +1,6 @@ +#![warn(clippy::unnecessary_fallible_conversions)] + +fn main() { + let _: i64 = 0i32.into(); + let _: i64 = 0i32.into(); +} diff --git a/tests/ui/unnecessary_fallible_conversions.rs b/tests/ui/unnecessary_fallible_conversions.rs new file mode 100644 index 00000000000..9fa6c08b1b0 --- /dev/null +++ b/tests/ui/unnecessary_fallible_conversions.rs @@ -0,0 +1,6 @@ +#![warn(clippy::unnecessary_fallible_conversions)] + +fn main() { + let _: i64 = 0i32.try_into().unwrap(); + let _: i64 = 0i32.try_into().expect("can't happen"); +} diff --git a/tests/ui/unnecessary_fallible_conversions.stderr b/tests/ui/unnecessary_fallible_conversions.stderr new file mode 100644 index 00000000000..b918fdf774b --- /dev/null +++ b/tests/ui/unnecessary_fallible_conversions.stderr @@ -0,0 +1,17 @@ +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions.rs:4:23 + | +LL | let _: i64 = 0i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: use: `into()` + | + = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions.rs:5:23 + | +LL | let _: i64 = 0i32.try_into().expect("can't happen"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `into()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/unnecessary_fallible_conversions_unfixable.rs b/tests/ui/unnecessary_fallible_conversions_unfixable.rs new file mode 100644 index 00000000000..68e617cc062 --- /dev/null +++ b/tests/ui/unnecessary_fallible_conversions_unfixable.rs @@ -0,0 +1,43 @@ +//@aux-build:proc_macros.rs +//@no-rustfix +#![warn(clippy::unnecessary_fallible_conversions)] + +extern crate proc_macros; + +struct Foo; +impl TryFrom for Foo { + type Error = (); + fn try_from(_: i32) -> Result { + Ok(Foo) + } +} +impl From for Foo { + fn from(_: i64) -> Self { + Foo + } +} + +fn main() { + // `Foo` only implements `TryFrom` and not `From`, so don't lint + let _: Result = 0i32.try_into(); + let _: Result = i32::try_into(0i32); + let _: Result = Foo::try_from(0i32); + + // ... it does impl From however + let _: Result = 0i64.try_into(); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result = i64::try_into(0i64); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result = Foo::try_from(0i64); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + + let _: Result = 0i32.try_into(); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result = i32::try_into(0i32); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + let _: Result = <_>::try_from(0i32); + //~^ ERROR: use of a fallible conversion when an infallible one could be used + + // From a macro + let _: Result = proc_macros::external!(0i32).try_into(); +} diff --git a/tests/ui/unnecessary_fallible_conversions_unfixable.stderr b/tests/ui/unnecessary_fallible_conversions_unfixable.stderr new file mode 100644 index 00000000000..286decf8f35 --- /dev/null +++ b/tests/ui/unnecessary_fallible_conversions_unfixable.stderr @@ -0,0 +1,41 @@ +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:27:34 + | +LL | let _: Result = 0i64.try_into(); + | ^^^^^^^^ help: use: `into` + | + = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:29:29 + | +LL | let _: Result = i64::try_into(0i64); + | ^^^^^^^^^^^^^ help: use: `Into::into` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:31:29 + | +LL | let _: Result = Foo::try_from(0i64); + | ^^^^^^^^^^^^^ help: use: `From::from` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:34:34 + | +LL | let _: Result = 0i32.try_into(); + | ^^^^^^^^ help: use: `into` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:36:29 + | +LL | let _: Result = i32::try_into(0i32); + | ^^^^^^^^^^^^^ help: use: `Into::into` + +error: use of a fallible conversion when an infallible one could be used + --> $DIR/unnecessary_fallible_conversions_unfixable.rs:38:29 + | +LL | let _: Result = <_>::try_from(0i32); + | ^^^^^^^^^^^^^ help: use: `From::from` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index a5feefbe0f0..803d3b39f37 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -1,5 +1,5 @@ #![deny(clippy::useless_conversion)] -#![allow(clippy::needless_if)] +#![allow(clippy::needless_if, clippy::unnecessary_fallible_conversions)] fn test_generic(val: T) -> T { let _ = T::try_from(val).unwrap(); -- cgit 1.4.1-3-g733a5 From bb9cc6d47c11d33087d5776ecc261b95c6dace74 Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Wed, 1 Nov 2023 14:10:42 +0100 Subject: refactor: extract common pat_is_wild to clippy_utils This function was previously defined for the iter_kv_map, for_kw_map, and unused_enumerate_index lints. This commit extracts it into clippy_utils. --- clippy_lints/src/loops/for_kv_map.rs | 12 +----------- clippy_lints/src/loops/unused_enumerate_index.rs | 12 +----------- clippy_lints/src/methods/iter_kv_map.rs | 13 +------------ clippy_utils/src/lib.rs | 12 ++++++++++++ 4 files changed, 15 insertions(+), 34 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index ed620460dbe..94c951fc10a 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,9 +1,8 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -55,12 +54,3 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx } } } - -/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index 18b73f77e81..62a2ab1ccb4 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,8 +1,7 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; -use clippy_utils::sugg; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; @@ -61,12 +60,3 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx }, ); } - -/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index b44a2716dde..625325d4cf5 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -3,9 +3,8 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::is_local_used; +use clippy_utils::{pat_is_wild, sugg}; use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; @@ -84,13 +83,3 @@ pub(super) fn check<'tcx>( } } } - -/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` -/// that is not locally used. -fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id), - _ => false, - } -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 11467138a58..7497d4b2cf1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2960,3 +2960,15 @@ op_utils! { Shl ShlAssign Shr ShrAssign } + +/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_` +/// that is not locally used. +pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool { + match *pat { + PatKind::Wild => true, + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { + !visitors::is_local_used(cx, body, id) + }, + _ => false, + } +} -- cgit 1.4.1-3-g733a5 From 3b759bce9d01c27d776af54bc69784c79af06048 Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Wed, 1 Nov 2023 23:26:43 +0100 Subject: fix get_first false negative for VecDeque --- clippy_lints/src/methods/get_first.rs | 22 ++++++++++++++++++++++ tests/ui/get_first.fixed | 5 ++++- tests/ui/get_first.rs | 5 ++++- tests/ui/get_first.stderr | 10 ++++++++-- 4 files changed, 38 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index e7b4564c651..855246d8c9f 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Spanned; +use rustc_span::sym; use super::GET_FIRST; @@ -34,4 +36,24 @@ pub(super) fn check<'tcx>( ); } } + + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::VecDeque); + if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; + then { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.front()"), + app, + ); + } + } } diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index a7cdd2a93ba..710ebab1ef2 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -32,9 +32,12 @@ fn main() { let _ = z[0]; let vecdeque: VecDeque<_> = x.iter().cloned().collect(); + let _ = vecdeque.front(); + //~^ ERROR: accessing first element with `vecdeque.get(0)` + let _ = vecdeque.get(1); + let hashmap: HashMap = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); let btreemap: BTreeMap = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]); - let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice. let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice. let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice. diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index cca743c4bf5..ad2ba6ce2c3 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -32,9 +32,12 @@ fn main() { let _ = z[0]; let vecdeque: VecDeque<_> = x.iter().cloned().collect(); + let _ = vecdeque.get(0); + //~^ ERROR: accessing first element with `vecdeque.get(0)` + let _ = vecdeque.get(1); + let hashmap: HashMap = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); let btreemap: BTreeMap = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]); - let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice. let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice. let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice. diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr index 8ee66e33cc8..7474a2ada66 100644 --- a/tests/ui/get_first.stderr +++ b/tests/ui/get_first.stderr @@ -19,11 +19,17 @@ error: accessing first element with `z.get(0)` LL | let _ = z.get(0); | ^^^^^^^^ help: try: `z.first()` +error: accessing first element with `vecdeque.get(0)` + --> $DIR/get_first.rs:35:13 + | +LL | let _ = vecdeque.get(0); + | ^^^^^^^^^^^^^^^ help: try: `vecdeque.front()` + error: accessing first element with `non_primitives.get(0)` - --> $DIR/get_first.rs:45:13 + --> $DIR/get_first.rs:48:13 | LL | let _ = non_primitives.get(0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -- cgit 1.4.1-3-g733a5 From 61c76dd4ffd8c96acb45bfcd290f95ae0938513e Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Wed, 1 Nov 2023 23:35:28 +0100 Subject: remove code duplication --- clippy_lints/src/methods/get_first.rs | 38 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index 855246d8c9f..2e1dd3ec649 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -20,30 +20,23 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).instantiate_identity().is_slice(); + let identity = cx.tcx.type_of(impl_id).instantiate_identity(); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { - let mut app = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), - "try", - format!("{slice_name}.first()"), - app, - ); - } - } - - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::VecDeque); - if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; - then { - let mut app = Applicability::MachineApplicable; + if identity.is_slice() { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.first()"), + app, + ); + } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){ + let mut app = Applicability::MachineApplicable; let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); span_lint_and_sugg( cx, @@ -54,6 +47,7 @@ pub(super) fn check<'tcx>( format!("{slice_name}.front()"), app, ); + } } } } -- cgit 1.4.1-3-g733a5 From 62a82b361c02838afdf607d461726e0407f1a5ec Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 2 Nov 2023 17:12:25 +0100 Subject: Format let-chains across the code base In the updated nightly version, it seems that rustfmt now supports formatting let-chains. Since we're using them a lot, it's a lot of reformatting. --- clippy_lints/src/almost_complete_range.rs | 25 +-- clippy_lints/src/arc_with_non_send_sync.rs | 24 +-- clippy_lints/src/assertions_on_result_states.rs | 6 +- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/attrs.rs | 35 +++- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/bool_to_int_with_if.rs | 25 +-- clippy_lints/src/booleans.rs | 13 +- clippy_lints/src/box_default.rs | 15 +- clippy_lints/src/casts/as_ptr_cast_mut.rs | 17 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 9 +- clippy_lints/src/casts/unnecessary_cast.rs | 17 +- clippy_lints/src/default_instead_of_iter_empty.rs | 5 +- clippy_lints/src/dereference.rs | 45 +++-- clippy_lints/src/doc.rs | 13 +- clippy_lints/src/drop_forget_ref.rs | 8 +- clippy_lints/src/empty_structs_with_brackets.rs | 8 +- clippy_lints/src/equatable_if_let.rs | 7 +- clippy_lints/src/error_impl_error.rs | 28 +-- clippy_lints/src/eta_reduction.rs | 66 +++---- clippy_lints/src/excessive_bools.rs | 9 +- clippy_lints/src/explicit_write.rs | 17 +- clippy_lints/src/extra_unused_type_parameters.rs | 28 +-- clippy_lints/src/format.rs | 9 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/format_push_string.rs | 12 +- clippy_lints/src/from_over_into.rs | 8 +- clippy_lints/src/from_raw_with_void_ptr.rs | 22 ++- clippy_lints/src/functions/must_use.rs | 7 +- clippy_lints/src/functions/result.rs | 4 +- clippy_lints/src/if_then_some_else_none.rs | 15 +- clippy_lints/src/implied_bounds_in_impls.rs | 78 ++++---- clippy_lints/src/items_after_test_module.rs | 9 +- clippy_lints/src/iter_without_into_iter.rs | 32 ++-- clippy_lints/src/large_stack_arrays.rs | 52 ++--- clippy_lints/src/len_zero.rs | 35 ++-- clippy_lints/src/let_underscore.rs | 19 +- clippy_lints/src/lifetimes.rs | 8 +- clippy_lints/src/lines_filter_map_ok.rs | 49 +++-- clippy_lints/src/loops/explicit_iter_loop.rs | 38 ++-- clippy_lints/src/loops/never_loop.rs | 6 +- clippy_lints/src/manual_assert.rs | 14 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_clamp.rs | 70 +++---- clippy_lints/src/manual_float_methods.rs | 74 ++++--- clippy_lints/src/manual_hash_one.rs | 5 +- clippy_lints/src/manual_is_ascii_check.rs | 14 +- clippy_lints/src/manual_let_else.rs | 37 ++-- clippy_lints/src/manual_main_separator_str.rs | 42 ++-- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 45 ++--- clippy_lints/src/manual_retain.rs | 44 +++-- clippy_lints/src/manual_string_new.rs | 29 ++- clippy_lints/src/matches/manual_filter.rs | 20 +- clippy_lints/src/matches/redundant_guards.rs | 39 +--- clippy_lints/src/matches/single_match.rs | 3 +- clippy_lints/src/methods/bytes_nth.rs | 11 +- clippy_lints/src/methods/filter_map.rs | 30 +-- clippy_lints/src/methods/filter_map_bool_then.rs | 2 +- clippy_lints/src/methods/format_collect.rs | 16 +- clippy_lints/src/methods/get_unwrap.rs | 6 +- clippy_lints/src/methods/iter_out_of_bounds.rs | 2 +- clippy_lints/src/methods/iter_overeager_cloned.rs | 88 ++++----- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/mod.rs | 212 ++++++++++++++------- clippy_lints/src/methods/needless_collect.rs | 37 ++-- clippy_lints/src/methods/or_fun_call.rs | 6 +- clippy_lints/src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/methods/read_line_without_trim.rs | 9 +- clippy_lints/src/methods/readonly_write_lock.rs | 21 +- clippy_lints/src/methods/seek_from_current.rs | 18 +- .../src/methods/seek_to_start_instead_of_rewind.rs | 18 +- clippy_lints/src/methods/str_splitn.rs | 16 +- clippy_lints/src/methods/string_lit_chars_any.rs | 2 +- .../src/methods/suspicious_command_arg_space.rs | 7 +- clippy_lints/src/methods/type_id_on_box.rs | 4 +- .../methods/unnecessary_fallible_conversions.rs | 29 +-- .../src/methods/unnecessary_literal_unwrap.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 87 +++++---- clippy_lints/src/min_ident_chars.rs | 8 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/missing_asserts_for_indexing.rs | 23 ++- clippy_lints/src/needless_bool.rs | 8 +- .../src/needless_borrows_for_generic_args.rs | 37 ++-- .../src/needless_parens_on_range_literals.rs | 6 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 11 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/no_effect.rs | 11 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 3 +- clippy_lints/src/non_canonical_impls.rs | 25 +-- clippy_lints/src/only_used_in_recursion.rs | 15 +- .../src/operators/arithmetic_side_effects.rs | 16 +- clippy_lints/src/operators/eq_op.rs | 19 +- clippy_lints/src/option_env_unwrap.rs | 23 ++- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 5 +- clippy_lints/src/permissions_set_readonly_false.rs | 8 +- clippy_lints/src/ptr.rs | 185 +++++++++--------- clippy_lints/src/pub_use.rs | 23 +-- clippy_lints/src/question_mark.rs | 19 +- clippy_lints/src/read_zero_byte_vec.rs | 23 ++- clippy_lints/src/redundant_async_block.rs | 24 +-- clippy_lints/src/redundant_closure_call.rs | 21 +- clippy_lints/src/redundant_type_annotations.rs | 20 +- clippy_lints/src/ref_patterns.rs | 2 +- clippy_lints/src/reserve_after_initialization.rs | 37 ++-- clippy_lints/src/same_name_method.rs | 14 +- clippy_lints/src/significant_drop_tightening.rs | 33 ++-- clippy_lints/src/std_instead_of_core.rs | 21 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 29 ++- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/swap_ptr_to_ref.rs | 14 +- .../src/transmute/transmute_undefined_repr.rs | 22 +-- clippy_lints/src/transmute/transmuting_null.rs | 12 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 16 +- clippy_lints/src/unit_types/let_unit_value.rs | 11 +- clippy_lints/src/unnecessary_map_on_constructor.rs | 30 +-- .../src/unnecessary_struct_initialization.rs | 16 +- clippy_lints/src/unused_peekable.rs | 10 +- clippy_lints/src/unused_rounding.rs | 19 +- clippy_lints/src/useless_conversion.rs | 65 ++++--- .../utils/internal_lints/lint_without_lint_pass.rs | 5 +- .../utils/internal_lints/unnecessary_def_path.rs | 3 +- clippy_lints/src/vec.rs | 5 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/visibility.rs | 4 +- clippy_lints/src/write.rs | 15 +- clippy_utils/src/check_proc_macro.rs | 4 +- clippy_utils/src/consts.rs | 22 ++- clippy_utils/src/hir_utils.rs | 8 +- clippy_utils/src/lib.rs | 88 ++++----- clippy_utils/src/source.rs | 6 +- clippy_utils/src/ty.rs | 22 ++- clippy_utils/src/ty/type_certainty/mod.rs | 4 +- src/driver.rs | 6 +- tests/ui/auxiliary/proc_macros.rs | 10 +- tests/ui/bool_to_int_with_if.fixed | 8 +- tests/ui/bool_to_int_with_if.rs | 8 +- tests/ui/bool_to_int_with_if.stderr | 2 +- tests/ui/comparison_to_empty.fixed | 8 +- tests/ui/comparison_to_empty.rs | 8 +- tests/ui/comparison_to_empty.stderr | 8 +- tests/ui/manual_filter.rs | 4 +- tests/ui/manual_filter.stderr | 6 +- tests/ui/manual_let_else.rs | 4 +- tests/ui/manual_let_else.stderr | 48 ++--- tests/ui/manual_map_option_2.fixed | 4 +- tests/ui/manual_map_option_2.rs | 4 +- tests/ui/manual_map_option_2.stderr | 19 +- tests/ui/needless_if.fixed | 16 +- tests/ui/needless_if.rs | 16 +- tests/ui/needless_if.stderr | 21 +- tests/ui/needless_late_init.fixed | 4 +- tests/ui/needless_late_init.rs | 4 +- tests/ui/redundant_guards.fixed | 2 +- tests/ui/redundant_guards.rs | 2 +- tests/ui/redundant_pattern_matching_option.fixed | 13 +- tests/ui/redundant_pattern_matching_option.rs | 13 +- tests/ui/redundant_pattern_matching_option.stderr | 56 +++--- 159 files changed, 1799 insertions(+), 1471 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 82c6712506d..e85878eb570 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -82,33 +82,20 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg ( Ok(LitKind::Byte(b'a') | LitKind::Char('a')), Ok(LitKind::Byte(b'z') | LitKind::Char('z')) - ) - | ( + ) | ( Ok(LitKind::Byte(b'A') | LitKind::Char('A')), Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')), - ) - | ( + ) | ( Ok(LitKind::Byte(b'0') | LitKind::Char('0')), Ok(LitKind::Byte(b'9') | LitKind::Char('9')), ) ) && !in_external_macro(cx.sess(), span) { - span_lint_and_then( - cx, - ALMOST_COMPLETE_RANGE, - span, - "almost complete ascii range", - |diag| { - if let Some((span, sugg)) = sugg { - diag.span_suggestion( - span, - "use an inclusive range", - sugg, - Applicability::MaybeIncorrect, - ); - } + span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| { + if let Some((span, sugg)) = sugg { + diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect); } - ); + }); } } diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 40e8281b260..192bc7d9ddc 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -62,19 +62,21 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { ARC_WITH_NON_SEND_SYNC, expr.span, "usage of an `Arc` that is not `Send` or `Sync`", - |diag| with_forced_trimmed_paths!({ - if !is_send { - diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); - } - if !is_sync { - diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); - } + |diag| { + with_forced_trimmed_paths!({ + if !is_send { + diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); + } + if !is_sync { + diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); + } - diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); + diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); - diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); - } - )); + diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); + }); + }, + ); } } } diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 2980c9d6db3..71ec87a8874 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { return; } } - let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""}; + let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" }; let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => { @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { ), app, ); - } + }, "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => { span_lint_and_sugg( cx, @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { ), app, ); - } + }, _ => (), }; } diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 6aab91a7f18..ec2447dae96 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath}; +use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 7a5e3d3f30f..64bfa8d904c 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -602,9 +602,26 @@ fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) { if let AttrArgs::Delimited(args) = &normal_attr.item.args && let mut tt_iter = args.tokens.trees() - && let Some(TokenTree::Token(Token { kind: TokenKind::Ident(sym::expected, _), .. }, _)) = tt_iter.next() - && let Some(TokenTree::Token(Token { kind: TokenKind::Eq, .. }, _)) = tt_iter.next() - && let Some(TokenTree::Token(Token { kind: TokenKind::Literal(_), .. }, _)) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Ident(sym::expected, _), + .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Eq, .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Literal(_), + .. + }, + _, + )) = tt_iter.next() { // `#[should_panic(expected = "..")]` found, good return; @@ -914,7 +931,9 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { for item in items { if let NestedMetaItem::MetaItem(meta) = item { - if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() { + if meta.has_name(sym!(features)) + && let Some(val) = meta.value_str() + { span_lint_and_sugg( cx, MAYBE_MISUSED_CFG, @@ -933,16 +952,16 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { } fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) && - let Some(items) = attr.meta_item_list() + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() { check_nested_cfg(cx, &items); } } fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) && - let Some(items) = attr.meta_item_list() + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() { check_nested_misused_cfg(cx, &items); } diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index e5ec504fa91..06b74b972b7 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{CoroutineSource, Body, CoroutineKind}; +use rustc_hir::{Body, CoroutineKind, CoroutineSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index ca305d0c6e5..156cb34df9c 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -55,7 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { } fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr) + if let Some(If { + cond, + then, + r#else: Some(r#else), + }) = If::hir(expr) && let Some(then_lit) = int_literal(then) && let Some(else_lit) = int_literal(r#else) { @@ -90,19 +94,18 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx> let into_snippet = snippet.clone().maybe_par(); let as_snippet = snippet.as_ty(ty); - span_lint_and_then(cx, + span_lint_and_then( + cx, BOOL_TO_INT_WITH_IF, expr.span, "boolean to int conversion using if", |diag| { - diag.span_suggestion( - expr.span, - "replace with from", - suggestion, - applicability, - ); - diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options")); - }); + diag.span_suggestion(expr.span, "replace with from", suggestion, applicability); + diag.note(format!( + "`{as_snippet}` or `{into_snippet}.into()` can also be valid options" + )); + }, + ); }; } @@ -110,7 +113,7 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx> fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { if let ExprKind::Block(block, _) = expr.kind && let Block { - stmts: [], // Shouldn't lint if statements with side effects + stmts: [], // Shouldn't lint if statements with side effects expr: Some(expr), .. } = block diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 04cca9e3177..37ce65676c7 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -472,8 +472,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { self.bool_expr(e); }, ExprKind::Unary(UnOp::Not, inner) => { - if let ExprKind::Unary(UnOp::Not, ex) = inner.kind && - !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() { + if let ExprKind::Unary(UnOp::Not, ex) = inner.kind + && !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() + { return; } if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { @@ -500,10 +501,10 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && - !inner.span.from_expansion() && - let Some(suggestion) = simplify_not(self.cx, inner) - && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind + && !inner.span.from_expansion() + && let Some(suggestion) = simplify_not(self.cx, inner) + && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow { span_lint_and_sugg( self.cx, diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 47672cb5fb5..9c78c6e532d 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -61,9 +61,9 @@ impl LateLintPass<'_> for BoxDefault { } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) } else { - return + return; }, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } @@ -110,7 +110,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Node::Expr(Expr { kind: ExprKind::Call(path, args), .. - }) | Node::Block(Block { + }) + | Node::Block(Block { expr: Some(Expr { kind: ExprKind::Call(path, args), @@ -119,10 +120,10 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .. }), ) => { - if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && - let Some(sig) = expr_sig(cx, path) && - let Some(input) = sig.input(index) && - !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() + if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(sig) = expr_sig(cx, path) + && let Some(input) = sig.input(index) + && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() { input.no_bound_vars().is_some() } else { diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 1e56ed5f450..55294f5f386 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -9,12 +9,19 @@ use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::AS_PTR_CAST_MUT; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) { - if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind() - && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = - cx.typeck_results().node_type(cast_expr.hir_id).kind() + if let ty::RawPtr( + ptrty @ TypeAndMut { + mutbl: Mutability::Mut, .. + }, + ) = cast_to.kind() + && let ty::RawPtr(TypeAndMut { + mutbl: Mutability::Not, .. + }) = cx.typeck_results().node_type(cast_expr.hir_id).kind() && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind && method_name.ident.name == rustc_span::sym::as_ptr - && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id) + && let Some(as_ptr_did) = cx + .typeck_results() + .type_dependent_def_id(cast_expr.peel_blocks().hir_id) && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() @@ -30,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, &format!("casting the result of `as_ptr` to *{ptrty}"), "replace with", format!("{recv}.as_mut_ptr()"), - applicability + applicability, ); } } diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 9e8ef282537..f12f03fbe79 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -26,8 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { // There probably is no obvious reason to do this, just to be consistent with `as` cases. && !is_hir_ty_cfg_dependant(cx, cast_to) { - let (cast_from, cast_to) = - (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); + let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr)); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } } @@ -81,9 +80,9 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { cx.tcx.get_diagnostic_name(def_id), Some( sym::ptr_write_unaligned - | sym::ptr_read_unaligned - | sym::intrinsics_unaligned_volatile_load - | sym::intrinsics_unaligned_volatile_store + | sym::ptr_read_unaligned + | sym::intrinsics_unaligned_volatile_load + | sym::intrinsics_unaligned_volatile_store ) ) { diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 86057bb74ee..61bfce07e1a 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -97,7 +97,9 @@ pub(super) fn check<'tcx>( } // skip cast of fn call that returns type alias - if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) { + if let ExprKind::Cast(inner, ..) = expr.kind + && is_cast_from_ty_alias(cx, inner, cast_from) + { return false; } @@ -189,11 +191,10 @@ fn lint_unnecessary_cast( let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) && let ExprKind::MethodCall(..) = parent_expr.kind && literal_str.starts_with('-') - { - format!("({literal_str}_{cast_to})") - - } else { - format!("{literal_str}_{cast_to}") + { + format!("({literal_str}_{cast_to})") + } else { + format!("{literal_str}_{cast_to}") }; span_lint_and_sugg( @@ -269,7 +270,9 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx && let Some(parent) = get_parent_node(cx.tcx, hir_id) && let Node::Local(l) = parent { - if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) { + if let Some(e) = l.init + && is_cast_from_ty_alias(cx, e, cast_from) + { return ControlFlow::Break::<()>(()); } diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 77f8243c969..553b670fdb7 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -68,7 +68,10 @@ fn make_sugg( _ => None, }) { - format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0) + format!( + "std::iter::empty::<{}>()", + snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0 + ) } else { "std::iter::empty()".to_owned() } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index ca4913ce1d1..6c109a51f83 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -353,23 +353,26 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && let arg_ty - = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) + && let arg_ty = cx + .tcx + .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target)) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = cx .typeck_results() - .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() - && let impl_ty = if cx.tcx.fn_sig(fn_id) - .instantiate_identity() - .skip_binder() - .inputs()[0].is_ref() - { - // Trait methods taking `&self` - sub_ty - } else { - // Trait methods taking `self` - arg_ty - } && impl_ty.is_ref() + .node_args_opt(hir_id) + .map(|args| &args[1..]) + .unwrap_or_default() + && let impl_ty = + if cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder().inputs()[0] + .is_ref() + { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } + && impl_ty.is_ref() && implements_trait( cx, impl_ty, @@ -414,9 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let (required_refs, msg) = if can_auto_borrow { (1, if deref_count == 1 { borrow_msg } else { deref_msg }) } else if let Some(&Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), - .. - }) = next_adjust + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), + .. + }) = next_adjust && matches!(mutability, AutoBorrowMutability::Mut { .. }) && !stability.is_reborrow_stable() { @@ -705,9 +708,11 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo { match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) - if child.hir_id == e.hir_id => true, - ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) - | ExprKind::Field(_, _) => true, + if child.hir_id == e.hir_id => + { + true + }, + ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) | ExprKind::Field(_, _) => true, _ => false, } } else { diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index e2f595dcf18..d4a698521ac 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -569,9 +569,7 @@ fn check_doc<'a, Events: Iterator, Range, Range, text: &str, edition: Edition, range: Range LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg, note_span) = match fn_name { - // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types + // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, + // forgetting_copy_types sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return, sym::mem_forget if arg_ty.is_ref() => return, sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return, @@ -100,8 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { if !(arg_ty.needs_drop(cx.tcx, cx.param_env) || is_must_use_func_call(cx, arg) || is_must_use_ty(cx, arg_ty) - || drop_is_single_call_in_arm - ) => + || drop_is_single_call_in_arm) => { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span)) }, @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { } else { (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span)) } - } + }, _ => return, }; span_lint_and_note( diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index 3122c1c1757..4e2a8b73c0a 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -35,7 +35,8 @@ impl EarlyLintPass for EmptyStructsWithBrackets { if let ItemKind::Struct(var_data, _) = &item.kind && has_brackets(var_data) - && has_no_fields(cx, var_data, span_after_ident) { + && has_no_fields(cx, var_data, span_after_ident) + { span_lint_and_then( cx, EMPTY_STRUCTS_WITH_BRACKETS, @@ -46,8 +47,9 @@ impl EarlyLintPass for EmptyStructsWithBrackets { span_after_ident, "remove the brackets", ";", - Applicability::Unspecified); - }, + Applicability::Unspecified, + ); + }, ); } } diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index c691e6c5402..575fead5bf3 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Let(let_expr) = expr.kind - && unary_pattern(let_expr.pat) { + && unary_pattern(let_expr.pat) + { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; @@ -79,7 +80,9 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { "({})", snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0, ), - _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(), + _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability) + .0 + .to_string(), }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index 6d429fbd035..bc878555c66 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -41,10 +41,11 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { }; match item.kind { - ItemKind::TyAlias(..) if item.ident.name == sym::Error - && is_visible_outside_module(cx, item.owner_id.def_id) - && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() - && implements_trait(cx, ty, error_def_id, &[]) => + ItemKind::TyAlias(..) + if item.ident.name == sym::Error + && is_visible_outside_module(cx, item.owner_id.def_id) + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && implements_trait(cx, ty, error_def_id, &[]) => { span_lint( cx, @@ -53,13 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { "exported type alias named `Error` that implements `Error`", ); }, - ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) - && error_def_id == trait_def_id - && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) - && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) - && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) - && ident.name == sym::Error - && is_visible_outside_module(cx, def_id) => + ItemKind::Impl(imp) + if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) + && error_def_id == trait_def_id + && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) + && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) + && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) + && ident.name == sym::Error + && is_visible_outside_module(cx, def_id) => { span_lint_hir_and_then( cx, @@ -69,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { "exported type named `Error` that implements `Error`", |diag| { diag.span_note(item.span, "`Error` was implemented here"); - } + }, ); - } + }, _ => {}, } } diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 38066503c07..fad8fbf0449 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -119,19 +119,21 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { match body.value.kind { ExprKind::Call(callee, args) - if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) => + if matches!( + callee.kind, + ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..)) + ) => { let callee_ty = typeck.expr_ty(callee).peel_refs(); - if matches!( - type_diagnostic_name(cx, callee_ty), - Some(sym::Arc | sym::Rc) - ) || !check_inputs(typeck, body.params, None, args) { + if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) + || !check_inputs(typeck, body.params, None, args) + { return; } - let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or( - callee_ty, - |a| a.target.peel_refs(), - ); + let callee_ty_adjusted = typeck + .expr_adjustments(callee) + .last() + .map_or(callee_ty, |a| a.target.peel_refs()); let sig = match callee_ty_adjusted.kind() { ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(), @@ -160,36 +162,26 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { // For now ignore all callee types which reference a type parameter. && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_))) { - span_lint_and_then( - cx, - REDUNDANT_CLOSURE, - expr.span, - "redundant closure", - |diag| { - if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if let Ok((ClosureKind::FnMut, _)) - = cx.tcx.infer_ctxt().build().type_implements_fn_trait( - cx.param_env, - Binder::bind_with_vars(callee_ty_adjusted, List::empty()), - ImplPolarity::Positive, - ) && path_to_local(callee) - .map_or( - false, - |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr), - ) - { - // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {snippet}"); - } - diag.span_suggestion( - expr.span, - "replace the closure with the function itself", - snippet, - Applicability::MachineApplicable, - ); + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { + if let Some(mut snippet) = snippet_opt(cx, callee.span) { + if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait( + cx.param_env, + Binder::bind_with_vars(callee_ty_adjusted, List::empty()), + ImplPolarity::Positive, + ) && path_to_local(callee).map_or(false, |l| { + local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) + }) { + // Mutable closure is used after current expr; we cannot consume it. + snippet = format!("&mut {snippet}"); } + diag.span_suggestion( + expr.span, + "replace the closure with the function itself", + snippet, + Applicability::MachineApplicable, + ); } - ); + }); } }, ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => { diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 1b0b88896ea..1d18e194d15 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { // functions with a body are already checked by `check_fn` if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind && fn_sig.header.abi == Abi::Rust - { + { self.check_fn_sig(cx, fn_sig.decl, fn_sig.span); } } @@ -174,11 +174,8 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust - && get_parent_as_impl(cx.tcx, hir_id) - .map_or(true, - |impl_item| impl_item.of_trait.is_none() - ) - { + && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none()) + { self.check_fn_sig(cx, fn_decl, span); } } diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 595da886601..4b5bcb06a1e 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -58,7 +58,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { Some(sym::io_stderr) => ("stderr", "e"), _ => return, }; - let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { return; }; + let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { + return; + }; // ordering is important here, since `writeln!` uses `write!` internally let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { @@ -78,18 +80,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { macro_name.replace("write", "print"), ) } else { - ( - format!("{dest_name}().write_fmt(...)"), - "print".into(), - ) + (format!("{dest_name}().write_fmt(...)"), "print".into()) }; let mut applicability = Applicability::MachineApplicable; - let inputs_snippet = snippet_with_applicability( - cx, - format_args_inputs_span(&format_args), - "..", - &mut applicability, - ); + let inputs_snippet = + snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_WRITE, diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 73034b94206..d6c746901fc 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -177,20 +177,22 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .iter() .rev() .map(|(idx, param)| { - if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) { - // Extend the current span forward, up until the next param in the list. - param.span.until(next.span) - } else { - // Extend the current span back to include the comma following the previous - // param. If the span of the next param in the list has already been - // extended, we continue the chain. This is why we're iterating in reverse. - end = Some(param.def_id); + if let Some(next) = explicit_params.get(idx + 1) + && end != Some(next.def_id) + { + // Extend the current span forward, up until the next param in the list. + param.span.until(next.span) + } else { + // Extend the current span back to include the comma following the previous + // param. If the span of the next param in the list has already been + // extended, we continue the chain. This is why we're iterating in reverse. + end = Some(param.def_id); - // idx will never be 0, else we'd be removing the entire list of generics - let prev = explicit_params[idx - 1]; - let prev_span = self.get_bound_span(prev); - self.get_bound_span(param).with_lo(prev_span.hi()) - } + // idx will never be 0, else we'd be removing the entire list of generics + let prev = explicit_params[idx - 1]; + let prev_span = self.get_bound_span(prev); + self.get_bound_span(param).with_lo(prev_span.hi()) + } }) .collect() }; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index fd34c8cddc0..18ed05c1ca6 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -54,7 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let Some(snippet) = snippet_opt(cx, format_args.span) else { + return; + }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); @@ -76,13 +78,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { _ => false, }; let sugg = if is_new_string { - snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability) + .0 + .into_owned() } else { let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); format!("{}.to_string()", sugg.maybe_par()) }; span_useless_format(cx, call_site, sugg, applicability); - } }, _ => {}, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 7d60fdd1b03..3c1f2d9d5dc 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -370,7 +370,7 @@ fn check_one_arg( }; fixes.push((pos_span, replacement)); fixes.push((arg_span, String::new())); - true // successful inlining, continue checking + true // successful inlining, continue checking } else { // Do not continue inlining (return false) in case // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 858ec91412b..ac45f5aedfa 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -58,7 +58,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { arms.iter().any(|arm| is_format(cx, arm.body)) }, Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => { - is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e)) + is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) }, _ => false, } @@ -69,17 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let arg = match expr.kind { ExprKind::MethodCall(_, _, [arg], _) => { - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && - match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, fn_def_id, &paths::PUSH_STR) + { arg } else { return; } - } - ExprKind::AssignOp(op, left, arg) - if op.node == BinOpKind::Add && is_string(cx, left) => { - arg }, + ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg, _ => return, }; if is_format(cx, arg) { diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 4ccdba910eb..5477532bb95 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -88,7 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { cx.tcx.sess.source_map().guess_head_span(item.span), "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true", |diag| { - // If the target type is likely foreign mention the orphan rules as it's a common source of confusion + // If the target type is likely foreign mention the orphan rules as it's a common source of + // confusion if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) { diag.help( "`impl From for Foreign` is allowed by the orphan rules, for more information see\n\ @@ -96,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { ); } - let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty()); + let message = format!( + "replace the `Into` implementation with `From<{}>`", + middle_trait_ref.self_ty() + ); if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) { diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable); } else { diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index b66746d08f8..d9138d48b2c 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -40,14 +40,22 @@ declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]); impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name == sym!(from_raw) - && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) - && let arg_kind = cx.typeck_results().expr_ty(arg).kind() - && let RawPtr(TypeAndMut { ty, .. }) = arg_kind - && is_c_void(cx, *ty) { + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind + && seg.ident.name == sym!(from_raw) + && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) + && let arg_kind = cx.typeck_results().expr_ty(arg).kind() + && let RawPtr(TypeAndMut { ty, .. }) = arg_kind + && is_c_void(cx, *ty) + { let msg = format!("creating a `{type_str}` from a void raw pointer"); - span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type"); + span_lint_and_help( + cx, + FROM_RAW_WITH_VOID_PTR, + expr.span, + &msg, + Some(arg.span), + "cast this to a pointer of the appropriate type", + ); } } } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 57df5683c9d..3aaf63ce340 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -118,9 +118,10 @@ fn check_needless_must_use( if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(); if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) - && !is_must_use_ty(cx, future_ty) { - return; - } + && !is_must_use_ty(cx, future_ty) + { + return; + } } span_lint_and_help( diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 90fc0d4f662..485235514de 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -21,7 +21,9 @@ fn result_err_ty<'tcx>( ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !in_external_macro(cx.sess(), item_span) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output()) + && let ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output()) && is_type_diagnostic_item(cx, ty, sym::Result) && let ty::Adt(_, args) = ty.kind() { diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 55dab10ac88..66c10ab228f 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -76,7 +76,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { let ctxt = expr.span.ctxt(); - if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) + if let Some(higher::If { + cond, + then, + r#else: Some(els), + }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind @@ -86,7 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && !contains_return(then_block.stmts) { let mut app = Applicability::Unspecified; - let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) + .maybe_par() + .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() @@ -100,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { "then" }; - let help = format!( - "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`", - ); + let help = + format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",); span_lint_and_help( cx, IF_THEN_SOME_ELSE_NONE, diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index cbe2b9c1dd4..ff27a5d666d 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -230,19 +230,24 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { // Example: // `impl Deref + DerefMut` is not allowed. // `DerefMut::Target` needs to match `Deref::Target`. - let implied_bounds: Vec<_> = opaque_ty.bounds.iter().filter_map(|bound| { - if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound - && let [.., path] = poly_trait.trait_ref.path.segments - && poly_trait.bound_generic_params.is_empty() - && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates - && !predicates.is_empty() // If the trait has no supertrait, there is nothing to add. - { - Some((bound.span(), path, predicates, trait_def_id)) - } else { - None - } - }).collect(); + let implied_bounds: Vec<_> = opaque_ty + .bounds + .iter() + .filter_map(|bound| { + if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound + && let [.., path] = poly_trait.trait_ref.path.segments + && poly_trait.bound_generic_params.is_empty() + && let Some(trait_def_id) = path.res.opt_def_id() + && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates + && !predicates.is_empty() + // If the trait has no supertrait, there is nothing to add. + { + Some((bound.span(), path, predicates, trait_def_id)) + } else { + None + } + }) + .collect(); // Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec. // This involves some extra logic when generic arguments are present, since @@ -253,30 +258,31 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { && let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() - && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = implied_bounds - .iter() - .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { - let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); - let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); + && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = + implied_bounds + .iter() + .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { + let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); + let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); - preds.iter().find_map(|(clause, _)| { - if let ClauseKind::Trait(tr) = clause.kind().skip_binder() - && tr.def_id() == def_id - && is_same_generics( - cx.tcx, - tr.trait_ref.args, - implied_by_args, - implied_args, - implied_by_def_id, - def_id, - ) - { - Some((span, implied_by_args, implied_by_bindings)) - } else { - None - } + preds.iter().find_map(|(clause, _)| { + if let ClauseKind::Trait(tr) = clause.kind().skip_binder() + && tr.def_id() == def_id + && is_same_generics( + cx.tcx, + tr.trait_ref.args, + implied_by_args, + implied_args, + implied_by_def_id, + def_id, + ) + { + Some((span, implied_by_args, implied_by_bindings)) + } else { + None + } + }) }) - }) { emit_lint( cx, @@ -286,7 +292,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { implied_bindings, implied_by_bindings, implied_by_args, - implied_by_span + implied_by_span, ); } } diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index fde6bff9417..35e01862cee 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -74,9 +74,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if let Some(last) = after.last() && after.iter().all(|&item| { - !matches!(item.kind, ItemKind::Mod(_)) - && !item.span.from_expansion() - && !is_from_proc_macro(cx, item) + !matches!(item.kind, ItemKind::Mod(_)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item) }) && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id())) { @@ -99,10 +97,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", - vec![ - (prev.span.shrink_to_hi(), items), - (items_span, String::new()) - ], + vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 3f45c5dc259..3c291f25590 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -155,17 +155,18 @@ impl LateLintPass<'_> for IterWithoutIntoIter { if let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind && let Some(trait_ref) = imp.of_trait - && trait_ref.trait_def_id().is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && trait_ref + .trait_def_id() + .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() && let expected_method_name = match mtbl { Mutability::Mut => sym::iter_mut, Mutability::Not => sym::iter, } - && !deref_chain(cx, ty) - .any(|ty| { - // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method - ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) - }) + && !deref_chain(cx, ty).any(|ty| { + // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method + ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) + }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { if item.ident.name == sym!(IntoIter) { Some(cx.tcx.hir().impl_item(item.id).expect_type().span) @@ -185,7 +186,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { // to avoid name ambiguities, as there might be an inherent into_iter method // that we don't want to call. let sugg = format!( -" + " impl {self_ty_without_ref} {{ fn {expected_method_name}({ref_self}self) -> {iter_ty} {{ <{ref_self}Self as IntoIterator>::into_iter(self) @@ -203,9 +204,9 @@ impl {self_ty_without_ref} {{ sugg, // Just like iter_without_into_iter, this suggestion is on a best effort basis // and requires potentially adding lifetimes or moving them around. - Applicability::Unspecified + Applicability::Unspecified, ); - } + }, ); } } @@ -254,18 +255,22 @@ impl {self_ty_without_ref} {{ cx, ITER_WITHOUT_INTO_ITER, item.span, - &format!("`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident), + &format!( + "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", + item.ident + ), |diag| { // Get the lower span of the `impl` block, and insert the suggestion right before it: // impl X { // ^ fn iter(&self) -> impl IntoIterator { ... } // } - let span_behind_impl = cx.tcx + let span_behind_impl = cx + .tcx .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id) .shrink_to_lo(); let sugg = format!( -" + " impl IntoIterator for {self_ty_snippet} {{ type IntoIter = {ret_ty}; type Item = {iter_ty}; @@ -283,7 +288,8 @@ impl IntoIterator for {self_ty_snippet} {{ // such as adding some lifetimes in the associated types, or importing types. Applicability::Unspecified, ); - }); + }, + ); } } } diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 0a5901bce04..5e312ab7240 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -39,27 +39,35 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind - && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) - && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) - && !cx.tcx.hir().parent_iter(expr.hir_id) - .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) - && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { - span_lint_and_help( - cx, - LARGE_STACK_ARRAYS, - expr.span, - &format!( - "allocating a local array larger than {} bytes", - self.maximum_allowed_size - ), - None, - &format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), - ); - } + && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() + && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) + && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { + matches!( + node, + Node::Item(Item { + kind: ItemKind::Static(..), + .. + }) + ) + }) + && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) + { + span_lint_and_help( + cx, + LARGE_STACK_ARRAYS, + expr.span, + &format!( + "allocating a local array larger than {} bytes", + self.maximum_allowed_size + ), + None, + &format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + ), + ); + } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index c06b35ca0da..08f095859e5 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -181,8 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { let mut applicability = Applicability::MachineApplicable; let lit1 = peel_ref_operators(cx, lt.init); - let lit_str = - Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); + let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par(); span_lint_and_sugg( cx, @@ -288,18 +287,26 @@ enum LenOutput { } fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - if let ty::Alias(_, alias_ty) = ty.kind() && - let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) && - let Item { kind: ItemKind::OpaqueTy(opaque), .. } = item && - opaque.bounds.len() == 1 && - let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] && - generic_args.bindings.len() == 1 && - let TypeBindingKind::Equality { - term: rustc_hir::Term::Ty(rustc_hir::Ty {kind: TyKind::Path(QPath::Resolved(_, path)), .. }), - } = &generic_args.bindings[0].kind && - path.segments.len() == 1 { - return Some(&path.segments[0]); - } + if let ty::Alias(_, alias_ty) = ty.kind() + && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) + && let Item { + kind: ItemKind::OpaqueTy(opaque), + .. + } = item + && opaque.bounds.len() == 1 + && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] + && generic_args.bindings.len() == 1 + && let TypeBindingKind::Equality { + term: + rustc_hir::Term::Ty(rustc_hir::Ty { + kind: TyKind::Path(QPath::Resolved(_, path)), + .. + }), + } = &generic_args.bindings[0].kind + && path.segments.len() == 1 + { + return Some(&path.segments[0]); + } None } diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 7a19b1c4273..04f23a213f2 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -159,14 +159,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { binding or dropping explicitly with `std::mem::drop`", ); } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() - && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) { + && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) + { span_lint_and_help( cx, LET_UNDERSCORE_FUTURE, local.span, "non-binding `let` on a future", None, - "consider awaiting the future or dropping explicitly with `std::mem::drop`" + "consider awaiting the future or dropping explicitly with `std::mem::drop`", ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( @@ -203,17 +204,17 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { return; } - span_lint_and_help( + span_lint_and_help( cx, LET_UNDERSCORE_UNTYPED, local.span, "non-binding `let` without a type annotation", - Some( - Span::new(local.pat.span.hi(), - local.pat.span.hi() + BytePos(1), - local.pat.span.ctxt(), - local.pat.span.parent() - )), + Some(Span::new( + local.pat.span.hi(), + local.pat.span.hi() + BytePos(1), + local.pat.span.ctxt(), + local.pat.span.parent(), + )), "consider adding a type annotation", ); } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 35d7a9540af..4b89c0fa361 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -517,9 +517,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) { let trait_ref = &poly_tref.trait_ref; - if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| { - self.cx.tcx.lang_items().get(item) == Some(id) - }) { + if let Some(id) = trait_ref.trait_def_id() + && lang_items::FN_TRAITS + .iter() + .any(|&item| self.cx.tcx.lang_items().get(item) == Some(id)) + { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_trait_ref(trait_ref); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 1304654efa6..0a5f5a80cb7 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -59,41 +59,56 @@ declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && - is_trait_method(cx, expr, sym::Iterator) && - (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) + if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind + && is_trait_method(cx, expr, sym::Iterator) + && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) { let lint = match &fm_arg.kind { // Detect `Result::ok` - ExprKind::Path(qpath) => - cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did| - match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(), + ExprKind::Path(qpath) => cx + .qpath_res(qpath, fm_arg.hir_id) + .opt_def_id() + .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)) + .unwrap_or_default(), // Detect `|x| x.ok()` - ExprKind::Closure(Closure { body, .. }) => - if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) && - let ExprKind::MethodCall(method, receiver, [], _) = value.kind && - path_to_local_id(receiver, param.pat.hir_id) && - let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) + ExprKind::Closure(Closure { body, .. }) => { + if let Body { + params: [param], value, .. + } = cx.tcx.hir().body(*body) + && let ExprKind::MethodCall(method, receiver, [], _) = value.kind + && path_to_local_id(receiver, param.pat.hir_id) + && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) { is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" } else { false } + }, _ => false, }; if lint { - span_lint_and_then(cx, + span_lint_and_then( + cx, LINES_FILTER_MAP_OK, fm_span, - &format!("`{}()` will run forever if the iterator repeatedly produces an `Err`", fm_method.ident), + &format!( + "`{}()` will run forever if the iterator repeatedly produces an `Err`", + fm_method.ident + ), |diag| { diag.span_note( fm_receiver.span, "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); - diag.span_suggestion(fm_span, "replace with", "map_while(Result::ok)", Applicability::MaybeIncorrect); - }); - } + diag.span_suggestion( + fm_span, + "replace with", + "map_while(Result::ok)", + Applicability::MaybeIncorrect, + ); + }, + ); + } } } } diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 92ee033df47..1c2b7a169fc 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -113,7 +113,9 @@ fn is_ref_iterable<'tcx>( let typeck = cx.typeck_results(); if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let Some(fn_id) = typeck.type_dependent_def_id(call_expr.hir_id) - && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) + && let sig = cx + .tcx + .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output && let param_env = cx.tcx.param_env(fn_id) && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[]) @@ -131,8 +133,9 @@ fn is_ref_iterable<'tcx>( return Some((AdjustKind::None, self_ty)); } - let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty) - .instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); + let res_ty = cx + .tcx + .erase_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() { Some(mutbl) } else { @@ -157,7 +160,7 @@ fn is_ref_iterable<'tcx>( let self_ty = if mutbl.is_mut() { self_ty } else { - Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl }) + Ty::new_ref(cx.tcx, region, TypeAndMut { ty, mutbl }) }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = @@ -172,10 +175,7 @@ fn is_ref_iterable<'tcx>( && !self_ty.is_ref() { // Attempt to borrow - let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut { - ty: self_ty, - mutbl, - }); + let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl }); if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty @@ -187,12 +187,14 @@ fn is_ref_iterable<'tcx>( match adjustments { [] => Some((AdjustKind::None, self_ty)), &[ - Adjustment { kind: Adjust::Deref(_), ..}, + Adjustment { + kind: Adjust::Deref(_), .. + }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), target, }, - .. + .., ] => { if enforce_iter_loop_reborrow && target != self_ty @@ -205,8 +207,14 @@ fn is_ref_iterable<'tcx>( } else { None } - } - &[Adjustment { kind: Adjust::Deref(_), target }, ..] => { + }, + &[ + Adjustment { + kind: Adjust::Deref(_), + target, + }, + .., + ] => { if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = @@ -217,13 +225,13 @@ fn is_ref_iterable<'tcx>( } else { None } - } + }, &[ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), target, }, - .. + .., ] => { if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) @@ -235,7 +243,7 @@ fn is_ref_iterable<'tcx>( } else { None } - } + }, _ => None, } } else { diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 3d8a4cd948a..cc054cb4669 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -271,9 +271,9 @@ fn never_loop_expr<'tcx>( NeverLoopResult::Normal } }); - if let NeverLoopResult::Diverging = result && - let Some(macro_call) = root_macro_call_first_node(cx, expr) && - let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) + if let NeverLoopResult::Diverging = result + && let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id) { // We return MayContinueMainLoop here because we treat `todo!()` // as potentially containing any code, including a continue of the main loop. diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 044d99bc0f7..9a3da975f83 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -64,7 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); - // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block + // we show to the user the suggestion without the comments, but when applying the fix, include the + // comments in the block span_lint_and_then( cx, MANUAL_ASSERT, @@ -77,16 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { expr.span.shrink_to_lo(), "add comments back", comments, - applicability + applicability, ); } - diag.span_suggestion( - expr.span, - "try instead", - sugg, - applicability - ); - } + diag.span_suggestion(expr.span, "try instead", sugg, applicability); + }, ); } } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index c0b67a14388..998de38a995 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, + Block, Body, Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index ec87ff3ef6a..09c90e38e11 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -225,11 +225,11 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx then, r#else: Some(else_if), }) = If::hir(expr) - && let Some(If { - cond: else_if_cond, - then: else_if_then, - r#else: Some(else_body), - }) = If::hir(peel_blocks(else_if)) + && let Some(If { + cond: else_if_cond, + then: else_if_then, + r#else: Some(else_body), + }) = If::hir(peel_blocks(else_if)) { let params = is_clamp_meta_pattern( cx, @@ -275,7 +275,12 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O _ => return None, }; Some(ClampSuggestion { - params: InputMinMax { input, min, max, is_float }, + params: InputMinMax { + input, + min, + max, + is_float, + }, span: expr.span, make_assignment: None, hir_with_ignore_attr: None, @@ -346,11 +351,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) ("max", "min") => (inner_arg, outer_arg), _ => return None, } - } + }, _ => return None, }; Some(ClampSuggestion { - params: InputMinMax { input, min, max, is_float }, + params: InputMinMax { + input, + min, + max, + is_float, + }, span, make_assignment: None, hir_with_ignore_attr: None, @@ -384,7 +394,8 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt // Find possible min/max branches let minmax_values = |a: &'tcx Arm<'tcx>| { if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind - && let Some(Guard::If(e)) = a.guard { + && let Some(Guard::If(e)) = a.guard + { Some((e, var_hir_id, a.body)) } else { None @@ -441,18 +452,20 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> .filter_map(|(maybe_set_first, maybe_set_second)| { if let StmtKind::Expr(first_expr) = *maybe_set_first && let StmtKind::Expr(second_expr) = *maybe_set_second - && let Some(If { cond: first_cond, then: first_then, r#else: None }) = If::hir(first_expr) - && let Some(If { cond: second_cond, then: second_then, r#else: None }) = If::hir(second_expr) - && let ExprKind::Assign( - maybe_input_first_path, - maybe_min_max_first, - _ - ) = peel_blocks_with_stmt(first_then).kind - && let ExprKind::Assign( - maybe_input_second_path, - maybe_min_max_second, - _ - ) = peel_blocks_with_stmt(second_then).kind + && let Some(If { + cond: first_cond, + then: first_then, + r#else: None, + }) = If::hir(first_expr) + && let Some(If { + cond: second_cond, + then: second_then, + r#else: None, + }) = If::hir(second_expr) + && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = + peel_blocks_with_stmt(first_then).kind + && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) = + peel_blocks_with_stmt(second_then).kind && eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path) && let Some(first_bin) = BinaryOp::new(first_cond) && let Some(second_bin) = BinaryOp::new(second_cond) @@ -462,7 +475,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> &second_bin, maybe_min_max_first, maybe_min_max_second, - None + None, ) { Some(ClampSuggestion { @@ -505,16 +518,9 @@ fn is_if_elseif_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> then: else_if_then, r#else: None, }) = If::hir(peel_blocks(else_if)) - && let ExprKind::Assign( - maybe_input_first_path, - maybe_min_max_first, - _ - ) = peel_blocks_with_stmt(then).kind - && let ExprKind::Assign( - maybe_input_second_path, - maybe_min_max_second, - _ - ) = peel_blocks_with_stmt(else_if_then).kind + && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = peel_blocks_with_stmt(then).kind + && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) = + peel_blocks_with_stmt(else_if_then).kind { let params = is_clamp_meta_pattern( cx, diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index c27ce062338..0c4101ceb6b 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -114,46 +114,40 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { _ => return, }; - span_lint_and_then( - cx, - variant.lint(), - expr.span, - variant.msg(), - |diag| { - match variant { - Variant::ManualIsInfinite => { - diag.span_suggestion( - expr.span, - "use the dedicated method instead", - format!("{local_snippet}.is_infinite()"), - Applicability::MachineApplicable, - ); - }, - Variant::ManualIsFinite => { - // TODO: There's probably some better way to do this, i.e., create - // multiple suggestions with notes between each of them - diag.span_suggestion_verbose( - expr.span, - "use the dedicated method instead", - format!("{local_snippet}.is_finite()"), - Applicability::MaybeIncorrect, - ) - .span_suggestion_verbose( - expr.span, - "this will alter how it handles NaN; if that is a problem, use instead", - format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), - Applicability::MaybeIncorrect, - ) - .span_suggestion_verbose( - expr.span, - "or, for conciseness", - format!("!{local_snippet}.is_infinite()"), - Applicability::MaybeIncorrect, - ); - }, - } - }, - ); + span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| { + match variant { + Variant::ManualIsInfinite => { + diag.span_suggestion( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_infinite()"), + Applicability::MachineApplicable, + ); + }, + Variant::ManualIsFinite => { + // TODO: There's probably some better way to do this, i.e., create + // multiple suggestions with notes between each of them + diag.span_suggestion_verbose( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_finite()"), + Applicability::MaybeIncorrect, + ) + .span_suggestion_verbose( + expr.span, + "this will alter how it handles NaN; if that is a problem, use instead", + format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), + Applicability::MaybeIncorrect, + ) + .span_suggestion_verbose( + expr.span, + "or, for conciseness", + format!("!{local_snippet}.is_infinite()"), + Applicability::MaybeIncorrect, + ); + }, + } + }); } } } diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 19f2e1dc42c..472b4eb9006 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -117,12 +117,11 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, // `needless_borrows_for_generic_args` will take care of // removing the `&` when it isn't needed - format!("{build_hasher}.hash_one(&{hashed_value})") - ) + format!("{build_hasher}.hash_one(&{hashed_value})"), + ), ], Applicability::MachineApplicable, ); - } }, ); diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 17415b58d9e..468f4170732 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -98,15 +98,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { } if let Some(macro_call) = root_macro_call(expr.span) - && is_matches_macro(cx, macro_call.def_id) { + && is_matches_macro(cx, macro_call.def_id) + { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); check_is_ascii(cx, macro_call.span, recv, &range); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind && path.ident.name == sym!(contains) - && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed }) - = higher::Range::hir(receiver) { + && let Some(higher::Range { + start: Some(start), + end: Some(end), + limits: RangeLimits::Closed, + }) = higher::Range::hir(receiver) + { let range = check_range(start, end); if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind { check_is_ascii(cx, expr.span, e, &range); @@ -168,7 +173,8 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { if let ExprKind::Lit(start_lit) = &start.kind - && let ExprKind::Lit(end_lit) = &end.kind { + && let ExprKind::Lit(end_lit) = &end.kind + { match (&start_lit.node, &end_lit.node) { (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar, (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar, diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 7888fc10a0b..170a040d4ae 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -56,21 +56,20 @@ impl<'tcx> QuestionMark { return; } - if let StmtKind::Local(local) = stmt.kind && - let Some(init) = local.init && - local.els.is_none() && - local.ty.is_none() && - init.span.eq_ctxt(stmt.span) && - let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) + if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && local.els.is_none() + && local.ty.is_none() + && init.span.eq_ctxt(stmt.span) + && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => { - if - let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) && - let Some(if_else) = if_else && - expr_diverges(cx, if_else) && - let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) && - (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) + if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) + && let Some(if_else) = if_else + && expr_diverges(cx, if_else) + && let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) + && (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) { emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else); } @@ -96,7 +95,9 @@ impl<'tcx> QuestionMark { .iter() .enumerate() .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types)); - let Some((idx, diverging_arm)) = diverging_arm_opt else { return; }; + let Some((idx, diverging_arm)) = diverging_arm_opt else { + return; + }; // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement. // However, if it arrives in second position, its pattern may cover some cases already covered // by the diverging one. @@ -106,7 +107,7 @@ impl<'tcx> QuestionMark { } let pat_arm = &arms[1 - idx]; let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else { - return + return; }; emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body); @@ -217,8 +218,8 @@ fn replace_in_pattern( let fields = fields .iter() .map(|fld| { - if let PatKind::Binding(_, _, name, None) = fld.pat.kind && - let Some(pat_to_put) = ident_map.get(&name.name) + if let PatKind::Binding(_, _, name, None) = fld.pat.kind + && let Some(pat_to_put) = ident_map.get(&name.name) { let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app); let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app); @@ -464,8 +465,8 @@ fn expr_simple_identity_map<'a, 'hir>( } let mut ident_map = FxHashMap::default(); for (sub_pat, path) in sub_pats.iter().zip(paths.iter()) { - if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind && - let [path_seg] = path.segments + if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind + && let [path_seg] = path.segments { let ident = path_seg.ident; if !pat_bindings.remove(&ident) { diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 8f5e7982242..23f47c86fcc 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -47,27 +47,27 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); impl LateLintPass<'_> for ManualMainSeparatorStr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && - let (target, _) = peel_hir_expr_refs(expr) && - is_trait_method(cx, target, sym::ToString) && - let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && - path.ident.name == sym::to_string && - let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && - let Res::Def(DefKind::Const, receiver_def_id) = path.res && - match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && - let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && - ty.is_str() - { - span_lint_and_sugg( - cx, - MANUAL_MAIN_SEPARATOR_STR, - expr.span, - "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", - "replace with", - "std::path::MAIN_SEPARATOR_STR".to_owned(), - Applicability::MachineApplicable, - ); - } + if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) + && let (target, _) = peel_hir_expr_refs(expr) + && is_trait_method(cx, target, sym::ToString) + && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind + && path.ident.name == sym::to_string + && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind + && let Res::Def(DefKind::Const, receiver_def_id) = path.res + && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) + && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() + && ty.is_str() + { + span_lint_and_sugg( + cx, + MANUAL_MAIN_SEPARATOR_STR, + expr.span, + "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", + "replace with", + "std::path::MAIN_SEPARATOR_STR".to_owned(), + Applicability::MachineApplicable, + ); + } } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 4c44ac7fa11..fc8f2363001 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -138,7 +138,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { ); } diag.span_help(field.span, "remove this field"); - } + }, ); } } diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index b435fcf61df..bc8372fbd41 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -76,30 +76,31 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { // Also ensures the const is nonzero since zero can't be a divisor && const1 == const2 && const2 == const3 && let Some(hir_id) = path_to_local(expr3) - && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) { - // Apply only to params or locals with annotated types - match cx.tcx.hir().find_parent(hir_id) { - Some(Node::Param(..)) => (), - Some(Node::Local(local)) => { - let Some(ty) = local.ty else { return }; - if matches!(ty.kind, TyKind::Infer) { - return; - } + && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) + { + // Apply only to params or locals with annotated types + match cx.tcx.hir().find_parent(hir_id) { + Some(Node::Param(..)) => (), + Some(Node::Local(local)) => { + let Some(ty) = local.ty else { return }; + if matches!(ty.kind, TyKind::Infer) { + return; } - _ => return, - }; + }, + _ => return, + }; - let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; - span_lint_and_sugg( - cx, - MANUAL_REM_EUCLID, - expr.span, - "manual `rem_euclid` implementation", - "consider using", - format!("{rem_of}.rem_euclid({const1})"), - app, - ); + let mut app = Applicability::MachineApplicable; + let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; + span_lint_and_sugg( + cx, + MANUAL_REM_EUCLID, + expr.span, + "manual `rem_euclid` implementation", + "consider using", + format!("{rem_of}.rem_euclid({const1})"), + app, + ); } } diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index f902b48fa81..2f8682d0418 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -97,7 +97,8 @@ fn check_into_iter( && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn() && match_acceptable_type(cx, left_expr, msrv) - && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) + { suggest(cx, parent_expr, left_expr, target_expr); } } @@ -120,7 +121,8 @@ fn check_iter( && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) && match_acceptable_def_path(cx, iter_expr_def_id) && match_acceptable_type(cx, left_expr, msrv) - && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) + { suggest(cx, parent_expr, left_expr, filter_expr); } } @@ -144,33 +146,35 @@ fn check_to_owned( && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() && is_type_lang_item(cx, ty, hir::LangItem::String) - && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) { + && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) + { suggest(cx, parent_expr, left_expr, filter_expr); } } fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) { if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind - && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = closure.kind && let filter_body = cx.tcx.hir().body(body) && let [filter_params] = filter_body.params && let Some(sugg) = match filter_params.pat.kind { - hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) - }, - hir::PatKind::Tuple([key_pat, value_pat], _) => { - make_sugg(cx, key_pat, value_pat, left_expr, filter_body) - }, - hir::PatKind::Ref(pat, _) => { - match pat.kind { - hir::PatKind::Binding(_, _, filter_param_ident, None) => { - Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, ".."))) - }, - _ => None - } + hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!( + "{}.retain(|{filter_param_ident}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, filter_body.value.span, "..") + )), + hir::PatKind::Tuple([key_pat, value_pat], _) => make_sugg(cx, key_pat, value_pat, left_expr, filter_body), + hir::PatKind::Ref(pat, _) => match pat.kind { + hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!( + "{}.retain(|{filter_param_ident}| {})", + snippet(cx, left_expr.span, ".."), + snippet(cx, filter_body.value.span, "..") + )), + _ => None, }, - _ => None - } { + _ => None, + } + { span_lint_and_sugg( cx, MANUAL_RETAIN, @@ -178,7 +182,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E "this expression can be written more simply using `.retain()`", "consider calling `.retain()` instead", sugg, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index 726087d4562..f8afae0e1f5 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -65,9 +65,9 @@ impl LateLintPass<'_> for ManualStringNew { /// Checks if an expression's kind corresponds to an empty &str. fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { - if let ExprKind::Lit(lit) = expr_kind && - let LitKind::Str(value, _) = lit.node && - value == symbol::kw::Empty + if let ExprKind::Lit(lit) = expr_kind + && let LitKind::Str(value, _) = lit.node + && value == symbol::kw::Empty { return true; } @@ -110,23 +110,22 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_ if let ExprKind::Path(qpath) = &func.kind { if let QPath::TypeRelative(_, _) = qpath { // String::from(...) or String::try_from(...) - if let QPath::TypeRelative(ty, path_seg) = qpath && - [sym::from, sym::try_from].contains(&path_seg.ident.name) && - let TyKind::Path(qpath) = &ty.kind && - let QPath::Resolved(_, path) = qpath && - let [path_seg] = path.segments && - path_seg.ident.name == sym::String && - is_expr_kind_empty_str(arg_kind) + if let QPath::TypeRelative(ty, path_seg) = qpath + && [sym::from, sym::try_from].contains(&path_seg.ident.name) + && let TyKind::Path(qpath) = &ty.kind + && let QPath::Resolved(_, path) = qpath + && let [path_seg] = path.segments + && path_seg.ident.name == sym::String + && is_expr_kind_empty_str(arg_kind) { warn_then_suggest(cx, span); } } else if let QPath::Resolved(_, path) = qpath { // From::from(...) or TryFrom::try_from(...) - if let [path_seg1, path_seg2] = path.segments && - is_expr_kind_empty_str(arg_kind) && ( - (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) || - (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from) - ) + if let [path_seg1, path_seg2] = path.segments + && is_expr_kind_empty_str(arg_kind) + && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) + || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)) { warn_then_suggest(cx, span); } diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index e0181a4757c..cdb51c33aaf 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -99,12 +99,20 @@ pub(super) fn check_match<'tcx>( ) { let ty = cx.typeck_results().expr_ty(expr); if is_type_diagnostic_item(cx, ty, sym::Option) - && let [first_arm, second_arm] = arms - && first_arm.guard.is_none() - && second_arm.guard.is_none() - { - check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body); - } + && let [first_arm, second_arm] = arms + && first_arm.guard.is_none() + && second_arm.guard.is_none() + { + check( + cx, + expr, + scrutinee, + first_arm.pat, + first_arm.body, + Some(second_arm.pat), + second_arm.body, + ); + } } pub(super) fn check_if_let<'tcx>( diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 0efeeacc9d9..4a44d596a46 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -27,8 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { arm, Arm { pat: Pat { - kind: PatKind::Wild, - .. + kind: PatKind::Wild, .. }, .. }, @@ -42,14 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => arm.pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - if_expr.span, - pat_span, - &binding, - arm.guard, - ); + emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard); } // `Some(x) if let Some(2) = x` else if let Guard::IfLet(let_expr) = guard @@ -60,14 +52,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => let_expr.pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - let_expr.span, - pat_span, - &binding, - None, - ); + emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None); } // `Some(x) if x == Some(2)` // `Some(x) if Some(2) == x` @@ -93,14 +78,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (ExprKind::AddrOf(..), None) | (_, Some(_)) => continue, _ => pat.span, }; - emit_redundant_guards( - cx, - outer_arm, - if_expr.span, - pat_span, - &binding, - None, - ); + emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None); } } } @@ -116,7 +94,9 @@ fn get_pat_binding<'tcx>( guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>, ) -> Option { - if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) { + if let Some(local) = path_to_local(guard_expr) + && !is_local_used(cx, outer_arm.body, local) + { let mut span = None; let mut byref_ident = None; let mut multiple_bindings = false; @@ -223,10 +203,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..), ) }, - ExprKind::AddrOf(..) - | ExprKind::Array(..) - | ExprKind::Tup(..) - | ExprKind::Struct(..) => true, + ExprKind::AddrOf(..) | ExprKind::Array(..) | ExprKind::Tup(..) | ExprKind::Struct(..) => true, ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true, _ => false, } { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 5b92c0f7dc8..48efd023017 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -20,8 +20,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { if let Some(ff) = get_source_text(cx, span) && let Some(text) = ff.as_str() { - text.as_bytes().windows(2) - .any(|w| w == b"//" || w == b"/*") + text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") } else { false } diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index c5fc145b289..baafb7030aa 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -24,8 +24,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability); if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) - && let Some((name, _, _, _, _)) = method_call(parent) - && name == "unwrap" { + && let Some((name, _, _, _, _)) = method_call(parent) + && name == "unwrap" + { span_lint_and_sugg( cx, BYTES_NTH, @@ -33,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes()[{n}]",), - applicability + applicability, ); } else { span_lint_and_sugg( @@ -42,8 +43,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E expr.span, &format!("called `.bytes().nth()` on a `{caller_type}`"), "try", - format!("{receiver}.as_bytes().get({n}).copied()"), - applicability + format!("{receiver}.as_bytes().get({n}).copied()"), + applicability, ); }; } diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index c9eaa185acc..22b67923e50 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -159,7 +159,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome, OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk, OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"), - } + }, }) } else { None @@ -189,7 +189,8 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // scrutinee variant_span variant_ident else_ let (scrutinee, else_, variant_ident, variant_span) = match higher::IfLetOrMatch::parse(cx, map_body.value) { - // For `if let` we want to check that the variant matching arm references the local created by its pattern + // For `if let` we want to check that the variant matching arm references the local created by + // its pattern Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_))) if let Some((ident, span)) = expr_uses_local(pat, then) => { @@ -211,7 +212,10 @@ impl<'tcx> OffendingFilterExpr<'tcx> { && let Some(mac) = root_macro_call(else_.peel_blocks().span) && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable)) { - Some(CheckResult::PatternMatching { variant_span, variant_ident }) + Some(CheckResult::PatternMatching { + variant_span, + variant_ident, + }) } else { None } @@ -228,18 +232,20 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap()) // vs. // .filter_map(|x| effect(x)) - // + // // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) - && path.ident.name == sym!(is_some) - { - Some(Self::IsSome { receiver, side_effect_expr_span }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) - && path.ident.name == sym!(is_ok) - { - Some(Self::IsOk { receiver, side_effect_expr_span }) + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym!(is_some) { + Some(Self::IsSome { + receiver, + side_effect_expr_span, + }) + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym!(is_ok) { + Some(Self::IsOk { + receiver, + side_effect_expr_span, + }) } else { None } diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 33657254965..9950c442855 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & "use `filter` then `map` instead", format!( "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})", - derefs="*".repeat(needed_derefs) + derefs = "*".repeat(needed_derefs) ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/format_collect.rs b/clippy_lints/src/methods/format_collect.rs index 1f8863f8521..3e5162ef458 100644 --- a/clippy_lints/src/methods/format_collect.rs +++ b/clippy_lints/src/methods/format_collect.rs @@ -24,10 +24,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, m && let Some(mac) = root_macro_call_first_node(cx, value) && is_format_macro(cx, mac.def_id) { - span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| { - diag.span_help(map_span, "call `fold` instead") - .span_help(value.span.source_callsite(), "... and use the `write!` macro here") - .note("this can be written more efficiently by appending to a `String` directly"); - }); + span_lint_and_then( + cx, + FORMAT_COLLECT, + expr.span, + "use of `format!` to build up a string from an iterator", + |diag| { + diag.span_help(map_span, "call `fold` instead") + .span_help(value.span.source_callsite(), "... and use the `write!` macro here") + .note("this can be written more efficiently by appending to a `String` directly"); + }, + ); } } diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index a8f090d1de1..afdcb3b6549 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -43,9 +43,9 @@ pub(super) fn check<'tcx>( // by not requiring an explicit reference let needs_ref = if let Some(parent) = get_parent_expr(cx, expr) && let hir::ExprKind::Unary(hir::UnOp::Deref, _) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::Index(..) = parent.kind + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Index(..) = parent.kind { if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { // if the user explicitly dereferences the result, we can adjust diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs index 99ea7f03df4..29e69b111de 100644 --- a/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -51,7 +51,7 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> Some(0) } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) { Some(1) - } else { + } else { None } } diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index a49dd98db87..eac6df0545f 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -60,9 +60,15 @@ pub(super) fn check<'tcx>( } if let Op::NeedlessMove(_, expr) = op { - let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ; - let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return }; - let mut delegate = MoveDelegate {used_move : HirIdSet::default()}; + let rustc_hir::ExprKind::Closure(closure) = expr.kind else { + return; + }; + let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { + return; + }; + let mut delegate = MoveDelegate { + used_move: HirIdSet::default(), + }; let infcx = cx.tcx.infer_ctxt().build(); ExprUseVisitor::new( @@ -77,7 +83,7 @@ pub(super) fn check<'tcx>( let mut to_be_discarded = false; p.pat.walk(|it| { - if delegate.used_move.contains(&it.hir_id){ + if delegate.used_move.contains(&it.hir_id) { to_be_discarded = true; return false; } @@ -87,8 +93,8 @@ pub(super) fn check<'tcx>( | PatKind::Ref(_, Mutability::Mut) => { to_be_discarded = true; false - } - _ => { true } + }, + _ => true, } }); @@ -99,46 +105,42 @@ pub(super) fn check<'tcx>( let (lint, msg, trailing_clone) = match op { Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), - Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"), + Op::LaterCloned | Op::FixClosure(_, _) => ( + ITER_OVEREAGER_CLONED, + "unnecessarily eager cloning of iterator items", + ".cloned()", + ), }; - span_lint_and_then( - cx, - lint, - expr.span, - msg, - |diag| { - match op { - Op::RmCloned | Op::LaterCloned => { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(mut snip) = snippet_opt(cx, method_span) { - snip.push_str(trailing_clone); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); - } - } - Op::FixClosure(name, predicate_expr) => { - if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { - let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { - predicate.replacen('|', "|&", 1) - } else { - format!("|&x| {predicate}(x)") - }; - let snip = format!(".{name}({new_closure}).cloned()" ); - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); - } - } - Op::NeedlessMove(_, _) => { - let method_span = expr.span.with_lo(cloned_call.span.hi()); - if let Some(snip) = snippet_opt(cx, method_span) { - let replace_span = expr.span.with_lo(cloned_recv.span.hi()); - diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); - } - } + span_lint_and_then(cx, lint, expr.span, msg, |diag| match op { + Op::RmCloned | Op::LaterCloned => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(mut snip) = snippet_opt(cx, method_span) { + snip.push_str(trailing_clone); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); } - } - ); + }, + Op::FixClosure(name, predicate_expr) => { + if let Some(predicate) = snippet_opt(cx, predicate_expr.span) { + let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind { + predicate.replacen('|', "|&", 1) + } else { + format!("|&x| {predicate}(x)") + }; + let snip = format!(".{name}({new_closure}).cloned()"); + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable); + } + }, + Op::NeedlessMove(_, _) => { + let method_span = expr.span.with_lo(cloned_call.span.hi()); + if let Some(snip) = snippet_opt(cx, method_span) { + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); + diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); + } + }, + }); } } diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 5fc968f793f..51145afda7f 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( fold_span, "usage of `Iterator::fold` on a type that implements `Try`", "use `try_fold` instead", - format!("try_fold({init_snip}, {args_snip} ...)", ), + format!("try_fold({init_snip}, {args_snip} ...)",), Applicability::HasPlaceholders, ); } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 90f6bc5e3d3..a71a136eba5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3932,21 +3932,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } if sig.decl.implicit_self.has_implicit_self() - && !(self.avoid_breaking_exported_api + && !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)) - && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() - && let Some(first_arg_ty) = first_arg_ty_opt - { - wrong_self_convention::check( - cx, - name, - self_ty, - first_arg_ty, - first_arg.pat.span, - implements_trait, - false - ); - } + && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next() + && let Some(first_arg_ty) = first_arg_ty_opt + { + wrong_self_convention::check( + cx, + name, + self_ty, + first_arg_ty, + first_arg.pat.span, + implements_trait, + false, + ); + } } // if this impl block implements a trait, lint in trait definition instead @@ -4031,10 +4031,16 @@ impl Methods { }, ("all", [arg]) => { if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::NeedlessMove(name, arg), false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ); } - } + }, ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); @@ -4042,24 +4048,35 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, - ("any", [arg]) => { - match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), - Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params => { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); - } - _ => {} - } - } + ("any", [arg]) => match method_call(recv) { + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ), + Some(("chars", recv, _, _, _)) + if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params => + { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + }, + _ => {}, + }, ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); - } + }, ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, - ("as_bytes" | "is_empty", []) => if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); }, + ("as_bytes" | "is_empty", []) => { + if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { + redundant_as_str::check(cx, expr, recv, as_str_span, span); + } + }, ("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), @@ -4081,12 +4098,14 @@ impl Methods { }, Some(("drain", recv, args, ..)) => { drain_collect::check(cx, args, expr, recv); - } + }, _ => {}, } }, ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned , false), + Some(("cloned", recv2, [], _, _)) => { + iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false); + }, Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => { iter_count::check(cx, expr, recv2, name2); }, @@ -4114,7 +4133,9 @@ 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, span, err_span, &self.msrv), + Some(("err", recv, [], err_span, _)) => { + err_expect::check(cx, expr, recv, span, err_span, &self.msrv); + }, _ => unwrap_expect_used::check( cx, expr, @@ -4141,13 +4162,19 @@ impl Methods { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, - (name @ ( "filter" | "find" ) , [arg]) => { + (name @ ("filter" | "find"), [arg]) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::FixClosure(name, arg), false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::FixClosure(name, arg), + false, + ); } - } + }, ("filter_map", [arg]) => { unnecessary_filter_map::check(cx, expr, arg, name); filter_map_bool_then::check(cx, expr, arg, call_span); @@ -4161,20 +4188,34 @@ 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, iter_overeager_cloned::Op::LaterCloned , 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, + iter_overeager_cloned::Op::LaterCloned, + true, + ), _ => {}, }, ("fold", [init, acc]) => { manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, - ("for_each", [arg]) => { - match method_call(recv) { - Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), - _ => {} - } + ("for_each", [arg]) => match method_call(recv) { + Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), + false, + ), + _ => {}, }, ("get", [arg]) => { get_first::check(cx, expr, recv, arg); @@ -4198,8 +4239,14 @@ impl Methods { }, ("last", []) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned , false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } }, ("lock", []) => { @@ -4209,14 +4256,23 @@ impl Methods { if name == "map" { map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { - Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => iter_kv_map::check(cx, map_name, expr, recv2, m_arg), - Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, m_arg), false), - _ => {} + Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { + iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + }, + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::NeedlessMove(name, m_arg), + false, + ), + _ => {}, } } 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), @@ -4238,20 +4294,34 @@ impl Methods { ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { - ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false), + ("cloned", []) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), ("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), - ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2), + ("rev", []) => manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } }, ("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, iter_overeager_cloned::Op::LaterCloned , false), + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + 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), @@ -4276,7 +4346,7 @@ impl Methods { }, ("read_line", [arg]) => { read_line_without_trim::check(cx, expr, recv, arg); - } + }, ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, @@ -4307,10 +4377,16 @@ impl Methods { iter_out_of_bounds::check_skip(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned , false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } - } + }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, @@ -4335,8 +4411,14 @@ impl Methods { ("take", [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { - iter_overeager_cloned::check(cx, expr, recv, recv2, - iter_overeager_cloned::Op::LaterCloned, false); + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::LaterCloned, + false, + ); } }, ("take", []) => needless_option_take::check(cx, expr, recv), @@ -4348,7 +4430,7 @@ impl Methods { }, ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => { unnecessary_fallible_conversions::check_method(cx, expr); - } + }, ("to_owned", []) => { if !suspicious_to_owned::check(cx, expr, recv) { implicit_clone::check(cx, name, expr, recv); @@ -4359,7 +4441,7 @@ impl Methods { }, ("type_id", []) => { type_id_on_box::check(cx, recv, expr.span); - } + }, ("unwrap", []) => { match method_call(recv) { Some(("get", recv, [get_arg], _, _)) => { @@ -4411,7 +4493,7 @@ impl Methods { }, ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); - } + }, ("unwrap_or_else", [u_arg]) => { match method_call(recv) { Some(("map", recv, [map_arg], _, _)) @@ -4424,10 +4506,10 @@ impl Methods { }, ("wake", []) => { waker_clone_wake::check(cx, expr, recv); - } + }, ("write", []) => { readonly_write_lock::check(cx, expr, recv); - } + }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index a1f8e27654f..2ef71be3217 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -87,21 +87,17 @@ pub(super) fn check<'tcx>( } }, Node::Local(l) => { - if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) - = l.pat.kind + if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) - && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter() + && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList] + .into_iter() .any(|item| is_type_diagnostic_item(cx, ty, item)) && let iter_ty = cx.typeck_results().expr_ty(iter_expr) && let Some(block) = get_enclosing_block(cx, l.hir_id) && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) && let [iter_call] = &*iter_calls { - let mut used_count_visitor = UsedCountVisitor { - cx, - id, - count: 0, - }; + let mut used_count_visitor = UsedCountVisitor { cx, id, count: 0 }; walk_block(&mut used_count_visitor, block); if used_count_visitor.count > 1 { return; @@ -117,13 +113,11 @@ pub(super) fn check<'tcx>( span, NEEDLESS_COLLECT_MSG, |diag| { - let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); + let iter_replacement = + format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx)); diag.multipart_suggestion( iter_call.get_suggestion_text(), - vec![ - (l.span, String::new()), - (iter_call.span, iter_replacement) - ], + vec![(l.span, String::new()), (iter_call.span, iter_replacement)], Applicability::MaybeIncorrect, ); }, @@ -175,11 +169,12 @@ fn check_collect_into_intoiterator<'tcx>( .into_iter() .filter_map(|p| { if let ClauseKind::Trait(t) = p.kind().skip_binder() - && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { - Some(t.self_ty()) - } else { - None - } + && cx.tcx.is_diagnostic_item(sym::IntoIterator, t.trait_ref.def_id) + { + Some(t.self_ty()) + } else { + None + } }) .any(|ty| ty == inputs[arg_idx]) { @@ -213,7 +208,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.args) + Ty::new_projection(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args), ) { iter_item_ty == into_iter_item_ty @@ -239,7 +234,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - iter_trait, ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) - && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, args) + && let proj_ty = Ty::new_projection(cx.tcx, iter_item.def_id, args) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id)) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 942f3bd79a6..b942346d5c3 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -235,10 +235,10 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) let body = cx.tcx.hir().body(body); if body.params.is_empty() - && let hir::Expr{ kind, .. } = &body.value - && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind + && let hir::Expr { kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, self_arg, _, _) = kind && ident.name == sym::to_string - && let hir::Expr{ kind, .. } = self_arg + && let hir::Expr { kind, .. } = self_arg && let hir::ExprKind::Lit(lit) = kind && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node { diff --git a/clippy_lints/src/methods/path_ends_with_ext.rs b/clippy_lints/src/methods/path_ends_with_ext.rs index 9ec0ef0ea39..094ead9f4ad 100644 --- a/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/clippy_lints/src/methods/path_ends_with_ext.rs @@ -46,7 +46,7 @@ pub(super) fn check( "this looks like a failed attempt at checking for the file extension", "try", sugg, - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs index 81f9e2a77fc..3b903ec5cdb 100644 --- a/clippy_lints/src/methods/read_line_without_trim.rs +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -46,9 +46,12 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< span, "calling `.parse()` without trimming the trailing newline character", |diag| { - diag.span_note(call.span, "call to `.read_line()` here, \ + diag.span_note( + call.span, + "call to `.read_line()` here, \ which leaves a trailing newline character in the buffer, \ - which in turn will cause `.parse()` to fail"); + which in turn will cause `.parse()` to fail", + ); diag.span_suggestion( expr.span, @@ -56,7 +59,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< format!("{local_snippet}.trim_end()"), Applicability::MachineApplicable, ); - } + }, ); } diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs index e3ec921da0c..1184dd4525a 100644 --- a/clippy_lints/src/methods/readonly_write_lock.rs +++ b/clippy_lints/src/methods/readonly_write_lock.rs @@ -26,13 +26,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id) && let Node::Local(local) = parent && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) - && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| { - local.span.contains(decl.source_info.span) - }) - && let Some(usages) = visit_local_usage(&[local], mir, Location { - block: START_BLOCK, - statement_index: 0, - }) + && let Some((local, _)) = mir + .local_decls + .iter_enumerated() + .find(|(_, decl)| local.span.contains(decl.source_info.span)) + && let Some(usages) = visit_local_usage( + &[local], + mir, + Location { + block: START_BLOCK, + statement_index: 0, + }, + ) && let [usage] = usages.as_slice() { let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty(); @@ -45,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver "this write lock is used only for reading", "consider using a read lock instead", format!("{}.read()", snippet(cx, receiver.span, "")), - Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness + Applicability::MaybeIncorrect, // write lock might be intentional for enforcing exclusiveness ); } } diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index 4ea87027a9e..63d41677fee 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -33,15 +33,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' } fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let ExprKind::Call(f, args) = expr.kind && - let ExprKind::Path(ref path) = f.kind && - let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) { + if let ExprKind::Call(f, args) = expr.kind + && let ExprKind::Path(ref path) = f.kind + && let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) + { // check if argument of `SeekFrom::Current` is `0` - if args.len() == 1 && - let ExprKind::Lit(lit) = args[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { - return true + if args.len() == 1 + && let ExprKind::Lit(lit) = args[0].kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + { + return true; } } diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 50d4de7a680..9f38460357b 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -23,15 +23,15 @@ pub(super) fn check<'tcx>( return; } - if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) && - implements_trait(cx, ty, seek_trait_id, &[]) && - let ExprKind::Call(func, args1) = arg.kind && - let ExprKind::Path(ref path) = func.kind && - let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && - match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) && - args1.len() == 1 && - let ExprKind::Lit(lit) = args1[0].kind && - let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) + && implements_trait(cx, ty, seek_trait_id, &[]) + && let ExprKind::Call(func, args1) = arg.kind + && let ExprKind::Path(ref path) = func.kind + && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) + && args1.len() == 1 + && let ExprKind::Lit(lit) = args1[0].kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node { let method_call_span = expr.span.with_lo(name_span.lo()); span_lint_and_then( diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 6e00e0fd1fb..9da61bca52c 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -133,13 +133,11 @@ fn check_manual_split_once_indirect( && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? - && let mut stmts = enclosing_block .stmts .iter() .skip_while(|stmt| stmt.hir_id != iter_stmt_id) .skip(1) - && let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? && let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)? && first.unwrap_kind == second.unwrap_kind @@ -173,18 +171,8 @@ fn check_manual_split_once_indirect( ); let remove_msg = format!("remove the `{iter_ident}` usages"); - diag.span_suggestion( - first.span, - remove_msg.clone(), - "", - app, - ); - diag.span_suggestion( - second.span, - remove_msg, - "", - app, - ); + diag.span_suggestion(first.span, remove_msg.clone(), "", app); + diag.span_suggestion(second.span, remove_msg, "", app); }); } diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index fb8075e2362..5f6f027a3b5 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -52,7 +52,7 @@ pub(super) fn check<'tcx>( format!("matches!({scrutinee_snip}, {pat_snip})"), Applicability::MachineApplicable, ); - } + }, ); } } diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs index 8959e2c1d75..b2c5987e43d 100644 --- a/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -25,13 +25,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg |diag: &mut Diagnostic| { diag.multipart_suggestion_verbose( "consider splitting the argument", - vec![ - (span, "args".to_string()), - (arg.span, format!("[{arg1:?}, {arg2:?}]")), - ], + vec![(span, "args".to_string()), (arg.span, format!("[{arg1:?}, {arg2:?}]"))], Applicability::MaybeIncorrect, ); - } + }, ); } } diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index 3404bdfe79b..4917936a932 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -44,11 +44,11 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) diag.note( "this returns the type id of the literal type `Box` instead of the \ - type id of the boxed value, which is most likely not what you want" + type id of the boxed value, which is most likely not what you want", ) .note( "if this is intentional, use `TypeId::of::>()` instead, \ - which makes it more clear" + which makes it more clear", ) .span_suggestion( receiver.span, diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index 6660ad215d8..bb32b1bb7fc 100644 --- a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -43,16 +43,15 @@ fn check<'tcx>( // what `>::Error` is: it's always `Infallible` && implements_trait(cx, self_ty, from_into_trait, &[other_ty]) { - let parent_unwrap_call = get_parent_expr(cx, expr) - .and_then(|parent| { - if let ExprKind::MethodCall(path, .., span) = parent.kind - && let sym::unwrap | sym::expect = path.ident.name - { - Some(span) - } else { - None - } - }); + let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| { + if let ExprKind::MethodCall(path, .., span) = parent.kind + && let sym::unwrap | sym::expect = path.ident.name + { + Some(span) + } else { + None + } + }); let (sugg, span, applicability) = match kind { FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => { @@ -63,8 +62,12 @@ fn check<'tcx>( // `try_into().unwrap()` specifically can be trivially replaced with just `into()`, // so that can be machine-applicable - ("into()", primary_span.with_hi(unwrap_span.hi()), Applicability::MachineApplicable) - } + ( + "into()", + primary_span.with_hi(unwrap_span.hi()), + Applicability::MachineApplicable, + ) + }, FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified), FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified), FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified), @@ -77,7 +80,7 @@ fn check<'tcx>( "use of a fallible conversion when an infallible one could be used", "use", sugg.into(), - applicability + applicability, ); } } diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 3e19d72ec91..a1125d70db3 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -81,7 +81,7 @@ pub(super) fn check( { suggs.extend([ (block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()), - (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()) + (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()), ]); } Some(suggs) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 78d4bae60e5..772686d93dd 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -382,10 +382,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Block(..) => continue, Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind - && let output_ty = return_ty(cx, item.owner_id) - && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) - && fn_ctxt.can_coerce(ty, output_ty) + && let output_ty = return_ty(cx, item.owner_id) + && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) + && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) + && fn_ctxt.can_coerce(ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { return false; @@ -393,12 +393,15 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let body = cx.tcx.hir().body(*body_id); let body_expr = &body.value; let mut count = 0; - return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 }); + return find_all_ret_expressions(cx, body_expr, |_| { + count += 1; + count <= 1 + }); } - } + }, Node::Expr(parent_expr) => { - if let Some((callee_def_id, call_generic_args, recv, call_args)) - = get_callee_generic_args_and_args(cx, parent_expr) + if let Some((callee_def_id, call_generic_args, recv, call_args)) = + get_callee_generic_args_and_args(cx, parent_expr) { // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually // call `tcx.try_instantiate_and_normalize_erasing_regions` further down @@ -420,40 +423,49 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< return false; } - let mut trait_predicates = cx.tcx.param_env(callee_def_id) - .caller_bounds().iter().filter(|predicate| { - if let ClauseKind::Trait(trait_predicate) - = predicate.kind().skip_binder() - && trait_predicate.trait_ref.self_ty() == *param_ty - { - true - } else { - false - } - }); + let mut trait_predicates = + cx.tcx + .param_env(callee_def_id) + .caller_bounds() + .iter() + .filter(|predicate| { + if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == *param_ty + { + true + } else { + false + } + }); - let new_subst = cx.tcx.mk_args_from_iter( - call_generic_args.iter() - .enumerate() - .map(|(i, t)| - if i == (*param_index as usize) { - GenericArg::from(ty) - } else { - t - })); + let new_subst = cx + .tcx + .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| { + if i == (*param_index as usize) { + GenericArg::from(ty) + } else { + t + } + })); if trait_predicates.any(|predicate| { let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); - !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) + !cx.tcx + .infer_ctxt() + .build() + .predicate_must_hold_modulo_regions(&obligation) }) { return false; } let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { - if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder::bind(output_ty)) { + if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( + new_subst, + cx.param_env, + EarlyBinder::bind(output_ty), + ) { expr = parent_expr; ty = new_ty; continue; @@ -515,10 +527,11 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) || - implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { - true - } else { - false - } + && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) + || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) + { + true + } else { + false + } } diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index c79a1a7b9d4..4ad12e899fe 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -107,13 +107,17 @@ impl Visitor<'_> for IdentVisitor<'_, '_> { let str = ident.as_str(); if conf.is_ident_too_short(cx, str, ident.span) { - if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind { + if let Node::Item(item) = node + && let ItemKind::Use(..) = item.kind + { return; } // `struct Awa(T)` // ^ if let Node::PathSegment(path) = node { - if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind { + if let Res::Def(def_kind, ..) = path.res + && let DefKind::TyParam = def_kind + { return; } if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local()) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a102b5dfde6..01eace6c48c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { ), |diag| { diag.span_note(definition_span, format!("`{name}` is defined here")); - } + }, ); } } diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 094939f862e..dccf72d3c84 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -200,9 +200,13 @@ impl<'hir> IndexEntry<'hir> { /// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`, /// for `..=5` this returns `Some(5)` fn upper_index_expr(expr: &Expr<'_>) -> Option { - if let ExprKind::Lit(lit) = &expr.kind && let LitKind::Int(index, _) = lit.node { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(index, _) = lit.node + { Some(index as usize) - } else if let Some(higher::Range { end: Some(end), limits, .. }) = higher::Range::hir(expr) + } else if let Some(higher::Range { + end: Some(end), limits, .. + }) = higher::Range::hir(expr) && let ExprKind::Lit(lit) = &end.kind && let LitKind::Int(index @ 1.., _) = lit.node { @@ -228,7 +232,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh if let Some(entry) = entry { match entry { - IndexEntry::StrayAssert { asserted_len, comparison, assert_span, slice } => { + IndexEntry::StrayAssert { + asserted_len, + comparison, + assert_span, + slice, + } => { *entry = IndexEntry::AssertWithIndex { highest_index: index, asserted_len: *asserted_len, @@ -238,8 +247,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh comparison: *comparison, }; }, - IndexEntry::IndexWithoutAssert { highest_index, indexes, .. } - | IndexEntry::AssertWithIndex { highest_index, indexes, .. } => { + IndexEntry::IndexWithoutAssert { + highest_index, indexes, .. + } + | IndexEntry::AssertWithIndex { + highest_index, indexes, .. + } => { indexes.push(expr.span); *highest_index = (*highest_index).max(index); }, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 025eba2d166..02c177c9227 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -207,9 +207,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { _ => (), } } - if let Some((lhs_a, a)) = fetch_assign(then) && - let Some((lhs_b, b)) = fetch_assign(r#else) && - SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) + if let Some((lhs_a, a)) = fetch_assign(then) + && let Some((lhs_b, b)) = fetch_assign(r#else) + && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); @@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { "this if-then-else expression assigns a bool literal", "you can reduce it to", sugg, - applicability + applicability, ); } } diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 53f449f2d43..dcfb109a4c4 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -87,18 +87,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { && let ty::Param(ty) = *ty.value.skip_binder().kind() && let Some((hir_id, fn_id, i)) = match use_cx.node { ExprUseNode::MethodArg(_, _, 0) => None, - ExprUseNode::MethodArg(hir_id, None, i) => { - cx.typeck_results().type_dependent_def_id(hir_id).map(|id| (hir_id, id, i)) - }, - ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i) - if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) { - Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => { - Some((hir_id, id, i)) + ExprUseNode::MethodArg(hir_id, None, i) => cx + .typeck_results() + .type_dependent_def_id(hir_id) + .map(|id| (hir_id, id, i)), + ExprUseNode::FnArg( + &Expr { + kind: ExprKind::Path(ref p), + hir_id, + .. }, + i, + ) if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) { + Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => Some((hir_id, id, i)), _ => None, }, _ => None, - } && let count = needless_borrow_count( + } + && let count = needless_borrow_count( cx, &mut self.possible_borrowers, fn_id, @@ -107,7 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { ty, expr, &self.msrv, - ) && count != 0 + ) + && count != 0 { span_lint_and_then( cx, @@ -119,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { let snip_span = peel_n_hir_expr_refs(expr, count).0.span; let snip = snippet_with_context(cx, snip_span, expr.span.ctxt(), "..", &mut app).0; diag.span_suggestion(expr.span, "change this to", snip.into_owned(), app); - } + }, ); } } @@ -245,7 +252,9 @@ fn needless_borrow_count<'tcx>( predicates.iter().all(|predicate| { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) + && cx + .tcx + .is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack() && ty.is_array() @@ -308,13 +317,13 @@ fn is_mixed_projection_predicate<'tcx>( match projection_ty.self_ty().kind() { ty::Alias(ty::Projection, inner_projection_ty) => { projection_ty = *inner_projection_ty; - } + }, ty::Param(param_ty) => { return (param_ty.index as usize) >= generics.parent_count; - } + }, _ => { return false; - } + }, } } } else { diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index 15589680220..7bbf1fb4cd9 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -46,9 +46,9 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool { } fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { - if is_start && - let ExprKind::Lit(literal) = e.kind && - let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node + if is_start + && let ExprKind::Lit(literal) = e.kind + && let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node { // don't check floating point literals on the start expression of a range return; diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index efb218cd316..d610ba520a4 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -225,7 +225,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind && !mutably_used_vars.contains(&canonical_id) { - self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input); + self.fn_def_ids_to_maybe_unused_mut + .entry(fn_def_id) + .or_default() + .push(input); } } } @@ -520,7 +523,11 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> { // #11182; do not lint if mutability is required elsewhere if let Node::Expr(expr) = cx.tcx.hir().get(hir_id) && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id) - && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind() + && let ty::FnDef(def_id, _) = cx + .tcx + .typeck(cx.tcx.hir().enclosing_body_owner(hir_id)) + .expr_ty(expr) + .kind() && let Some(def_id) = def_id.as_local() { if let Node::Expr(e) = parent diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 76a751012fb..074c9fef1b2 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 60b40aecafa..3a28e511fdd 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -103,11 +103,16 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { && final_stmt.hir_id == stmt.hir_id { let expr_ty = cx.typeck_results().expr_ty(expr); - let mut ret_ty = cx.tcx.fn_sig(item.owner_id).instantiate_identity().output().skip_binder(); + let mut ret_ty = cx + .tcx + .fn_sig(item.owner_id) + .instantiate_identity() + .output() + .skip_binder(); // Remove `impl Future` to get `T` - if cx.tcx.ty_is_opaque_future(ret_ty) && - let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + if cx.tcx.ty_is_opaque_future(ret_ty) + && let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index f2a7debc930..04d75014892 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -48,7 +48,8 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { && let Some((fn_attrs, _)) = snippet.split_once("fn") && !fn_attrs.contains("extern") { - let sugg_span = fn_sig.span + let sugg_span = fn_sig + .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 427e636bdf8..9689f63a013 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -131,12 +131,7 @@ impl LateLintPass<'_> for NonCanonicalImpls { if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) - && implements_trait( - cx, - trait_impl.self_ty(), - copy_def_id, - &[], - ) + && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[]) { if impl_item.ident.name == sym::clone { if block.stmts.is_empty() @@ -144,7 +139,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { && let ExprKind::Unary(UnOp::Deref, deref) = expr.kind && let ExprKind::Path(qpath) = deref.kind && last_path_segment(&qpath).ident.name == kw::SelfLower - {} else { + { + } else { span_lint_and_sugg( cx, NON_CANONICAL_CLONE_IMPL, @@ -197,10 +193,13 @@ impl LateLintPass<'_> for NonCanonicalImpls { && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) // Fix #11178, allow `Self::cmp(self, ..)` too && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified) - {} else { + { + } else { // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid // suggestion tons more complex. - if let [lhs, rhs, ..] = trait_impl.args.as_slice() && lhs != rhs { + if let [lhs, rhs, ..] = trait_impl.args.as_slice() + && lhs != rhs + { return; } @@ -238,12 +237,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { ], }; - diag.multipart_suggestion( - "change this to", - suggs, - Applicability::Unspecified, - ); - } + diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified); + }, ); } } diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index abc8927909b..ef7b367649f 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -244,7 +244,10 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { })) => { #[allow(trivial_casts)] if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into()) - && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity) + && let Some(trait_ref) = cx + .tcx + .impl_trait_ref(item.owner_id) + .map(EarlyBinder::instantiate_identity) && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id { ( @@ -288,8 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { // Recursive call. Track which index the parameter is used in. ExprKind::Call(callee, args) if path_def_id(cx, callee).map_or(false, |id| { - id == param.fn_id - && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) + id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) }) => { if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) { @@ -299,8 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { }, ExprKind::MethodCall(_, receiver, args, _) if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { - id == param.fn_id - && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) + id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) }) => { if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) { @@ -336,8 +337,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { // Only allow field accesses without auto-deref ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => { e = parent; - continue - } + continue; + }, _ => (), }, _ => (), diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index a10aa65e594..4e8631eefa1 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -71,7 +71,7 @@ impl ArithmeticSideEffects { rhs_has_allowed_ty || rhs_from_specific.contains("*") } { - true + true } else if let Some(rhs_from_glob) = self.allowed_binary.get("*") { rhs_from_glob.contains(rhs_ty_string_elem) } else { @@ -144,8 +144,10 @@ impl ArithmeticSideEffects { /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`, fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { let actual = peel_hir_expr_unary(expr).0; - if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { - return Some(n) + if let hir::ExprKind::Lit(lit) = actual.kind + && let ast::LitKind::Int(n, _) = lit.node + { + return Some(n); } if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); @@ -317,7 +319,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind { let body_span = cx.tcx.hir().span_with_body(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { + if let Some(span) = self.const_span + && span.contains(body_span) + { return; } self.const_span = Some(body_span); @@ -327,7 +331,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { let body_owner = cx.tcx.hir().body_owner(body.id()); let body_span = cx.tcx.hir().span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { + if let Some(span) = self.const_span + && span.contains(body_span) + { return; } self.const_span = None; diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 88d56631841..fd3502ad878 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -8,13 +8,14 @@ use rustc_lint::LateContext; use super::EQ_OP; pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let Some((macro_call, macro_name)) - = first_node_macro_backtrace(cx, e).find_map(|macro_call| { - let name = cx.tcx.item_name(macro_call.def_id); - matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne") - .then(|| (macro_call, name)) - }) - && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) + if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { + let name = cx.tcx.item_name(macro_call.def_id); + matches!( + name.as_str(), + "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" + ) + .then(|| (macro_call, name)) + }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) && eq_expr_value(cx, lhs, rhs) && macro_call.is_local() && !is_in_test_function(cx.tcx, e.hir_id) @@ -42,7 +43,9 @@ pub(crate) fn check<'tcx>( e.span, &format!("equal expressions as operands to `{}`", op.as_str()), |diag| { - if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() { + if let BinOpKind::Ne = op + && cx.typeck_results().expr_ty(left).is_floating_point() + { diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead"); } }, diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 9c7f7e1cd7f..7792efe6acd 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -46,16 +46,19 @@ impl EarlyLintPass for OptionEnvUnwrap { ); } - if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind && - matches!(seg.ident.name, sym::expect | sym::unwrap) { - if let ExprKind::Call(caller, _) = &receiver.kind && + if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind + && matches!(seg.ident.name, sym::expect | sym::unwrap) + { + if let ExprKind::Call(caller, _) = &receiver.kind && // If it exists, it will be ::core::option::Option::Some("").unwrap() (A method call in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() { - lint(cx, expr.span); - } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) - is_direct_expn_of(caller.span, "option_env").is_some() { - lint(cx, expr.span); - } - } + is_direct_expn_of(caller.span, "option_env").is_some() + { + lint(cx, expr.span); + } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR) + is_direct_expn_of(caller.span, "option_env").is_some() + { + lint(cx, expr.span); + } + } } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 4fd238cdc9f..d7cbbe13a26 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -240,7 +240,7 @@ fn try_convert_match<'tcx>( if let [first_arm, second_arm] = arms && first_arm.guard.is_none() && second_arm.guard.is_none() - { + { return if is_none_or_err_arm(cx, second_arm) { Some((first_arm.pat, first_arm.body, second_arm.body)) } else if is_none_or_err_arm(cx, first_arm) { diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 4814b3cd661..4d7a055dae1 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -208,7 +208,10 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size), + &format!( + "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", + self.ref_min_size + ), "consider passing by value instead", value_type, Applicability::Unspecified, diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index bca8d0b6be8..b98005d5922 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -43,9 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { "call to `set_readonly` with argument `false`", |diag| { diag.note("on Unix platforms this results in the file being world writable"); - diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\ - https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html"); - } + diag.help( + "you can set the desired permissions using `PermissionsExt`. For more information, see\n\ + https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html", + ); + }, ); } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 310051efc50..945b78185d9 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -289,10 +289,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | sym::ptr_write_volatile | sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut => &[0], - sym::ptr_copy - | sym::ptr_copy_nonoverlapping - | sym::ptr_swap - | sym::ptr_swap_nonoverlapping => &[0, 1], + sym::ptr_copy | sym::ptr_copy_nonoverlapping | sym::ptr_swap | sym::ptr_swap_nonoverlapping => &[0, 1], _ => return, }; @@ -416,7 +413,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -438,104 +434,93 @@ fn check_fn_args<'cx, 'tcx: 'cx>( && let [.., name] = path.segments && cx.tcx.item_name(adt.did()) == name.ident.name { - let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); - let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { - Some(sym::Vec) => ( - [("clone", ".to_owned()")].as_slice(), - DerefTy::Slice( - name.args - .and_then(|args| args.args.first()) - .and_then(|arg| if let GenericArg::Type(ty) = arg { - Some(ty.span) - } else { - None - }), - args.type_at(0), - ), - ), - _ if Some(adt.did()) == cx.tcx.lang_items().string() => ( - [("clone", ".to_owned()"), ("as_str", "")].as_slice(), - DerefTy::Str, - ), - Some(sym::PathBuf) => ( - [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), - DerefTy::Path, - ), - Some(sym::Cow) if mutability == Mutability::Not => { - if let Some((lifetime, ty)) = name.args - .and_then(|args| { - if let [GenericArg::Lifetime(lifetime), ty] = args.args { - return Some((lifetime, ty)); - } + let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); + let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Vec) => ( + [("clone", ".to_owned()")].as_slice(), + DerefTy::Slice( + name.args.and_then(|args| args.args.first()).and_then(|arg| { + if let GenericArg::Type(ty) = arg { + Some(ty.span) + } else { None - }) - { - if !lifetime.is_anonymous() - && fn_sig.output() - .walk() - .filter_map(|arg| { - arg.as_region().and_then(|lifetime| { - match lifetime.kind() { - ty::ReEarlyBound(r) => Some(r.def_id), - ty::ReLateBound(_, r) => r.kind.get_id(), - ty::ReFree(r) => r.bound_region.get_id(), - ty::ReStatic - | ty::ReVar(_) - | ty::RePlaceholder(_) - | ty::ReErased - | ty::ReError(_) => None, - } - }) - }) - .any(|def_id| { - matches!( - lifetime.res, - LifetimeName::Param(param_def_id) if def_id - .as_local() - .is_some_and(|def_id| def_id == param_def_id), - ) - }) - { - // `&Cow<'a, T>` when the return type uses 'a is okay - return None; } - - let ty_name = - snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); - - span_lint_hir_and_then( - cx, - PTR_ARG, - emission_id, - hir_ty.span, - "using a reference to `Cow` is not recommended", - |diag| { - diag.span_suggestion( - hir_ty.span, - "change this to", - format!("&{}{ty_name}", mutability.prefix_str()), - Applicability::Unspecified, - ); - } - ); + }), + args.type_at(0), + ), + ), + _ if Some(adt.did()) == cx.tcx.lang_items().string() => { + ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str) + }, + Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path), + Some(sym::Cow) if mutability == Mutability::Not => { + if let Some((lifetime, ty)) = name.args.and_then(|args| { + if let [GenericArg::Lifetime(lifetime), ty] = args.args { + return Some((lifetime, ty)); + } + None + }) { + if !lifetime.is_anonymous() + && fn_sig + .output() + .walk() + .filter_map(|arg| { + arg.as_region().and_then(|lifetime| match lifetime.kind() { + ty::ReEarlyBound(r) => Some(r.def_id), + ty::ReLateBound(_, r) => r.kind.get_id(), + ty::ReFree(r) => r.bound_region.get_id(), + ty::ReStatic + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => None, + }) + }) + .any(|def_id| { + matches!( + lifetime.res, + LifetimeName::Param(param_def_id) if def_id + .as_local() + .is_some_and(|def_id| def_id == param_def_id), + ) + }) + { + // `&Cow<'a, T>` when the return type uses 'a is okay + return None; } - return None; - }, - _ => return None, - }; - return Some(PtrArg { - idx: i, - emission_id, - span: hir_ty.span, - ty_did: adt.did(), - ty_name: name.ident.name, - method_renames, - ref_prefix: RefPrefix { - lt: *lt, - mutability, - }, - deref_ty, - }); + + let ty_name = snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); + + span_lint_hir_and_then( + cx, + PTR_ARG, + emission_id, + hir_ty.span, + "using a reference to `Cow` is not recommended", + |diag| { + diag.span_suggestion( + hir_ty.span, + "change this to", + format!("&{}{ty_name}", mutability.prefix_str()), + Applicability::Unspecified, + ); + }, + ); + } + return None; + }, + _ => return None, + }; + return Some(PtrArg { + idx: i, + emission_id, + span: hir_ty.span, + ty_did: adt.did(), + ty_name: name.ident.name, + method_renames, + ref_prefix: RefPrefix { lt: *lt, mutability }, + deref_ty, + }); } None }) diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs index a967b19b838..316a72988aa 100644 --- a/clippy_lints/src/pub_use.rs +++ b/clippy_lints/src/pub_use.rs @@ -41,16 +41,17 @@ declare_lint_pass!(PubUse => [PUB_USE]); impl EarlyLintPass for PubUse { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Use(_) = item.kind && - let VisibilityKind::Public = item.vis.kind { - span_lint_and_help( - cx, - PUB_USE, - item.span, - "using `pub use`", - None, - "move the exported item to a public module instead", - ); - } + if let ItemKind::Use(_) = item.kind + && let VisibilityKind::Public = item.vis.kind + { + span_lint_and_help( + cx, + PUB_USE, + item.span, + "using `pub use`", + None, + "move the exported item to a public module instead", + ); + } } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 4305792873c..b133635e883 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -98,16 +98,23 @@ enum IfBlockType<'hir> { } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind && - let Block { stmts: &[], expr: Some(els), .. } = els && - let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els) + if let StmtKind::Local(Local { + pat, + init: Some(init_expr), + els: Some(els), + .. + }) = stmt.kind + && let Block { + stmts: &[], + expr: Some(els), + .. + } = els + && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els) { let mut applicability = Applicability::MaybeIncorrect; let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability); let receiver_str = snippet_with_applicability(cx, inner_pat.span, "..", &mut applicability); - let sugg = format!( - "let {receiver_str} = {init_expr_str}?;", - ); + let sugg = format!("let {receiver_str} = {init_expr_str}?;",); span_lint_and_sugg( cx, QUESTION_MARK, diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 9405b49665e..b27d4cc6e4f 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -59,7 +59,10 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { { let visitor = |expr: &Expr<'_>| { if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind - && let PathSegment { ident: read_or_read_exact, .. } = *path + && let PathSegment { + ident: read_or_read_exact, + .. + } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind @@ -72,15 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { } }; - let (read_found, next_stmt_span) = - if let Some(next_stmt) = block.stmts.get(idx + 1) { + let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) { // case { .. stmt; stmt; .. } (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span) } else if let Some(e) = block.expr { // case { .. stmt; expr } (for_each_expr(e, visitor).is_some(), e.span) } else { - return + return; }; if read_found && !next_stmt_span.from_expansion() { @@ -93,13 +95,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({len}, 0); {}", + format!( + "{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, next_stmt_span, "..") ), applicability, ); - } + }, VecInitKind::WithExprCapacity(hir_id) => { let e = cx.tcx.hir().expect_expr(hir_id); span_lint_and_sugg( @@ -108,14 +111,15 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", "try", - format!("{}.resize({}, 0); {}", + format!( + "{}.resize({}, 0); {}", ident.as_str(), snippet(cx, e.span, ".."), snippet(cx, next_stmt_span, "..") ), applicability, ); - } + }, _ => { span_lint( cx, @@ -123,8 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { next_stmt_span, "reading zero byte data to `Vec`", ); - - } + }, } } } diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 8dfc849bff9..90297ca8bb6 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource}; +use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -69,12 +69,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { /// If `expr` is a desugared `async` block, return the original expression if it does not capture /// any variable by ref. fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && - let body = cx.tcx.hir().body(*body) && - matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) + if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind + && let body = cx.tcx.hir().body(*body) + && matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) { - cx - .typeck_results() + cx.typeck_results() .closure_min_captures .get(def_id) .map_or(true, |m| { @@ -93,12 +92,13 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op /// If `expr` is a desugared `.await`, return the original expression if it does not come from a /// macro expansion. fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && - let ExprKind::Call(_, [into_future_arg]) = match_value.kind && - let ctxt = expr.span.ctxt() && - for_each_expr(into_future_arg, |e| - walk_span_to_context(e.span, ctxt) - .map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))).is_none() + if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind + && let ExprKind::Call(_, [into_future_arg]) = match_value.kind + && let ctxt = expr.span.ctxt() + && for_each_expr(into_future_arg, |e| { + walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) + }) + .is_none() { Some(into_future_arg) } else { diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index be57ed05e78..e679fab5323 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -98,11 +98,15 @@ fn find_innermost_closure<'tcx>( && steps > 0 { expr = body.value; - data = Some((body.value, closure.fn_decl, if is_async_closure(body) { - ty::Asyncness::Yes - } else { - ty::Asyncness::No - })); + data = Some(( + body.value, + closure.fn_decl, + if is_async_closure(body) { + ty::Asyncness::Yes + } else { + ty::Asyncness::No + }, + )); steps -= 1; } @@ -154,7 +158,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { |diag| { if fn_decl.inputs.is_empty() { let mut applicability = Applicability::MachineApplicable; - let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); + let mut hint = + Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind @@ -173,10 +178,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { full_expr.span, "try doing something like", hint.maybe_par(), - applicability + applicability, ); } - } + }, ); } } diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 5a3bee1caad..f6af9cac3de 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -145,8 +145,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { hir::ExprKind::Call(init_call, _) => { if let hir::TyKind::Path(ty_path) = &ty.kind && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path - - && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) { + && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) + { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } }, @@ -164,11 +164,11 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id) && let Some(return_type) = func_ty_to_return_type(cx, func_ty) - && is_same_type(cx, resolved_path_ty.res, if is_ref { - return_type.peel_refs() - } else { - return_type - }) + && is_same_type( + cx, + resolved_path_ty.res, + if is_ref { return_type.peel_refs() } else { return_type }, + ) { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } @@ -177,10 +177,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { hir::ExprKind::Path(init_path) => { // TODO: check for non primty if let Some(primty) = extract_primty(&ty.kind) - && let hir::QPath::TypeRelative(init_ty, _) = init_path && let Some(primty_init) = extract_primty(&init_ty.kind) - && primty == primty_init { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); @@ -205,8 +203,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { }, LitKind::Err => (), } - } - _ => () + }, + _ => (), } }; } diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index ce4ca7b06e9..8b3dabde9be 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -29,7 +29,7 @@ declare_lint_pass!(RefPatterns => [REF_PATTERNS]); impl EarlyLintPass for RefPatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind - && !pat.span.from_expansion() + && !pat.span.from_expansion() { span_lint_and_help( cx, diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index c2294303082..1975946c6e6 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -74,15 +74,24 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) - && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) + && !matches!( + init, + VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: local.span, - init_part: snippet(cx, local.span.shrink_to_lo() - .to(init_expr.span.source_callsite().shrink_to_lo()), "..") - .into_owned(), - space_hint: String::new() + init_part: snippet( + cx, + local + .span + .shrink_to_lo() + .to(init_expr.span.source_callsite().shrink_to_lo()), + "..", + ) + .into_owned(), + space_hint: String::new(), }); } } @@ -94,15 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let Res::Local(id) = path.res && !in_external_macro(cx.sess(), expr.span) && let Some(init) = get_vec_init_kind(cx, right) - && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)) + && !matches!( + init, + VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_) + ) { self.searcher = Some(VecReserveSearcher { local_id: id, err_span: expr.span, - init_part: snippet(cx, left.span.shrink_to_lo() - .to(right.span.source_callsite().shrink_to_lo()), "..") - .into_owned(), // see `assign_expression` test - space_hint: String::new() + init_part: snippet( + cx, + left.span.shrink_to_lo().to(right.span.source_callsite().shrink_to_lo()), + "..", + ) + .into_owned(), // see `assign_expression` test + space_hint: String::new(), }); } } @@ -118,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { self.searcher = Some(VecReserveSearcher { err_span: searcher.err_span.to(stmt.span), space_hint: snippet(cx, space_hint.span, "..").into_owned(), - .. searcher + ..searcher }); } else { searcher.display_err(cx); diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index d7fd3163801..9587326ca00 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -120,9 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { } }; - for impl_item_ref in (*items).iter().filter(|impl_item_ref| { - matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) - }) { + for impl_item_ref in (*items) + .iter() + .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })) + { let method_name = impl_item_ref.ident.name; methods_in_trait.remove(&method_name); check_trait_method(method_name, impl_item_ref.span); @@ -133,9 +134,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { } }, None => { - for impl_item_ref in (*items).iter().filter(|impl_item_ref| { - matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }) - }) { + for impl_item_ref in (*items) + .iter() + .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })) + { let method_name = impl_item_ref.ident.name; let impl_span = impl_item_ref.span; let hir_id = impl_item_ref.id.hir_id(); diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 4b248c9c790..57bcee1a871 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -236,9 +236,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx fn manage_has_expensive_expr_after_last_attr(&mut self) { let has_expensive_stmt = match self.ap.curr_stmt.kind { hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false, - hir::StmtKind::Local(local) if let Some(expr) = local.init - && let hir::ExprKind::Path(_) = expr.kind => false, - _ => true + hir::StmtKind::Local(local) + if let Some(expr) = local.init + && let hir::ExprKind::Path(_) = expr.kind => + { + false + }, + _ => true, }; if has_expensive_stmt { for apa in self.ap.apas.values_mut() { @@ -292,8 +296,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o && { if let Some(local_hir_id) = path_to_local(expr) { local_hir_id == hir_id - } - else { + } else { true } } @@ -306,8 +309,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o let expr_or_init = expr_or_init(self.cx, expr); if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind { local_expr.span.to(span) - } - else { + } else { expr_or_init.span } }, @@ -317,8 +319,12 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o modify_apa_params(&mut apa); let _ = self.ap.apas.insert(hir_id, apa); } else { - let Some(hir_id) = path_to_local(expr) else { return; }; - let Some(apa) = self.ap.apas.get_mut(&hir_id) else { return; }; + let Some(hir_id) = path_to_local(expr) else { + return; + }; + let Some(apa) = self.ap.apas.get_mut(&hir_id) else { + return; + }; match self.ap.curr_stmt.kind { hir::StmtKind::Local(local) => { if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { @@ -437,19 +443,20 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_ { let has_ident = |local_expr: &hir::Expr<'_>| { if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind - && let [first_arg_ps, .. ] = arg_path.segments + && let [first_arg_ps, ..] = arg_path.segments && &first_arg_ps.ident == first_bind_ident { true - } - else { + } else { false } }; if has_ident(first_arg) { return true; } - if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) { + if let hir::ExprKind::Tup(value) = &first_arg.kind + && value.iter().any(has_ident) + { return true; } } diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index a50ba0c0c7e..d07a44770cc 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -106,16 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { { let (lint, used_mod, replace_with) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { - sym::core => ( - STD_INSTEAD_OF_CORE, - "std", - "core", - ), - sym::alloc => ( - STD_INSTEAD_OF_ALLOC, - "std", - "alloc", - ), + sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), + sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { self.prev_span = path.span; return; @@ -123,11 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { }, sym::alloc => { if cx.tcx.crate_name(def_id.krate) == sym::core { - ( - ALLOC_INSTEAD_OF_CORE, - "alloc", - "core", - ) + (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { self.prev_span = path.span; return; @@ -143,7 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { &format!("used import from `{used_mod}` instead of `{replace_with}`"), &format!("consider importing the item from `{replace_with}`"), replace_with.to_string(), - Applicability::MachineApplicable); + Applicability::MachineApplicable, + ); self.prev_span = path.span; } } diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 42cf034f22a..4340c23f830 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -38,21 +38,18 @@ impl LateLintPass<'_> for ConfusingXorAndPow { && let ExprKind::Lit(lit_right) = &right.kind && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..)) && matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..)) - && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal()) - { - span_lint_and_sugg( - cx, - SUSPICIOUS_XOR_USED_AS_POW, - expr.span, - "`^` is not the exponentiation operator", - "did you mean to write", - format!( - "{}.pow({})", - lit_left.node, - lit_right.node - ), - Applicability::MaybeIncorrect, - ); - } + && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node) + .is_some_and(|x| x.is_decimal()) + { + span_lint_and_sugg( + cx, + SUSPICIOUS_XOR_USED_AS_POW, + expr.span, + "`^` is not the exponentiation operator", + "did you mean to write", + format!("{}.pow({})", lit_left.node, lit_right.node), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index b24252a90d9..660e6835e46 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -232,7 +232,7 @@ fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool { } else { false } - } + }, } } diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 1667b74da7f..6a6c94425d1 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -58,9 +58,14 @@ impl LateLintPass<'_> for SwapPtrToRef { let mut app = Applicability::MachineApplicable; let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0; let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0; - diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app); + diag.span_suggestion( + e.span, + "use ptr::swap", + format!("core::ptr::swap({snip1}, {snip2})"), + app, + ); } - } + }, ); } } @@ -73,7 +78,10 @@ fn is_ptr_to_ref(cx: &LateContext<'_>, e: &Expr<'_>, ctxt: SyntaxContext) -> (bo && let ExprKind::Unary(UnOp::Deref, derefed_expr) = borrowed_expr.kind && cx.typeck_results().expr_ty(derefed_expr).is_unsafe_ptr() { - (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span)) + ( + true, + (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span), + ) } else { (false, None) } diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index c61eb0a9311..7c2223ca3ab 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -98,17 +98,17 @@ pub(super) fn check<'tcx>( }, (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { - let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) - = (from_ty.kind(), to_ty.kind()) - && from_def == to_def - { - if same_except_params(from_subs, to_subs) { - return false; - } - Some(from_def.did()) - } else { - None - }; + let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) = + (from_ty.kind(), to_ty.kind()) + && from_def == to_def + { + if same_except_params(from_subs, to_subs) { + return false; + } + Some(from_def.did()) + } else { + None + }; span_lint_and_then( cx, TRANSMUTE_UNDEFINED_REPR, diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 770914e99e1..471bd44b5d5 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -16,8 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) + if let ExprKind::Path(ref _qpath) = arg.kind + && let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; @@ -25,15 +25,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching: // `std::mem::transmute(0 as *const i32)` - if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) { + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind + && is_integer_literal(inner_expr, 0) + { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; } // Catching: // `std::mem::transmute(std::ptr::null::())` - if let ExprKind::Call(func1, []) = arg.kind && - is_path_diagnostic_item(cx, func1, sym::ptr_null) + if let ExprKind::Call(func1, []) = arg.kind + && is_path_diagnostic_item(cx, func1, sym::ptr_null) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 4d0b548d0a2..32aebdd8c0f 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -638,7 +638,9 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option { fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { let source_map = cx.sess().source_map(); let ctxt = span.ctxt(); - if ctxt.is_root() && let Some(search_span) = get_body_search_span(cx) { + if ctxt.is_root() + && let Some(search_span) = get_body_search_span(cx) + { if let Ok(unsafe_line) = source_map.lookup_line(span.lo()) && let Some(body_span) = walk_span_to_context(search_span, SyntaxContext::root()) && let Ok(body_line) = source_map.lookup_line(body_span.lo()) @@ -648,11 +650,13 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { // Get the text from the start of function body to the unsafe block. // fn foo() { some_stuff; unsafe { stuff }; other_stuff; } // ^-------------^ - body_line.line < unsafe_line.line && text_has_safety_comment( - src, - &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos, - ).is_some() + body_line.line < unsafe_line.line + && text_has_safety_comment( + src, + &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) + .is_some() } else { // Problem getting source text. Pretend a comment was found. true diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index e7915953d85..ef67f4b04b5 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { && expr_needs_inferred_result(cx, init) { if !matches!(local.pat.kind, PatKind::Wild) - && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) + && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) { span_lint_and_then( cx, @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { } } else { if let ExprKind::Match(_, _, MatchSource::AwaitDesugar) = init.kind { - return + return; } span_lint_and_then( @@ -55,12 +55,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { if let Some(expr) = &local.init { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; - diag.span_suggestion( - local.span, - "omit the `let` binding", - format!("{snip};"), - app, - ); + diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app); } }, ); diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index b154f75c7ca..9107b2b99b8 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -36,19 +36,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { return; } if let hir::ExprKind::MethodCall(path, recv, args, ..) = expr.kind - && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)){ - let (constructor_path, constructor_item) = - if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind - && let hir::ExprKind::Path(constructor_path) = constructor.kind - && let Some(arg) = constructor_args.first() - { - if constructor.span.from_expansion() || arg.span.from_expansion() { - return; - } - (constructor_path, arg) - } else { + && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)) + { + let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) = + recv.kind + && let hir::ExprKind::Path(constructor_path) = constructor.kind + && let Some(arg) = constructor_args.first() + { + if constructor.span.from_expansion() || arg.span.from_expansion() { return; - }; + } + (constructor_path, arg) + } else { + return; + }; let constructor_symbol = match constructor_path { hir::QPath::Resolved(_, path) => { if let Some(path_segment) = path.segments.last() { @@ -82,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { cx, UNNECESSARY_MAP_ON_CONSTRUCTOR, expr.span, - &format!("unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name), + &format!( + "unnecessary {} on constructor {constructor_snippet}(_)", + path.ident.name + ), "try", format!("{constructor_snippet}({fun_snippet}({constructor_arg_snippet}))"), applicability, diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index b75df0dec9a..c35a2afab48 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -42,9 +42,9 @@ declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); impl LateLintPass<'_> for UnnecessaryStruct { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { - if let Some(parent) = get_parent_expr(cx, expr) && - let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) && - parent_ty.is_any_ptr() + if let Some(parent) = get_parent_expr(cx, expr) + && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) + && parent_ty.is_any_ptr() { if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { // When the type implements `Copy`, a reference to the new struct works on the @@ -59,9 +59,9 @@ impl LateLintPass<'_> for UnnecessaryStruct { } // TODO: do not propose to replace *XX if XX is not Copy - if let ExprKind::Unary(UnOp::Deref, target) = base.kind && - matches!(target.kind, ExprKind::Path(..)) && - !is_copy(cx, cx.typeck_results().expr_ty(expr)) + if let ExprKind::Unary(UnOp::Deref, target) = base.kind + && matches!(target.kind, ExprKind::Path(..)) + && !is_copy(cx, cx.typeck_results().expr_ty(expr)) { // `*base` cannot be used instead of the struct in the general case if it is not Copy. return; @@ -81,8 +81,8 @@ impl LateLintPass<'_> for UnnecessaryStruct { } fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(hir_id) = path_to_local(expr) && - let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + if let Some(hir_id) = path_to_local(expr) + && let Node::Pat(pat) = cx.tcx.hir().get(hir_id) { matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) } else { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 66b52dc94c2..0473ecaabeb 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { ident.span, "`peek` never called on `Peekable` iterator", None, - "consider removing the call to `peekable`" - ); + "consider removing the call to `peekable`", + ); } } } @@ -131,11 +131,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { // If the Peekable is passed to a function, stop ExprKind::Call(_, args) => { if let Some(func_did) = fn_def_id(self.cx, expr) - && let Some(into_iter_did) = self - .cx - .tcx - .lang_items() - .into_iter_fn() + && let Some(into_iter_did) = self.cx.tcx.lang_items().into_iter_fn() && func_did == into_iter_did { // Probably a for loop desugar, stop searching diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index de43c5cbae4..fbb36bea068 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -31,18 +31,21 @@ declare_clippy_lint! { declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> { - if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind + if let ExprKind::MethodCall(box MethodCall { + seg: name_ident, + receiver, + .. + }) = &expr.kind && let method_name = name_ident.ident.name.as_str() && (method_name == "ceil" || method_name == "round" || method_name == "floor") && let ExprKind::Lit(token_lit) = &receiver.kind && token_lit.is_semantic_float() - && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::() { - (f.fract() == 0.0).then(|| - (method_name, snippet(cx, receiver.span, "..").to_string()) - ) - } else { - None - } + && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::() + { + (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string())) + } else { + None + } } impl EarlyLintPass for UnusedRounding { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index edb5935f606..28f1d487eb5 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -215,20 +215,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { did, args, cx.typeck_results().node_args(recv.hir_id), - MethodOrFunction::Function + MethodOrFunction::Function, )) - } + }, ExprKind::MethodCall(.., args, _) => { - cx.typeck_results().type_dependent_def_id(parent.hir_id) - .map(|did| { - return ( - did, - args, - cx.typeck_results().node_args(parent.hir_id), - MethodOrFunction::Method - ); - }) - } + cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| { + return ( + did, + args, + cx.typeck_results().node_args(parent.hir_id), + MethodOrFunction::Method, + ); + }) + }, _ => None, }; @@ -244,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { into_iter_did, cx.typeck_results().expr_ty(into_iter_recv), param.index, - node_args + node_args, ) && self.expn_depth == 0 { @@ -255,26 +254,38 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let plural = if depth == 0 { "" } else { "s" }; let mut applicability = Applicability::MachineApplicable; - let sugg = snippet_with_applicability(cx, into_iter_recv.span.source_callsite(), "", &mut applicability).into_owned(); - span_lint_and_then(cx, USELESS_CONVERSION, e.span, "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", |diag| { - diag.span_suggestion( - e.span, - format!("consider removing the `.into_iter()`{plural}"), - sugg, - applicability, - ); - diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); - }); + let sugg = snippet_with_applicability( + cx, + into_iter_recv.span.source_callsite(), + "", + &mut applicability, + ) + .into_owned(); + span_lint_and_then( + cx, + USELESS_CONVERSION, + e.span, + "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", + |diag| { + diag.span_suggestion( + e.span, + format!("consider removing the `.into_iter()`{plural}"), + sugg, + applicability, + ); + diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); + }, + ); // Early return to avoid linting again with contradicting suggestions return; } } - if let Some(id) = path_to_local(recv) && - let Node::Pat(pat) = cx.tcx.hir().get(id) && - let PatKind::Binding(ann, ..) = pat.kind && - ann != BindingAnnotation::MUT + if let Some(id) = path_to_local(recv) + && let Node::Pat(pat) = cx.tcx.hir().get(id) + && let PatKind::Binding(ann, ..) = pat.kind + && ann != BindingAnnotation::MUT { // Do not remove .into_iter() applied to a non-mutable local variable used in // a larger expression context as it would differ in mutability. diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index bbb5ade8b9f..00e352961bd 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -153,8 +153,9 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { let fields; if is_lint_ref_ty { if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind - && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind { - fields = struct_fields; + && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind + { + fields = struct_fields; } else { return; } diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index a3acb8f1762..81be04659b9 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -270,7 +270,8 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { let alloc = alloc.inner(); str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) - .ok().map(ToOwned::to_owned) + .ok() + .map(ToOwned::to_owned) } else { None } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 17294450acf..a9dd44afaf7 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -110,14 +110,15 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } else { ControlFlow::Break(()) } - }).is_continue(); + }) + .is_continue(); if only_slice_uses { self.check_vec_macro( cx, &vec_args, expr.span.ctxt().outer_expn_data().call_site, - SuggestedType::Array + SuggestedType::Array, ); } } diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index eb9bac4210b..c8b9402f1ae 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -211,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { found: searcher.found + 1, err_span: searcher.err_span.to(stmt.span), last_push_expr: expr.hir_id, - .. searcher + ..searcher }); } else { searcher.display_err(cx); diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 49637652001..8abcc964b89 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -82,7 +82,9 @@ impl EarlyLintPass for Visibility { if !in_external_macro(cx.sess(), item.span) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { - if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) { + if **path == kw::SelfLower + && let Some(false) = is_from_proc_macro(cx, item.vis.span) + { span_lint_and_sugg( cx, NEEDLESS_PUB_SELF, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index ea22be24a0d..b6f942a90d3 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -342,7 +342,10 @@ impl<'tcx> LateLintPass<'tcx> for Write { } fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind + if let ItemKind::Impl(Impl { + of_trait: Some(trait_ref), + .. + }) = &item.kind && let Some(trait_id) = trait_ref.trait_def_id() { cx.tcx.is_diagnostic_item(sym::Debug, trait_id) @@ -508,7 +511,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue }; + let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { + continue; + }; let format_string_is_raw = format_string_snippet.starts_with('r'); let replacement = match (format_string_is_raw, replace_raw) { @@ -537,7 +542,8 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { if let Some(replacement) = replacement // `format!("{}", "a")`, `format!("{named}", named = "b") // ~~~~~ ~~~~~~~~~~~~~ - && let Some(removal_span) = format_arg_removal_span(format_args, index) { + && let Some(removal_span) = format_arg_removal_span(format_args, index) + { let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw); suggestion.push((*placeholder_span, replacement)); suggestion.push((removal_span, String::new())); @@ -549,7 +555,8 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { if !suggestion.is_empty() { for piece in &format_args.template { if let Some((span, index)) = positional_arg_piece_span(piece) - && suggestion.iter().all(|(s, _)| *s != span) { + && suggestion.iter().all(|(s, _)| *s != span) + { let decrement = replaced_position.iter().filter(|i| **i < index).count(); suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); } diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 6be8b8bb916..3bac0626f88 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -292,7 +292,9 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { (Pat::Str("#!["), Pat::Str("]")) }; - if let Some(ident) = attr.ident() && let Pat::Str(old_pat) = pat.0 { + if let Some(ident) = attr.ident() + && let Pat::Str(old_pat) = pat.0 + { // TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of // refactoring // NOTE: This will likely have false positives, like `allow = 1` diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 79c04c7c7f4..b7d8c0a8fd7 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -405,8 +405,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field) { mir_to_const(self.lcx, desired_field) - } - else { + } else { result } }, @@ -462,11 +461,15 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { // Check if this constant is based on `cfg!(..)`, // which is NOT constant for our purposes. if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) - && let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. }) = node - && let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx - .tcx - .hir() - .get(body_id.hir_id) + && let Node::Item(Item { + kind: ItemKind::Const(.., body_id), + .. + }) = node + && let Node::Expr(Expr { + kind: ExprKind::Lit(_), + span, + .. + }) = self.lcx.tcx.hir().get(body_id.hir_id) && is_direct_expn_of(*span, "cfg").is_some() { return None; @@ -531,7 +534,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo) && let Some(src) = src.as_str() { - use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace}; + use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; if !tokenize(src) .map(|t| t.kind) .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) @@ -717,8 +720,7 @@ fn field_of_struct<'tcx>( && let Some(&(val, ty)) = dc.fields.get(field_idx) { Some(mir::Const::Val(val, ty)) - } - else { + } else { None } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 52214e733f1..2a8b2ebd5fb 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1142,12 +1142,8 @@ fn eq_span_tokens( let pred = |t: &(_, _)| pred(t.0); let map = |(_, x)| x; - let ltok = tokenize_with_text(lsrc) - .filter(pred) - .map(map); - let rtok = tokenize_with_text(rsrc) - .filter(pred) - .map(map); + let ltok = tokenize_with_text(lsrc).filter(pred).map(map); + let rtok = tokenize_with_text(rsrc).filter(pred).map(map); ltok.eq(rtok) } else { // Unable to access the source. Conservatively assume the blocks aren't equal. diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 7497d4b2cf1..1181dfc0ef9 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -287,7 +287,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { match *qpath { QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)), - QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) }, + QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath), _ => false, } } @@ -863,8 +863,8 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool { - if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind && - seg.ident.name == sym::from + if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind + && seg.ident.name == sym::from { match arg.kind { ExprKind::Lit(hir::Lit { @@ -873,12 +873,12 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: & }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String), ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec), ExprKind::Repeat(_, ArrayLen::Body(len)) => { - if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind && - let LitKind::Int(v, _) = const_lit.node + if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind + && let LitKind::Int(v, _) = const_lit.node { - return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec); + return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec); } - } + }, _ => (), } } @@ -1515,32 +1515,30 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti false } }); - let end_is_none_or_max = end.map_or(true, |end| { - match limits { - RangeLimits::Closed => { - if let rustc_ty::Adt(_, subst) = ty.kind() - && let bnd_ty = subst.type_at(0) - && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) - && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) - && let Some(end_const) = constant(cx, cx.typeck_results(), end) - { - end_const == max_const - } else { - false - } - }, - RangeLimits::HalfOpen => { - if let Some(container_path) = container_path - && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind - { - container_path.res == path.res - } else { - false - } - }, - } + let end_is_none_or_max = end.map_or(true, |end| match limits { + RangeLimits::Closed => { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) + && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) + && let Some(end_const) = constant(cx, cx.typeck_results(), end) + { + end_const == max_const + } else { + false + } + }, + RangeLimits::HalfOpen => { + if let Some(container_path) = container_path + && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }, }); return start_is_none_or_min && end_is_none_or_max; } @@ -2101,7 +2099,8 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) }, ExprKind::Path(QPath::Resolved(_, path)) if path.segments.iter().all(|seg| seg.infer_args) - && let Some(did) = path.res.opt_def_id() => { + && let Some(did) = path.res.opt_def_id() => + { cx.tcx.is_diagnostic_item(sym::convert_identity, did) }, _ => false, @@ -2455,7 +2454,8 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym for id in tcx.hir().module_items(module) { if matches!(tcx.def_kind(id.owner_id), DefKind::Const) && let item = tcx.hir().item(id) - && let ItemKind::Const(ty, _generics, _body) = item.kind { + && let ItemKind::Const(ty, _generics, _body) = item.kind + { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { // We could also check for the type name `test::TestDescAndFn` if let Res::Def(DefKind::Struct, _) = path.res { @@ -2719,7 +2719,9 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio let ctxt = e.span.ctxt(); walk_to_expr_usage(cx, e, &mut |parent, child_id| { // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead. - if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) { + if adjustments.is_empty() + && let Node::Expr(e) = cx.tcx.hir().get(child_id) + { adjustments = cx.typeck_results().expr_adjustments(e); } match parent { @@ -2916,13 +2918,13 @@ pub fn pat_and_expr_can_be_question_mark<'a, 'hir>( pat: &'a Pat<'hir>, else_body: &Expr<'_>, ) -> Option<&'a Pat<'hir>> { - if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind && - is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) && - !is_refutable(cx, inner_pat) && - let else_body = peel_blocks(else_body) && - let ExprKind::Ret(Some(ret_val)) = else_body.kind && - let ExprKind::Path(ret_path) = ret_val.kind && - is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone) + if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind + && is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) + && !is_refutable(cx, inner_pat) + && let else_body = peel_blocks(else_body) + && let ExprKind::Ret(Some(ret_val)) = else_body.kind + && let ExprKind::Path(ret_path) = ret_val.kind + && is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone) { Some(inner_pat) } else { diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 916f7892944..a4a6f8e15f9 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -70,9 +70,9 @@ pub fn expr_block( app: &mut Applicability, ) -> String { let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app); - if !from_macro && - let ExprKind::Block(block, _) = expr.kind && - block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + if !from_macro + && let ExprKind::Block(block, _) = expr.kind + && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { format!("{code}") } else { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 673b259523e..7eff93881b2 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -890,7 +890,9 @@ pub fn for_each_top_level_late_bound_region( impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow> TypeVisitor> for V { type BreakTy = B; fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { - if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index { + if let RegionKind::ReLateBound(idx, bound) = r.kind() + && idx.as_u32() == self.index + { (self.f)(bound) } else { ControlFlow::Continue(()) @@ -984,16 +986,16 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc .iter() .try_fold(false, |found, p| { if let ty::ClauseKind::Trait(p) = p.kind().skip_binder() - && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() - && ty.index == self_ty.index - { - // This should use `super_traits_of`, but that's a private function. - if p.trait_ref.def_id == fn_once_id { - return Some(true); - } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id { - return None; + && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() + && ty.index == self_ty.index + { + // This should use `super_traits_of`, but that's a private function. + if p.trait_ref.def_id == fn_once_id { + return Some(true); + } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id { + return None; + } } - } Some(found) }) .unwrap_or(false) diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 75064672326..76fa15e1588 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -267,7 +267,9 @@ fn path_segment_certainty( /// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`. /// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`. fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option { - if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() { + if path_segment.res == Res::Err + && let Some(def_id) = parent_certainty.to_def_id() + { let mut def_path = cx.get_def_path(def_id); def_path.push(path_segment.ident.name); let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::>()); diff --git a/src/driver.rs b/src/driver.rs index 74f8ed69b4d..7bb49d08da6 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -266,10 +266,12 @@ pub fn main() { if clippy_enabled { args.extend(clippy_args); rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }) - .set_using_internal_features(using_internal_features).run() + .set_using_internal_features(using_internal_features) + .run() } else { rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }) - .set_using_internal_features(using_internal_features).run() + .set_using_internal_features(using_internal_features) + .run() } })) } diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 43df654389b..3303eb14567 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -379,7 +379,8 @@ impl MacroArm { p.span(), )?; self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out); - self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) + self.args + .push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) } else { self.add_multi_arg_def(dollar_span, g.span(), out); self.args.push(TT::Group(g)); @@ -436,7 +437,12 @@ impl Expander { && p.as_char() == ESCAPE_CHAR && let Some(arm) = self.arm.as_mut() { - arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?; + arm.add_arg( + p.span(), + mem::replace(&mut input.tt, tt), + &mut input.iter, + &mut self.expn, + )?; if input.next().is_none() { return Ok(()); } diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 44d7f6e6d79..167263d31df 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -80,9 +80,7 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/10452 let should_not_lint = [(); if true { 1 } else { 0 }]; - let should_not_lint = const { - if true { 1 } else { 0 } - }; + let should_not_lint = const { if true { 1 } else { 0 } }; some_fn(a); } @@ -110,7 +108,9 @@ fn if_let(a: Enum, b: Enum) { 0 }; - if let Enum::A = a && let Enum::B = b { + if let Enum::A = a + && let Enum::B = b + { 1 } else { 0 diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index 7d989ae4bb3..f3f055eb7f0 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -112,9 +112,7 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/10452 let should_not_lint = [(); if true { 1 } else { 0 }]; - let should_not_lint = const { - if true { 1 } else { 0 } - }; + let should_not_lint = const { if true { 1 } else { 0 } }; some_fn(a); } @@ -142,7 +140,9 @@ fn if_let(a: Enum, b: Enum) { 0 }; - if let Enum::A = a && let Enum::B = b { + if let Enum::A = a + && let Enum::B = b + { 1 } else { 0 diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr index 837ed05d3a6..714da8a4169 100644 --- a/tests/ui/bool_to_int_with_if.stderr +++ b/tests/ui/bool_to_int_with_if.stderr @@ -99,7 +99,7 @@ LL | | }; = note: `!b as i32` or `(!b).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:124:5 + --> $DIR/bool_to_int_with_if.rs:122:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index 90eb50715a2..e102b13a761 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -15,7 +15,9 @@ fn main() { let s = [0].as_slice(); if s.is_empty() {} if s.is_empty() {} - if s.is_empty() && s.is_empty() {} + if s.is_empty() + && s.is_empty() + {} // Allow comparisons to non-empty let s = String::new(); @@ -28,5 +30,7 @@ fn main() { if let [0] = &*v {} let s = [0].as_slice(); if let [0] = s {} - if let [0] = &*s && s == [0] {} + if let [0] = &*s + && s == [0] + {} } diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 0964c4a20a9..69a6c967d38 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -15,7 +15,9 @@ fn main() { let s = [0].as_slice(); if let [] = s {} if let [] = &*s {} - if let [] = &*s && s == [] {} + if let [] = &*s + && s == [] + {} // Allow comparisons to non-empty let s = String::new(); @@ -28,5 +30,7 @@ fn main() { if let [0] = &*v {} let s = [0].as_slice(); if let [0] = s {} - if let [0] = &*s && s == [0] {} + if let [0] = &*s + && s == [0] + {} } diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr index b97ab4c3c93..83d431fd52b 100644 --- a/tests/ui/comparison_to_empty.stderr +++ b/tests/ui/comparison_to_empty.stderr @@ -46,14 +46,14 @@ LL | if let [] = &*s {} error: comparison to empty slice using `if let` --> $DIR/comparison_to_empty.rs:18:8 | -LL | if let [] = &*s && s == [] {} +LL | if let [] = &*s | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> $DIR/comparison_to_empty.rs:18:24 + --> $DIR/comparison_to_empty.rs:19:12 | -LL | if let [] = &*s && s == [] {} - | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` +LL | && s == [] + | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: aborting due to 9 previous errors diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs index 06968f8bae4..ee44909f37e 100644 --- a/tests/ui/manual_filter.rs +++ b/tests/ui/manual_filter.rs @@ -191,9 +191,7 @@ fn main() { None => None, }; let _ = match Some(15) { - Some(x) => unsafe { - if f(x) { Some(x) } else { None } - }, + Some(x) => unsafe { if f(x) { Some(x) } else { None } }, None => None, }; diff --git a/tests/ui/manual_filter.stderr b/tests/ui/manual_filter.stderr index 1490f209735..b23ad887eb2 100644 --- a/tests/ui/manual_filter.stderr +++ b/tests/ui/manual_filter.stderr @@ -169,15 +169,13 @@ error: manual implementation of `Option::filter` | LL | let _ = match Some(15) { | _____________^ -LL | | Some(x) => unsafe { -LL | | if f(x) { Some(x) } else { None } -LL | | }, +LL | | Some(x) => unsafe { if f(x) { Some(x) } else { None } }, LL | | None => None, LL | | }; | |_____^ help: try: `Some(15).filter(|&x| unsafe { f(x) })` error: manual implementation of `Option::filter` - --> $DIR/manual_filter.rs:203:12 + --> $DIR/manual_filter.rs:201:12 | LL | } else if let Some(x) = Some(16) { | ____________^ diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs index 6775fdc921f..27717ab3a73 100644 --- a/tests/ui/manual_let_else.rs +++ b/tests/ui/manual_let_else.rs @@ -35,9 +35,7 @@ fn fire() { let v = if let Some(v) = g() { //~^ ERROR: this could be rewritten as `let...else` // Blocks around the identity should have no impact - { - { v } - } + { { v } } } else { // Some computation should still make it fire g(); diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr index 49dbd7615e0..2b6504a1827 100644 --- a/tests/ui/manual_let_else.stderr +++ b/tests/ui/manual_let_else.stderr @@ -31,7 +31,7 @@ error: this could be rewritten as `let...else` LL | / let v = if let Some(v) = g() { LL | | LL | | // Blocks around the identity should have no impact -LL | | { +LL | | { { v } } ... | LL | | return; LL | | }; @@ -47,25 +47,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:49:9 + --> $DIR/manual_let_else.rs:47:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:51:9 + --> $DIR/manual_let_else.rs:49:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:56:5 + --> $DIR/manual_let_else.rs:54:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:60:5 + --> $DIR/manual_let_else.rs:58:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -83,7 +83,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:68:5 + --> $DIR/manual_let_else.rs:66:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -101,7 +101,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:76:5 + --> $DIR/manual_let_else.rs:74:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -121,7 +121,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:87:5 + --> $DIR/manual_let_else.rs:85:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -143,13 +143,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:98:5 + --> $DIR/manual_let_else.rs:96:5 | LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:102:5 + --> $DIR/manual_let_else.rs:100:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -170,7 +170,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:112:5 + --> $DIR/manual_let_else.rs:110:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -191,7 +191,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:122:5 + --> $DIR/manual_let_else.rs:120:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -220,7 +220,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:140:5 + --> $DIR/manual_let_else.rs:138:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | @@ -238,7 +238,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:148:5 + --> $DIR/manual_let_else.rs:146:5 | LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { LL | | @@ -256,7 +256,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:158:13 + --> $DIR/manual_let_else.rs:156:13 | LL | let $n = if let Some(v) = $e { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` @@ -267,19 +267,19 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:167:5 + --> $DIR/manual_let_else.rs:165:5 | LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:171:5 + --> $DIR/manual_let_else.rs:169:5 | LL | let mut v = if let Variant::B(b) = e() { b } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:176:5 + --> $DIR/manual_let_else.rs:174:5 | LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { LL | | @@ -297,19 +297,19 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:183:5 + --> $DIR/manual_let_else.rs:181:5 | LL | let v = if let Variant::A(.., a) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:187:5 + --> $DIR/manual_let_else.rs:185:5 | LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:191:5 + --> $DIR/manual_let_else.rs:189:5 | LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -327,7 +327,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:199:5 + --> $DIR/manual_let_else.rs:197:5 | LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -345,7 +345,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:207:5 + --> $DIR/manual_let_else.rs:205:5 | LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { LL | | @@ -363,7 +363,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:324:5 + --> $DIR/manual_let_else.rs:322:5 | LL | / let _ = match ff { LL | | diff --git a/tests/ui/manual_map_option_2.fixed b/tests/ui/manual_map_option_2.fixed index 513f6e32340..f5bb4e0af1b 100644 --- a/tests/ui/manual_map_option_2.fixed +++ b/tests/ui/manual_map_option_2.fixed @@ -42,9 +42,7 @@ fn main() { // Lint. `s` is captured by reference, so no lifetime issues. let s = Some(String::new()); - let _ = s.as_ref().map(|x| { - if let Some(ref s) = s { (x.clone(), s) } else { panic!() } - }); + let _ = s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }); // Issue #7820 unsafe fn f(x: u32) -> u32 { diff --git a/tests/ui/manual_map_option_2.rs b/tests/ui/manual_map_option_2.rs index fd186743fe2..cbc2356e0a2 100644 --- a/tests/ui/manual_map_option_2.rs +++ b/tests/ui/manual_map_option_2.rs @@ -46,9 +46,7 @@ fn main() { // Lint. `s` is captured by reference, so no lifetime issues. let s = Some(String::new()); let _ = match &s { - Some(x) => Some({ - if let Some(ref s) = s { (x.clone(), s) } else { panic!() } - }), + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), None => None, }; diff --git a/tests/ui/manual_map_option_2.stderr b/tests/ui/manual_map_option_2.stderr index bf242c0416c..d3754f22d89 100644 --- a/tests/ui/manual_map_option_2.stderr +++ b/tests/ui/manual_map_option_2.stderr @@ -26,22 +26,13 @@ error: manual implementation of `Option::map` | LL | let _ = match &s { | _____________^ -LL | | Some(x) => Some({ -LL | | if let Some(ref s) = s { (x.clone(), s) } else { panic!() } -LL | | }), +LL | | Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), LL | | None => None, LL | | }; - | |_____^ - | -help: try - | -LL ~ let _ = s.as_ref().map(|x| { -LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() } -LL ~ }); - | + | |_____^ help: try: `s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } })` error: manual implementation of `Option::map` - --> $DIR/manual_map_option_2.rs:60:17 + --> $DIR/manual_map_option_2.rs:58:17 | LL | let _ = match Some(0) { | _________________^ @@ -51,7 +42,7 @@ LL | | }; | |_________^ help: try: `Some(0).map(|x| f(x))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option_2.rs:65:13 + --> $DIR/manual_map_option_2.rs:63:13 | LL | let _ = match Some(0) { | _____________^ @@ -61,7 +52,7 @@ LL | | }; | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })` error: manual implementation of `Option::map` - --> $DIR/manual_map_option_2.rs:69:13 + --> $DIR/manual_map_option_2.rs:67:13 | LL | let _ = match Some(0) { | _____________^ diff --git a/tests/ui/needless_if.fixed b/tests/ui/needless_if.fixed index b84182c5756..be35dcddbe6 100644 --- a/tests/ui/needless_if.fixed +++ b/tests/ui/needless_if.fixed @@ -39,11 +39,21 @@ fn main() { } // Do not lint `if let` or let chains if let true = true {} - if let true = true && true {} - if true && let true = true {} + if let true = true + && true + {} + if true + && let true = true + {} // Can lint nested `if let`s ({ - if let true = true && true { true } else { false } + if let true = true + && true + { + true + } else { + false + } } && true); external! { if (true) {} } with_span! { diff --git a/tests/ui/needless_if.rs b/tests/ui/needless_if.rs index 6c6023c72dc..e2ad17e69a8 100644 --- a/tests/ui/needless_if.rs +++ b/tests/ui/needless_if.rs @@ -39,11 +39,21 @@ fn main() { } // Do not lint `if let` or let chains if let true = true {} - if let true = true && true {} - if true && let true = true {} + if let true = true + && true + {} + if true + && let true = true + {} // Can lint nested `if let`s if { - if let true = true && true { true } else { false } + if let true = true + && true + { + true + } else { + false + } } && true {} external! { if (true) {} } diff --git a/tests/ui/needless_if.stderr b/tests/ui/needless_if.stderr index ed5b9452b86..c3e83c0f1f5 100644 --- a/tests/ui/needless_if.stderr +++ b/tests/ui/needless_if.stderr @@ -29,10 +29,13 @@ LL + }); | error: this `if` branch is empty - --> $DIR/needless_if.rs:45:5 + --> $DIR/needless_if.rs:49:5 | LL | / if { -LL | | if let true = true && true { true } else { false } +LL | | if let true = true +LL | | && true +LL | | { +... | LL | | } && true LL | | {} | |______^ @@ -40,24 +43,30 @@ LL | | {} help: you can remove it | LL ~ ({ -LL + if let true = true && true { true } else { false } +LL + if let true = true +LL + && true +LL + { +LL + true +LL + } else { +LL + false +LL + } LL + } && true); | error: this `if` branch is empty - --> $DIR/needless_if.rs:83:5 + --> $DIR/needless_if.rs:93:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> $DIR/needless_if.rs:85:5 + --> $DIR/needless_if.rs:95:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> $DIR/needless_if.rs:89:5 + --> $DIR/needless_if.rs:99:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 9f45da04862..891b2b01437 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -230,7 +230,9 @@ fn does_not_lint() { } let x; - if true && let Some(n) = Some("let chains too") { + if true + && let Some(n) = Some("let chains too") + { x = 1; } else { x = 2; diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 0dab0faad56..55399511639 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -230,7 +230,9 @@ fn does_not_lint() { } let x; - if true && let Some(n) = Some("let chains too") { + if true + && let Some(n) = Some("let chains too") + { x = 1; } else { x = 2; diff --git a/tests/ui/redundant_guards.fixed b/tests/ui/redundant_guards.fixed index f23116a7e1c..f8af9092725 100644 --- a/tests/ui/redundant_guards.fixed +++ b/tests/ui/redundant_guards.fixed @@ -48,7 +48,7 @@ fn main() { Some(x) if let Some(1) = x => { x; .. - } + }, _ => todo!(), }; let y = 1; diff --git a/tests/ui/redundant_guards.rs b/tests/ui/redundant_guards.rs index c0206b4cec7..b46f8a6207e 100644 --- a/tests/ui/redundant_guards.rs +++ b/tests/ui/redundant_guards.rs @@ -48,7 +48,7 @@ fn main() { Some(x) if let Some(1) = x => { x; .. - } + }, _ => todo!(), }; let y = 1; diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 60f9fb6d493..c9b76262d70 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -16,10 +16,15 @@ fn issue_11174(boolean: bool, maybe_some: Option) -> bool { fn issue_11174_edge_cases(boolean: bool, boolean2: bool, maybe_some: Option) { let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses - let _ = match maybe_some { // can't use `matches!` here - // because `expr` metavars in macros don't allow let exprs - None if let Some(x) = Some(0) && x > 5 => true, - _ => false + let _ = match maybe_some { + // can't use `matches!` here + // because `expr` metavars in macros don't allow let exprs + None if let Some(x) = Some(0) + && x > 5 => + { + true + }, + _ => false, }; } diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 94bbb569c2a..a5f9caf659c 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -16,10 +16,15 @@ fn issue_11174(boolean: bool, maybe_some: Option) -> bool { fn issue_11174_edge_cases(boolean: bool, boolean2: bool, maybe_some: Option) { let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses - let _ = match maybe_some { // can't use `matches!` here - // because `expr` metavars in macros don't allow let exprs - None if let Some(x) = Some(0) && x > 5 => true, - _ => false + let _ = match maybe_some { + // can't use `matches!` here + // because `expr` metavars in macros don't allow let exprs + None if let Some(x) = Some(0) + && x > 5 => + { + true + }, + _ => false, }; } diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index fdf395d8286..a75551c56f2 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -14,49 +14,49 @@ LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard nee | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:27:12 + --> $DIR/redundant_pattern_matching_option.rs:32:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:29:12 + --> $DIR/redundant_pattern_matching_option.rs:34:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:31:12 + --> $DIR/redundant_pattern_matching_option.rs:36:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:37:15 + --> $DIR/redundant_pattern_matching_option.rs:42:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:39:15 + --> $DIR/redundant_pattern_matching_option.rs:44:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:41:15 + --> $DIR/redundant_pattern_matching_option.rs:46:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:44:15 + --> $DIR/redundant_pattern_matching_option.rs:49:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:52:5 + --> $DIR/redundant_pattern_matching_option.rs:57:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -65,7 +65,7 @@ LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:57:5 + --> $DIR/redundant_pattern_matching_option.rs:62:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -74,7 +74,7 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:62:13 + --> $DIR/redundant_pattern_matching_option.rs:67:13 | LL | let _ = match None::<()> { | _____________^ @@ -84,55 +84,55 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:68:20 + --> $DIR/redundant_pattern_matching_option.rs:73:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:74:20 + --> $DIR/redundant_pattern_matching_option.rs:79:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:76:19 + --> $DIR/redundant_pattern_matching_option.rs:81:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:82:12 + --> $DIR/redundant_pattern_matching_option.rs:87:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:97:12 + --> $DIR/redundant_pattern_matching_option.rs:102:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:99:12 + --> $DIR/redundant_pattern_matching_option.rs:104:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:101:15 + --> $DIR/redundant_pattern_matching_option.rs:106:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:103:15 + --> $DIR/redundant_pattern_matching_option.rs:108:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:105:5 + --> $DIR/redundant_pattern_matching_option.rs:110:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -141,7 +141,7 @@ LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:110:5 + --> $DIR/redundant_pattern_matching_option.rs:115:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -150,19 +150,19 @@ LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:118:12 + --> $DIR/redundant_pattern_matching_option.rs:123:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:119:12 + --> $DIR/redundant_pattern_matching_option.rs:124:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:125:5 + --> $DIR/redundant_pattern_matching_option.rs:130:5 | LL | / match x { LL | | Some(_) => true, @@ -171,7 +171,7 @@ LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:130:5 + --> $DIR/redundant_pattern_matching_option.rs:135:5 | LL | / match x { LL | | None => true, @@ -180,7 +180,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:135:5 + --> $DIR/redundant_pattern_matching_option.rs:140:5 | LL | / match x { LL | | Some(_) => false, @@ -189,7 +189,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:140:5 + --> $DIR/redundant_pattern_matching_option.rs:145:5 | LL | / match x { LL | | None => false, @@ -198,13 +198,13 @@ LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:155:13 + --> $DIR/redundant_pattern_matching_option.rs:160:13 | LL | let _ = matches!(x, Some(_)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:157:13 + --> $DIR/redundant_pattern_matching_option.rs:162:13 | LL | let _ = matches!(x, None); | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` -- cgit 1.4.1-3-g733a5 From 9681b4afe09600c175c951705f0a69a51ac30ac8 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 10 Nov 2023 17:29:28 +0000 Subject: Run `if-to-let-chain clippy*/**/*.rs` https://github.com/Alexendoo/if-to-let-chain --- clippy_lints/src/allow_attributes.rs | 34 +- clippy_lints/src/attrs.rs | 124 ++++--- clippy_lints/src/blocks_in_if_conditions.rs | 16 +- clippy_lints/src/booleans.rs | 20 +- clippy_lints/src/borrow_deref_ref.rs | 106 +++--- clippy_lints/src/cargo/multiple_crate_versions.rs | 46 ++- clippy_lints/src/cargo/wildcard_dependencies.rs | 24 +- clippy_lints/src/casts/cast_sign_loss.rs | 24 +- .../src/casts/cast_slice_different_sizes.rs | 36 +- .../src/casts/cast_slice_from_raw_parts.rs | 56 ++-- clippy_lints/src/casts/char_lit_as_u8.rs | 48 ++- clippy_lints/src/casts/ptr_cast_constness.rs | 44 ++- clippy_lints/src/casts/unnecessary_cast.rs | 92 +++--- clippy_lints/src/checked_conversions.rs | 110 +++---- clippy_lints/src/collapsible_if.rs | 100 +++--- clippy_lints/src/copy_iterator.rs | 32 +- clippy_lints/src/crate_in_macro_def.rs | 66 ++-- clippy_lints/src/create_dir.rs | 30 +- clippy_lints/src/default.rs | 174 +++++----- .../src/default_constructed_unit_structs.rs | 44 ++- clippy_lints/src/default_numeric_fallback.rs | 122 ++++--- clippy_lints/src/dereference.rs | 36 +- clippy_lints/src/derivable_impls.rs | 132 ++++---- clippy_lints/src/derive.rs | 236 +++++++------ clippy_lints/src/doc.rs | 32 +- clippy_lints/src/empty_drop.rs | 42 ++- clippy_lints/src/endian_bytes.rs | 34 +- clippy_lints/src/exhaustive_items.rs | 64 ++-- clippy_lints/src/exit.rs | 20 +- clippy_lints/src/explicit_write.rs | 24 +- clippy_lints/src/fallible_impl_from.rs | 64 ++-- clippy_lints/src/float_literal.rs | 106 +++--- clippy_lints/src/floating_point_arithmetic.rs | 364 ++++++++++----------- clippy_lints/src/format_args.rs | 84 +++-- clippy_lints/src/format_impl.rs | 112 +++---- clippy_lints/src/formatting.rs | 210 ++++++------ clippy_lints/src/from_str_radix_10.rs | 66 ++-- clippy_lints/src/functions/impl_trait_in_params.rs | 66 ++-- clippy_lints/src/functions/misnamed_getters.rs | 30 +- clippy_lints/src/functions/result.rs | 92 +++--- clippy_lints/src/if_let_mutex.rs | 18 +- clippy_lints/src/implicit_hasher.rs | 68 ++-- clippy_lints/src/implicit_saturating_add.rs | 62 ++-- clippy_lints/src/implicit_saturating_sub.rs | 138 ++++---- .../src/inconsistent_struct_constructor.rs | 82 +++-- clippy_lints/src/index_refutable_slice.rs | 54 ++- clippy_lints/src/instant_subtraction.rs | 36 +- clippy_lints/src/large_const_arrays.rs | 64 ++-- clippy_lints/src/large_include_file.rs | 56 ++-- clippy_lints/src/len_zero.rs | 56 ++-- clippy_lints/src/let_if_seq.rs | 142 ++++---- clippy_lints/src/let_with_type_underscore.rs | 38 +-- clippy_lints/src/lifetimes.rs | 22 +- clippy_lints/src/literal_representation.rs | 114 ++++--- clippy_lints/src/loops/explicit_counter_loop.rs | 98 +++--- clippy_lints/src/loops/manual_find.rs | 172 +++++----- clippy_lints/src/loops/manual_flatten.rs | 104 +++--- clippy_lints/src/loops/manual_memcpy.rs | 64 ++-- clippy_lints/src/loops/missing_spin_loop.rs | 40 ++- clippy_lints/src/loops/mut_range_bound.rs | 30 +- clippy_lints/src/loops/needless_range_loop.rs | 168 +++++----- clippy_lints/src/loops/same_item_push.rs | 116 +++---- clippy_lints/src/loops/single_element_loop.rs | 56 ++-- clippy_lints/src/loops/utils.rs | 24 +- .../src/loops/while_immutable_condition.rs | 26 +- clippy_lints/src/loops/while_let_on_iterator.rs | 26 +- clippy_lints/src/macro_use.rs | 38 +-- clippy_lints/src/main_recursion.rs | 28 +- clippy_lints/src/manual_async_fn.rs | 176 +++++----- clippy_lints/src/manual_bits.rs | 80 +++-- clippy_lints/src/manual_strip.rs | 162 +++++---- clippy_lints/src/map_unit_fn.rs | 18 +- clippy_lints/src/match_result_ok.rs | 52 ++- clippy_lints/src/matches/collapsible_match.rs | 94 +++--- .../src/matches/infallible_destructuring_match.rs | 60 ++-- clippy_lints/src/matches/manual_filter.rs | 26 +- clippy_lints/src/matches/manual_unwrap_or.rs | 82 +++-- clippy_lints/src/matches/manual_utils.rs | 46 ++- clippy_lints/src/matches/match_as_ref.rs | 42 ++- clippy_lints/src/matches/match_like_matches.rs | 128 ++++---- clippy_lints/src/matches/match_on_vec_items.rs | 54 ++- clippy_lints/src/matches/match_same_arms.rs | 28 +- .../src/matches/match_str_case_mismatch.rs | 44 ++- clippy_lints/src/matches/match_wild_err_arm.rs | 26 +- .../src/matches/redundant_pattern_match.rs | 30 +- .../src/matches/rest_pat_in_fully_bound_struct.rs | 36 +- clippy_lints/src/matches/single_match.rs | 84 +++-- clippy_lints/src/matches/try_err.rs | 158 +++++---- clippy_lints/src/mem_replace.rs | 98 +++--- clippy_lints/src/methods/bind_instead_of_map.rs | 92 +++--- clippy_lints/src/methods/bytecount.rs | 74 ++--- clippy_lints/src/methods/bytes_count_to_len.rs | 34 +- .../case_sensitive_file_extension_comparisons.rs | 82 +++-- clippy_lints/src/methods/chars_cmp.rs | 48 ++- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 42 ++- clippy_lints/src/methods/err_expect.rs | 32 +- clippy_lints/src/methods/extend_with_drain.rs | 52 ++- clippy_lints/src/methods/filetype_is_file.rs | 28 +- clippy_lints/src/methods/filter_map.rs | 146 ++++----- .../src/methods/from_iter_instead_of_collect.rs | 102 +++--- clippy_lints/src/methods/get_first.rs | 40 ++- clippy_lints/src/methods/implicit_clone.rs | 54 ++- clippy_lints/src/methods/inefficient_to_string.rs | 60 ++-- clippy_lints/src/methods/into_iter_on_ref.rs | 34 +- clippy_lints/src/methods/iter_cloned_collect.rs | 30 +- clippy_lints/src/methods/iter_kv_map.rs | 96 +++--- clippy_lints/src/methods/iter_next_slice.rs | 44 ++- clippy_lints/src/methods/iter_skip_next.rs | 22 +- clippy_lints/src/methods/manual_ok_or.rs | 46 ++- .../src/methods/manual_saturating_arithmetic.rs | 18 +- clippy_lints/src/methods/manual_str_repeat.rs | 70 ++-- clippy_lints/src/methods/map_clone.rs | 92 +++--- .../src/methods/map_collect_result_unit.rs | 38 +-- clippy_lints/src/methods/map_identity.rs | 30 +- clippy_lints/src/methods/mod.rs | 62 ++-- clippy_lints/src/methods/mut_mutex_lock.rs | 32 +- clippy_lints/src/methods/no_effect_replace.rs | 16 +- clippy_lints/src/methods/ok_expect.rs | 28 +- clippy_lints/src/methods/option_as_ref_deref.rs | 38 +-- clippy_lints/src/methods/option_map_or_none.rs | 40 ++- clippy_lints/src/methods/or_fun_call.rs | 92 +++--- .../src/methods/path_buf_push_overwrite.rs | 42 ++- clippy_lints/src/methods/range_zip_with_len.rs | 32 +- clippy_lints/src/methods/search_is_some.rs | 102 +++--- clippy_lints/src/methods/single_char_pattern.rs | 34 +- clippy_lints/src/methods/str_splitn.rs | 50 ++- clippy_lints/src/methods/suspicious_map.rs | 36 +- clippy_lints/src/methods/suspicious_splitn.rs | 64 ++-- clippy_lints/src/methods/suspicious_to_owned.rs | 64 ++-- clippy_lints/src/methods/uninit_assumed_init.rs | 24 +- clippy_lints/src/methods/unnecessary_fold.rs | 90 +++-- .../src/methods/unnecessary_iter_cloned.rs | 116 ++++--- clippy_lints/src/methods/unnecessary_join.rs | 34 +- clippy_lints/src/methods/unnecessary_sort_by.rs | 86 +++-- clippy_lints/src/methods/unnecessary_to_owned.rs | 310 +++++++++--------- clippy_lints/src/methods/useless_asref.rs | 12 +- clippy_lints/src/methods/utils.rs | 62 ++-- clippy_lints/src/methods/vec_resize_to_zero.rs | 46 ++- clippy_lints/src/methods/zst_offset.rs | 12 +- clippy_lints/src/misc.rs | 126 ++++--- clippy_lints/src/mismatching_type_param_order.rs | 98 +++--- clippy_lints/src/missing_doc.rs | 18 +- clippy_lints/src/missing_enforced_import_rename.rs | 36 +- clippy_lints/src/mixed_read_write_in_expression.rs | 10 +- clippy_lints/src/needless_arbitrary_self_type.rs | 90 +++-- clippy_lints/src/needless_continue.rs | 28 +- clippy_lints/src/needless_for_each.rs | 94 +++--- clippy_lints/src/needless_late_init.rs | 34 +- .../src/needless_parens_on_range_literals.rs | 24 +- clippy_lints/src/needless_pass_by_value.rs | 184 +++++------ clippy_lints/src/needless_question_mark.rs | 44 ++- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 62 ++-- clippy_lints/src/neg_multiply.rs | 42 ++- clippy_lints/src/new_without_default.rs | 122 ++++--- clippy_lints/src/no_effect.rs | 138 ++++---- clippy_lints/src/non_copy_const.rs | 34 +- clippy_lints/src/non_octal_unix_permissions.rs | 44 ++- clippy_lints/src/non_send_fields_in_send_ty.rs | 124 ++++--- clippy_lints/src/nonstandard_macro_braces.rs | 28 +- clippy_lints/src/operators/assign_op_pattern.rs | 68 ++-- clippy_lints/src/operators/const_comparisons.rs | 136 ++++---- clippy_lints/src/operators/float_cmp.rs | 10 +- .../src/operators/float_equality_without_abs.rs | 60 ++-- clippy_lints/src/operators/modulo_arithmetic.rs | 16 +- clippy_lints/src/operators/op_ref.rs | 56 ++-- clippy_lints/src/operators/ptr_eq.rs | 30 +- clippy_lints/src/option_if_let_else.rs | 116 ++++--- clippy_lints/src/overflow_check_conditional.rs | 60 ++-- clippy_lints/src/partialeq_ne_impl.rs | 30 +- clippy_lints/src/pass_by_ref_or_value.rs | 30 +- clippy_lints/src/precedence.rs | 36 +- clippy_lints/src/question_mark.rs | 140 ++++---- clippy_lints/src/ranges.rs | 204 ++++++------ clippy_lints/src/rc_clone_in_vec_init.rs | 34 +- clippy_lints/src/redundant_clone.rs | 114 +++---- clippy_lints/src/redundant_closure_call.rs | 50 ++- clippy_lints/src/redundant_locals.rs | 48 ++- clippy_lints/src/redundant_pub_crate.rs | 42 ++- clippy_lints/src/redundant_slicing.rs | 148 +++++---- clippy_lints/src/ref_option_ref.rs | 46 ++- clippy_lints/src/reference.rs | 88 +++-- clippy_lints/src/regex.rs | 12 +- clippy_lints/src/return_self_not_must_use.rs | 52 ++- clippy_lints/src/returns.rs | 80 +++-- clippy_lints/src/same_name_method.rs | 38 +-- clippy_lints/src/self_named_constructors.rs | 28 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 44 ++- clippy_lints/src/size_of_in_element_count.rs | 78 ++--- clippy_lints/src/slow_vector_initialization.rs | 112 +++---- clippy_lints/src/strings.rs | 278 ++++++++-------- clippy_lints/src/strlen_on_c_strings.rs | 78 +++-- clippy_lints/src/suspicious_doc_comments.rs | 24 +- clippy_lints/src/suspicious_operation_groupings.rs | 104 +++--- clippy_lints/src/suspicious_trait_impl.rs | 46 ++- clippy_lints/src/swap.rs | 68 ++-- clippy_lints/src/tests_outside_test_module.rs | 26 +- clippy_lints/src/to_digit_is_some.rs | 92 +++--- clippy_lints/src/trailing_empty_array.rs | 22 +- clippy_lints/src/trait_bounds.rs | 302 ++++++++--------- clippy_lints/src/transmute/mod.rs | 80 +++-- .../src/transmute/transmute_float_to_int.rs | 16 +- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 106 +++--- .../src/transmute/transmute_undefined_repr.rs | 14 +- clippy_lints/src/types/borrowed_box.rs | 144 ++++---- clippy_lints/src/types/box_collection.rs | 44 ++- clippy_lints/src/types/option_option.rs | 30 +- clippy_lints/src/types/rc_mutex.rs | 30 +- clippy_lints/src/types/utils.rs | 16 +- clippy_lints/src/uninit_vec.rs | 72 ++-- clippy_lints/src/unit_return_expecting_ord.rs | 82 +++-- clippy_lints/src/unit_types/unit_arg.rs | 38 +-- clippy_lints/src/unnamed_address.rs | 84 +++-- .../src/unnecessary_owned_empty_strings.rs | 74 ++--- clippy_lints/src/unnecessary_self_imports.rs | 54 ++- clippy_lints/src/unnecessary_wraps.rs | 38 +-- clippy_lints/src/unused_self.rs | 36 +- clippy_lints/src/unused_unit.rs | 72 ++-- clippy_lints/src/unwrap.rs | 190 ++++++----- clippy_lints/src/unwrap_in_result.rs | 12 +- clippy_lints/src/use_self.rs | 184 +++++------ clippy_lints/src/useless_conversion.rs | 108 +++--- .../src/utils/internal_lints/collapsible_calls.rs | 76 +++-- .../internal_lints/compiler_lint_functions.rs | 30 +- .../src/utils/internal_lints/if_chain_style.rs | 38 +-- .../internal_lints/interning_defined_symbol.rs | 88 +++-- .../src/utils/internal_lints/invalid_paths.rs | 22 +- .../utils/internal_lints/lint_without_lint_pass.rs | 14 +- .../src/utils/internal_lints/metadata_collector.rs | 120 ++++--- .../src/utils/internal_lints/msrv_attr_impl.rs | 48 ++- .../utils/internal_lints/outer_expn_data_pass.rs | 32 +- .../utils/internal_lints/unnecessary_def_path.rs | 190 ++++++----- clippy_lints/src/vec.rs | 44 ++- clippy_lints/src/wildcard_imports.rs | 118 ++++--- clippy_lints/src/zero_div_zero.rs | 50 ++- clippy_lints/src/zero_sized_map_values.rs | 26 +- clippy_utils/src/consts.rs | 40 ++- clippy_utils/src/higher.rs | 74 ++--- clippy_utils/src/lib.rs | 140 ++++---- 238 files changed, 7895 insertions(+), 8761 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index e3f4cf79d31..98299e1e4bd 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -52,24 +52,22 @@ declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); impl LateLintPass<'_> for AllowAttribute { // Separate each crate's features. fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) { - if_chain! { - if !in_external_macro(cx.sess(), attr.span); - if cx.tcx.features().lint_reasons; - if let AttrStyle::Outer = attr.style; - if let Some(ident) = attr.ident(); - if ident.name == rustc_span::symbol::sym::allow; - if !is_from_proc_macro(cx, &attr); - then { - span_lint_and_sugg( - cx, - ALLOW_ATTRIBUTES, - ident.span, - "#[allow] attribute found", - "replace it with", - "expect".into(), - Applicability::MachineApplicable, - ); - } + if !in_external_macro(cx.sess(), attr.span) + && cx.tcx.features().lint_reasons + && let AttrStyle::Outer = attr.style + && let Some(ident) = attr.ident() + && ident.name == rustc_span::symbol::sym::allow + && !is_from_proc_macro(cx, &attr) + { + span_lint_and_sugg( + cx, + ALLOW_ATTRIBUTES, + ident.span, + "#[allow] attribute found", + "replace it with", + "expect".into(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 64bfa8d904c..112ded59e13 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -471,13 +471,11 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { return; } for item in items { - if_chain! { - if let NestedMetaItem::MetaItem(mi) = &item; - if let MetaItemKind::NameValue(lit) = &mi.kind; - if mi.has_name(sym::since); - then { - check_semver(cx, item.span(), lit); - } + if let NestedMetaItem::MetaItem(mi) = &item + && let MetaItemKind::NameValue(lit) = &mi.kind + && mi.has_name(sym::since) + { + check_semver(cx, item.span(), lit); } } } @@ -580,15 +578,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { /// Returns the lint name if it is clippy lint. fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { - if_chain! { - if let Some(meta_item) = lint.meta_item(); - if meta_item.path.segments.len() > 1; - if let tool_name = meta_item.path.segments[0].ident; - if tool_name.name == sym::clippy; - then { - let lint_name = meta_item.path.segments.last().unwrap().ident.name; - return Some(lint_name); - } + if let Some(meta_item) = lint.meta_item() + && meta_item.path.segments.len() > 1 + && let tool_name = meta_item.path.segments[0].ident + && tool_name.name == sym::clippy + { + let lint_name = meta_item.path.segments.last().unwrap().ident.name; + return Some(lint_name); } None } @@ -857,18 +853,17 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It } fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) { - if_chain! { - if msrv.meets(msrvs::TOOL_ATTRIBUTES); + if msrv.meets(msrvs::TOOL_ATTRIBUTES) // check cfg_attr - if attr.has_name(sym::cfg_attr); - if let Some(items) = attr.meta_item_list(); - if items.len() == 2; + && attr.has_name(sym::cfg_attr) + && let Some(items) = attr.meta_item_list() + && items.len() == 2 // check for `rustfmt` - if let Some(feature_item) = items[0].meta_item(); - if feature_item.has_name(sym::rustfmt); + && let Some(feature_item) = items[0].meta_item() + && feature_item.has_name(sym::rustfmt) // check for `rustfmt_skip` and `rustfmt::skip` - if let Some(skip_item) = &items[1].meta_item(); - if skip_item.has_name(sym!(rustfmt_skip)) + && let Some(skip_item) = &items[1].meta_item() + && (skip_item.has_name(sym!(rustfmt_skip)) || skip_item .path .segments @@ -876,21 +871,20 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr .expect("empty path in attribute") .ident .name - == sym::skip; + == sym::skip) // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - if attr.style == AttrStyle::Outer; - then { - span_lint_and_sugg( - cx, - DEPRECATED_CFG_ATTR, - attr.span, - "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", - "use", - "#[rustfmt::skip]".to_string(), - Applicability::MachineApplicable, - ); - } + && attr.style == AttrStyle::Outer + { + span_lint_and_sugg( + cx, + DEPRECATED_CFG_ATTR, + attr.span, + "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", + "use", + "#[rustfmt::skip]".to_string(), + Applicability::MachineApplicable, + ); } } @@ -990,12 +984,10 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { mismatched.extend(find_mismatched_target_os(list)); }, MetaItemKind::Word => { - if_chain! { - if let Some(ident) = meta.ident(); - if let Some(os) = find_os(ident.name.as_str()); - then { - mismatched.push((os, ident.span)); - } + if let Some(ident) = meta.ident() + && let Some(os) = find_os(ident.name.as_str()) + { + mismatched.push((os, ident.span)); } }, MetaItemKind::NameValue(..) => {}, @@ -1006,30 +998,28 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { mismatched } - if_chain! { - if attr.has_name(sym::cfg); - if let Some(list) = attr.meta_item_list(); - let mismatched = find_mismatched_target_os(&list); - if !mismatched.is_empty(); - then { - let mess = "operating system used in target family position"; - - span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { - // Avoid showing the unix suggestion multiple times in case - // we have more than one mismatch for unix-like systems - let mut unix_suggested = false; - - for (os, span) in mismatched { - let sugg = format!("target_os = \"{os}\""); - diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); - - if !unix_suggested && is_unix(os) { - diag.help("did you mean `unix`?"); - unix_suggested = true; - } + if attr.has_name(sym::cfg) + && let Some(list) = attr.meta_item_list() + && let mismatched = find_mismatched_target_os(&list) + && !mismatched.is_empty() + { + let mess = "operating system used in target family position"; + + span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { + // Avoid showing the unix suggestion multiple times in case + // we have more than one mismatch for unix-like systems + let mut unix_suggested = false; + + for (os, span) in mismatched { + let sugg = format!("target_os = \"{os}\""); + diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); + + if !unix_suggested && is_unix(os) { + diag.help("did you mean `unix`?"); + unix_suggested = true; } - }); - } + } + }); } } diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 04bf541a5bd..9ad68f115ea 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -114,15 +114,13 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { let _: Option = for_each_expr(cond, |e| { if let ExprKind::Closure(closure) = e.kind { // do not lint if the closure is called using an iterator (see #1141) - if_chain! { - if let Some(parent) = get_parent_expr(cx, e); - if let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind; - let caller = cx.typeck_results().expr_ty(self_arg); - if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(cx, caller, iter_id, &[]); - then { - return ControlFlow::Continue(Descend::No); - } + if let Some(parent) = get_parent_expr(cx, e) + && let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind + && let caller = cx.typeck_results().expr_ty(self_arg) + && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) + && implements_trait(cx, caller, iter_id, &[]) + { + return ControlFlow::Continue(Descend::No); } let body = cx.tcx.hir().body(closure.body); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 37ce65676c7..69550f6879a 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -152,17 +152,15 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { return Ok(Bool::Term(n as u8)); } - if_chain! { - if let ExprKind::Binary(e_binop, e_lhs, e_rhs) = &e.kind; - if implements_ord(self.cx, e_lhs); - if let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind; - if negate(e_binop.node) == Some(expr_binop.node); - if eq_expr_value(self.cx, e_lhs, expr_lhs); - if eq_expr_value(self.cx, e_rhs, expr_rhs); - then { - #[expect(clippy::cast_possible_truncation)] - return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); - } + if let ExprKind::Binary(e_binop, e_lhs, e_rhs) = &e.kind + && implements_ord(self.cx, e_lhs) + && let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind + && negate(e_binop.node) == Some(expr_binop.node) + && eq_expr_value(self.cx, e_lhs, expr_lhs) + && eq_expr_value(self.cx, e_rhs, expr_rhs) + { + #[expect(clippy::cast_possible_truncation)] + return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); } } let n = self.terminals.len(); diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 739ce8f67c2..33b7bde3a41 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -49,69 +49,67 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { - if_chain! { - if !e.span.from_expansion(); - if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind; - if !addrof_target.span.from_expansion(); - if let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind; - if !deref_target.span.from_expansion(); - if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ); - let ref_ty = cx.typeck_results().expr_ty(deref_target); - if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind(); - if !is_from_proc_macro(cx, e); - then{ + if !e.span.from_expansion() + && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind + && !addrof_target.span.from_expansion() + && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind + && !deref_target.span.from_expansion() + && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ) + && let ref_ty = cx.typeck_results().expr_ty(deref_target) + && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() + && !is_from_proc_macro(cx, e) + { - if let Some(parent_expr) = get_parent_expr(cx, e){ - if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) && - !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) { - return; - } + if let Some(parent_expr) = get_parent_expr(cx, e){ + if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) && + !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) { + return; + } - // modification to `&mut &*x` is different from `&mut x` - if matches!(deref_target.kind, ExprKind::Path(..) - | ExprKind::Field(..) - | ExprKind::Index(..) - | ExprKind::Unary(UnOp::Deref, ..)) - && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) { - return; - } + // modification to `&mut &*x` is different from `&mut x` + if matches!(deref_target.kind, ExprKind::Path(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Unary(UnOp::Deref, ..)) + && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) { + return; } + } - span_lint_and_then( - cx, - BORROW_DEREF_REF, - e.span, - "deref on an immutable reference", - |diag| { - diag.span_suggestion( - e.span, - "if you would like to reborrow, try removing `&*`", - snippet_opt(cx, deref_target.span).unwrap(), - Applicability::MachineApplicable - ); + span_lint_and_then( + cx, + BORROW_DEREF_REF, + e.span, + "deref on an immutable reference", + |diag| { + diag.span_suggestion( + e.span, + "if you would like to reborrow, try removing `&*`", + snippet_opt(cx, deref_target.span).unwrap(), + Applicability::MachineApplicable + ); - // has deref trait -> give 2 help - // doesn't have deref trait -> give 1 help - if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){ - if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { - return; - } + // has deref trait -> give 2 help + // doesn't have deref trait -> give 1 help + if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){ + if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { + return; } + } - diag.span_suggestion( - e.span, - "if you would like to deref, try using `&**`", - format!( - "&**{}", - &snippet_opt(cx, deref_target.span).unwrap(), - ), - Applicability::MaybeIncorrect - ); + diag.span_suggestion( + e.span, + "if you would like to deref, try using `&**`", + format!( + "&**{}", + &snippet_opt(cx, deref_target.span).unwrap(), + ), + Applicability::MaybeIncorrect + ); - } - ); + } + ); - } } } } diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index f9b17d45e9f..446b1f961b9 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -15,31 +15,29 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { let mut packages = metadata.packages.clone(); packages.sort_by(|a, b| a.name.cmp(&b.name)); - if_chain! { - if let Some(resolve) = &metadata.resolve; - if let Some(local_id) = packages + if let Some(resolve) = &metadata.resolve + && let Some(local_id) = packages .iter() - .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None }); - then { - for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { - let group: Vec<&Package> = group.collect(); - - if group.len() <= 1 { - continue; - } - - if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) { - let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect(); - versions.sort(); - let versions = versions.iter().join(", "); - - span_lint( - cx, - MULTIPLE_CRATE_VERSIONS, - DUMMY_SP, - &format!("multiple versions for dependency `{name}`: {versions}"), - ); - } + .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None }) + { + for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { + let group: Vec<&Package> = group.collect(); + + if group.len() <= 1 { + continue; + } + + if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) { + let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect(); + versions.sort(); + let versions = versions.iter().join(", "); + + span_lint( + cx, + MULTIPLE_CRATE_VERSIONS, + DUMMY_SP, + &format!("multiple versions for dependency `{name}`: {versions}"), + ); } } } diff --git a/clippy_lints/src/cargo/wildcard_dependencies.rs b/clippy_lints/src/cargo/wildcard_dependencies.rs index 7fa6acbf557..f255963e480 100644 --- a/clippy_lints/src/cargo/wildcard_dependencies.rs +++ b/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -9,19 +9,17 @@ use super::WILDCARD_DEPENDENCIES; pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { for dep in &metadata.packages[0].dependencies { // VersionReq::any() does not work - if_chain! { - if let Ok(wildcard_ver) = semver::VersionReq::parse("*"); - if let Some(ref source) = dep.source; - if !source.starts_with("git"); - if dep.req == wildcard_ver; - then { - span_lint( - cx, - WILDCARD_DEPENDENCIES, - DUMMY_SP, - &format!("wildcard dependency for `{}`", dep.name), - ); - } + if let Ok(wildcard_ver) = semver::VersionReq::parse("*") + && let Some(ref source) = dep.source + && !source.starts_with("git") + && dep.req == wildcard_ver + { + span_lint( + cx, + WILDCARD_DEPENDENCIES, + DUMMY_SP, + &format!("wildcard dependency for `{}`", dep.name), + ); } } } diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index a83dfd94dc2..71a2581613d 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -28,13 +28,11 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast // Don't lint for positive constants. let const_val = constant(cx, cx.typeck_results(), cast_op); - if_chain! { - if let Some(Constant::Int(n)) = const_val; - if let ty::Int(ity) = *cast_from.kind(); - if sext(cx.tcx, n, ity) >= 0; - then { - return false; - } + if let Some(Constant::Int(n)) = const_val + && let ty::Int(ity) = *cast_from.kind() + && sext(cx.tcx, n, ity) >= 0 + { + return false; } // Don't lint for the result of methods that always return non-negative values. @@ -42,13 +40,11 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast let mut method_name = path.ident.name.as_str(); let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; - if_chain! { - if method_name == "unwrap"; - if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]); - if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind; - then { - method_name = inner_path.ident.name.as_str(); - } + if method_name == "unwrap" + && let Some(arglist) = method_chain_args(cast_op, &["unwrap"]) + && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind + { + method_name = inner_path.ident.name.as_str(); } if allowed_methods.iter().any(|&name| method_name == name) { diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index d1410402913..6eae45e6c7b 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -69,26 +69,24 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let map = cx.tcx.hir(); - if_chain! { - if let Some(parent_id) = map.opt_parent_id(expr.hir_id); - if let Some(parent) = map.find(parent_id); - then { - let expr = match parent { - Node::Block(block) => { - if let Some(parent_expr) = block.expr { - parent_expr - } else { - return false; - } - }, - Node::Expr(expr) => expr, - _ => return false, - }; + if let Some(parent_id) = map.opt_parent_id(expr.hir_id) + && let Some(parent) = map.find(parent_id) + { + let expr = match parent { + Node::Block(block) => { + if let Some(parent_expr) = block.expr { + parent_expr + } else { + return false; + } + }, + Node::Expr(expr) => expr, + _ => return false, + }; - matches!(expr.kind, ExprKind::Cast(..)) - } else { - false - } + matches!(expr.kind, ExprKind::Cast(..)) + } else { + false } } diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index badadf2c9f6..bacbea39768 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -25,34 +25,32 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { } pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) { - if_chain! { - if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS); - if let ty::RawPtr(ptrty) = cast_to.kind(); - if let ty::Slice(_) = ptrty.ty.kind(); - if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - if let Some(rpk) = raw_parts_kind(cx, fun_def_id); - let ctxt = expr.span.ctxt(); - if cast_expr.span.ctxt() == ctxt; - then { - let func = match rpk { - RawPartsKind::Immutable => "from_raw_parts", - RawPartsKind::Mutable => "from_raw_parts_mut" - }; - let span = expr.span; - let mut applicability = Applicability::MachineApplicable; - let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0; - let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0; - span_lint_and_sugg( - cx, - CAST_SLICE_FROM_RAW_PARTS, - span, - &format!("casting the result of `{func}` to {cast_to}"), - "replace with", - format!("core::ptr::slice_{func}({ptr}, {len})"), - applicability - ); - } + if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) + && let ty::RawPtr(ptrty) = cast_to.kind() + && let ty::Slice(_) = ptrty.ty.kind() + && let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(rpk) = raw_parts_kind(cx, fun_def_id) + && let ctxt = expr.span.ctxt() + && cast_expr.span.ctxt() == ctxt + { + let func = match rpk { + RawPartsKind::Immutable => "from_raw_parts", + RawPartsKind::Mutable => "from_raw_parts_mut" + }; + let span = expr.span; + let mut applicability = Applicability::MachineApplicable; + let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0; + let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0; + span_lint_and_sugg( + cx, + CAST_SLICE_FROM_RAW_PARTS, + span, + &format!("casting the result of `{func}` to {cast_to}"), + "replace with", + format!("core::ptr::slice_{func}({ptr}, {len})"), + applicability + ); } } diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index 82e07c98a7e..802f2614796 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -10,32 +10,30 @@ use rustc_middle::ty::{self, UintTy}; use super::CHAR_LIT_AS_U8; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Cast(e, _) = &expr.kind; - if let ExprKind::Lit(l) = &e.kind; - if let LitKind::Char(c) = l.node; - if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind(); - then { - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability); + if let ExprKind::Cast(e, _) = &expr.kind + && let ExprKind::Lit(l) = &e.kind + && let LitKind::Char(c) = l.node + && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind() + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability); - span_lint_and_then( - cx, - CHAR_LIT_AS_U8, - expr.span, - "casting a character literal to `u8` truncates", - |diag| { - diag.note("`char` is four bytes wide, but `u8` is a single byte"); + span_lint_and_then( + cx, + CHAR_LIT_AS_U8, + expr.span, + "casting a character literal to `u8` truncates", + |diag| { + diag.note("`char` is four bytes wide, but `u8` is a single byte"); - if c.is_ascii() { - diag.span_suggestion( - expr.span, - "use a byte literal instead", - format!("b{snippet}"), - applicability, - ); - } - }); - } + if c.is_ascii() { + diag.span_suggestion( + expr.span, + "use a byte literal instead", + format!("b{snippet}"), + applicability, + ); + } + }); } } diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 0172e933649..68a409824e7 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -17,29 +17,27 @@ pub(super) fn check<'tcx>( cast_to: Ty<'tcx>, msrv: &Msrv, ) { - if_chain! { - if msrv.meets(msrvs::POINTER_CAST_CONSTNESS); - if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind(); - if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind(); - if matches!((from_mutbl, to_mutbl), - (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)); - if from_ty == to_ty; - then { - let sugg = Sugg::hir(cx, cast_expr, "_"); - let constness = match *to_mutbl { - Mutability::Not => "const", - Mutability::Mut => "mut", - }; + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) + && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind() + && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind() + && matches!((from_mutbl, to_mutbl), + (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)) + && from_ty == to_ty + { + let sugg = Sugg::hir(cx, cast_expr, "_"); + let constness = match *to_mutbl { + Mutability::Not => "const", + Mutability::Mut => "mut", + }; - span_lint_and_sugg( - cx, - PTR_CAST_CONSTNESS, - expr.span, - "`as` casting between raw pointers while changing only its constness", - &format!("try `pointer::cast_{constness}`, a safer alternative"), - format!("{}.cast_{constness}()", sugg.maybe_par()), - Applicability::MachineApplicable, - ); - } + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + "`as` casting between raw pointers while changing only its constness", + &format!("try `pointer::cast_{constness}`, a safer alternative"), + format!("{}.cast_{constness}()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 61bfce07e1a..e060977d253 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -25,40 +25,38 @@ pub(super) fn check<'tcx>( ) -> bool { let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default(); - if_chain! { - if let ty::RawPtr(..) = cast_from.kind(); + if let ty::RawPtr(..) = cast_from.kind() // check both mutability and type are the same - if cast_from.kind() == cast_to.kind(); - if let ExprKind::Cast(_, cast_to_hir) = expr.kind; + && cast_from.kind() == cast_to.kind() + && let ExprKind::Cast(_, cast_to_hir) = expr.kind // Ignore casts to e.g. type aliases and infer types // - p as pointer_alias // - p as _ - if let TyKind::Ptr(to_pointee) = cast_to_hir.kind; - then { - match to_pointee.ty.kind { - // Ignore casts to pointers that are aliases or cfg dependant, e.g. - // - p as *const std::ffi::c_char (alias) - // - p as *const std::os::raw::c_char (cfg dependant) - TyKind::Path(qpath) => { - if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) { - return false; - } - }, - // Ignore `p as *const _` - TyKind::Infer => return false, - _ => {}, - } - - span_lint_and_sugg( - cx, - UNNECESSARY_CAST, - expr.span, - &format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"), - "try", - cast_str.clone(), - Applicability::MaybeIncorrect, - ); + && let TyKind::Ptr(to_pointee) = cast_to_hir.kind + { + match to_pointee.ty.kind { + // Ignore casts to pointers that are aliases or cfg dependant, e.g. + // - p as *const std::ffi::c_char (alias) + // - p as *const std::os::raw::c_char (cfg dependant) + TyKind::Path(qpath) => { + if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) { + return false; + } + }, + // Ignore `p as *const _` + TyKind::Infer => return false, + _ => {}, } + + span_lint_and_sugg( + cx, + UNNECESSARY_CAST, + expr.span, + &format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"), + "try", + cast_str.clone(), + Applicability::MaybeIncorrect, + ); } // skip cast of local that is a type alias @@ -86,14 +84,12 @@ pub(super) fn check<'tcx>( } // skip cast to non-primitive type - if_chain! { - if let ExprKind::Cast(_, cast_to) = expr.kind; - if let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind; - if let Res::PrimTy(_) = path.res; - then {} - else { - return false; - } + if let ExprKind::Cast(_, cast_to) = expr.kind + && let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind + && let Res::PrimTy(_) = path.res + {} + else { + return false; } // skip cast of fn call that returns type alias @@ -106,18 +102,16 @@ pub(super) fn check<'tcx>( if let Some(lit) = get_numeric_literal(cast_expr) { let literal_str = &cast_str; - if_chain! { - if let LitKind::Int(n, _) = lit.node; - if let Some(src) = snippet_opt(cx, cast_expr.span); - if cast_to.is_floating_point(); - if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node); - let from_nbits = 128 - n.leading_zeros(); - let to_nbits = fp_ty_mantissa_nbits(cast_to); - if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal(); - then { - lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); - return true - } + if let LitKind::Int(n, _) = lit.node + && let Some(src) = snippet_opt(cx, cast_expr.span) + && cast_to.is_floating_point() + && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) + && let from_nbits = 128 - n.leading_zeros() + && let to_nbits = fp_ty_mantissa_nbits(cast_to) + && from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal() + { + lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); + return true } match lit.node { diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index d31c2268a65..26ec1dd2d43 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -55,20 +55,18 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { return; } - let result = if_chain! { - if !in_constant(cx, item.hir_id); - if !in_external_macro(cx.sess(), item.span); - if let ExprKind::Binary(op, left, right) = &item.kind; - - then { - match op.node { - BinOpKind::Ge | BinOpKind::Le => single_check(item), - BinOpKind::And => double_check(cx, left, right), - _ => None, - } - } else { - None + let result = if !in_constant(cx, item.hir_id) + && !in_external_macro(cx.sess(), item.span) + && let ExprKind::Binary(op, left, right) = &item.kind + + { + match op.node { + BinOpKind::Ge | BinOpKind::Le => single_check(item), + BinOpKind::And => double_check(cx, left, right), + _ => None, } + } else { + None }; if let Some(cv) = result { @@ -193,16 +191,14 @@ impl ConversionType { /// Check for `expr <= (to_type::MAX as from_type)` fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - if_chain! { - if let ExprKind::Binary(ref op, left, right) = &expr.kind; - if let Some((candidate, check)) = normalize_le_ge(op, left, right); - if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX"); - - then { - Conversion::try_new(candidate, from, to) - } else { - None - } + if let ExprKind::Binary(ref op, left, right) = &expr.kind + && let Some((candidate, check)) = normalize_le_ge(op, left, right) + && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX") + + { + Conversion::try_new(candidate, from, to) + } else { + None } } @@ -243,33 +239,29 @@ fn get_types_from_cast<'a>( ) -> Option<(&'a str, &'a str)> { // `to_type::max_value() as from_type` // or `to_type::MAX as from_type` - let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! { + let call_from_cast: Option<(&Expr<'_>, &str)> = if let ExprKind::Cast(limit, from_type) = &expr.kind // to_type::max_value(), from_type - if let ExprKind::Cast(limit, from_type) = &expr.kind; - if let TyKind::Path(ref from_type_path) = &from_type.kind; - if let Some(from_sym) = int_ty_to_sym(from_type_path); + && let TyKind::Path(ref from_type_path) = &from_type.kind + && let Some(from_sym) = int_ty_to_sym(from_type_path) - then { - Some((limit, from_sym)) - } else { - None - } + { + Some((limit, from_sym)) + } else { + None }; // `from_type::from(to_type::max_value())` let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { - if_chain! { + if let ExprKind::Call(from_func, [limit]) = &expr.kind // `from_type::from, to_type::max_value()` - if let ExprKind::Call(from_func, [limit]) = &expr.kind; // `from_type::from` - if let ExprKind::Path(ref path) = &from_func.kind; - if let Some(from_sym) = get_implementing_type(path, INTS, "from"); + && let ExprKind::Path(ref path) = &from_func.kind + && let Some(from_sym) = get_implementing_type(path, INTS, "from") - then { - Some((limit, from_sym)) - } else { - None - } + { + Some((limit, from_sym)) + } else { + None } }); @@ -298,31 +290,27 @@ fn get_types_from_cast<'a>( /// Gets the type which implements the called function fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> { - if_chain! { - if let QPath::TypeRelative(ty, path) = &path; - if path.ident.name.as_str() == function; - if let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind; - if let [int] = tp.segments; - then { - let name = int.ident.name.as_str(); - candidates.iter().find(|c| &name == *c).copied() - } else { - None - } + if let QPath::TypeRelative(ty, path) = &path + && path.ident.name.as_str() == function + && let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind + && let [int] = tp.segments + { + let name = int.ident.name.as_str(); + candidates.iter().find(|c| &name == *c).copied() + } else { + None } } /// Gets the type as a string, if it is a supported integer fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { - if_chain! { - if let QPath::Resolved(_, path) = *path; - if let [ty] = path.segments; - then { - let name = ty.ident.name.as_str(); - INTS.iter().find(|c| &name == *c).copied() - } else { - None - } + if let QPath::Resolved(_, path) = *path + && let [ty] = path.segments + { + let name = ty.ident.name.as_str(); + INTS.iter().find(|c| &name == *c).copied() + } else { + None } } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index d21ef195d9b..763a2d2ad89 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -121,64 +121,60 @@ fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool { } fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: &ast::Expr) { - if_chain! { - if let ast::ExprKind::Block(ref block, _) = else_.kind; - if !block_starts_with_comment(cx, block); - if let Some(else_) = expr_block(block); - if else_.attrs.is_empty(); - if !else_.span.from_expansion(); - if let ast::ExprKind::If(..) = else_.kind; - then { - // Prevent "elseif" - // Check that the "else" is followed by whitespace - let up_to_else = then_span.between(block.span); - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false }; + if let ast::ExprKind::Block(ref block, _) = else_.kind + && !block_starts_with_comment(cx, block) + && let Some(else_) = expr_block(block) + && else_.attrs.is_empty() + && !else_.span.from_expansion() + && let ast::ExprKind::If(..) = else_.kind + { + // Prevent "elseif" + // Check that the "else" is followed by whitespace + let up_to_else = then_span.between(block.span); + let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false }; - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - COLLAPSIBLE_ELSE_IF, - block.span, - "this `else { if .. }` block can be collapsed", - "collapse nested if block", - format!( - "{}{}", - if requires_space { " " } else { "" }, - snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability) - ), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + COLLAPSIBLE_ELSE_IF, + block.span, + "this `else { if .. }` block can be collapsed", + "collapse nested if block", + format!( + "{}{}", + if requires_space { " " } else { "" }, + snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability) + ), + applicability, + ); } } fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) { - if_chain! { - if !block_starts_with_comment(cx, then); - if let Some(inner) = expr_block(then); - if inner.attrs.is_empty(); - if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind; + if !block_starts_with_comment(cx, then) + && let Some(inner) = expr_block(then) + && inner.attrs.is_empty() + && let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind // Prevent triggering on `if c { if let a = b { .. } }`. - if !matches!(check_inner.kind, ast::ExprKind::Let(..)); - let ctxt = expr.span.ctxt(); - if inner.span.ctxt() == ctxt; - then { - span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| { - let mut app = Applicability::MachineApplicable; - let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app); - let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app); - diag.span_suggestion( - expr.span, - "collapse nested if block", - format!( - "if {} {}", - lhs.and(&rhs), - snippet_block(cx, content.span, "..", Some(expr.span)), - ), - app, // snippet - ); - }); - } + && !matches!(check_inner.kind, ast::ExprKind::Let(..)) + && let ctxt = expr.span.ctxt() + && inner.span.ctxt() == ctxt + { + span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| { + let mut app = Applicability::MachineApplicable; + let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app); + let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app); + diag.span_suggestion( + expr.span, + "collapse nested if block", + format!( + "if {} {}", + lhs.and(&rhs), + snippet_block(cx, content.span, "..", Some(expr.span)), + ), + app, // snippet + ); + }); } } diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 5d04ad0112d..9d578054188 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -38,25 +38,23 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for CopyIterator { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if_chain! { - if let ItemKind::Impl(Impl { + if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), .. - }) = item.kind; - let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - if is_copy(cx, ty); - if let Some(trait_id) = trait_ref.trait_def_id(); - if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id); - then { - span_lint_and_note( - cx, - COPY_ITERATOR, - item.span, - "you are implementing `Iterator` on a `Copy` type", - None, - "consider implementing `IntoIterator` instead", - ); - } + }) = item.kind + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && is_copy(cx, ty) + && let Some(trait_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Iterator, trait_id) + { + span_lint_and_note( + cx, + COPY_ITERATOR, + item.span, + "you are implementing `Iterator` on a `Copy` type", + None, + "consider implementing `IntoIterator` instead", + ); } } } diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index a2005638d24..8d9b2ebff7f 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -53,35 +53,31 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]); impl EarlyLintPass for CrateInMacroDef { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if_chain! { - if item.attrs.iter().any(is_macro_export); - if let ItemKind::MacroDef(macro_def) = &item.kind; - let tts = macro_def.body.tokens.clone(); - if let Some(span) = contains_unhygienic_crate_reference(&tts); - then { - span_lint_and_sugg( - cx, - CRATE_IN_MACRO_DEF, - span, - "`crate` references the macro call's crate", - "to reference the macro definition's crate, use", - String::from("$crate"), - Applicability::MachineApplicable, - ); - } + if item.attrs.iter().any(is_macro_export) + && let ItemKind::MacroDef(macro_def) = &item.kind + && let tts = macro_def.body.tokens.clone() + && let Some(span) = contains_unhygienic_crate_reference(&tts) + { + span_lint_and_sugg( + cx, + CRATE_IN_MACRO_DEF, + span, + "`crate` references the macro call's crate", + "to reference the macro definition's crate, use", + String::from("$crate"), + Applicability::MachineApplicable, + ); } } } fn is_macro_export(attr: &Attribute) -> bool { - if_chain! { - if let AttrKind::Normal(normal) = &attr.kind; - if let [segment] = normal.item.path.segments.as_slice(); - then { - segment.ident.name == sym::macro_export - } else { - false - } + if let AttrKind::Normal(normal) = &attr.kind + && let [segment] = normal.item.path.segments.as_slice() + { + segment.ident.name == sym::macro_export + } else { + false } } @@ -89,14 +85,12 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { let mut prev_is_dollar = false; let mut cursor = tts.trees(); while let Some(curr) = cursor.next() { - if_chain! { - if !prev_is_dollar; - if let Some(span) = is_crate_keyword(curr); - if let Some(next) = cursor.look_ahead(0); - if is_token(next, &TokenKind::ModSep); - then { - return Some(span); - } + if !prev_is_dollar + && let Some(span) = is_crate_keyword(curr) + && let Some(next) = cursor.look_ahead(0) + && is_token(next, &TokenKind::ModSep) + { + return Some(span); } if let TokenTree::Delimited(_, _, tts) = &curr { let span = contains_unhygienic_crate_reference(tts); @@ -110,11 +104,9 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { } fn is_crate_keyword(tt: &TokenTree) -> Option { - if_chain! { - if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }, _) = tt; - if symbol.as_str() == "crate"; - then { Some(*span) } else { None } - } + if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }, _) = tt + && symbol.as_str() == "crate" + { Some(*span) } else { None } } fn is_token(tt: &TokenTree, kind: &TokenKind) -> bool { diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 2bca695c43b..cd92f38b0ca 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -33,22 +33,20 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Call(func, [arg, ..]) = expr.kind; - if let ExprKind::Path(ref path) = func.kind; - if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id); - then { - span_lint_and_sugg( - cx, - CREATE_DIR, - expr.span, - "calling `std::fs::create_dir` where there may be a better way", - "consider calling `std::fs::create_dir_all` instead", - format!("create_dir_all({})", snippet(cx, arg.span, "..")), - Applicability::MaybeIncorrect, - ) - } + if let ExprKind::Call(func, [arg, ..]) = expr.kind + && let ExprKind::Path(ref path) = func.kind + && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id) + { + span_lint_and_sugg( + cx, + CREATE_DIR, + expr.span, + "calling `std::fs::create_dir` where there may be a better way", + "consider calling `std::fs::create_dir_all` instead", + format!("create_dir_all({})", snippet(cx, arg.span, "..")), + Applicability::MaybeIncorrect, + ) } } } diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index c74b2b8831e..1ad71631089 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -81,33 +81,31 @@ impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]); impl<'tcx> LateLintPass<'tcx> for Default { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if !expr.span.from_expansion(); + if !expr.span.from_expansion() // Avoid cases already linted by `field_reassign_with_default` - if !self.reassigned_linted.contains(&expr.span); - if let ExprKind::Call(path, ..) = expr.kind; - if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); - if let ExprKind::Path(ref qpath) = path.kind; - if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); - if !is_update_syntax_base(cx, expr); + && !self.reassigned_linted.contains(&expr.span) + && let ExprKind::Call(path, ..) = expr.kind + && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::default_fn, def_id) + && !is_update_syntax_base(cx, expr) // Detect and ignore ::default() because these calls do explicitly name the type. - if let QPath::Resolved(None, _path) = qpath; - let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, ..) = expr_ty.kind(); - if !is_from_proc_macro(cx, expr); - then { - let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did()))); - span_lint_and_sugg( - cx, - DEFAULT_TRAIT_ACCESS, - expr.span, - &format!("calling `{replacement}` is more clear than this expression"), - "try", - replacement, - Applicability::Unspecified, // First resolve the TODO above - ); - } + && let QPath::Resolved(None, _path) = qpath + && let expr_ty = cx.typeck_results().expr_ty(expr) + && let ty::Adt(def, ..) = expr_ty.kind() + && !is_from_proc_macro(cx, expr) + { + let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did()))); + span_lint_and_sugg( + cx, + DEFAULT_TRAIT_ACCESS, + expr.span, + &format!("calling `{replacement}` is more clear than this expression"), + "try", + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); } } @@ -124,38 +122,36 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find all binding statements like `let mut _ = T::default()` where `T::default()` is the // `default` method of the `Default` trait, and store statement index in current block being // checked and the name of the bound variable - let (local, variant, binding_name, binding_type, span) = if_chain! { + let (local, variant, binding_name, binding_type, span) = if let StmtKind::Local(local) = stmt.kind // only take `let ...` statements - if let StmtKind::Local(local) = stmt.kind; - if let Some(expr) = local.init; - if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); - if !expr.span.from_expansion(); + && let Some(expr) = local.init + && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id) + && !expr.span.from_expansion() // only take bindings to identifiers - if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind; + && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind // only when assigning `... = Default::default()` - if is_expr_default(expr, cx); - let binding_type = cx.typeck_results().node_type(binding_id); - if let Some(adt) = binding_type.ty_adt_def(); - if adt.is_struct(); - let variant = adt.non_enum_variant(); - if adt.did().is_local() || !variant.is_field_list_non_exhaustive(); - let module_did = cx.tcx.parent_module(stmt.hir_id); - if variant + && is_expr_default(expr, cx) + && let binding_type = cx.typeck_results().node_type(binding_id) + && let Some(adt) = binding_type.ty_adt_def() + && adt.is_struct() + && let variant = adt.non_enum_variant() + && (adt.did().is_local() || !variant.is_field_list_non_exhaustive()) + && let module_did = cx.tcx.parent_module(stmt.hir_id) + && variant .fields .iter() - .all(|field| field.vis.is_accessible_from(module_did, cx.tcx)); - let all_fields_are_copy = variant + .all(|field| field.vis.is_accessible_from(module_did, cx.tcx)) + && let all_fields_are_copy = variant .fields .iter() .all(|field| { is_copy(cx, cx.tcx.type_of(field.did).instantiate_identity()) - }); - if !has_drop(cx, binding_type) || all_fields_are_copy; - then { - (local, variant, ident.name, binding_type, expr.span) - } else { - continue; - } + }) + && (!has_drop(cx, binding_type) || all_fields_are_copy) + { + (local, variant, ident.name, binding_type, expr.span) + } else { + continue; }; let init_ctxt = local.span.ctxt(); @@ -216,21 +212,19 @@ impl<'tcx> LateLintPass<'tcx> for Default { .join(", "); // give correct suggestion if generics are involved (see #6944) - let binding_type = if_chain! { - if let ty::Adt(adt_def, args) = binding_type.kind(); - if !args.is_empty(); - then { - let adt_def_ty_name = cx.tcx.item_name(adt_def.did()); - let generic_args = args.iter().collect::>(); - let tys_str = generic_args - .iter() - .map(ToString::to_string) - .collect::>() - .join(", "); - format!("{adt_def_ty_name}::<{}>", &tys_str) - } else { - binding_type.to_string() - } + let binding_type = if let ty::Adt(adt_def, args) = binding_type.kind() + && !args.is_empty() + { + let adt_def_ty_name = cx.tcx.item_name(adt_def.did()); + let generic_args = args.iter().collect::>(); + let tys_str = generic_args + .iter() + .map(ToString::to_string) + .collect::>() + .join(", "); + format!("{adt_def_ty_name}::<{}>", &tys_str) + } else { + binding_type.to_string() }; let sugg = if ext_with_default { @@ -260,48 +254,42 @@ impl<'tcx> LateLintPass<'tcx> for Default { /// Checks if the given expression is the `default` method belonging to the `Default` trait. fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { - if_chain! { - if let ExprKind::Call(fn_expr, _) = &expr.kind; - if let ExprKind::Path(qpath) = &fn_expr.kind; - if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); - then { - // right hand side of assignment is `Default::default` - cx.tcx.is_diagnostic_item(sym::default_fn, def_id) - } else { - false - } + if let ExprKind::Call(fn_expr, _) = &expr.kind + && let ExprKind::Path(qpath) = &fn_expr.kind + && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) + { + // right hand side of assignment is `Default::default` + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) + } else { + false } } /// Returns the reassigned field and the assigning expression (right-hand side of assign). fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> { - if_chain! { + if let StmtKind::Semi(later_expr) = this.kind // only take assignments - if let StmtKind::Semi(later_expr) = this.kind; - if let ExprKind::Assign(assign_lhs, assign_rhs, _) = later_expr.kind; + && let ExprKind::Assign(assign_lhs, assign_rhs, _) = later_expr.kind // only take assignments to fields where the left-hand side field is a field of // the same binding as the previous statement - if let ExprKind::Field(binding, field_ident) = assign_lhs.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind; - if let Some(second_binding_name) = path.segments.last(); - if second_binding_name.ident.name == binding_name; - then { - Some((field_ident, assign_rhs)) - } else { - None - } + && let ExprKind::Field(binding, field_ident) = assign_lhs.kind + && let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind + && let Some(second_binding_name) = path.segments.last() + && second_binding_name.ident.name == binding_name + { + Some((field_ident, assign_rhs)) + } else { + None } } /// Returns whether `expr` is the update syntax base: `Foo { a: 1, .. base }` fn is_update_syntax_base<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let ExprKind::Struct(_, _, Some(base)) = parent.kind; - then { - base.hir_id == expr.hir_id - } else { - false - } + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::Struct(_, _, Some(base)) = parent.kind + { + base.hir_id == expr.hir_id + } else { + false } } diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index bf070432ef9..edd47be5840 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -56,32 +56,30 @@ fn is_alias(ty: hir::Ty<'_>) -> bool { impl LateLintPass<'_> for DefaultConstructedUnitStructs { fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if_chain!( + if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind // make sure we have a call to `Default::default` - if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind; - if let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind; + && let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind // make sure this isn't a type alias: // `::Assoc` cannot be used as a constructor - if !is_alias(*base); - if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); - if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); + && !is_alias(*base) + && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) + && cx.tcx.is_diagnostic_item(sym::default_fn, def_id) // make sure we have a struct with no fields (unit struct) - if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); - if def.is_struct(); - if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant(); - if !var.is_field_list_non_exhaustive(); - if !expr.span.from_expansion() && !qpath.span().from_expansion(); - then { - span_lint_and_sugg( - cx, - DEFAULT_CONSTRUCTED_UNIT_STRUCTS, - expr.span.with_lo(qpath.qself_span().hi()), - "use of `default` to create a unit struct", - "remove this call to `default`", - String::new(), - Applicability::MachineApplicable, - ) - } - ); + && let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind() + && def.is_struct() + && let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant() + && !var.is_field_list_non_exhaustive() + && !expr.span.from_expansion() && !qpath.span().from_expansion() + { + span_lint_and_sugg( + cx, + DEFAULT_CONSTRUCTED_UNIT_STRUCTS, + expr.span.with_lo(qpath.qself_span().hi()), + "use of `default` to create a unit struct", + "remove this call to `default`", + String::new(), + Applicability::MachineApplicable, + ) + }; } } diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index b296ea20f9c..62583b99eaa 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -82,41 +82,39 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { /// Check whether a passed literal has potential to cause fallback or not. fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { - if_chain! { - if !in_external_macro(self.cx.sess(), lit.span); - if matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))); - if matches!(lit.node, - LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)); - then { - let (suffix, is_float) = match lit_ty.kind() { - ty::Int(IntTy::I32) => ("i32", false), - ty::Float(FloatTy::F64) => ("f64", true), - // Default numeric fallback never results in other types. + if !in_external_macro(self.cx.sess(), lit.span) + && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))) + && matches!(lit.node, + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)) + { + let (suffix, is_float) = match lit_ty.kind() { + ty::Int(IntTy::I32) => ("i32", false), + ty::Float(FloatTy::F64) => ("f64", true), + // Default numeric fallback never results in other types. + _ => return, + }; + + let src = if let Some(src) = snippet_opt(self.cx, lit.span) { + src + } else { + match lit.node { + LitKind::Int(src, _) => format!("{src}"), + LitKind::Float(src, _) => format!("{src}"), _ => return, - }; - - let src = if let Some(src) = snippet_opt(self.cx, lit.span) { - src - } else { - match lit.node { - LitKind::Int(src, _) => format!("{src}"), - LitKind::Float(src, _) => format!("{src}"), - _ => return, - } - }; - let sugg = numeric_literal::format(&src, Some(suffix), is_float); - span_lint_hir_and_then( - self.cx, - DEFAULT_NUMERIC_FALLBACK, - emit_hir_id, - lit.span, - "default numeric fallback might occur", - |diag| { - diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect); - } - ); - } - } + } + }; + let sugg = numeric_literal::format(&src, Some(suffix), is_float); + span_lint_hir_and_then( + self.cx, + DEFAULT_NUMERIC_FALLBACK, + emit_hir_id, + lit.span, + "default numeric fallback might occur", + |diag| { + diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect); + } + ); + } } } @@ -149,36 +147,34 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { ExprKind::Struct(_, fields, base) => { let ty = self.cx.typeck_results().expr_ty(expr); - if_chain! { - if let Some(adt_def) = ty.ty_adt_def(); - if adt_def.is_struct(); - if let Some(variant) = adt_def.variants().iter().next(); - then { - let fields_def = &variant.fields; - - // Push field type then visit each field expr. - for field in *fields { - let bound = - fields_def - .iter() - .find_map(|f_def| { - if f_def.ident(self.cx.tcx) == field.ident - { Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) } - else { None } - }); - self.ty_bounds.push(bound.into()); - self.visit_expr(field.expr); - self.ty_bounds.pop(); - } - - // Visit base with no bound. - if let Some(base) = base { - self.ty_bounds.push(ExplicitTyBound(false)); - self.visit_expr(base); - self.ty_bounds.pop(); - } - return; + if let Some(adt_def) = ty.ty_adt_def() + && adt_def.is_struct() + && let Some(variant) = adt_def.variants().iter().next() + { + let fields_def = &variant.fields; + + // Push field type then visit each field expr. + for field in *fields { + let bound = + fields_def + .iter() + .find_map(|f_def| { + if f_def.ident(self.cx.tcx) == field.ident + { Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) } + else { None } + }); + self.ty_bounds.push(bound.into()); + self.visit_expr(field.expr); + self.ty_bounds.pop(); } + + // Visit base with no bound. + if let Some(base) = base { + self.ty_bounds.push(ExplicitTyBound(false)); + self.visit_expr(base); + self.ty_bounds.pop(); + } + return; } }, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 6c109a51f83..34dd43cfe84 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -597,26 +597,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { return; } - if_chain! { - if !pat.span.from_expansion(); - if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind(); + if !pat.span.from_expansion() + && let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind() // only lint immutable refs, because borrowed `&mut T` cannot be moved out - if let ty::Ref(_, _, Mutability::Not) = *tam.kind(); - then { - let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0; - self.current_body = self.current_body.or(cx.enclosing_body); - self.ref_locals.insert( - id, - Some(RefPat { - always_deref: true, - spans: vec![pat.span], - app, - replacements: vec![(pat.span, snip.into())], - hir_id: pat.hir_id, - }), - ); - } + && let ty::Ref(_, _, Mutability::Not) = *tam.kind() + { + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0; + self.current_body = self.current_body.or(cx.enclosing_body); + self.ref_locals.insert( + id, + Some(RefPat { + always_deref: true, + spans: vec![pat.span], + app, + replacements: vec![(pat.span, snip.into())], + hir_id: pat.hir_id, + }), + ); } } } diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index a450becc647..233391ff3bb 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -148,83 +148,79 @@ fn check_struct<'tcx>( } fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) { - if_chain! { - if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind; - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res; - if let variant_id = cx.tcx.parent(id); - if let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id); - if variant_def.fields.is_empty(); - if !variant_def.is_field_list_non_exhaustive(); - - then { - let enum_span = cx.tcx.def_span(adt_def.did()); - let indent_enum = indent_of(cx, enum_span).unwrap_or(0); - let variant_span = cx.tcx.def_span(variant_def.def_id); - let indent_variant = indent_of(cx, variant_span).unwrap_or(0); - span_lint_and_then( - cx, - DERIVABLE_IMPLS, - item.span, - "this `impl` can be derived", - |diag| { - diag.span_suggestion_hidden( - item.span, - "remove the manual implementation...", - String::new(), - Applicability::MachineApplicable - ); - diag.span_suggestion( - enum_span.shrink_to_lo(), - "...and instead derive it...", - format!( - "#[derive(Default)]\n{indent}", - indent = " ".repeat(indent_enum), - ), - Applicability::MachineApplicable - ); - diag.span_suggestion( - variant_span.shrink_to_lo(), - "...and mark the default variant", - format!( - "#[default]\n{indent}", - indent = " ".repeat(indent_variant), - ), - Applicability::MachineApplicable - ); - } - ); - } + if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind + && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res + && let variant_id = cx.tcx.parent(id) + && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id) + && variant_def.fields.is_empty() + && !variant_def.is_field_list_non_exhaustive() + + { + let enum_span = cx.tcx.def_span(adt_def.did()); + let indent_enum = indent_of(cx, enum_span).unwrap_or(0); + let variant_span = cx.tcx.def_span(variant_def.def_id); + let indent_variant = indent_of(cx, variant_span).unwrap_or(0); + span_lint_and_then( + cx, + DERIVABLE_IMPLS, + item.span, + "this `impl` can be derived", + |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable + ); + diag.span_suggestion( + enum_span.shrink_to_lo(), + "...and instead derive it...", + format!( + "#[derive(Default)]\n{indent}", + indent = " ".repeat(indent_enum), + ), + Applicability::MachineApplicable + ); + diag.span_suggestion( + variant_span.shrink_to_lo(), + "...and mark the default variant", + format!( + "#[default]\n{indent}", + indent = " ".repeat(indent_variant), + ), + Applicability::MachineApplicable + ); + } + ); } } impl<'tcx> LateLintPass<'tcx> for DerivableImpls { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if_chain! { - if let ItemKind::Impl(Impl { + if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: [child], self_ty, .. - }) = item.kind; - if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); - if !item.span.from_expansion(); - if let Some(def_id) = trait_ref.trait_def_id(); - if cx.tcx.is_diagnostic_item(sym::Default, def_id); - if let impl_item_hir = child.id.hir_id(); - if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir); - if let ImplItemKind::Fn(_, b) = &impl_item.kind; - if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); - if let &Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind(); - if let attrs = cx.tcx.hir().attrs(item.hir_id()); - if !attrs.iter().any(|attr| attr.doc_str().is_some()); - if cx.tcx.hir().attrs(impl_item_hir).is_empty(); - - then { - if adt_def.is_struct() { - check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b)); - } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) { - check_enum(cx, item, func_expr, adt_def); - } + }) = item.kind + && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) + && !item.span.from_expansion() + && let Some(def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Default, def_id) + && let impl_item_hir = child.id.hir_id() + && let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir) + && let ImplItemKind::Fn(_, b) = &impl_item.kind + && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b) + && let &Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() + && let attrs = cx.tcx.hir().attrs(item.hir_id()) + && !attrs.iter().any(|attr| attr.doc_str().is_some()) + && cx.tcx.hir().attrs(impl_item_hir).is_empty() + + { + if adt_def.is_struct() { + check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b)); + } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) { + check_enum(cx, item, func_expr, adt_def); } } } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 6aaa9e39b8b..6913c87ae01 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -233,42 +233,40 @@ fn check_hash_peq<'tcx>( ty: Ty<'tcx>, hash_is_automatically_derived: bool, ) { - if_chain! { - if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait(); - if let Some(def_id) = trait_ref.trait_def_id(); - if cx.tcx.is_diagnostic_item(sym::Hash, def_id); - then { - // Look for the PartialEq implementations for `ty` - cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { - let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); - - if !hash_is_automatically_derived || peq_is_automatically_derived { - return; - } - - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - - // Only care about `impl PartialEq for Foo` - // For `impl PartialEq for A, input_types is [A, B] - if trait_ref.instantiate_identity().args.type_at(1) == ty { - span_lint_and_then( - cx, - DERIVED_HASH_WITH_MANUAL_EQ, - span, - "you are deriving `Hash` but have implemented `PartialEq` explicitly", - |diag| { - if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - diag.span_note( - cx.tcx.hir().span(hir_id), - "`PartialEq` implemented here" - ); - } + if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait() + && let Some(def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Hash, def_id) + { + // Look for the PartialEq implementations for `ty` + cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { + let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); + + if !hash_is_automatically_derived || peq_is_automatically_derived { + return; + } + + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialEq for Foo` + // For `impl PartialEq for A, input_types is [A, B] + if trait_ref.instantiate_identity().args.type_at(1) == ty { + span_lint_and_then( + cx, + DERIVED_HASH_WITH_MANUAL_EQ, + span, + "you are deriving `Hash` but have implemented `PartialEq` explicitly", + |diag| { + if let Some(local_def_id) = impl_id.as_local() { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); + diag.span_note( + cx.tcx.hir().span(hir_id), + "`PartialEq` implemented here" + ); } - ); - } - }); - } + } + ); + } + }); } } @@ -280,49 +278,47 @@ fn check_ord_partial_ord<'tcx>( ty: Ty<'tcx>, ord_is_automatically_derived: bool, ) { - if_chain! { - if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord); - if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait(); - if let Some(def_id) = &trait_ref.trait_def_id(); - if *def_id == ord_trait_def_id; - then { - // Look for the PartialOrd implementations for `ty` - cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { - let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); - - if partial_ord_is_automatically_derived == ord_is_automatically_derived { - return; - } - - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - - // Only care about `impl PartialOrd for Foo` - // For `impl PartialOrd for A, input_types is [A, B] - if trait_ref.instantiate_identity().args.type_at(1) == ty { - let mess = if partial_ord_is_automatically_derived { - "you are implementing `Ord` explicitly but have derived `PartialOrd`" - } else { - "you are deriving `Ord` but have implemented `PartialOrd` explicitly" - }; - - span_lint_and_then( - cx, - DERIVE_ORD_XOR_PARTIAL_ORD, - span, - mess, - |diag| { - if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - diag.span_note( - cx.tcx.hir().span(hir_id), - "`PartialOrd` implemented here" - ); - } + if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord) + && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait() + && let Some(def_id) = &trait_ref.trait_def_id() + && *def_id == ord_trait_def_id + { + // Look for the PartialOrd implementations for `ty` + cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { + let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); + + if partial_ord_is_automatically_derived == ord_is_automatically_derived { + return; + } + + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialOrd for Foo` + // For `impl PartialOrd for A, input_types is [A, B] + if trait_ref.instantiate_identity().args.type_at(1) == ty { + let mess = if partial_ord_is_automatically_derived { + "you are implementing `Ord` explicitly but have derived `PartialOrd`" + } else { + "you are deriving `Ord` but have implemented `PartialOrd` explicitly" + }; + + span_lint_and_then( + cx, + DERIVE_ORD_XOR_PARTIAL_ORD, + span, + mess, + |diag| { + if let Some(local_def_id) = impl_id.as_local() { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); + diag.span_note( + cx.tcx.hir().span(hir_id), + "`PartialOrd` implemented here" + ); } - ); - } - }); - } + } + ); + } + }); } } @@ -395,27 +391,25 @@ fn check_unsafe_derive_deserialize<'tcx>( visitor.has_unsafe } - if_chain! { - if let Some(trait_def_id) = trait_ref.trait_def_id(); - if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE); - if let ty::Adt(def, _) = ty.kind(); - if let Some(local_def_id) = def.did().as_local(); - let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id); - if cx.tcx.inherent_impls(def.did()) + if let Some(trait_def_id) = trait_ref.trait_def_id() + && match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE) + && let ty::Adt(def, _) = ty.kind() + && let Some(local_def_id) = def.did().as_local() + && let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id) + && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id) + && cx.tcx.inherent_impls(def.did()) .iter() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) - .any(|imp| has_unsafe(cx, imp)); - then { - span_lint_and_help( - cx, - UNSAFE_DERIVE_DESERIALIZE, - item.span, - "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", - None, - "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html" - ); - } + .any(|imp| has_unsafe(cx, imp)) + { + span_lint_and_help( + cx, + UNSAFE_DERIVE_DESERIALIZE, + item.span, + "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", + None, + "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html" + ); } } @@ -432,12 +426,10 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { return; } - if_chain! { - if let Some(header) = kind.header(); - if header.unsafety == Unsafety::Unsafe; - then { - self.has_unsafe = true; - } + if let Some(header) = kind.header() + && header.unsafety == Unsafety::Unsafe + { + self.has_unsafe = true; } walk_fn(self, kind, decl, body_id, id); @@ -464,30 +456,28 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint. fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { - if_chain! { - if let ty::Adt(adt, args) = ty.kind(); - if cx.tcx.visibility(adt.did()).is_public(); - if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq); - if let Some(def_id) = trait_ref.trait_def_id(); - if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); - let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id); - if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]); + if let ty::Adt(adt, args) = ty.kind() + && cx.tcx.visibility(adt.did()).is_public() + && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq) + && let Some(def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) + && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]) // If all of our fields implement `Eq`, we can implement `Eq` too - if adt + && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[])); - then { - span_lint_and_sugg( - cx, - DERIVE_PARTIAL_EQ_WITHOUT_EQ, - span.ctxt().outer_expn_data().call_site, - "you are deriving `PartialEq` and can implement `Eq`", - "consider deriving `Eq` as well", - "PartialEq, Eq".to_string(), - Applicability::MachineApplicable, - ) - } + .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[])) + { + span_lint_and_sugg( + cx, + DERIVE_PARTIAL_EQ_WITHOUT_EQ, + span.ctxt().outer_expn_data().call_site, + "you are deriving `PartialEq` and can implement `Eq`", + "consider deriving `Eq` as well", + "PartialEq, Eq".to_string(), + Applicability::MachineApplicable, + ) } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index d4a698521ac..f6dde3232bf 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -429,23 +429,21 @@ fn lint_for_missing_headers( "docs for function returning `Result` missing `# Errors` section", ); } else { - if_chain! { - if let Some(body_id) = body_id; - if let Some(future) = cx.tcx.lang_items().future_trait(); - let typeck = cx.tcx.typeck_body(body_id); - let body = cx.tcx.hir().body(body_id); - let ret_ty = typeck.expr_ty(body.value); - if implements_trait(cx, ret_ty, future, &[]); - if let ty::Coroutine(_, subs, _) = ret_ty.kind(); - if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result); - then { - span_lint( - cx, - MISSING_ERRORS_DOC, - span, - "docs for function returning `Result` missing `# Errors` section", - ); - } + if let Some(body_id) = body_id + && let Some(future) = cx.tcx.lang_items().future_trait() + && let typeck = cx.tcx.typeck_body(body_id) + && let body = cx.tcx.hir().body(body_id) + && let ret_ty = typeck.expr_ty(body.value) + && implements_trait(cx, ret_ty, future, &[]) + && let ty::Coroutine(_, subs, _) = ret_ty.kind() + && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) + { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); } } } diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 5fcdca7cf36..da1103f39e0 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -36,31 +36,29 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]); impl LateLintPass<'_> for EmptyDrop { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if_chain! { - if let ItemKind::Impl(Impl { + if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: [child], .. - }) = item.kind; - if trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait(); - if let impl_item_hir = child.id.hir_id(); - if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir); - if let ImplItemKind::Fn(_, b) = &impl_item.kind; - if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); - let func_expr = peel_blocks(func_expr); - if let ExprKind::Block(block, _) = func_expr.kind; - if block.stmts.is_empty() && block.expr.is_none(); - then { - span_lint_and_sugg( - cx, - EMPTY_DROP, - item.span, - "empty drop implementation", - "try removing this impl", - String::new(), - Applicability::MaybeIncorrect - ); - } + }) = item.kind + && trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait() + && let impl_item_hir = child.id.hir_id() + && let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir) + && let ImplItemKind::Fn(_, b) = &impl_item.kind + && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b) + && let func_expr = peel_blocks(func_expr) + && let ExprKind::Block(block, _) = func_expr.kind + && block.stmts.is_empty() && block.expr.is_none() + { + span_lint_and_sugg( + cx, + EMPTY_DROP, + item.span, + "empty drop implementation", + "try removing this impl", + String::new(), + Applicability::MaybeIncorrect + ); } } } diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index affd0822120..6f5a0cb8801 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -114,27 +114,23 @@ impl LateLintPass<'_> for EndianBytes { return; } - if_chain! { - if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind; - if args.is_empty(); - let ty = cx.typeck_results().expr_ty(receiver); - if ty.is_primitive_ty(); - if maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty); - then { - return; - } + if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind + && args.is_empty() + && let ty = cx.typeck_results().expr_ty(receiver) + && ty.is_primitive_ty() + && maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty) + { + return; } - if_chain! { - if let ExprKind::Call(function, ..) = expr.kind; - if let ExprKind::Path(qpath) = function.kind; - if let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id(); - if let Some(function_name) = cx.get_def_path(def_id).last(); - let ty = cx.typeck_results().expr_ty(expr); - if ty.is_primitive_ty(); - then { - maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty); - } + if let ExprKind::Call(function, ..) = expr.kind + && let ExprKind::Path(qpath) = function.kind + && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id() + && let Some(function_name) = cx.get_def_path(def_id).last() + && let ty = cx.typeck_results().expr_ty(expr) + && ty.is_primitive_ty() + { + maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty); } } } diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index f976cfd3f22..201bf13a0df 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -71,40 +71,38 @@ declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]); impl LateLintPass<'_> for ExhaustiveItems { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if_chain! { - if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind; - if cx.effective_visibilities.is_exported(item.owner_id.def_id); - let attrs = cx.tcx.hir().attrs(item.hir_id()); - if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)); - then { - let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { - if v.fields().iter().any(|f| { - !cx.tcx.visibility(f.def_id).is_public() - }) { - // skip structs with private fields - return; - } - (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive") - } else { - (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive") - }; - let suggestion_span = item.span.shrink_to_lo(); - let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); - span_lint_and_then( - cx, - lint, - item.span, - msg, - |diag| { - let sugg = format!("#[non_exhaustive]\n{indent}"); - diag.span_suggestion(suggestion_span, - "try adding #[non_exhaustive]", - sugg, - Applicability::MaybeIncorrect); - } - ); + if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind + && cx.effective_visibilities.is_exported(item.owner_id.def_id) + && let attrs = cx.tcx.hir().attrs(item.hir_id()) + && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) + { + let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { + if v.fields().iter().any(|f| { + !cx.tcx.visibility(f.def_id).is_public() + }) { + // skip structs with private fields + return; + } + (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive") + } else { + (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive") + }; + let suggestion_span = item.span.shrink_to_lo(); + let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); + span_lint_and_then( + cx, + lint, + item.span, + msg, + |diag| { + let sugg = format!("#[non_exhaustive]\n{indent}"); + diag.span_suggestion(suggestion_span, + "try adding #[non_exhaustive]", + sugg, + Applicability::MaybeIncorrect); + } + ); - } } } } diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index e14b1c556ec..a366749560b 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -42,19 +42,17 @@ declare_lint_pass!(Exit => [EXIT]); impl<'tcx> LateLintPass<'tcx> for Exit { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(path_expr, _args) = e.kind; - if let ExprKind::Path(ref path) = path_expr.kind; - if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::process_exit, def_id); - let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id; - if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent); + if let ExprKind::Call(path_expr, _args) = e.kind + && let ExprKind::Path(ref path) = path_expr.kind + && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::process_exit, def_id) + && let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id + && let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent) // If the next item up is a function we check if it is an entry point // and only then emit a linter warning - if !is_entrypoint_fn(cx, parent.to_def_id()); - then { - span_lint(cx, EXIT, e.span, "usage of `process::exit`"); - } + && !is_entrypoint_fn(cx, parent.to_def_id()) + { + span_lint(cx, EXIT, e.span, "usage of `process::exit`"); } } } diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 4b5bcb06a1e..c8d901d08bd 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -101,30 +101,28 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { /// If `kind` is a block that looks like `{ let result = $expr; result }` then /// returns $expr. Otherwise returns `kind`. fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) -> &'tcx ExprKind<'hir> { - if_chain! { - if let ExprKind::Block(block, _label @ None) = kind; - if let Block { + if let ExprKind::Block(block, _label @ None) = kind + && let Block { stmts: [Stmt { kind: StmtKind::Local(local), .. }], expr: Some(expr_end_of_block), rules: BlockCheckMode::DefaultBlock, .. - } = block; + } = block // Find id of the local that expr_end_of_block resolves to - if let ExprKind::Path(QPath::Resolved(None, expr_path)) = expr_end_of_block.kind; - if let Res::Local(expr_res) = expr_path.res; - if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res); + && let ExprKind::Path(QPath::Resolved(None, expr_path)) = expr_end_of_block.kind + && let Res::Local(expr_res) = expr_path.res + && let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res) // Find id of the local we found in the block - if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind; + && let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind // If those two are the same hir id - if res_pat.hir_id == local_hir_id; + && res_pat.hir_id == local_hir_id - if let Some(init) = local.init; - then { - return &init.kind; - } + && let Some(init) = local.init + { + return &init.kind; } kind } diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index efb69476b94..5824f462f4b 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -53,13 +53,11 @@ declare_lint_pass!(FallibleImplFrom => [FALLIBLE_IMPL_FROM]); impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { // check for `impl From for ..` - if_chain! { - if let hir::ItemKind::Impl(impl_) = &item.kind; - if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id); - if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id); - then { - lint_impl_body(cx, item.span, impl_.items); - } + if let hir::ItemKind::Impl(impl_) = &item.kind + && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) + && cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id) + { + lint_impl_body(cx, item.span, impl_.items); } } } @@ -98,34 +96,32 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl } for impl_item in impl_items { - if_chain! { - if impl_item.ident.name == sym::from; - if let ImplItemKind::Fn(_, body_id) = - cx.tcx.hir().impl_item(impl_item.id).kind; - then { - // check the body for `begin_panic` or `unwrap` - let body = cx.tcx.hir().body(body_id); - let mut fpu = FindPanicUnwrap { - lcx: cx, - typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id), - result: Vec::new(), - }; - fpu.visit_expr(body.value); + if impl_item.ident.name == sym::from + && let ImplItemKind::Fn(_, body_id) = + cx.tcx.hir().impl_item(impl_item.id).kind + { + // check the body for `begin_panic` or `unwrap` + let body = cx.tcx.hir().body(body_id); + let mut fpu = FindPanicUnwrap { + lcx: cx, + typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id), + result: Vec::new(), + }; + fpu.visit_expr(body.value); - // if we've found one, lint - if !fpu.result.is_empty() { - span_lint_and_then( - cx, - FALLIBLE_IMPL_FROM, - impl_span, - "consider implementing `TryFrom` instead", - move |diag| { - diag.help( - "`From` is intended for infallible conversions only. \ - Use `TryFrom` if there's a possibility for the conversion to fail"); - diag.span_note(fpu.result, "potential failure(s)"); - }); - } + // if we've found one, lint + if !fpu.result.is_empty() { + span_lint_and_then( + cx, + FALLIBLE_IMPL_FROM, + impl_span, + "consider implementing `TryFrom` instead", + move |diag| { + diag.help( + "`From` is intended for infallible conversions only. \ + Use `TryFrom` if there's a possibility for the conversion to fail"); + diag.span_note(fpu.result, "potential failure(s)"); + }); } } } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 506a1191747..07640a77584 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -64,73 +64,71 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]); impl<'tcx> LateLintPass<'tcx> for FloatLiteral { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { let ty = cx.typeck_results().expr_ty(expr); - if_chain! { - if let ty::Float(fty) = *ty.kind(); - if let hir::ExprKind::Lit(lit) = expr.kind; - if let LitKind::Float(sym, lit_float_ty) = lit.node; - then { - let sym_str = sym.as_str(); - let formatter = FloatFormat::new(sym_str); - // Try to bail out if the float is for sure fine. - // If its within the 2 decimal digits of being out of precision we - // check if the parsed representation is the same as the string - // since we'll need the truncated string anyway. - let digits = count_digits(sym_str); - let max = max_digits(fty); - let type_suffix = match lit_float_ty { - LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"), - LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"), - LitFloatType::Unsuffixed => None - }; - let (is_whole, is_inf, mut float_str) = match fty { - FloatTy::F32 => { - let value = sym_str.parse::().unwrap(); + if let ty::Float(fty) = *ty.kind() + && let hir::ExprKind::Lit(lit) = expr.kind + && let LitKind::Float(sym, lit_float_ty) = lit.node + { + let sym_str = sym.as_str(); + let formatter = FloatFormat::new(sym_str); + // Try to bail out if the float is for sure fine. + // If its within the 2 decimal digits of being out of precision we + // check if the parsed representation is the same as the string + // since we'll need the truncated string anyway. + let digits = count_digits(sym_str); + let max = max_digits(fty); + let type_suffix = match lit_float_ty { + LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"), + LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"), + LitFloatType::Unsuffixed => None + }; + let (is_whole, is_inf, mut float_str) = match fty { + FloatTy::F32 => { + let value = sym_str.parse::().unwrap(); - (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) - }, - FloatTy::F64 => { - let value = sym_str.parse::().unwrap(); + (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) + }, + FloatTy::F64 => { + let value = sym_str.parse::().unwrap(); - (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) - }, - }; + (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) + }, + }; - if is_inf { - return; - } - - if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { - // Normalize the literal by stripping the fractional portion - if sym_str.split('.').next().unwrap() != float_str { - // If the type suffix is missing the suggestion would be - // incorrectly interpreted as an integer so adding a `.0` - // suffix to prevent that. - if type_suffix.is_none() { - float_str.push_str(".0"); - } + if is_inf { + return; + } - span_lint_and_sugg( - cx, - LOSSY_FLOAT_LITERAL, - expr.span, - "literal cannot be represented as the underlying type without loss of precision", - "consider changing the type or replacing it with", - numeric_literal::format(&float_str, type_suffix, true), - Applicability::MachineApplicable, - ); + if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { + // Normalize the literal by stripping the fractional portion + if sym_str.split('.').next().unwrap() != float_str { + // If the type suffix is missing the suggestion would be + // incorrectly interpreted as an integer so adding a `.0` + // suffix to prevent that. + if type_suffix.is_none() { + float_str.push_str(".0"); } - } else if digits > max as usize && float_str.len() < sym_str.len() { + span_lint_and_sugg( cx, - EXCESSIVE_PRECISION, + LOSSY_FLOAT_LITERAL, expr.span, - "float has excessive precision", - "consider changing the type or truncating it to", + "literal cannot be represented as the underlying type without loss of precision", + "consider changing the type or replacing it with", numeric_literal::format(&float_str, type_suffix, true), Applicability::MachineApplicable, ); } + } else if digits > max as usize && float_str.len() < sym_str.len() { + span_lint_and_sugg( + cx, + EXCESSIVE_PRECISION, + expr.span, + "float has excessive precision", + "consider changing the type or truncating it to", + numeric_literal::format(&float_str, type_suffix, true), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 09a9d9924de..21cedf17385 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -133,30 +133,28 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su expr = inner_expr; } - if_chain! { + if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind() // if the expression is a float literal and it is unsuffixed then // add a suffix so the suggestion is valid and unambiguous - if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind(); - if let ExprKind::Lit(lit) = &expr.kind; - if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node; - then { - let op = format!( - "{suggestion}{}{}", - // Check for float literals without numbers following the decimal - // separator such as `2.` and adds a trailing zero - if sym.as_str().ends_with('.') { - "0" - } else { - "" - }, - float_ty.name_str() - ).into(); - - suggestion = match suggestion { - Sugg::MaybeParen(_) => Sugg::MaybeParen(op), - _ => Sugg::NonParen(op) - }; - } + && let ExprKind::Lit(lit) = &expr.kind + && let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node + { + let op = format!( + "{suggestion}{}{}", + // Check for float literals without numbers following the decimal + // separator such as `2.` and adds a trailing zero + if sym.as_str().ends_with('.') { + "0" + } else { + "" + }, + float_ty.name_str() + ).into(); + + suggestion = match suggestion { + Sugg::MaybeParen(_) => Sugg::MaybeParen(op), + _ => Sugg::NonParen(op) + }; } suggestion.maybe_par() @@ -359,35 +357,31 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { ) = receiver.kind { // check if expression of the form x * x + y * y - if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind; - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind; - if eq_expr_value(cx, lmul_lhs, lmul_rhs); - if eq_expr_value(cx, rmul_lhs, rmul_rhs); - then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, ".."))); - } + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind + && let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind + && eq_expr_value(cx, lmul_lhs, lmul_rhs) + && eq_expr_value(cx, rmul_lhs, rmul_rhs) + { + return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, ".."))); } // check if expression of the form x.powi(2) + y.powi(2) - if_chain! { - if let ExprKind::MethodCall( + if let ExprKind::MethodCall( PathSegment { ident: lmethod_name, .. }, largs_0, [largs_1, ..], _ - ) = &add_lhs.kind; - if let ExprKind::MethodCall( + ) = &add_lhs.kind + && let ExprKind::MethodCall( PathSegment { ident: rmethod_name, .. }, rargs_0, [rargs_1, ..], _ - ) = &add_rhs.kind; - if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1); - if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1); - if Int(2) == lvalue && Int(2) == rvalue; - then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); - } + ) = &add_rhs.kind + && lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi" + && let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1) + && let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1) + && Int(2) == lvalue && Int(2) == rvalue + { + return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); } } @@ -411,39 +405,35 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { // TODO: Lint expressions of the form `x.exp() - y` where y > 1 // and suggest usage of `x.exp_m1() - (y - 1)` instead fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind; - if cx.typeck_results().expr_ty(lhs).is_floating_point(); - if let Some(value) = constant(cx, cx.typeck_results(), rhs); - if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; - if cx.typeck_results().expr_ty(self_arg).is_floating_point(); - if path.ident.name.as_str() == "exp"; - then { - span_lint_and_sugg( - cx, - IMPRECISE_FLOPS, - expr.span, - "(e.pow(x) - 1) can be computed more accurately", - "consider using", - format!( - "{}.exp_m1()", - Sugg::hir(cx, self_arg, "..").maybe_par() - ), - Applicability::MachineApplicable, - ); - } + if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind + && cx.typeck_results().expr_ty(lhs).is_floating_point() + && let Some(value) = constant(cx, cx.typeck_results(), rhs) + && (F32(1.0) == value || F64(1.0) == value) + && let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind + && cx.typeck_results().expr_ty(self_arg).is_floating_point() + && path.ident.name.as_str() == "exp" + { + span_lint_and_sugg( + cx, + IMPRECISE_FLOPS, + expr.span, + "(e.pow(x) - 1) can be computed more accurately", + "consider using", + format!( + "{}.exp_m1()", + Sugg::hir(cx, self_arg, "..").maybe_par() + ), + Applicability::MachineApplicable, + ); } } fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { - if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind; - if cx.typeck_results().expr_ty(lhs).is_floating_point(); - if cx.typeck_results().expr_ty(rhs).is_floating_point(); - then { - return Some((lhs, rhs)); - } + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind + && cx.typeck_results().expr_ty(lhs).is_floating_point() + && cx.typeck_results().expr_ty(rhs).is_floating_point() + { + return Some((lhs, rhs)); } None @@ -553,60 +543,56 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a } fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr); - let if_body_expr = peel_blocks(then); - let else_body_expr = peel_blocks(r#else); - if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr); - then { - let positive_abs_sugg = ( - "manual implementation of `abs` method", - format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), - ); - let negative_abs_sugg = ( - "manual implementation of negation of `abs` method", - format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), - ); - let sugg = if is_testing_positive(cx, cond, body) { - if if_expr_positive { - positive_abs_sugg - } else { - negative_abs_sugg - } - } else if is_testing_negative(cx, cond, body) { - if if_expr_positive { - negative_abs_sugg - } else { - positive_abs_sugg - } + if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr) + && let if_body_expr = peel_blocks(then) + && let else_body_expr = peel_blocks(r#else) + && let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr) + { + let positive_abs_sugg = ( + "manual implementation of `abs` method", + format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), + ); + let negative_abs_sugg = ( + "manual implementation of negation of `abs` method", + format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), + ); + let sugg = if is_testing_positive(cx, cond, body) { + if if_expr_positive { + positive_abs_sugg } else { - return; - }; - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - sugg.0, - "try", - sugg.1, - Applicability::MachineApplicable, - ); - } + negative_abs_sugg + } + } else if is_testing_negative(cx, cond, body) { + if if_expr_positive { + negative_abs_sugg + } else { + positive_abs_sugg + } + } else { + return; + }; + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + sugg.0, + "try", + sugg.1, + Applicability::MachineApplicable, + ); } } fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { - if_chain! { - if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind; - if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind; - then { - return method_name_a.as_str() == method_name_b.as_str() && - args_a.len() == args_b.len() && - ( - ["ln", "log2", "log10"].contains(&method_name_a.as_str()) || - method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]) - ); - } + if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind + && let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind + { + return method_name_a.as_str() == method_name_b.as_str() && + args_a.len() == args_b.len() && + ( + ["ln", "log2", "log10"].contains(&method_name_a.as_str()) || + method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]) + ); } false @@ -614,103 +600,95 @@ fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_> fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { // check if expression of the form x.logN() / y.logN() - if_chain! { - if let ExprKind::Binary( + if let ExprKind::Binary( Spanned { node: BinOpKind::Div, .. }, lhs, rhs, - ) = &expr.kind; - if are_same_base_logs(cx, lhs, rhs); - if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind; - if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind; - then { - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "log base can be expressed more clearly", - "consider using", - format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),), - Applicability::MachineApplicable, - ); - } + ) = &expr.kind + && are_same_base_logs(cx, lhs, rhs) + && let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind + && let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind + { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "log base can be expressed more clearly", + "consider using", + format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),), + Applicability::MachineApplicable, + ); } } fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Binary( + if let ExprKind::Binary( Spanned { node: BinOpKind::Div, .. }, div_lhs, div_rhs, - ) = &expr.kind; - if let ExprKind::Binary( + ) = &expr.kind + && let ExprKind::Binary( Spanned { node: BinOpKind::Mul, .. }, mul_lhs, mul_rhs, - ) = &div_lhs.kind; - if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs); - if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs); - then { - // TODO: also check for constant values near PI/180 or 180/PI - if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && - (F32(180_f32) == lvalue || F64(180_f64) == lvalue) + ) = &div_lhs.kind + && let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs) + && let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs) + { + // TODO: also check for constant values near PI/180 or 180/PI + if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && + (F32(180_f32) == lvalue || F64(180_f64) == lvalue) + { + let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); + if let ExprKind::Lit(literal) = mul_lhs.kind + && let ast::LitKind::Float(ref value, float_type) = literal.node + && float_type == ast::LitFloatType::Unsuffixed { - let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); - if_chain! { - if let ExprKind::Lit(literal) = mul_lhs.kind; - if let ast::LitKind::Float(ref value, float_type) = literal.node; - if float_type == ast::LitFloatType::Unsuffixed; - then { - if value.as_str().ends_with('.') { - proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); - } else { - proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); - } - } + if value.as_str().ends_with('.') { + proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); + } else { + proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); } - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "conversion to degrees can be done more accurately", - "consider using", - proposal, - Applicability::MachineApplicable, - ); - } else if - (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && - (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) + } + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to degrees can be done more accurately", + "consider using", + proposal, + Applicability::MachineApplicable, + ); + } else if + (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && + (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) + { + let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); + if let ExprKind::Lit(literal) = mul_lhs.kind + && let ast::LitKind::Float(ref value, float_type) = literal.node + && float_type == ast::LitFloatType::Unsuffixed { - let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); - if_chain! { - if let ExprKind::Lit(literal) = mul_lhs.kind; - if let ast::LitKind::Float(ref value, float_type) = literal.node; - if float_type == ast::LitFloatType::Unsuffixed; - then { - if value.as_str().ends_with('.') { - proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); - } else { - proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); - } - } + if value.as_str().ends_with('.') { + proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); + } else { + proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); } - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "conversion to radians can be done more accurately", - "consider using", - proposal, - Applicability::MachineApplicable, - ); } + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to radians can be done more accurately", + "consider using", + proposal, + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 3c1f2d9d5dc..737ea05d92d 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -404,49 +404,47 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb } fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) { - if_chain! { - if !value.span.from_expansion(); - if let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind; - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id); - if is_diag_trait_item(cx, method_def_id, sym::ToString); - let receiver_ty = cx.typeck_results().expr_ty(receiver); - if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display); - let (n_needed_derefs, target) = - count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()); - if implements_trait(cx, target, display_trait_id, &[]); - if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait(); - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); - then { - let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); - if n_needed_derefs == 0 && !needs_ref { - span_lint_and_sugg( - cx, - TO_STRING_IN_FORMAT_ARGS, - to_string_span.with_lo(receiver.span.hi()), - &format!( - "`to_string` applied to a type that implements `Display` in `{name}!` args" - ), - "remove this", - String::new(), - Applicability::MachineApplicable, - ); - } else { - span_lint_and_sugg( - cx, - TO_STRING_IN_FORMAT_ARGS, - value.span, - &format!( - "`to_string` applied to a type that implements `Display` in `{name}!` args" - ), - "use this", - format!( - "{}{:*>n_needed_derefs$}{receiver_snippet}", - if needs_ref { "&" } else { "" }, - "" - ), - Applicability::MachineApplicable, - ); - } + if !value.span.from_expansion() + && let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) + && is_diag_trait_item(cx, method_def_id, sym::ToString) + && let receiver_ty = cx.typeck_results().expr_ty(receiver) + && let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display) + && let (n_needed_derefs, target) = + count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) + && implements_trait(cx, target, display_trait_id, &[]) + && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + { + let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); + if n_needed_derefs == 0 && !needs_ref { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + to_string_span.with_lo(receiver.span.hi()), + &format!( + "`to_string` applied to a type that implements `Display` in `{name}!` args" + ), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + value.span, + &format!( + "`to_string` applied to a type that implements `Display` in `{name}!` args" + ), + "use this", + format!( + "{}{:*>n_needed_derefs$}{receiver_snippet}", + if needs_ref { "&" } else { "" }, + "" + ), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 08ee7032c09..7eee3a97669 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -141,27 +141,25 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { } fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { + if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind // Get the hir_id of the object we are calling the method on - if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind; // Is the method to_string() ? - if path.ident.name == sym::to_string; + && path.ident.name == sym::to_string // Is the method a part of the ToString trait? (i.e. not to_string() implemented // separately) - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diag_trait_item(cx, expr_def_id, sym::ToString); + && let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && is_diag_trait_item(cx, expr_def_id, sym::ToString) // Is the method is called on self - if let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind; - if let [segment] = path.segments; - if segment.ident.name == kw::SelfLower; - then { - span_lint( - cx, - RECURSIVE_FORMAT_IMPL, - expr.span, - "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion", - ); - } + && let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind + && let [segment] = path.segments + && segment.ident.name == kw::SelfLower + { + span_lint( + cx, + RECURSIVE_FORMAT_IMPL, + expr.span, + "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion", + ); } } @@ -215,55 +213,51 @@ fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_ } fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) { - if_chain! { - if let Some(macro_call) = root_macro_call_first_node(cx, expr); - if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id); - then { - let replacement = match name { - sym::print_macro | sym::eprint_macro => "write", - sym::println_macro | sym::eprintln_macro => "writeln", - _ => return, - }; + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id) + { + let replacement = match name { + sym::print_macro | sym::eprint_macro => "write", + sym::println_macro | sym::eprintln_macro => "writeln", + _ => return, + }; - let name = name.as_str().strip_suffix("_macro").unwrap(); + let name = name.as_str().strip_suffix("_macro").unwrap(); - span_lint_and_sugg( - cx, - PRINT_IN_FORMAT_IMPL, - macro_call.span, - &format!("use of `{name}!` in `{}` impl", impl_trait.name), - "replace with", - if let Some(formatter_name) = impl_trait.formatter_name { - format!("{replacement}!({formatter_name}, ..)") - } else { - format!("{replacement}!(..)") - }, - Applicability::HasPlaceholders, - ); - } + span_lint_and_sugg( + cx, + PRINT_IN_FORMAT_IMPL, + macro_call.span, + &format!("use of `{name}!` in `{}` impl", impl_trait.name), + "replace with", + if let Some(formatter_name) = impl_trait.formatter_name { + format!("{replacement}!({formatter_name}, ..)") + } else { + format!("{replacement}!(..)") + }, + Applicability::HasPlaceholders, + ); } } fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { - if_chain! { - if impl_item.ident.name == sym::fmt; - if let ImplItemKind::Fn(_, body_id) = impl_item.kind; - if let Some(Impl { of_trait: Some(trait_ref),..}) = get_parent_as_impl(cx.tcx, impl_item.hir_id()); - if let Some(did) = trait_ref.trait_def_id(); - if let Some(name) = cx.tcx.get_diagnostic_name(did); - if matches!(name, sym::Debug | sym::Display); - then { - let body = cx.tcx.hir().body(body_id); - let formatter_name = body.params.get(1) - .and_then(|param| param.pat.simple_ident()) - .map(|ident| ident.name); + if impl_item.ident.name == sym::fmt + && let ImplItemKind::Fn(_, body_id) = impl_item.kind + && let Some(Impl { of_trait: Some(trait_ref),..}) = get_parent_as_impl(cx.tcx, impl_item.hir_id()) + && let Some(did) = trait_ref.trait_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(did) + && matches!(name, sym::Debug | sym::Display) + { + let body = cx.tcx.hir().body(body_id); + let formatter_name = body.params.get(1) + .and_then(|param| param.pat.simple_ident()) + .map(|ident| ident.name); - Some(FormatTraitNames { - name, - formatter_name, - }) - } else { - None - } + Some(FormatTraitNames { + name, + formatter_name, + }) + } else { + None } } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 10ddc3bda34..be35b850c0a 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -168,93 +168,87 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { /// Implementation of the `SUSPICIOUS_UNARY_OP_FORMATTING` lint. fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { - if_chain! { - if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind; - if !lhs.span.from_expansion() && !rhs.span.from_expansion(); + if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind + && !lhs.span.from_expansion() && !rhs.span.from_expansion() // span between BinOp LHS and RHS - let binop_span = lhs.span.between(rhs.span); + && let binop_span = lhs.span.between(rhs.span) // if RHS is an UnOp - if let ExprKind::Unary(op, ref un_rhs) = rhs.kind; + && let ExprKind::Unary(op, ref un_rhs) = rhs.kind // from UnOp operator to UnOp operand - let unop_operand_span = rhs.span.until(un_rhs.span); - if let Some(binop_snippet) = snippet_opt(cx, binop_span); - if let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span); - let binop_str = BinOpKind::to_string(&binop.node); + && let unop_operand_span = rhs.span.until(un_rhs.span) + && let Some(binop_snippet) = snippet_opt(cx, binop_span) + && let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span) + && let binop_str = BinOpKind::to_string(&binop.node) // no space after BinOp operator and space after UnOp operator - if binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' '); - then { - let unop_str = UnOp::to_string(op); - let eqop_span = lhs.span.between(un_rhs.span); - span_lint_and_help( - cx, - SUSPICIOUS_UNARY_OP_FORMATTING, - eqop_span, - &format!( - "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ - `{binop_str}{unop_str}` is a single operator" - ), - None, - &format!( - "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`" - ), - ); - } + && binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ') + { + let unop_str = UnOp::to_string(op); + let eqop_span = lhs.span.between(un_rhs.span); + span_lint_and_help( + cx, + SUSPICIOUS_UNARY_OP_FORMATTING, + eqop_span, + &format!( + "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ + `{binop_str}{unop_str}` is a single operator" + ), + None, + &format!( + "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`" + ), + ); } } /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`. fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { - if_chain! { - if let ExprKind::If(_, then, Some(else_)) = &expr.kind; - if is_block(else_) || is_if(else_); - if !then.span.from_expansion() && !else_.span.from_expansion(); - if !in_external_macro(cx.sess(), expr.span); + if let ExprKind::If(_, then, Some(else_)) = &expr.kind + && (is_block(else_) || is_if(else_)) + && !then.span.from_expansion() && !else_.span.from_expansion() + && !in_external_macro(cx.sess(), expr.span) // workaround for rust-lang/rust#43081 - if expr.span.lo().0 != 0 && expr.span.hi().0 != 0; + && expr.span.lo().0 != 0 && expr.span.hi().0 != 0 // this will be a span from the closing ‘}’ of the “then” block (excluding) to // the “if” of the “else if” block (excluding) - let else_span = then.span.between(else_.span); + && let else_span = then.span.between(else_.span) // the snippet should look like " else \n " with maybe comments anywhere // it’s bad when there is a ‘\n’ after the “else” - if let Some(else_snippet) = snippet_opt(cx, else_span); - if let Some((pre_else, post_else)) = else_snippet.split_once("else"); - if let Some((_, post_else_post_eol)) = post_else.split_once('\n'); + && let Some(else_snippet) = snippet_opt(cx, else_span) + && let Some((pre_else, post_else)) = else_snippet.split_once("else") + && let Some((_, post_else_post_eol)) = post_else.split_once('\n') - then { - // Allow allman style braces `} \n else \n {` - if_chain! { - if is_block(else_); - if let Some((_, pre_else_post_eol)) = pre_else.split_once('\n'); - // Exactly one eol before and after the else - if !pre_else_post_eol.contains('\n'); - if !post_else_post_eol.contains('\n'); - then { - return; - } - } - - // Don't warn if the only thing inside post_else_post_eol is a comment block. - let trimmed_post_else_post_eol = post_else_post_eol.trim(); - if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") { - return - } + { + // Allow allman style braces `} \n else \n {` + if is_block(else_) + && let Some((_, pre_else_post_eol)) = pre_else.split_once('\n') + // Exactly one eol before and after the else + && !pre_else_post_eol.contains('\n') + && !post_else_post_eol.contains('\n') + { + return; + } - let else_desc = if is_if(else_) { "if" } else { "{..}" }; - span_lint_and_note( - cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - &format!("this is an `else {else_desc}` but the formatting might hide it"), - None, - &format!( - "to remove this lint, remove the `else` or remove the new line between \ - `else` and `{else_desc}`", - ), - ); + // Don't warn if the only thing inside post_else_post_eol is a comment block. + let trimmed_post_else_post_eol = post_else_post_eol.trim(); + if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") { + return } + + let else_desc = if is_if(else_) { "if" } else { "{..}" }; + span_lint_and_note( + cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + &format!("this is an `else {else_desc}` but the formatting might hide it"), + None, + &format!( + "to remove this lint, remove the `else` or remove the new line between \ + `else` and `{else_desc}`", + ), + ); } } @@ -272,61 +266,57 @@ fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize { fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Array(ref array) = expr.kind { for element in array { - if_chain! { - if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span); - let space_span = lhs.span.between(op.span); - if let Some(space_snippet) = snippet_opt(cx, space_span); - let lint_span = lhs.span.with_lo(lhs.span.hi()); - if space_snippet.contains('\n'); - if indentation(cx, op.span) <= indentation(cx, lhs.span); - then { - span_lint_and_note( - cx, - POSSIBLE_MISSING_COMMA, - lint_span, - "possibly missing a comma here", - None, - "to remove this lint, add a comma or write the expr in a single line", - ); - } + if let ExprKind::Binary(ref op, ref lhs, _) = element.kind + && has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span) + && let space_span = lhs.span.between(op.span) + && let Some(space_snippet) = snippet_opt(cx, space_span) + && let lint_span = lhs.span.with_lo(lhs.span.hi()) + && space_snippet.contains('\n') + && indentation(cx, op.span) <= indentation(cx, lhs.span) + { + span_lint_and_note( + cx, + POSSIBLE_MISSING_COMMA, + lint_span, + "possibly missing a comma here", + None, + "to remove this lint, add a comma or write the expr in a single line", + ); } } } } fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { - if_chain! { - if !first.span.from_expansion() && !second.span.from_expansion(); - if matches!(first.kind, ExprKind::If(..)); - if is_block(second) || is_if(second); + if !first.span.from_expansion() && !second.span.from_expansion() + && matches!(first.kind, ExprKind::If(..)) + && (is_block(second) || is_if(second)) // Proc-macros can give weird spans. Make sure this is actually an `if`. - if is_span_if(cx, first.span); + && is_span_if(cx, first.span) // If there is a line break between the two expressions, don't lint. // If there is a non-whitespace character, this span came from a proc-macro. - let else_span = first.span.between(second.span); - if let Some(else_snippet) = snippet_opt(cx, else_span); - if !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace()); - then { - let (looks_like, next_thing) = if is_if(second) { - ("an `else if`", "the second `if`") - } else { - ("an `else {..}`", "the next block") - }; + && let else_span = first.span.between(second.span) + && let Some(else_snippet) = snippet_opt(cx, else_span) + && !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace()) + { + let (looks_like, next_thing) = if is_if(second) { + ("an `else if`", "the second `if`") + } else { + ("an `else {..}`", "the next block") + }; - span_lint_and_note( - cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - &format!("this looks like {looks_like} but the `else` is missing"), - None, - &format!( - "to remove this lint, add the missing `else` or add a new line before {next_thing}", - ), - ); - } + span_lint_and_note( + cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + &format!("this looks like {looks_like} but the `else` is missing"), + None, + &format!( + "to remove this lint, add the missing `else` or add a new line before {next_thing}", + ), + ); } } diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 74a60b6a0d2..804b6d31e61 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -46,52 +46,50 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]); impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { - if_chain! { - if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind; - if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind; + if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind + && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind // check if the first part of the path is some integer primitive - if let TyKind::Path(ty_qpath) = &ty.kind; - let ty_res = cx.qpath_res(ty_qpath, ty.hir_id); - if let def::Res::PrimTy(prim_ty) = ty_res; - if matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_)); + && let TyKind::Path(ty_qpath) = &ty.kind + && let ty_res = cx.qpath_res(ty_qpath, ty.hir_id) + && let def::Res::PrimTy(prim_ty) = ty_res + && matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_)) // check if the second part of the path indeed calls the associated // function `from_str_radix` - if pathseg.ident.name.as_str() == "from_str_radix"; + && pathseg.ident.name.as_str() == "from_str_radix" // check if the second argument is a primitive `10` - if is_integer_literal(radix, 10); + && is_integer_literal(radix, 10) - then { - let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { - let ty = cx.typeck_results().expr_ty(expr); - if is_ty_stringish(cx, ty) { - expr - } else { - &src - } + { + let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { + let ty = cx.typeck_results().expr_ty(expr); + if is_ty_stringish(cx, ty) { + expr } else { &src - }; + } + } else { + &src + }; - let sugg = Sugg::hir_with_applicability( - cx, - expr, - "", - &mut Applicability::MachineApplicable - ).maybe_par(); + let sugg = Sugg::hir_with_applicability( + cx, + expr, + "", + &mut Applicability::MachineApplicable + ).maybe_par(); - span_lint_and_sugg( - cx, - FROM_STR_RADIX_10, - exp.span, - "this call to `from_str_radix` can be replaced with a call to `str::parse`", - "try", - format!("{sugg}.parse::<{}>()", prim_ty.name_str()), - Applicability::MaybeIncorrect - ); - } + span_lint_and_sugg( + cx, + FROM_STR_RADIX_10, + exp.span, + "this call to `from_str_radix` can be replaced with a call to `str::parse`", + "try", + format!("{sugg}.parse::<{}>()", prim_ty.name_str()), + Applicability::MaybeIncorrect + ); } } } diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index ee66c841ed2..4afff8a2434 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -52,54 +52,48 @@ fn report( } pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { - if_chain! { - if let FnKind::ItemFn(ident, generics, _) = kind; - if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public(); - if !is_in_test_function(cx.tcx, hir_id); - then { - for param in generics.params { - if param.is_impl_trait() { - report(cx, param, ident, generics, body.params[0].span); - }; - } + if let FnKind::ItemFn(ident, generics, _) = kind + && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() + && !is_in_test_function(cx.tcx, hir_id) + { + for param in generics.params { + if param.is_impl_trait() { + report(cx, param, ident, generics, body.params[0].span); + }; } } } pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { - if_chain! { - if let ImplItemKind::Fn(_, body_id) = impl_item.kind; - if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id()); - if let hir::ItemKind::Impl(impl_) = item.kind; - if let hir::Impl { of_trait, .. } = *impl_; - if of_trait.is_none(); - let body = cx.tcx.hir().body(body_id); - if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public(); - if !is_in_test_function(cx.tcx, impl_item.hir_id()); - then { - for param in impl_item.generics.params { - if param.is_impl_trait() { - report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span); - } + if let ImplItemKind::Fn(_, body_id) = impl_item.kind + && let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id()) + && let hir::ItemKind::Impl(impl_) = item.kind + && let hir::Impl { of_trait, .. } = *impl_ + && of_trait.is_none() + && let body = cx.tcx.hir().body(body_id) + && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() + && !is_in_test_function(cx.tcx, impl_item.hir_id()) + { + for param in impl_item.generics.params { + if param.is_impl_trait() { + report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span); } } } } pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) { - if_chain! { - if !avoid_breaking_exported_api; - if let TraitItemKind::Fn(_, _) = trait_item.kind; - if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id()); + if !avoid_breaking_exported_api + && let TraitItemKind::Fn(_, _) = trait_item.kind + && let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id()) // ^^ (Will always be a trait) - if !item.vis_span.is_empty(); // Is public - if !is_in_test_function(cx.tcx, trait_item.hir_id()); - then { - for param in trait_item.generics.params { - if param.is_impl_trait() { - let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1)); - report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi()); - } + && !item.vis_span.is_empty() // Is public + && !is_in_test_function(cx.tcx, trait_item.hir_id()) + { + for param in trait_item.generics.params { + if param.is_impl_trait() { + let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1)); + report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi()); } } } diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index 18f7368dafb..77718893300 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -43,15 +43,13 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: // Body must be &(mut) .name // self_data is not necessarily self, to also lint sub-getters, etc… - let block_expr = if_chain! { - if let ExprKind::Block(block,_) = body.value.kind; - if block.stmts.is_empty(); - if let Some(block_expr) = block.expr; - then { - block_expr - } else { - return; - } + let block_expr = if let ExprKind::Block(block,_) = body.value.kind + && block.stmts.is_empty() + && let Some(block_expr) = block.expr + { + block_expr + } else { + return; }; let expr_span = block_expr.span; @@ -61,14 +59,12 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: } else { block_expr }; - let (self_data, used_ident) = if_chain! { - if let ExprKind::Field(self_data, ident) = expr.kind; - if ident.name.as_str() != name; - then { - (self_data, ident) - } else { - return; - } + let (self_data, used_ident) = if let ExprKind::Field(self_data, ident) = expr.kind + && ident.name.as_str() != name + { + (self_data, ident) + } else { + return; }; let mut used_field = None; diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 485235514de..aab9cce1e00 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -86,59 +86,57 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S } fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { - if_chain! { - if let Adt(adt, subst) = err_ty.kind(); - if let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local(); - if let Some(hir::Node::Item(item)) = cx + if let Adt(adt, subst) = err_ty.kind() + && let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local() + && let Some(hir::Node::Item(item)) = cx .tcx .hir() - .find_by_def_id(local_def_id); - if let hir::ItemKind::Enum(ref def, _) = item.kind; - then { - let variants_size = AdtVariantInfo::new(cx, *adt, subst); - if let Some((first_variant, variants)) = variants_size.split_first() - && first_variant.size >= large_err_threshold - { - span_lint_and_then( - cx, - RESULT_LARGE_ERR, - hir_ty_span, - "the `Err`-variant returned from this function is very large", - |diag| { - diag.span_label( - def.variants[first_variant.ind].span, - format!("the largest variant contains at least {} bytes", variants_size[0].size), - ); + .find_by_def_id(local_def_id) + && let hir::ItemKind::Enum(ref def, _) = item.kind + { + let variants_size = AdtVariantInfo::new(cx, *adt, subst); + if let Some((first_variant, variants)) = variants_size.split_first() + && first_variant.size >= large_err_threshold + { + span_lint_and_then( + cx, + RESULT_LARGE_ERR, + hir_ty_span, + "the `Err`-variant returned from this function is very large", + |diag| { + diag.span_label( + def.variants[first_variant.ind].span, + format!("the largest variant contains at least {} bytes", variants_size[0].size), + ); - for variant in variants { - if variant.size >= large_err_threshold { - let variant_def = &def.variants[variant.ind]; - diag.span_label( - variant_def.span, - format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size), - ); - } + for variant in variants { + if variant.size >= large_err_threshold { + let variant_def = &def.variants[variant.ind]; + diag.span_label( + variant_def.span, + format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size), + ); } - - diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); } - ); - } + + diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); + } + ); } - else { - let ty_size = approx_ty_size(cx, err_ty); - if ty_size >= large_err_threshold { - span_lint_and_then( - cx, - RESULT_LARGE_ERR, - hir_ty_span, - "the `Err`-variant returned from this function is very large", - |diag: &mut Diagnostic| { - diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); - diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); - }, - ); - } + } + else { + let ty_size = approx_ty_size(cx, err_ty); + if ty_size >= large_err_threshold { + span_lint_and_then( + cx, + RESULT_LARGE_ERR, + hir_ty_span, + "the `Err`-variant returned from this function is very large", + |diag: &mut Diagnostic| { + diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); + diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); + }, + ); } } } diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index e614a8f694f..7f111925657 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -127,15 +127,13 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { } fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if_chain! { - if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; - if path.ident.as_str() == "lock"; - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if is_type_diagnostic_item(cx, ty, sym::Mutex); - then { - Some(self_arg) - } else { - None - } + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind + && path.ident.as_str() == "lock" + && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() + && is_type_diagnostic_item(cx, ty, sym::Mutex) + { + Some(self_arg) + } else { + None } } diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index a1fcce18ff6..16af49a092a 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -337,42 +337,40 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't } fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(fun, args) = e.kind; - if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind; - if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; - if let Some(ty_did) = ty_path.res.opt_def_id(); - then { - if self.target.ty() != self.maybe_typeck_results.unwrap().expr_ty(e) { - return; - } + if let ExprKind::Call(fun, args) = e.kind + && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind + && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind + && let Some(ty_did) = ty_path.res.opt_def_id() + { + if self.target.ty() != self.maybe_typeck_results.unwrap().expr_ty(e) { + return; + } - if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { - if method.ident.name == sym::new { - self.suggestions - .insert(e.span, "HashMap::default()".to_string()); - } else if method.ident.name == sym!(with_capacity) { - self.suggestions.insert( - e.span, - format!( - "HashMap::with_capacity_and_hasher({}, Default::default())", - snippet(self.cx, args[0].span, "capacity"), - ), - ); - } - } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { - if method.ident.name == sym::new { - self.suggestions - .insert(e.span, "HashSet::default()".to_string()); - } else if method.ident.name == sym!(with_capacity) { - self.suggestions.insert( - e.span, - format!( - "HashSet::with_capacity_and_hasher({}, Default::default())", - snippet(self.cx, args[0].span, "capacity"), - ), - ); - } + if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { + if method.ident.name == sym::new { + self.suggestions + .insert(e.span, "HashMap::default()".to_string()); + } else if method.ident.name == sym!(with_capacity) { + self.suggestions.insert( + e.span, + format!( + "HashMap::with_capacity_and_hasher({}, Default::default())", + snippet(self.cx, args[0].span, "capacity"), + ), + ); + } + } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { + if method.ident.name == sym::new { + self.suggestions + .insert(e.span, "HashSet::default()".to_string()); + } else if method.ident.name == sym!(with_capacity) { + self.suggestions.insert( + e.span, + format!( + "HashSet::with_capacity_and_hasher({}, Default::default())", + snippet(self.cx, args[0].span, "capacity"), + ), + ); } } } diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index 24f62490f96..af21d261644 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -40,42 +40,40 @@ declare_lint_pass!(ImplicitSaturatingAdd => [IMPLICIT_SATURATING_ADD]); impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::If(cond, then, None) = expr.kind; - if let ExprKind::DropTemps(expr1) = cond.kind; - if let Some((c, op_node, l)) = get_const(cx, expr1); - if let BinOpKind::Ne | BinOpKind::Lt = op_node; - if let ExprKind::Block(block, None) = then.kind; - if let Block { + if let ExprKind::If(cond, then, None) = expr.kind + && let ExprKind::DropTemps(expr1) = cond.kind + && let Some((c, op_node, l)) = get_const(cx, expr1) + && let BinOpKind::Ne | BinOpKind::Lt = op_node + && let ExprKind::Block(block, None) = then.kind + && let Block { stmts: [Stmt { kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }], expr: None, ..} | - Block { stmts: [], expr: Some(ex), ..} = block; - if let ExprKind::AssignOp(op1, target, value) = ex.kind; - let ty = cx.typeck_results().expr_ty(target); - if Some(c) == get_int_max(ty); - let ctxt = expr.span.ctxt(); - if ex.span.ctxt() == ctxt; - if expr1.span.ctxt() == ctxt; - if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target); - if BinOpKind::Add == op1.node; - if let ExprKind::Lit(lit) = value.kind; - if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node; - if block.expr.is_none(); - then { - let mut app = Applicability::MachineApplicable; - let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0; - let sugg = if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind - && else_.hir_id == expr.hir_id - { - format!("{{{code} = {code}.saturating_add(1); }}") - } else { - format!("{code} = {code}.saturating_add(1);") - }; - span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app); - } + Block { stmts: [], expr: Some(ex), ..} = block + && let ExprKind::AssignOp(op1, target, value) = ex.kind + && let ty = cx.typeck_results().expr_ty(target) + && Some(c) == get_int_max(ty) + && let ctxt = expr.span.ctxt() + && ex.span.ctxt() == ctxt + && expr1.span.ctxt() == ctxt + && clippy_utils::SpanlessEq::new(cx).eq_expr(l, target) + && BinOpKind::Add == op1.node + && let ExprKind::Lit(lit) = value.kind + && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node + && block.expr.is_none() + { + let mut app = Applicability::MachineApplicable; + let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0; + let sugg = if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind + && else_.hir_id == expr.hir_id + { + format!("{{{code} = {code}.saturating_add(1); }}") + } else { + format!("{code} = {code}.saturating_add(1);") + }; + span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app); } } } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 859404289d9..3a45c68c255 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -46,83 +46,77 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if expr.span.from_expansion() { return; } - if_chain! { - if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr); + if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr) // Check if the conditional expression is a binary operation - if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind; + && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind // Ensure that the binary operator is >, !=, or < - if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node; + && (BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node) // Check if assign operation is done - if let Some(target) = subtracts_one(cx, then); + && let Some(target) = subtracts_one(cx, then) // Extracting out the variable name - if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind; + && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind - then { - // Handle symmetric conditions in the if statement - let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { - if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_left, cond_right) - } else { - return; - } - } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { - if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_right, cond_left) - } else { - return; - } + { + // Handle symmetric conditions in the if statement + let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { + if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node { + (cond_left, cond_right) } else { return; - }; - - // Check if the variable in the condition statement is an integer - if !cx.typeck_results().expr_ty(cond_var).is_integral() { + } + } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { + if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node { + (cond_right, cond_left) + } else { return; } + } else { + return; + }; - // Get the variable name - let var_name = ares_path.segments[0].ident.name.as_str(); - match cond_num_val.kind { - ExprKind::Lit(cond_lit) => { - // Check if the constant is zero - if let LitKind::Int(0, _) = cond_lit.node { - if cx.typeck_results().expr_ty(cond_left).is_signed() { - } else { - print_lint_and_sugg(cx, var_name, expr); - }; - } - }, - ExprKind::Path(QPath::TypeRelative(_, name)) => { - if_chain! { - if name.ident.as_str() == "MIN"; - if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(const_id); - if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl - if cx.tcx.type_of(impl_id).instantiate_identity().is_integral(); - then { - print_lint_and_sugg(cx, var_name, expr) - } - } - }, - ExprKind::Call(func, []) => { - if_chain! { - if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind; - if name.ident.as_str() == "min_value"; - if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(func_id); - if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl - if cx.tcx.type_of(impl_id).instantiate_identity().is_integral(); - then { - print_lint_and_sugg(cx, var_name, expr) - } - } - }, - _ => (), - } + // Check if the variable in the condition statement is an integer + if !cx.typeck_results().expr_ty(cond_var).is_integral() { + return; + } + + // Get the variable name + let var_name = ares_path.segments[0].ident.name.as_str(); + match cond_num_val.kind { + ExprKind::Lit(cond_lit) => { + // Check if the constant is zero + if let LitKind::Int(0, _) = cond_lit.node { + if cx.typeck_results().expr_ty(cond_left).is_signed() { + } else { + print_lint_and_sugg(cx, var_name, expr); + }; + } + }, + ExprKind::Path(QPath::TypeRelative(_, name)) => { + if name.ident.as_str() == "MIN" + && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(const_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr) + } + }, + ExprKind::Call(func, []) => { + if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind + && name.ident.as_str() == "min_value" + && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(func_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr) + } + }, + _ => (), } } } @@ -135,18 +129,16 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp (BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target) }, ExprKind::Assign(target, value, _) => { - if_chain! { - if let ExprKind::Binary(ref op1, left1, right1) = value.kind; - if BinOpKind::Sub == op1.node; + if let ExprKind::Binary(ref op1, left1, right1) = value.kind + && BinOpKind::Sub == op1.node - if SpanlessEq::new(cx).eq_expr(left1, target); + && SpanlessEq::new(cx).eq_expr(left1, target) - if is_integer_literal(right1, 1); - then { - Some(target) - } else { - None - } + && is_integer_literal(right1, 1) + { + Some(target) + } else { + None } }, _ => None, diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index a84f7351ad6..14842800b57 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -66,54 +66,52 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if !expr.span.from_expansion(); - if let ExprKind::Struct(qpath, fields, base) = expr.kind; - let ty = cx.typeck_results().expr_ty(expr); - if let Some(adt_def) = ty.ty_adt_def(); - if adt_def.is_struct(); - if let Some(variant) = adt_def.variants().iter().next(); - if fields.iter().all(|f| f.is_shorthand); - then { - let mut def_order_map = FxHashMap::default(); - for (idx, field) in variant.fields.iter().enumerate() { - def_order_map.insert(field.name, idx); - } + if !expr.span.from_expansion() + && let ExprKind::Struct(qpath, fields, base) = expr.kind + && let ty = cx.typeck_results().expr_ty(expr) + && let Some(adt_def) = ty.ty_adt_def() + && adt_def.is_struct() + && let Some(variant) = adt_def.variants().iter().next() + && fields.iter().all(|f| f.is_shorthand) + { + let mut def_order_map = FxHashMap::default(); + for (idx, field) in variant.fields.iter().enumerate() { + def_order_map.insert(field.name, idx); + } - if is_consistent_order(fields, &def_order_map) { - return; - } + if is_consistent_order(fields, &def_order_map) { + return; + } - let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect(); - ordered_fields.sort_unstable_by_key(|id| def_order_map[id]); + let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect(); + ordered_fields.sort_unstable_by_key(|id| def_order_map[id]); - let mut fields_snippet = String::new(); - let (last_ident, idents) = ordered_fields.split_last().unwrap(); - for ident in idents { - let _: fmt::Result = write!(fields_snippet, "{ident}, "); - } - fields_snippet.push_str(&last_ident.to_string()); + let mut fields_snippet = String::new(); + let (last_ident, idents) = ordered_fields.split_last().unwrap(); + for ident in idents { + let _: fmt::Result = write!(fields_snippet, "{ident}, "); + } + fields_snippet.push_str(&last_ident.to_string()); - let base_snippet = if let Some(base) = base { - format!(", ..{}", snippet(cx, base.span, "..")) - } else { - String::new() - }; + let base_snippet = if let Some(base) = base { + format!(", ..{}", snippet(cx, base.span, "..")) + } else { + String::new() + }; - let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}", - snippet(cx, qpath.span(), ".."), - ); + let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}", + snippet(cx, qpath.span(), ".."), + ); - span_lint_and_sugg( - cx, - INCONSISTENT_STRUCT_CONSTRUCTOR, - expr.span, - "struct constructor field order is inconsistent with struct definition field order", - "try", - sugg, - Applicability::MachineApplicable, - ) - } + span_lint_and_sugg( + cx, + INCONSISTENT_STRUCT_CONSTRUCTOR, + expr.span, + "struct constructor field order is inconsistent with struct definition field order", + "try", + sugg, + Applicability::MachineApplicable, + ) } } } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index c2f1f18e39d..5b831af3045 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -70,20 +70,18 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); - if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr); - if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id); - if self.msrv.meets(msrvs::SLICE_PATTERNS); + if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) + && let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr) + && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) + && self.msrv.meets(msrvs::SLICE_PATTERNS) - let found_slices = find_slice_values(cx, let_pat); - if !found_slices.is_empty(); - let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then); - if !filtered_slices.is_empty(); - then { - for slice in filtered_slices.values() { - lint_slice(cx, slice); - } + && let found_slices = find_slice_values(cx, let_pat) + && !found_slices.is_empty() + && let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then) + && !filtered_slices.is_empty() + { + for slice in filtered_slices.values() { + lint_slice(cx, slice); } } } @@ -245,28 +243,26 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { max_suggested_slice, } = *self; - if_chain! { + if let Some(use_info) = slice_lint_info.get_mut(&local_id) // Check if this is even a local we're interested in - if let Some(use_info) = slice_lint_info.get_mut(&local_id); - let map = cx.tcx.hir(); + && let map = cx.tcx.hir() // Checking for slice indexing - let parent_id = map.parent_id(expr.hir_id); - if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); - if let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind; - if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr); - if let Ok(index_value) = index_value.try_into(); - if index_value < max_suggested_slice; + && let parent_id = map.parent_id(expr.hir_id) + && let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id) + && let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind + && let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr) + && let Ok(index_value) = index_value.try_into() + && index_value < max_suggested_slice // Make sure that this slice index is read only - let maybe_addrof_id = map.parent_id(parent_id); - if let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id); - if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind; - then { - use_info.index_use.push((index_value, map.span(parent_expr.hir_id))); - return; - } + && let maybe_addrof_id = map.parent_id(parent_id) + && let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id) + && let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind + { + use_info.index_use.push((index_value, map.span(parent_expr.hir_id))); + return; } // The slice was used for something other than indexing diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 32b2cb4385f..d8966dddeac 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -89,26 +89,22 @@ impl LateLintPass<'_> for InstantSubtraction { rhs, ) = expr.kind { - if_chain! { - if is_instant_now_call(cx, lhs); - - if is_an_instant(cx, rhs); - if let Some(sugg) = Sugg::hir_opt(cx, rhs); - - then { - print_manual_instant_elapsed_sugg(cx, expr, sugg) - } else { - if_chain! { - if !expr.span.from_expansion(); - if self.msrv.meets(msrvs::TRY_FROM); - - if is_an_instant(cx, lhs); - if is_a_duration(cx, rhs); - - then { - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr) - } - } + if is_instant_now_call(cx, lhs) + + && is_an_instant(cx, rhs) + && let Some(sugg) = Sugg::hir_opt(cx, rhs) + + { + print_manual_instant_elapsed_sugg(cx, expr, sugg) + } else { + if !expr.span.from_expansion() + && self.msrv.meets(msrvs::TRY_FROM) + + && is_an_instant(cx, lhs) + && is_a_duration(cx, rhs) + + { + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr) } } } diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index a4f3d498345..385945045bc 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -47,43 +47,41 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if_chain! { - if !item.span.from_expansion(); - if let ItemKind::Const(_, generics, _) = &item.kind; + if !item.span.from_expansion() + && let ItemKind::Const(_, generics, _) = &item.kind // Since static items may not have generics, skip generic const items. // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it // doesn't account for empty where-clauses that only consist of keyword `where` IINM. - if generics.params.is_empty() && !generics.has_where_clause_predicates; - let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); - if let ty::Array(element_type, cst) = ty.kind(); - if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); - if let Ok(element_count) = element_count.try_to_target_usize(cx.tcx); - if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); - if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size); + && generics.params.is_empty() && !generics.has_where_clause_predicates + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let ty::Array(element_type, cst) = ty.kind() + && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() + && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) + && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) - then { - let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); - let sugg_span = Span::new( - hi_pos - BytePos::from_usize("const".len()), - hi_pos, - item.span.ctxt(), - item.span.parent(), - ); - span_lint_and_then( - cx, - LARGE_CONST_ARRAYS, - item.span, - "large array defined as const", - |diag| { - diag.span_suggestion( - sugg_span, - "make this a static item", - "static", - Applicability::MachineApplicable, - ); - } - ); - } + { + let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); + let sugg_span = Span::new( + hi_pos - BytePos::from_usize("const".len()), + hi_pos, + item.span.ctxt(), + item.span.parent(), + ); + span_lint_and_then( + cx, + LARGE_CONST_ARRAYS, + item.span, + "large array defined as const", + |diag| { + diag.span_suggestion( + sugg_span, + "make this a static item", + "static", + Applicability::MachineApplicable, + ); + } + ); } } } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 566901de347..f998a00edee 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -50,37 +50,35 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]); impl LateLintPass<'_> for LargeIncludeFile { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if_chain! { - if let Some(macro_call) = root_macro_call_first_node(cx, expr); - if !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id); - if cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) - || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id); - if let ExprKind::Lit(lit) = &expr.kind; - then { - let len = match &lit.node { - // include_bytes - LitKind::ByteStr(bstr, _) => bstr.len(), - // include_str - LitKind::Str(sym, _) => sym.as_str().len(), - _ => return, - }; + if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id) + && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) + || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) + && let ExprKind::Lit(lit) = &expr.kind + { + let len = match &lit.node { + // include_bytes + LitKind::ByteStr(bstr, _) => bstr.len(), + // include_str + LitKind::Str(sym, _) => sym.as_str().len(), + _ => return, + }; - if len as u64 <= self.max_file_size { - return; - } - - span_lint_and_note( - cx, - LARGE_INCLUDE_FILE, - expr.span, - "attempted to include a large file", - None, - &format!( - "the configuration allows a maximum size of {} bytes", - self.max_file_size - ), - ); + if len as u64 <= self.max_file_size { + return; } + + span_lint_and_note( + cx, + LARGE_INCLUDE_FILE, + expr.span, + "attempted to include a large file", + None, + &format!( + "the configuration allows a maximum size of {} bytes", + self.max_file_size + ), + ); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 08f095859e5..6d9cec5e957 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -131,37 +131,35 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if_chain! { - if item.ident.name == sym::len; - if let ImplItemKind::Fn(sig, _) = &item.kind; - if sig.decl.implicit_self.has_implicit_self(); - if sig.decl.inputs.len() == 1; - if cx.effective_visibilities.is_exported(item.owner_id.def_id); - if matches!(sig.decl.output, FnRetTy::Return(_)); - if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()); - if imp.of_trait.is_none(); - if let TyKind::Path(ty_path) = &imp.self_ty.kind; - if let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id(); - if let Some(local_id) = ty_id.as_local(); - let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id); - if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id); - if let Some(output) = parse_len_output( + if item.ident.name == sym::len + && let ImplItemKind::Fn(sig, _) = &item.kind + && sig.decl.implicit_self.has_implicit_self() + && sig.decl.inputs.len() == 1 + && cx.effective_visibilities.is_exported(item.owner_id.def_id) + && matches!(sig.decl.output, FnRetTy::Return(_)) + && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) + && imp.of_trait.is_none() + && let TyKind::Path(ty_path) = &imp.self_ty.kind + && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() + && let Some(local_id) = ty_id.as_local() + && let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id) + && !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id) + && let Some(output) = parse_len_output( cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder() - ); - then { - let (name, kind) = match cx.tcx.hir().find(ty_hir_id) { - Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"), - Some(Node::Item(x)) => match x.kind { - ItemKind::Struct(..) => (x.ident.name, "struct"), - ItemKind::Enum(..) => (x.ident.name, "enum"), - ItemKind::Union(..) => (x.ident.name, "union"), - _ => (x.ident.name, "type"), - } - _ => return, - }; - check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind) - } + ) + { + let (name, kind) = match cx.tcx.hir().find(ty_hir_id) { + Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"), + Some(Node::Item(x)) => match x.kind { + ItemKind::Struct(..) => (x.ident.name, "struct"), + ItemKind::Enum(..) => (x.ident.name, "enum"), + ItemKind::Union(..) => (x.ident.name, "union"), + _ => (x.ident.name, "type"), + } + _ => return, + }; + check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind) } } diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 2f6f36c3960..49c25e3dd9a 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -61,76 +61,74 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { let mut it = block.stmts.iter().peekable(); while let Some(stmt) = it.next() { - if_chain! { - if let Some(expr) = it.peek(); - if let hir::StmtKind::Local(local) = stmt.kind; - if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; - if let hir::StmtKind::Expr(if_) = expr.kind; - if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind; - if !is_local_used(cx, *cond, canonical_id); - if let hir::ExprKind::Block(then, _) = then.kind; - if let Some(value) = check_assign(cx, canonical_id, then); - if !is_local_used(cx, value, canonical_id); - then { - let span = stmt.span.to(if_.span); + if let Some(expr) = it.peek() + && let hir::StmtKind::Local(local) = stmt.kind + && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind + && let hir::StmtKind::Expr(if_) = expr.kind + && let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind + && !is_local_used(cx, *cond, canonical_id) + && let hir::ExprKind::Block(then, _) = then.kind + && let Some(value) = check_assign(cx, canonical_id, then) + && !is_local_used(cx, value, canonical_id) + { + let span = stmt.span.to(if_.span); - let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze( - cx.tcx, - cx.param_env, - ); - if has_interior_mutability { return; } + let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze( + cx.tcx, + cx.param_env, + ); + if has_interior_mutability { return; } - let (default_multi_stmts, default) = if let Some(else_) = else_ { - if let hir::ExprKind::Block(else_, _) = else_.kind { - if let Some(default) = check_assign(cx, canonical_id, else_) { - (else_.stmts.len() > 1, default) - } else if let Some(default) = local.init { - (true, default) - } else { - continue; - } + let (default_multi_stmts, default) = if let Some(else_) = else_ { + if let hir::ExprKind::Block(else_, _) = else_.kind { + if let Some(default) = check_assign(cx, canonical_id, else_) { + (else_.stmts.len() > 1, default) + } else if let Some(default) = local.init { + (true, default) } else { continue; } - } else if let Some(default) = local.init { - (false, default) } else { continue; - }; + } + } else if let Some(default) = local.init { + (false, default) + } else { + continue; + }; - let mutability = match mode { - BindingAnnotation(_, Mutability::Mut) => " ", - _ => "", - }; + let mutability = match mode { + BindingAnnotation(_, Mutability::Mut) => " ", + _ => "", + }; - // FIXME: this should not suggest `mut` if we can detect that the variable is not - // use mutably after the `if` + // FIXME: this should not suggest `mut` if we can detect that the variable is not + // use mutably after the `if` - let sug = format!( - "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", - name=ident.name, - cond=snippet(cx, cond.span, "_"), - then=if then.stmts.len() > 1 { " ..;" } else { "" }, - else=if default_multi_stmts { " ..;" } else { "" }, - value=snippet(cx, value.span, ""), - default=snippet(cx, default.span, ""), - ); - span_lint_and_then(cx, - USELESS_LET_IF_SEQ, - span, - "`if _ { .. } else { .. }` is an expression", - |diag| { - diag.span_suggestion( - span, - "it is more idiomatic to write", - sug, - Applicability::HasPlaceholders, - ); - if !mutability.is_empty() { - diag.note("you might not need `mut` at all"); - } - }); - } + let sug = format!( + "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", + name=ident.name, + cond=snippet(cx, cond.span, "_"), + then=if then.stmts.len() > 1 { " ..;" } else { "" }, + else=if default_multi_stmts { " ..;" } else { "" }, + value=snippet(cx, value.span, ""), + default=snippet(cx, default.span, ""), + ); + span_lint_and_then(cx, + USELESS_LET_IF_SEQ, + span, + "`if _ { .. } else { .. }` is an expression", + |diag| { + diag.span_suggestion( + span, + "it is more idiomatic to write", + sug, + Applicability::HasPlaceholders, + ); + if !mutability.is_empty() { + diag.note("you might not need `mut` at all"); + } + }); } } } @@ -141,20 +139,18 @@ fn check_assign<'tcx>( decl: hir::HirId, block: &'tcx hir::Block<'_>, ) -> Option<&'tcx hir::Expr<'tcx>> { - if_chain! { - if block.expr.is_none(); - if let Some(expr) = block.stmts.iter().last(); - if let hir::StmtKind::Semi(expr) = expr.kind; - if let hir::ExprKind::Assign(var, value, _) = expr.kind; - if path_to_local_id(var, decl); - then { - if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| is_local_used(cx, stmt, decl)) { - None - } else { - Some(value) - } - } else { + if block.expr.is_none() + && let Some(expr) = block.stmts.iter().last() + && let hir::StmtKind::Semi(expr) = expr.kind + && let hir::ExprKind::Assign(var, value, _) = expr.kind + && path_to_local_id(var, decl) + { + if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| is_local_used(cx, stmt, decl)) { None + } else { + Some(value) } + } else { + None } } diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 79d728a021c..e7b887d800b 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -27,27 +27,25 @@ declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); impl LateLintPass<'_> for UnderscoreTyped { fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { - if_chain! { - if !in_external_macro(cx.tcx.sess, local.span); - if let Some(ty) = local.ty; // Ensure that it has a type defined - if let TyKind::Infer = &ty.kind; // that type is '_' - if local.span.eq_ctxt(ty.span); - then { - // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, - // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` - if snippet(cx, ty.span, "_").trim() != "_" { - return; - } - - span_lint_and_help( - cx, - LET_WITH_TYPE_UNDERSCORE, - local.span, - "variable declared with type underscore", - Some(ty.span.with_lo(local.pat.span.hi())), - "remove the explicit type `_` declaration" - ) + if !in_external_macro(cx.tcx.sess, local.span) + && let Some(ty) = local.ty // Ensure that it has a type defined + && let TyKind::Infer = &ty.kind // that type is '_' + && local.span.eq_ctxt(ty.span) + { + // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, + // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` + if snippet(cx, ty.span, "_").trim() != "_" { + return; } + + span_lint_and_help( + cx, + LET_WITH_TYPE_UNDERSCORE, + local.span, + "variable declared with type underscore", + Some(ty.span.with_lo(local.pat.span.hi())), + "remove the explicit type `_` declaration" + ) }; } } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 4b89c0fa361..05cc9ac035f 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -310,20 +310,18 @@ fn elision_suggestions( // elision doesn't work for explicit self types, see rust-lang/rust#69064 fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { - if_chain! { - if let Some(ident) = ident; - if ident.name == kw::SelfLower; - if !func.implicit_self.has_implicit_self(); + if let Some(ident) = ident + && ident.name == kw::SelfLower + && !func.implicit_self.has_implicit_self() - if let Some(self_ty) = func.inputs.first(); - then { - let mut visitor = RefVisitor::new(cx); - visitor.visit_ty(self_ty); + && let Some(self_ty) = func.inputs.first() + { + let mut visitor = RefVisitor::new(cx); + visitor.visit_ty(self_ty); - !visitor.all_lts().is_empty() - } else { - false - } + !visitor.all_lts().is_empty() + } else { + false } } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 2c14bb72a9e..1e67183f13a 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -255,56 +255,54 @@ impl LiteralDigitGrouping { } fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { - if_chain! { - if let Some(src) = snippet_opt(cx, span); - if let Ok(lit_kind) = LitKind::from_token_lit(lit); - if let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind); - then { - if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) { - return; - } + if let Some(src) = snippet_opt(cx, span) + && let Ok(lit_kind) = LitKind::from_token_lit(lit) + && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) + { + if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) { + return; + } + + if Self::is_literal_uuid_formatted(&num_lit) { + return; + } - if Self::is_literal_uuid_formatted(&num_lit) { - return; + let result = (|| { + + let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?; + if let Some(fraction) = num_lit.fraction { + let fractional_group_size = Self::get_group_size( + fraction.rsplit('_'), + num_lit.radix, + self.lint_fraction_readability)?; + + let consistent = Self::parts_consistent(integral_group_size, + fractional_group_size, + num_lit.integer.len(), + fraction.len()); + if !consistent { + return Err(WarningType::InconsistentDigitGrouping); + }; } - let result = (|| { - - let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?; - if let Some(fraction) = num_lit.fraction { - let fractional_group_size = Self::get_group_size( - fraction.rsplit('_'), - num_lit.radix, - self.lint_fraction_readability)?; - - let consistent = Self::parts_consistent(integral_group_size, - fractional_group_size, - num_lit.integer.len(), - fraction.len()); - if !consistent { - return Err(WarningType::InconsistentDigitGrouping); - }; - } + Ok(()) + })(); - Ok(()) - })(); - - - if let Err(warning_type) = result { - let should_warn = match warning_type { - | WarningType::UnreadableLiteral - | WarningType::InconsistentDigitGrouping - | WarningType::UnusualByteGroupings - | WarningType::LargeDigitGroups => { - !span.from_expansion() - } - WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => { - true - } - }; - if should_warn { - warning_type.display(num_lit.format(), cx, span); + + if let Err(warning_type) = result { + let should_warn = match warning_type { + | WarningType::UnreadableLiteral + | WarningType::InconsistentDigitGrouping + | WarningType::UnusualByteGroupings + | WarningType::LargeDigitGroups => { + !span.from_expansion() + } + WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => { + true } + }; + if should_warn { + warning_type.display(num_lit.format(), cx, span); } } } @@ -478,20 +476,18 @@ impl DecimalLiteralRepresentation { } fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { // Lint integral literals. - if_chain! { - if let Ok(lit_kind) = LitKind::from_token_lit(lit); - if let LitKind::Int(val, _) = lit_kind; - if let Some(src) = snippet_opt(cx, span); - if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind); - if num_lit.radix == Radix::Decimal; - if val >= u128::from(self.threshold); - then { - let hex = format!("{val:#X}"); - let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); - let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| { - warning_type.display(num_lit.format(), cx, span); - }); - } + if let Ok(lit_kind) = LitKind::from_token_lit(lit) + && let LitKind::Int(val, _) = lit_kind + && let Some(src) = snippet_opt(cx, span) + && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) + && num_lit.radix == Radix::Decimal + && val >= u128::from(self.threshold) + { + let hex = format!("{val:#X}"); + let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); + let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| { + warning_type.display(num_lit.format(), cx, span); + }); } } diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 1953ee8a717..f49508cf97d 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -30,59 +30,57 @@ pub(super) fn check<'tcx>( let mut initialize_visitor = InitializeVisitor::new(cx, expr, id); walk_block(&mut initialize_visitor, block); - if_chain! { - if let Some((name, ty, initializer)) = initialize_visitor.get_result(); - if is_integer_const(cx, initializer, 0); - then { - let mut applicability = Applicability::MaybeIncorrect; - let span = expr.span.with_hi(arg.span.hi()); + if let Some((name, ty, initializer)) = initialize_visitor.get_result() + && is_integer_const(cx, initializer, 0) + { + let mut applicability = Applicability::MaybeIncorrect; + let span = expr.span.with_hi(arg.span.hi()); - let int_name = match ty.map(Ty::kind) { - // usize or inferred - Some(ty::Uint(UintTy::Usize)) | None => { - span_lint_and_sugg( - cx, - EXPLICIT_COUNTER_LOOP, - span, - &format!("the variable `{name}` is used as a loop counter"), - "consider using", - format!( - "for ({name}, {}) in {}.enumerate()", - snippet_with_applicability(cx, pat.span, "item", &mut applicability), - make_iterator_snippet(cx, arg, &mut applicability), - ), - applicability, - ); - return; - } - Some(ty::Int(int_ty)) => int_ty.name_str(), - Some(ty::Uint(uint_ty)) => uint_ty.name_str(), - _ => return, - }; + let int_name = match ty.map(Ty::kind) { + // usize or inferred + Some(ty::Uint(UintTy::Usize)) | None => { + span_lint_and_sugg( + cx, + EXPLICIT_COUNTER_LOOP, + span, + &format!("the variable `{name}` is used as a loop counter"), + "consider using", + format!( + "for ({name}, {}) in {}.enumerate()", + snippet_with_applicability(cx, pat.span, "item", &mut applicability), + make_iterator_snippet(cx, arg, &mut applicability), + ), + applicability, + ); + return; + } + Some(ty::Int(int_ty)) => int_ty.name_str(), + Some(ty::Uint(uint_ty)) => uint_ty.name_str(), + _ => return, + }; - span_lint_and_then( - cx, - EXPLICIT_COUNTER_LOOP, - span, - &format!("the variable `{name}` is used as a loop counter"), - |diag| { - diag.span_suggestion( - span, - "consider using", - format!( - "for ({name}, {}) in (0_{int_name}..).zip({})", - snippet_with_applicability(cx, pat.span, "item", &mut applicability), - make_iterator_snippet(cx, arg, &mut applicability), - ), - applicability, - ); + span_lint_and_then( + cx, + EXPLICIT_COUNTER_LOOP, + span, + &format!("the variable `{name}` is used as a loop counter"), + |diag| { + diag.span_suggestion( + span, + "consider using", + format!( + "for ({name}, {}) in (0_{int_name}..).zip({})", + snippet_with_applicability(cx, pat.span, "item", &mut applicability), + make_iterator_snippet(cx, arg, &mut applicability), + ), + applicability, + ); - diag.note(format!( - "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" - )); - }, - ); - } + diag.note(format!( + "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" + )); + }, + ); } } } diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index 0aaa66e6bce..2b49e188e3c 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -23,77 +23,75 @@ pub(super) fn check<'tcx>( let inner_expr = peel_blocks_with_stmt(body); // Check for the specific case that the result is returned and optimize suggestion for that (more // cases can be added later) - if_chain! { - if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr); - if let Some(binding_id) = get_binding(pat); - if let ExprKind::Block(block, _) = then.kind; - if let [stmt] = block.stmts; - if let StmtKind::Semi(semi) = stmt.kind; - if let ExprKind::Ret(Some(ret_value)) = semi.kind; - if let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind; - if is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome); - if path_res(cx, inner_ret) == Res::Local(binding_id); - if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr); - then { - let mut applicability = Applicability::MachineApplicable; - let mut snippet = make_iterator_snippet(cx, arg, &mut applicability); - // Checks if `pat` is a single reference to a binding (`&x`) - let is_ref_to_binding = - matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..))); - // If `pat` is not a binding or a reference to a binding (`x` or `&x`) - // we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`) - if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) { - snippet.push_str( - &format!( - ".map(|{}| {})", - snippet_with_applicability(cx, pat.span, "..", &mut applicability), - snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), - )[..], - ); - } - let ty = cx.typeck_results().expr_ty(inner_ret); - if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) { - snippet.push_str( - &format!( - ".find(|{}{}| {})", - "&".repeat(1 + usize::from(is_ref_to_binding)), - snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), - snippet_with_applicability(cx, cond.span, "..", &mut applicability), - )[..], - ); - if is_ref_to_binding { - snippet.push_str(".copied()"); - } - } else { - applicability = Applicability::MaybeIncorrect; - snippet.push_str( - &format!( - ".find(|{}| {})", - snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), - snippet_with_applicability(cx, cond.span, "..", &mut applicability), - )[..], - ); + if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr) + && let Some(binding_id) = get_binding(pat) + && let ExprKind::Block(block, _) = then.kind + && let [stmt] = block.stmts + && let StmtKind::Semi(semi) = stmt.kind + && let ExprKind::Ret(Some(ret_value)) = semi.kind + && let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind + && is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome) + && path_res(cx, inner_ret) == Res::Local(binding_id) + && let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr) + { + let mut applicability = Applicability::MachineApplicable; + let mut snippet = make_iterator_snippet(cx, arg, &mut applicability); + // Checks if `pat` is a single reference to a binding (`&x`) + let is_ref_to_binding = + matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..))); + // If `pat` is not a binding or a reference to a binding (`x` or `&x`) + // we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`) + if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) { + snippet.push_str( + &format!( + ".map(|{}| {})", + snippet_with_applicability(cx, pat.span, "..", &mut applicability), + snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), + )[..], + ); + } + let ty = cx.typeck_results().expr_ty(inner_ret); + if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) { + snippet.push_str( + &format!( + ".find(|{}{}| {})", + "&".repeat(1 + usize::from(is_ref_to_binding)), + snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), + snippet_with_applicability(cx, cond.span, "..", &mut applicability), + )[..], + ); + if is_ref_to_binding { + snippet.push_str(".copied()"); } - // Extends to `last_stmt` to include semicolon in case of `return None;` - let lint_span = span.to(last_stmt.span).to(last_ret.span); - span_lint_and_then( - cx, - MANUAL_FIND, - lint_span, - "manual implementation of `Iterator::find`", - |diag| { - if applicability == Applicability::MaybeIncorrect { - diag.note("you may need to dereference some variables"); - } - diag.span_suggestion( - lint_span, - "replace with an iterator", - snippet, - applicability, - ); - }, + } else { + applicability = Applicability::MaybeIncorrect; + snippet.push_str( + &format!( + ".find(|{}| {})", + snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), + snippet_with_applicability(cx, cond.span, "..", &mut applicability), + )[..], ); } + // Extends to `last_stmt` to include semicolon in case of `return None;` + let lint_span = span.to(last_stmt.span).to(last_ret.span); + span_lint_and_then( + cx, + MANUAL_FIND, + lint_span, + "manual implementation of `Iterator::find`", + |diag| { + if applicability == Applicability::MaybeIncorrect { + diag.note("you may need to dereference some variables"); + } + diag.span_suggestion( + lint_span, + "replace with an iterator", + snippet, + applicability, + ); + }, + ); } } @@ -124,34 +122,30 @@ fn last_stmt_and_ret<'tcx>( if let Some(ret) = block.expr { return Some((last_stmt, ret)); } - if_chain! { - if let [.., snd_last, _] = block.stmts; - if let StmtKind::Semi(last_expr) = last_stmt.kind; - if let ExprKind::Ret(Some(ret)) = last_expr.kind; - then { - return Some((snd_last, ret)); - } + if let [.., snd_last, _] = block.stmts + && let StmtKind::Semi(last_expr) = last_stmt.kind + && let ExprKind::Ret(Some(ret)) = last_expr.kind + { + return Some((snd_last, ret)); } } None } let mut parent_iter = cx.tcx.hir().parent_iter(expr.hir_id); - if_chain! { + if let Some((node_hir, Node::Stmt(..))) = parent_iter.next() // This should be the loop - if let Some((node_hir, Node::Stmt(..))) = parent_iter.next(); // This should be the function body - if let Some((_, Node::Block(block))) = parent_iter.next(); - if let Some((last_stmt, last_ret)) = extract(block); - if last_stmt.hir_id == node_hir; - if is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone); - if let Some((_, Node::Expr(_block))) = parent_iter.next(); + && let Some((_, Node::Block(block))) = parent_iter.next() + && let Some((last_stmt, last_ret)) = extract(block) + && last_stmt.hir_id == node_hir + && is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone) + && let Some((_, Node::Expr(_block))) = parent_iter.next() // This includes the function header - if let Some((_, func)) = parent_iter.next(); - if func.fn_kind().is_some(); - then { - Some((block.stmts.last().unwrap(), last_ret)) - } else { - None - } + && let Some((_, func)) = parent_iter.next() + && func.fn_kind().is_some() + { + Some((block.stmts.last().unwrap(), last_ret)) + } else { + None } } diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 559a2c03f14..7659b506e97 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -21,66 +21,64 @@ pub(super) fn check<'tcx>( span: Span, ) { let inner_expr = peel_blocks_with_stmt(body); - if_chain! { - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None }) - = higher::IfLet::hir(cx, inner_expr); + if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None }) + = higher::IfLet::hir(cx, inner_expr) // Ensure match_expr in `if let` statement is the same as the pat from the for-loop - if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; - if path_to_local_id(let_expr, pat_hir_id); + && let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind + && path_to_local_id(let_expr, pat_hir_id) // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` - if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind; - if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id); - if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); - let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id); - let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id); - if some_ctor || ok_ctor; + && let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind + && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id) + && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) + && let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id) + && let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id) + && (some_ctor || ok_ctor) // Ensure expr in `if let` is not used afterwards - if !is_local_used(cx, if_then, pat_hir_id); - then { - let if_let_type = if some_ctor { "Some" } else { "Ok" }; - // Prepare the error message - let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); + && !is_local_used(cx, if_then, pat_hir_id) + { + let if_let_type = if some_ctor { "Some" } else { "Ok" }; + // Prepare the error message + let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); - // Prepare the help message - let mut applicability = Applicability::MaybeIncorrect; - let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); - let copied = match cx.typeck_results().expr_ty(let_expr).kind() { - ty::Ref(_, inner, _) => match inner.kind() { - ty::Ref(..) => ".copied()", - _ => "" - } + // Prepare the help message + let mut applicability = Applicability::MaybeIncorrect; + let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); + let copied = match cx.typeck_results().expr_ty(let_expr).kind() { + ty::Ref(_, inner, _) => match inner.kind() { + ty::Ref(..) => ".copied()", _ => "" - }; + } + _ => "" + }; - let sugg = format!("{arg_snippet}{copied}.flatten()"); + let sugg = format!("{arg_snippet}{copied}.flatten()"); - // If suggestion is not a one-liner, it won't be shown inline within the error message. In that case, - // it will be shown in the extra `help` message at the end, which is why the first `help_msg` needs - // to refer to the correct relative position of the suggestion. - let help_msg = if sugg.contains('\n') { - "remove the `if let` statement in the for loop and then..." - } else { - "...and remove the `if let` statement in the for loop" - }; + // If suggestion is not a one-liner, it won't be shown inline within the error message. In that case, + // it will be shown in the extra `help` message at the end, which is why the first `help_msg` needs + // to refer to the correct relative position of the suggestion. + let help_msg = if sugg.contains('\n') { + "remove the `if let` statement in the for loop and then..." + } else { + "...and remove the `if let` statement in the for loop" + }; - span_lint_and_then( - cx, - MANUAL_FLATTEN, - span, - &msg, - |diag| { - diag.span_suggestion( - arg.span, - "try", - sugg, - applicability, - ); - diag.span_help( - inner_expr.span, - help_msg, - ); - } - ); - } + span_lint_and_then( + cx, + MANUAL_FLATTEN, + span, + &msg, + |diag| { + diag.span_suggestion( + arg.span, + "try", + sugg, + applicability, + ); + diag.span_help( + inner_expr.span, + help_msg, + ); + } + ); } } diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index d3fd0e8639e..9be888578b5 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -59,22 +59,20 @@ pub(super) fn check<'tcx>( .map(|o| { o.and_then(|(lhs, rhs)| { let rhs = fetch_cloned_expr(rhs); - if_chain! { - if let ExprKind::Index(base_left, idx_left, _) = lhs.kind; - if let ExprKind::Index(base_right, idx_right, _) = rhs.kind; - if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left)); - if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some(); - if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts); - if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts); + if let ExprKind::Index(base_left, idx_left, _) = lhs.kind + && let ExprKind::Index(base_right, idx_right, _) = rhs.kind + && let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left)) + && get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some() + && let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts) + && let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts) // Source and destination must be different - if path_to_local(base_left) != path_to_local(base_right); - then { - Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, - IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) - } else { - None - } + && path_to_local(base_left) != path_to_local(base_right) + { + Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, + IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) + } else { + None } }) }) @@ -118,23 +116,21 @@ fn build_manual_memcpy_suggestion<'tcx>( } let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { - if_chain! { - if let ExprKind::MethodCall(method, recv, [], _) = end.kind; - if method.ident.name == sym::len; - if path_to_local(recv) == path_to_local(base); - then { - if sugg.to_string() == end_str { - sugg::EMPTY.into() - } else { - sugg - } + if let ExprKind::MethodCall(method, recv, [], _) = end.kind + && method.ident.name == sym::len + && path_to_local(recv) == path_to_local(base) + { + if sugg.to_string() == end_str { + sugg::EMPTY.into() } else { - match limits { - ast::RangeLimits::Closed => { - sugg + &sugg::ONE.into() - }, - ast::RangeLimits::HalfOpen => sugg, - } + sugg + } + } else { + match limits { + ast::RangeLimits::Closed => { + sugg + &sugg::ONE.into() + }, + ast::RangeLimits::HalfOpen => sugg, } } }; @@ -331,11 +327,9 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti } fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { - if_chain! { - if let ExprKind::MethodCall(method, arg, [], _) = expr.kind; - if method.ident.name == sym::clone; - then { arg } else { expr } - } + if let ExprKind::MethodCall(method, arg, [], _) = expr.kind + && method.ident.name == sym::clone + { arg } else { expr } } fn get_details_from_idx<'tcx>( diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs index 7b7d19c753f..f332cd87707 100644 --- a/clippy_lints/src/loops/missing_spin_loop.rs +++ b/clippy_lints/src/loops/missing_spin_loop.rs @@ -31,26 +31,24 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind; - if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind; - if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name); - if let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind(); - if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()); - then { - span_lint_and_sugg( - cx, - MISSING_SPIN_LOOP, - body.span, - "busy-waiting loop should at least have a spin loop hint", - "try", - (if is_no_std_crate(cx) { - "{ core::hint::spin_loop() }" - } else { - "{ std::hint::spin_loop() }" - }).into(), - Applicability::MachineApplicable - ); - } + if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind + && let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind + && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name) + && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind() + && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()) + { + span_lint_and_sugg( + cx, + MISSING_SPIN_LOOP, + body.span, + "busy-waiting loop should at least have a spin loop hint", + "try", + (if is_no_std_crate(cx) { + "{ core::hint::spin_loop() }" + } else { + "{ std::hint::spin_loop() }" + }).into(), + Applicability::MachineApplicable + ); } } diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index b83d148b5f2..ad0b7e33354 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -12,19 +12,17 @@ use rustc_middle::ty; use rustc_span::source_map::Span; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { - if_chain! { - if let Some(higher::Range { + if let Some(higher::Range { start: Some(start), end: Some(end), .. - }) = higher::Range::hir(arg); - let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end)); - if mut_id_start.is_some() || mut_id_end.is_some(); - then { - let (span_low, span_high) = check_for_mutation(cx, body, mut_id_start, mut_id_end); - mut_warn_with_span(cx, span_low); - mut_warn_with_span(cx, span_high); - } + }) = higher::Range::hir(arg) + && let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end)) + && (mut_id_start.is_some() || mut_id_end.is_some()) + { + let (span_low, span_high) = check_for_mutation(cx, body, mut_id_start, mut_id_end); + mut_warn_with_span(cx, span_low); + mut_warn_with_span(cx, span_high); } } @@ -42,13 +40,11 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option) { } fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option { - if_chain! { - if let Some(hir_id) = path_to_local(bound); - if let Node::Pat(pat) = cx.tcx.hir().get(hir_id); - if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind; - then { - return Some(hir_id); - } + if let Some(hir_id) = path_to_local(bound) + && let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + && let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind + { + return Some(hir_id); } None } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index c4af46b8fd3..036247c2318 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -187,15 +187,13 @@ pub(super) fn check<'tcx>( } fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { - if_chain! { - if let ExprKind::MethodCall(method, recv, [], _) = expr.kind; - if method.ident.name == sym::len; - if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; - if path.segments.len() == 1; - if path.segments[0].ident.name == var; - then { - return true; - } + if let ExprKind::MethodCall(method, recv, [], _) = expr.kind + && method.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind + && path.segments.len() == 1 + && path.segments[0].ident.name == var + { + return true; } false @@ -207,17 +205,15 @@ fn is_end_eq_array_len<'tcx>( limits: ast::RangeLimits, indexed_ty: Ty<'tcx>, ) -> bool { - if_chain! { - if let ExprKind::Lit(lit) = end.kind; - if let ast::LitKind::Int(end_int, _) = lit.node; - if let ty::Array(_, arr_len_const) = indexed_ty.kind(); - if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env); - then { - return match limits { - ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(), - ast::RangeLimits::HalfOpen => end_int >= arr_len.into(), - }; - } + if let ExprKind::Lit(lit) = end.kind + && let ast::LitKind::Int(end_int, _) = lit.node + && let ty::Array(_, arr_len_const) = indexed_ty.kind() + && let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env) + { + return match limits { + ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(), + ast::RangeLimits::HalfOpen => end_int >= arr_len.into(), + }; } false @@ -248,51 +244,49 @@ struct VarVisitor<'a, 'tcx> { impl<'a, 'tcx> VarVisitor<'a, 'tcx> { fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool { - if_chain! { + if let ExprKind::Path(ref seqpath) = seqexpr.kind // the indexed container is referenced by a name - if let ExprKind::Path(ref seqpath) = seqexpr.kind; - if let QPath::Resolved(None, seqvar) = *seqpath; - if seqvar.segments.len() == 1; - if is_local_used(self.cx, idx, self.var); - then { - if self.prefer_mutable { - self.indexed_mut.insert(seqvar.segments[0].ident.name); - } - let index_used_directly = matches!(idx.kind, ExprKind::Path(_)); - let res = self.cx.qpath_res(seqpath, seqexpr.hir_id); - match res { - Res::Local(hir_id) => { - let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id); - let extent = self - .cx - .tcx - .region_scope_tree(parent_def_id) - .var_scope(hir_id.local_id) - .unwrap(); - if index_used_directly { - self.indexed_directly.insert( - seqvar.segments[0].ident.name, - (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), - ); - } else { - self.indexed_indirectly - .insert(seqvar.segments[0].ident.name, Some(extent)); - } - return false; // no need to walk further *on the variable* - }, - Res::Def(DefKind::Static(_) | DefKind::Const, ..) => { - if index_used_directly { - self.indexed_directly.insert( - seqvar.segments[0].ident.name, - (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), - ); - } else { - self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); - } - return false; // no need to walk further *on the variable* - }, - _ => (), - } + && let QPath::Resolved(None, seqvar) = *seqpath + && seqvar.segments.len() == 1 + && is_local_used(self.cx, idx, self.var) + { + if self.prefer_mutable { + self.indexed_mut.insert(seqvar.segments[0].ident.name); + } + let index_used_directly = matches!(idx.kind, ExprKind::Path(_)); + let res = self.cx.qpath_res(seqpath, seqexpr.hir_id); + match res { + Res::Local(hir_id) => { + let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id); + let extent = self + .cx + .tcx + .region_scope_tree(parent_def_id) + .var_scope(hir_id.local_id) + .unwrap(); + if index_used_directly { + self.indexed_directly.insert( + seqvar.segments[0].ident.name, + (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), + ); + } else { + self.indexed_indirectly + .insert(seqvar.segments[0].ident.name, Some(extent)); + } + return false; // no need to walk further *on the variable* + }, + Res::Def(DefKind::Static(_) | DefKind::Const, ..) => { + if index_used_directly { + self.indexed_directly.insert( + seqvar.segments[0].ident.name, + (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), + ); + } else { + self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None); + } + return false; // no need to walk further *on the variable* + }, + _ => (), } } true @@ -301,42 +295,36 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if_chain! { + if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind // a range index op - if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind; - if let Some(trait_id) = self + && let Some(trait_id) = self .cx .typeck_results() .type_dependent_def_id(expr.hir_id) - .and_then(|def_id| self.cx.tcx.trait_of_item(def_id)); - if (meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id)) - || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id)); - if !self.check(args_1, args_0, expr); - then { - return; - } + .and_then(|def_id| self.cx.tcx.trait_of_item(def_id)) + && ((meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id)) + || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id))) + && !self.check(args_1, args_0, expr) + { + return; } - if_chain! { + if let ExprKind::Index(seqexpr, idx, _) = expr.kind // an index op - if let ExprKind::Index(seqexpr, idx, _) = expr.kind; - if !self.check(idx, seqexpr, expr); - then { - return; - } + && !self.check(idx, seqexpr, expr) + { + return; } - if_chain! { + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind // directly using a variable - if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind; - if let Res::Local(local_id) = path.res; - then { - if local_id == self.var { - self.nonindex = true; - } else { - // not the correct variable, but still a variable - self.referenced.insert(path.segments[0].ident.name); - } + && let Res::Local(local_id) = path.res + { + if local_id == self.var { + self.nonindex = true; + } else { + // not the correct variable, but still a variable + self.referenced.insert(path.segments[0].ident.name); } } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 5fffb27cda2..0c0a9138b27 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -44,54 +44,50 @@ pub(super) fn check<'tcx>( // Determine whether it is safe to lint the body let mut same_item_push_visitor = SameItemPushVisitor::new(cx); walk_expr(&mut same_item_push_visitor, body); - if_chain! { - if same_item_push_visitor.should_lint(); - if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push; - let vec_ty = cx.typeck_results().expr_ty(vec); - let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); - if cx + if same_item_push_visitor.should_lint() + && let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push + && let vec_ty = cx.typeck_results().expr_ty(vec) + && let ty = vec_ty.walk().nth(1).unwrap().expect_ty() + && cx .tcx .lang_items() .clone_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])); - then { - // Make sure that the push does not involve possibly mutating values - match pushed_item.kind { - ExprKind::Path(ref qpath) => { - match cx.qpath_res(qpath, pushed_item.hir_id) { - // immutable bindings that are initialized with literal or constant - Res::Local(hir_id) => { - let node = cx.tcx.hir().get(hir_id); - if_chain! { - if let Node::Pat(pat) = node; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)); - let parent_node = cx.tcx.hir().parent_id(hir_id); - if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); - if let Some(init) = parent_let_expr.init; - then { - match init.kind { - // immutable bindings that are initialized with literal - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), - // immutable bindings that are initialized with constant - ExprKind::Path(ref path) => { - if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { - emit_lint(cx, vec, pushed_item, ctxt); - } - } - _ => {}, + .map_or(false, |id| implements_trait(cx, ty, id, &[])) + { + // Make sure that the push does not involve possibly mutating values + match pushed_item.kind { + ExprKind::Path(ref qpath) => { + match cx.qpath_res(qpath, pushed_item.hir_id) { + // immutable bindings that are initialized with literal or constant + Res::Local(hir_id) => { + let node = cx.tcx.hir().get(hir_id); + if let Node::Pat(pat) = node + && let PatKind::Binding(bind_ann, ..) = pat.kind + && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)) + && let parent_node = cx.tcx.hir().parent_id(hir_id) + && let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node) + && let Some(init) = parent_let_expr.init + { + match init.kind { + // immutable bindings that are initialized with literal + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), + // immutable bindings that are initialized with constant + ExprKind::Path(ref path) => { + if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { + emit_lint(cx, vec, pushed_item, ctxt); } } + _ => {}, } - }, - // constant - Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), - _ => {}, - } - }, - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), - _ => {}, - } + } + }, + // constant + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), + _ => {}, + } + }, + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), + _ => {}, } } } @@ -118,16 +114,14 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { } fn should_lint(&self) -> bool { - if_chain! { - if !self.non_deterministic_expr; - if !self.multiple_pushes; - if let Some((vec, _, _)) = self.vec_push; - if let Some(hir_id) = path_to_local(vec); - then { - !self.used_locals.contains(&hir_id) - } else { - false - } + if !self.non_deterministic_expr + && !self.multiple_pushes + && let Some((vec, _, _)) = self.vec_push + && let Some(hir_id) = path_to_local(vec) + { + !self.used_locals.contains(&hir_id) + } else { + false } } } @@ -180,18 +174,16 @@ fn get_vec_push<'tcx>( cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> { - if_chain! { + if let StmtKind::Semi(semi_stmt) = &stmt.kind // Extract method being called - if let StmtKind::Semi(semi_stmt) = &stmt.kind; - if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; + && let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind // Figure out the parameters for the method call - if let Some(pushed_item) = args.first(); + && let Some(pushed_item) = args.first() // Check that the method being called is push() on a Vec - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); - if path.ident.name.as_str() == "push"; - then { - return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) - } - } + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec) + && path.ident.name.as_str() == "push" + { + return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) + } None } diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index dfb800ccf71..0511ec011c4 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -66,36 +66,34 @@ pub(super) fn check<'tcx>( ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""), _ => return, }; - if_chain! { - if let ExprKind::Block(block, _) = body.kind; - if !block.stmts.is_empty(); - if !contains_break_or_continue(body); - then { - let mut applicability = Applicability::MachineApplicable; - let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); - let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability); - let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned(); - block_str.remove(0); - block_str.pop(); - let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)); + if let ExprKind::Block(block, _) = body.kind + && !block.stmts.is_empty() + && !contains_break_or_continue(body) + { + let mut applicability = Applicability::MachineApplicable; + let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); + let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability); + let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned(); + block_str.remove(0); + block_str.pop(); + let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)); - // Reference iterator from `&(mut) []` or `[].iter(_mut)()`. - if !prefix.is_empty() && ( - // Precedence of internal expression is less than or equal to precedence of `&expr`. - arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression) - ) { - arg_snip = format!("({arg_snip})").into(); - } - - span_lint_and_sugg( - cx, - SINGLE_ELEMENT_LOOP, - expr.span, - "for loop over a single element", - "try", - format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), - applicability, - ) + // Reference iterator from `&(mut) []` or `[].iter(_mut)()`. + if !prefix.is_empty() && ( + // Precedence of internal expression is less than or equal to precedence of `&expr`. + arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression) + ) { + arg_snip = format!("({arg_snip})").into(); } + + span_lint_and_sugg( + cx, + SINGLE_ELEMENT_LOOP, + expr.span, + "for loop over a single element", + "try", + format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), + applicability, + ) } } diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 0a2bd89eb3c..c4d89dc3f0e 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -145,20 +145,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { fn visit_local(&mut self, l: &'tcx Local<'_>) { // Look for declarations of the variable - if_chain! { - if l.pat.hir_id == self.var_id; - if let PatKind::Binding(.., ident, _) = l.pat.kind; - then { - let ty = l.ty.map(|_| self.cx.typeck_results().pat_ty(l.pat)); + if l.pat.hir_id == self.var_id + && let PatKind::Binding(.., ident, _) = l.pat.kind + { + let ty = l.ty.map(|_| self.cx.typeck_results().pat_ty(l.pat)); - self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| { - InitializeVisitorState::Initialized { - initializer: init, - ty, - name: ident.name, - } - }) - } + self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| { + InitializeVisitorState::Initialized { + initializer: init, + ty, + name: ident.name, + } + }) } walk_local(self, l); diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index 7f24f3c5dc2..d5b50db4501 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -95,20 +95,18 @@ struct VarCollectorVisitor<'a, 'tcx> { impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Path(ref qpath) = ex.kind; - if let QPath::Resolved(None, _) = *qpath; - then { - match self.cx.qpath_res(qpath, ex.hir_id) { - Res::Local(hir_id) => { - self.ids.insert(hir_id); - }, - Res::Def(DefKind::Static(_), def_id) => { - let mutable = self.cx.tcx.is_mutable_static(def_id); - self.def_ids.insert(def_id, mutable); - }, - _ => {}, - } + if let ExprKind::Path(ref qpath) = ex.kind + && let QPath::Resolved(None, _) = *qpath + { + match self.cx.qpath_res(qpath, ex.hir_id) { + Res::Local(hir_id) => { + self.ids.insert(hir_id); + }, + Res::Def(DefKind::Static(_), def_id) => { + let mutable = self.cx.tcx.is_mutable_static(def_id); + self.def_ids.insert(def_id, mutable); + }, + _ => {}, } } } diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 5153070cfe6..144f4b0fb4c 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -15,23 +15,21 @@ use rustc_span::symbol::sym; use rustc_span::Symbol; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! { - if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr); + let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr) // check for `Some(..)` pattern - if let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind; - if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome); + && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind + && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome) // check for call to `Iterator::next` - if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind; - if method_name.ident.name == sym::next; - if is_trait_method(cx, let_expr, sym::Iterator); - if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr); + && let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind + && method_name.ident.name == sym::next + && is_trait_method(cx, let_expr, sym::Iterator) + && let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr) // get the loop containing the match expression - if !uses_iter(cx, &iter_expr_struct, if_then); - then { - (let_expr, iter_expr_struct, iter_expr, some_pat, expr) - } else { - return; - } + && !uses_iter(cx, &iter_expr_struct, if_then) + { + (let_expr, iter_expr_struct, iter_expr, some_pat, expr) + } else { + return; }; let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 70c5182472a..42987e583af 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -90,30 +90,28 @@ impl MacroUseImports { impl<'tcx> LateLintPass<'tcx> for MacroUseImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if_chain! { - if cx.sess().opts.edition >= Edition::Edition2018; - if let hir::ItemKind::Use(path, _kind) = &item.kind; - let hir_id = item.hir_id(); - let attrs = cx.tcx.hir().attrs(hir_id); - if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)); - if let Some(id) = path.res.iter().find_map(|res| match res { + if cx.sess().opts.edition >= Edition::Edition2018 + && let hir::ItemKind::Use(path, _kind) = &item.kind + && let hir_id = item.hir_id() + && let attrs = cx.tcx.hir().attrs(hir_id) + && let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)) + && let Some(id) = path.res.iter().find_map(|res| match res { Res::Def(DefKind::Mod, id) => Some(id), _ => None, - }); - if !id.is_local(); - then { - for kid in cx.tcx.module_children(id) { - if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { - let span = mac_attr.span; - let def_path = cx.tcx.def_path_str(mac_id); - self.imports.push((def_path, span, hir_id)); - } - } - } else { - if item.span.from_expansion() { - self.push_unique_macro_pat_ty(cx, item.span); + }) + && !id.is_local() + { + for kid in cx.tcx.module_children(id) { + if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { + let span = mac_attr.span; + let def_path = cx.tcx.def_path_str(mac_id); + self.imports.push((def_path, span, hir_id)); } } + } else { + if item.span.from_expansion() { + self.push_unique_macro_pat_ty(cx, item.span); + } } } fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 20333c150e3..0be0b2850c4 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -43,21 +43,19 @@ impl LateLintPass<'_> for MainRecursion { return; } - if_chain! { - if let ExprKind::Call(func, _) = &expr.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind; - if let Some(def_id) = path.res.opt_def_id(); - if is_entrypoint_fn(cx, def_id); - then { - span_lint_and_help( - cx, - MAIN_RECURSION, - func.span, - &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), - None, - "consider using another function for this recursion" - ) - } + if let ExprKind::Call(func, _) = &expr.kind + && let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind + && let Some(def_id) = path.res.opt_def_id() + && is_entrypoint_fn(cx, def_id) + { + span_lint_and_help( + cx, + MAIN_RECURSION, + func.span, + &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), + None, + "consider using another function for this recursion" + ) } } } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 998de38a995..efa40a9929c 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -47,61 +47,57 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { span: Span, def_id: LocalDefId, ) { - if_chain! { - if let Some(header) = kind.header(); - if !header.asyncness.is_async(); + if let Some(header) = kind.header() + && !header.asyncness.is_async() // Check that this function returns `impl Future` - if let FnRetTy::Return(ret_ty) = decl.output; - if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty); - if let Some(output) = future_output_ty(trait_ref); - if captures_all_lifetimes(decl.inputs, &output_lifetimes); + && let FnRetTy::Return(ret_ty) = decl.output + && let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty) + && let Some(output) = future_output_ty(trait_ref) + && captures_all_lifetimes(decl.inputs, &output_lifetimes) // Check that the body of the function consists of one async block - if let ExprKind::Block(block, _) = body.value.kind; - if block.stmts.is_empty(); - if let Some(closure_body) = desugared_async_block(cx, block); - if let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = - cx.tcx.hir().get_by_def_id(def_id); - then { - let header_span = span.with_hi(ret_ty.span.hi()); - - span_lint_and_then( - cx, - MANUAL_ASYNC_FN, - header_span, - "this function can be simplified using the `async fn` syntax", - |diag| { - if_chain! { - if let Some(vis_snip) = snippet_opt(cx, *vis_span); - if let Some(header_snip) = snippet_opt(cx, header_span); - if let Some(ret_pos) = position_before_rarrow(&header_snip); - if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); - then { - let header_snip = if vis_snip.is_empty() { - format!("async {}", &header_snip[..ret_pos]) - } else { - format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) - }; - - let help = format!("make the function `async` and {ret_sugg}"); - diag.span_suggestion( - header_span, - help, - format!("{header_snip}{ret_snip}"), - Applicability::MachineApplicable - ); - - let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)); - diag.span_suggestion( - block.span, - "move the body of the async block to the enclosing function", - body_snip, - Applicability::MachineApplicable - ); - } - } - }, - ); - } + && let ExprKind::Block(block, _) = body.value.kind + && block.stmts.is_empty() + && let Some(closure_body) = desugared_async_block(cx, block) + && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = + cx.tcx.hir().get_by_def_id(def_id) + { + let header_span = span.with_hi(ret_ty.span.hi()); + + span_lint_and_then( + cx, + MANUAL_ASYNC_FN, + header_span, + "this function can be simplified using the `async fn` syntax", + |diag| { + if let Some(vis_snip) = snippet_opt(cx, *vis_span) + && let Some(header_snip) = snippet_opt(cx, header_span) + && let Some(ret_pos) = position_before_rarrow(&header_snip) + && let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output) + { + let header_snip = if vis_snip.is_empty() { + format!("async {}", &header_snip[..ret_pos]) + } else { + format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) + }; + + let help = format!("make the function `async` and {ret_sugg}"); + diag.span_suggestion( + header_span, + help, + format!("{header_snip}{ret_snip}"), + Applicability::MachineApplicable + ); + + let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)); + diag.span_suggestion( + block.span, + "move the body of the async block to the enclosing function", + body_snip, + Applicability::MachineApplicable + ); + } + }, + ); } } } @@ -110,48 +106,44 @@ fn future_trait_ref<'tcx>( cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>, ) -> Option<(&'tcx TraitRef<'tcx>, Vec)> { - if_chain! { - if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind; - let item = cx.tcx.hir().item(item_id); - if let ItemKind::OpaqueTy(opaque) = &item.kind; - if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { + if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind + && let item = cx.tcx.hir().item(item_id) + && let ItemKind::OpaqueTy(opaque) = &item.kind + && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { if let GenericBound::Trait(poly, _) = bound { Some(&poly.trait_ref) } else { None } - }); - if trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait(); - then { - let output_lifetimes = bounds - .iter() - .filter_map(|bound| { - if let GenericArg::Lifetime(lt) = bound { - Some(lt.res) - } else { - None - } - }) - .collect(); - - return Some((trait_ref, output_lifetimes)); - } + }) + && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait() + { + let output_lifetimes = bounds + .iter() + .filter_map(|bound| { + if let GenericArg::Lifetime(lt) = bound { + Some(lt.res) + } else { + None + } + }) + .collect(); + + return Some((trait_ref, output_lifetimes)); } None } fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> { - if_chain! { - if let Some(segment) = trait_ref.path.segments.last(); - if let Some(args) = segment.args; - if args.bindings.len() == 1; - let binding = &args.bindings[0]; - if binding.ident.name == sym::Output; - if let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind; - then { - return Some(output); - } + if let Some(segment) = trait_ref.path.segments.last() + && let Some(args) = segment.args + && args.bindings.len() == 1 + && let binding = &args.bindings[0] + && binding.ident.name == sym::Output + && let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind + { + return Some(output); } None @@ -181,17 +173,15 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) } fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { - if_chain! { - if let Some(block_expr) = block.expr; - if let Expr { + if let Some(block_expr) = block.expr + && let Expr { kind: ExprKind::Closure(&Closure { body, .. }), .. - } = block_expr; - let closure_body = cx.tcx.hir().body(body); - if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)); - then { - return Some(closure_body); - } + } = block_expr + && let closure_body = cx.tcx.hir().body(body) + && closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)) + { + return Some(closure_body); } None diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index cd614c8951c..3452177c525 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -53,32 +53,30 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { return; } - if_chain! { - if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind; - if let BinOpKind::Mul = &bin_op.node; - if !in_external_macro(cx.sess(), expr.span); - let ctxt = expr.span.ctxt(); - if left_expr.span.ctxt() == ctxt; - if right_expr.span.ctxt() == ctxt; - if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr); - if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_)); - if let ExprKind::Lit(lit) = &other_expr.kind; - if let LitKind::Int(8, _) = lit.node; - then { - let mut app = Applicability::MachineApplicable; - let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0; - let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS")); - - span_lint_and_sugg( - cx, - MANUAL_BITS, - expr.span, - "usage of `mem::size_of::()` to obtain the size of `T` in bits", - "consider using", - sugg, - app, - ); - } + if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind + && let BinOpKind::Mul = &bin_op.node + && !in_external_macro(cx.sess(), expr.span) + && let ctxt = expr.span.ctxt() + && left_expr.span.ctxt() == ctxt + && right_expr.span.ctxt() == ctxt + && let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr) + && matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_)) + && let ExprKind::Lit(lit) = &other_expr.kind + && let LitKind::Int(8, _) = lit.node + { + let mut app = Applicability::MachineApplicable; + let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0; + let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS")); + + span_lint_and_sugg( + cx, + MANUAL_BITS, + expr.span, + "usage of `mem::size_of::()` to obtain the size of `T` in bits", + "consider using", + sugg, + app, + ); } } @@ -98,22 +96,20 @@ fn get_one_size_of_ty<'tcx>( } fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> { - if_chain! { - if let ExprKind::Call(count_func, _func_args) = expr.kind; - if let ExprKind::Path(ref count_func_qpath) = count_func.kind; - - if let QPath::Resolved(_, count_func_path) = count_func_qpath; - if let Some(segment_zero) = count_func_path.segments.first(); - if let Some(args) = segment_zero.args; - if let Some(GenericArg::Type(real_ty)) = args.args.first(); - - if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id); - then { - cx.typeck_results().node_args(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty)) - } else { - None - } + if let ExprKind::Call(count_func, _func_args) = expr.kind + && let ExprKind::Path(ref count_func_qpath) = count_func.kind + + && let QPath::Resolved(_, count_func_path) = count_func_qpath + && let Some(segment_zero) = count_func_path.segments.first() + && let Some(args) = segment_zero.args + && let Some(GenericArg::Type(real_ty)) = args.args.first() + + && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id) + { + cx.typeck_results().node_args(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty)) + } else { + None } } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 9a9e6af5084..0559dc39363 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -71,55 +71,51 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { return; } - if_chain! { - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr); - if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind; - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id); - if let ExprKind::Path(target_path) = &target_arg.kind; - then { - let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { - StripKind::Prefix - } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) { - StripKind::Suffix - } else { - return; - }; - let target_res = cx.qpath_res(target_path, target_arg.hir_id); - if target_res == Res::Err { - return; - }; + if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) + && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) + && let ExprKind::Path(target_path) = &target_arg.kind + { + let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { + StripKind::Prefix + } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) { + StripKind::Suffix + } else { + return; + }; + let target_res = cx.qpath_res(target_path, target_arg.hir_id); + if target_res == Res::Err { + return; + }; + + if let Res::Local(hir_id) = target_res + && let Some(used_mutably) = mutated_variables(then, cx) + && used_mutably.contains(&hir_id) + { + return; + } - if_chain! { - if let Res::Local(hir_id) = target_res; - if let Some(used_mutably) = mutated_variables(then, cx); - if used_mutably.contains(&hir_id); - then { - return; - } - } + let strippings = find_stripping(cx, strip_kind, target_res, pattern, then); + if !strippings.is_empty() { - let strippings = find_stripping(cx, strip_kind, target_res, pattern, then); - if !strippings.is_empty() { - - let kind_word = match strip_kind { - StripKind::Prefix => "prefix", - StripKind::Suffix => "suffix", - }; - - let test_span = expr.span.until(then.span); - span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { - diag.span_note(test_span, format!("the {kind_word} was tested here")); - multispan_sugg( - diag, - &format!("try using the `strip_{kind_word}` method"), - vec![(test_span, - format!("if let Some() = {}.strip_{kind_word}({}) ", - snippet(cx, target_arg.span, ".."), - snippet(cx, pattern.span, "..")))] - .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), - ); - }); - } + let kind_word = match strip_kind { + StripKind::Prefix => "prefix", + StripKind::Suffix => "suffix", + }; + + let test_span = expr.span.until(then.span); + span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { + diag.span_note(test_span, format!("the {kind_word} was tested here")); + multispan_sugg( + diag, + &format!("try using the `strip_{kind_word}` method"), + vec![(test_span, + format!("if let Some() = {}.strip_{kind_word}({}) ", + snippet(cx, target_arg.span, ".."), + snippet(cx, pattern.span, "..")))] + .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), + ); + }); } } } @@ -129,15 +125,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if_chain! { - if let ExprKind::MethodCall(_, arg, [], _) = expr.kind; - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, method_def_id, &paths::STR_LEN); - then { - Some(arg) - } else { - None - } + if let ExprKind::MethodCall(_, arg, [], _) = expr.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, method_def_id, &paths::STR_LEN) + { + Some(arg) + } else { + None } } @@ -201,36 +195,32 @@ fn find_stripping<'tcx>( impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { - if_chain! { - if is_ref_str(self.cx, ex); - let unref = peel_ref(ex); - if let ExprKind::Index(indexed, index, _) = &unref.kind; - if let Some(higher::Range { start, end, .. }) = higher::Range::hir(index); - if let ExprKind::Path(path) = &indexed.kind; - if self.cx.qpath_res(path, ex.hir_id) == self.target; - then { - match (self.strip_kind, start, end) { - (StripKind::Prefix, Some(start), None) => { - if eq_pattern_length(self.cx, self.pattern, start) { - self.results.push(ex.span); - return; - } - }, - (StripKind::Suffix, None, Some(end)) => { - if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind; - if let Some(left_arg) = len_arg(self.cx, left); - if let ExprKind::Path(left_path) = &left_arg.kind; - if self.cx.qpath_res(left_path, left_arg.hir_id) == self.target; - if eq_pattern_length(self.cx, self.pattern, right); - then { - self.results.push(ex.span); - return; - } - } - }, - _ => {} - } + if is_ref_str(self.cx, ex) + && let unref = peel_ref(ex) + && let ExprKind::Index(indexed, index, _) = &unref.kind + && let Some(higher::Range { start, end, .. }) = higher::Range::hir(index) + && let ExprKind::Path(path) = &indexed.kind + && self.cx.qpath_res(path, ex.hir_id) == self.target + { + match (self.strip_kind, start, end) { + (StripKind::Prefix, Some(start), None) => { + if eq_pattern_length(self.cx, self.pattern, start) { + self.results.push(ex.span); + return; + } + }, + (StripKind::Suffix, None, Some(end)) => { + if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind + && let Some(left_arg) = len_arg(self.cx, left) + && let ExprKind::Path(left_path) = &left_arg.kind + && self.cx.qpath_res(left_path, left_arg.hir_id) == self.target + && eq_pattern_length(self.cx, self.pattern, right) + { + self.results.push(ex.span); + return; + } + }, + _ => {} } } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 766beb980a5..03df8a67540 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -164,16 +164,14 @@ fn unit_closure<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> { - if_chain! { - if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind; - let body = cx.tcx.hir().body(body); - let body_expr = &body.value; - if fn_decl.inputs.len() == 1; - if is_unit_expression(cx, body_expr); - if let Some(binding) = iter_input_pats(fn_decl, body).next(); - then { - return Some((binding, body_expr)); - } + if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind + && let body = cx.tcx.hir().body(body) + && let body_expr = &body.value + && fn_decl.inputs.len() == 1 + && is_unit_expression(cx, body_expr) + && let Some(binding) = iter_input_pats(fn_decl, body).next() + { + return Some((binding, body_expr)); } None } diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 841c020f2d3..750f8305730 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -56,33 +56,31 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { return; }; - if_chain! { - if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) - if let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind; //get operation - if ok_path.ident.as_str() == "ok"; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome); - let ctxt = expr.span.ctxt(); - if let_expr.span.ctxt() == ctxt; - if let_pat.span.ctxt() == ctxt; - then { - let mut applicability = Applicability::MachineApplicable; - let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0; - let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0; - let sugg = format!( - "{ifwhile} let Ok({some_expr_string}) = {}", - trimmed_ok.trim().trim_end_matches('.'), - ); - span_lint_and_sugg( - cx, - MATCH_RESULT_OK, - expr.span.with_hi(let_expr.span.hi()), - "matching on `Some` with `ok()` is redundant", - &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), - sugg, - applicability, - ); - } + if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result.ok(, _) + && let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind //get operation + && ok_path.ident.as_str() == "ok" + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) + && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome) + && let ctxt = expr.span.ctxt() + && let_expr.span.ctxt() == ctxt + && let_pat.span.ctxt() == ctxt + { + let mut applicability = Applicability::MachineApplicable; + let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0; + let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0; + let sugg = format!( + "{ifwhile} let Ok({some_expr_string}) = {}", + trimmed_ok.trim().trim_end_matches('.'), + ); + span_lint_and_sugg( + cx, + MATCH_RESULT_OK, + expr.span.with_hi(let_expr.span.hi()), + "matching on `Some` with `ok()` is redundant", + &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), + sugg, + applicability, + ); } } } diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 29b935fb61a..f9dc8440aca 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -40,76 +40,72 @@ fn check_arm<'tcx>( outer_else_body: Option<&'tcx Expr<'tcx>>, ) { let inner_expr = peel_blocks_with_stmt(outer_then_body); - if_chain! { - if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr); - if let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner { + if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr) + && let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner { IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)), - IfLetOrMatch::Match(scrutinee, arms, ..) => if_chain! { + IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none()) // if there are more than two arms, collapsing would be non-trivial - if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none()); // one of the arms must be "wild-like" - if let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a)); - then { - let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]); - Some((scrutinee, then.pat, Some(els.body))) - } else { - None - } + && let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a)) + { + let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]); + Some((scrutinee, then.pat, Some(els.body))) + } else { + None }, - }; - if outer_pat.span.eq_ctxt(inner_scrutinee.span); + } + && outer_pat.span.eq_ctxt(inner_scrutinee.span) // match expression must be a local binding // match { .. } - if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)); - if !pat_contains_or(inner_then_pat); + && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)) + && !pat_contains_or(inner_then_pat) // the binding must come from the pattern of the containing match arm // .... => match { .. } - if let (Some(binding_span), is_innermost_parent_pat_struct) - = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id); + && let (Some(binding_span), is_innermost_parent_pat_struct) + = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id) // the "else" branches must be equal - if match (outer_else_body, inner_else_body) { + && match (outer_else_body, inner_else_body) { (None, None) => true, (None, Some(e)) | (Some(e), None) => is_unit_expr(e), (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b), - }; + } // the binding must not be used in the if guard - if outer_guard.map_or( + && outer_guard.map_or( true, |(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id) - ); + ) // ...or anywhere in the inner expression - if match inner { + && match inner { IfLetOrMatch::IfLet(_, _, body, els) => { !is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id)) }, IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)), - }; - then { - let msg = format!( - "this `{}` can be collapsed into the outer `{}`", - if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" }, - if outer_is_match { "match" } else { "if let" }, - ); - // collapsing patterns need an explicit field name in struct pattern matching - // ex: Struct {x: Some(1)} - let replace_msg = if is_innermost_parent_pat_struct { - format!(", prefixed by {}:", snippet(cx, binding_span, "their field name")) - } else { - String::new() - }; - span_lint_and_then( - cx, - COLLAPSIBLE_MATCH, - inner_expr.span, - &msg, - |diag| { - let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); - help_span.push_span_label(binding_span, "replace this binding"); - help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); - diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern"); - }, - ); } + { + let msg = format!( + "this `{}` can be collapsed into the outer `{}`", + if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" }, + if outer_is_match { "match" } else { "if let" }, + ); + // collapsing patterns need an explicit field name in struct pattern matching + // ex: Struct {x: Some(1)} + let replace_msg = if is_innermost_parent_pat_struct { + format!(", prefixed by {}:", snippet(cx, binding_span, "their field name")) + } else { + String::new() + }; + span_lint_and_then( + cx, + COLLAPSIBLE_MATCH, + inner_expr.span, + &msg, + |diag| { + let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); + help_span.push_span_label(binding_span, "replace this binding"); + help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); + diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern"); + }, + ); } } diff --git a/clippy_lints/src/matches/infallible_destructuring_match.rs b/clippy_lints/src/matches/infallible_destructuring_match.rs index 3329f93b73c..313a9cba327 100644 --- a/clippy_lints/src/matches/infallible_destructuring_match.rs +++ b/clippy_lints/src/matches/infallible_destructuring_match.rs @@ -8,38 +8,36 @@ use rustc_lint::LateContext; use super::INFALLIBLE_DESTRUCTURING_MATCH; pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool { - if_chain! { - if !local.span.from_expansion(); - if let Some(expr) = local.init; - if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind; - if arms.len() == 1 && arms[0].guard.is_none(); - if let PatKind::TupleStruct( - QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind; - if args.len() == 1; - if let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind; - let body = peel_blocks(arms[0].body); - if path_to_local_id(body, arg); + if !local.span.from_expansion() + && let Some(expr) = local.init + && let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind + && arms.len() == 1 && arms[0].guard.is_none() + && let PatKind::TupleStruct( + QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind + && args.len() == 1 + && let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind + && let body = peel_blocks(arms[0].body) + && path_to_local_id(body, arg) - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - INFALLIBLE_DESTRUCTURING_MATCH, - local.span, - "you seem to be trying to use `match` to destructure a single infallible pattern. \ - Consider using `let`", - "try", - format!( - "let {}({}{}) = {};", - snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), - if binding.0 == ByRef::Yes { "ref " } else { "" }, - snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), - snippet_with_applicability(cx, target.span, "..", &mut applicability), - ), - applicability, - ); - return true; - } + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + INFALLIBLE_DESTRUCTURING_MATCH, + local.span, + "you seem to be trying to use `match` to destructure a single infallible pattern. \ + Consider using `let`", + "try", + format!( + "let {}({}{}) = {};", + snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), + if binding.0 == ByRef::Yes { "ref " } else { "" }, + snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), + snippet_with_applicability(cx, target.span, "..", &mut applicability), + ), + applicability, + ); + return true; } false } diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index cdb51c33aaf..bd8a9d10e8a 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -21,20 +21,18 @@ fn get_cond_expr<'tcx>( expr: &'tcx Expr<'_>, ctxt: SyntaxContext, ) -> Option> { - if_chain! { - if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr); - if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind; - if let PatKind::Binding(_,target, ..) = pat.kind; - if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr) - || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None` - then { - return Some(SomeExpr { - expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()), - needs_unsafe_block: contains_unsafe_block(cx, expr), - needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond - }) - } - }; + if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr) + && let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind + && let PatKind::Binding(_,target, ..) = pat.kind + && (is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr) + || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr)) // check that one expr resolves to `Some(x)`, the other to `None` + { + return Some(SomeExpr { + expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()), + needs_unsafe_block: contains_unsafe_block(cx, expr), + needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond + }) + }; None } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index b94501bf0ad..723528bbe2e 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -16,43 +16,40 @@ use super::MANUAL_UNWRAP_OR; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { let ty = cx.typeck_results().expr_ty(scrutinee); - if_chain! { - if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) { + if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) { Some("Option") } else if is_type_diagnostic_item(cx, ty, sym::Result) { Some("Result") } else { None - }; - if let Some(or_arm) = applicable_or_arm(cx, arms); - if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span); - if let Some(indent) = indent_of(cx, expr.span); - if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some(); - then { - let reindented_or_body = - reindent_multiline(or_body_snippet.into(), true, Some(indent)); - - let mut app = Applicability::MachineApplicable; - let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); - span_lint_and_sugg( - cx, - MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{ty_name}::unwrap_or`"), - "replace with", - format!( - "{suggestion}.unwrap_or({reindented_or_body})", - ), - app, - ); } + && let Some(or_arm) = applicable_or_arm(cx, arms) + && let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span) + && let Some(indent) = indent_of(cx, expr.span) + && constant_simple(cx, cx.typeck_results(), or_arm.body).is_some() + { + let reindented_or_body = + reindent_multiline(or_body_snippet.into(), true, Some(indent)); + + let mut app = Applicability::MachineApplicable; + let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); + span_lint_and_sugg( + cx, + MANUAL_UNWRAP_OR, expr.span, + &format!("this pattern reimplements `{ty_name}::unwrap_or`"), + "replace with", + format!( + "{suggestion}.unwrap_or({reindented_or_body})", + ), + app, + ); } } fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { - if_chain! { - if arms.len() == 2; - if arms.iter().all(|arm| arm.guard.is_none()); - if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| { + if arms.len() == 2 + && arms.iter().all(|arm| arm.guard.is_none()) + && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| { match arm.pat.kind { PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), PatKind::TupleStruct(ref qpath, [pat], _) => @@ -60,21 +57,20 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&' && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr), _ => false, } - }); - let unwrap_arm = &arms[1 - idx]; - if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind; - if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id); - if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); - if cx.tcx.lang_items().option_some_variant() == Some(variant_id) - || cx.tcx.lang_items().result_ok_variant() == Some(variant_id); - if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; - if path_to_local_id(unwrap_arm.body, binding_hir_id); - if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty(); - if !contains_return_break_continue_macro(or_arm.body); - then { - Some(or_arm) - } else { - None - } + }) + && let unwrap_arm = &arms[1 - idx] + && let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind + && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id) + && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) + && (cx.tcx.lang_items().option_some_variant() == Some(variant_id) + || cx.tcx.lang_items().result_ok_variant() == Some(variant_id)) + && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind + && path_to_local_id(unwrap_arm.body, binding_hir_id) + && cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty() + && !contains_return_break_continue_macro(or_arm.body) + { + Some(or_arm) + } else { + None } } diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index 781ee138c76..0627e458dfe 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -127,32 +127,30 @@ where let closure_expr_snip = some_expr.to_snippet_with_context(cx, expr_ctxt, &mut app); let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind { - if_chain! { - if !some_expr.needs_unsafe_block; - if let Some(func) = can_pass_as_func(cx, id, some_expr.expr); - if func.span.eq_ctxt(some_expr.expr.span); - then { - snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() - } else { - if path_to_local_id(some_expr.expr, id) - && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id) - && binding_ref.is_some() - { - return None; - } + if !some_expr.needs_unsafe_block + && let Some(func) = can_pass_as_func(cx, id, some_expr.expr) + && func.span.eq_ctxt(some_expr.expr.span) + { + snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() + } else { + if path_to_local_id(some_expr.expr, id) + && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id) + && binding_ref.is_some() + { + return None; + } - // `ref` and `ref mut` annotations were handled earlier. - let annotation = if matches!(annotation, BindingAnnotation::MUT) { - "mut " - } else { - "" - }; + // `ref` and `ref mut` annotations were handled earlier. + let annotation = if matches!(annotation, BindingAnnotation::MUT) { + "mut " + } else { + "" + }; - if some_expr.needs_unsafe_block { - format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}") - } else { - format!("|{annotation}{some_binding}| {closure_expr_snip}") - } + if some_expr.needs_unsafe_block { + format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}") + } else { + format!("|{annotation}{some_binding}| {closure_expr_snip}") } } } else if !is_wild_none && explicit_ref.is_none() { diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index d51cca040a2..812a0aab94f 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -26,18 +26,16 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: let output_ty = cx.typeck_results().expr_ty(expr); let input_ty = cx.typeck_results().expr_ty(ex); - let cast = if_chain! { - if let ty::Adt(_, args) = input_ty.kind(); - let input_ty = args.type_at(0); - if let ty::Adt(_, args) = output_ty.kind(); - let output_ty = args.type_at(0); - if let ty::Ref(_, output_ty, _) = *output_ty.kind(); - if input_ty != output_ty; - then { - ".map(|x| x as _)" - } else { - "" - } + let cast = if let ty::Adt(_, args) = input_ty.kind() + && let input_ty = args.type_at(0) + && let ty::Adt(_, args) = output_ty.kind() + && let output_ty = args.type_at(0) + && let ty::Ref(_, output_ty, _) = *output_ty.kind() + && input_ty != output_ty + { + ".map(|x| x as _)" + } else { + "" }; let mut applicability = Applicability::MachineApplicable; @@ -67,17 +65,15 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { - if_chain! { - if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind; - if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome); - if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind; - if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind; - if is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome); - if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind; - if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; - then { - return Some(mutabl) - } + if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind + && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome) + && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind + && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind + && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) + && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind + && path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name + { + return Some(mutabl) } None } diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index e2ddf11abe2..f100cb97a19 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -76,79 +76,77 @@ where ), >, { - if_chain! { - if !span_contains_comment(cx.sess().source_map(), expr.span); - if iter.len() >= 2; - if cx.typeck_results().expr_ty(expr).is_bool(); - if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back(); - let iter_without_last = iter.clone(); - if let Some((first_attrs, _, first_expr, first_guard)) = iter.next(); - if let Some(b0) = find_bool_lit(&first_expr.kind); - if let Some(b1) = find_bool_lit(&last_expr.kind); - if b0 != b1; - if first_guard.is_none() || iter.len() == 0; - if first_attrs.is_empty(); - if iter + if !span_contains_comment(cx.sess().source_map(), expr.span) + && iter.len() >= 2 + && cx.typeck_results().expr_ty(expr).is_bool() + && let Some((_, last_pat_opt, last_expr, _)) = iter.next_back() + && let iter_without_last = iter.clone() + && let Some((first_attrs, _, first_expr, first_guard)) = iter.next() + && let Some(b0) = find_bool_lit(&first_expr.kind) + && let Some(b1) = find_bool_lit(&last_expr.kind) + && b0 != b1 + && (first_guard.is_none() || iter.len() == 0) + && first_attrs.is_empty() + && iter .all(|arm| { find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty() - }); - then { - if let Some(last_pat) = last_pat_opt { - if !is_wild(last_pat) { - return false; - } + }) + { + if let Some(last_pat) = last_pat_opt { + if !is_wild(last_pat) { + return false; } + } - for arm in iter_without_last.clone() { - if let Some(pat) = arm.1 { - if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) { - return false; - } + for arm in iter_without_last.clone() { + if let Some(pat) = arm.1 { + if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) { + return false; } } + } - // The suggestion may be incorrect, because some arms can have `cfg` attributes - // evaluated into `false` and so such arms will be stripped before. - let mut applicability = Applicability::MaybeIncorrect; - let pat = { - use itertools::Itertools as _; - iter_without_last - .filter_map(|arm| { - let pat_span = arm.1?.span; - Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability)) - }) - .join(" | ") - }; - let pat_and_guard = if let Some(Guard::If(g)) = first_guard { - format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability)) - } else { - pat - }; - - // strip potential borrows (#6503), but only if the type is a reference - let mut ex_new = ex; - if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind { - if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() { - ex_new = ex_inner; - } - }; - span_lint_and_sugg( - cx, - MATCH_LIKE_MATCHES_MACRO, - expr.span, - &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }), - "try", - format!( - "{}matches!({}, {pat_and_guard})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), - applicability, - ); - true + // The suggestion may be incorrect, because some arms can have `cfg` attributes + // evaluated into `false` and so such arms will be stripped before. + let mut applicability = Applicability::MaybeIncorrect; + let pat = { + use itertools::Itertools as _; + iter_without_last + .filter_map(|arm| { + let pat_span = arm.1?.span; + Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability)) + }) + .join(" | ") + }; + let pat_and_guard = if let Some(Guard::If(g)) = first_guard { + format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability)) } else { - false - } + pat + }; + + // strip potential borrows (#6503), but only if the type is a reference + let mut ex_new = ex; + if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind { + if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() { + ex_new = ex_inner; + } + }; + span_lint_and_sugg( + cx, + MATCH_LIKE_MATCHES_MACRO, + expr.span, + &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }), + "try", + format!( + "{}matches!({}, {pat_and_guard})", + if b0 { "" } else { "!" }, + snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), + ), + applicability, + ); + true + } else { + false } } diff --git a/clippy_lints/src/matches/match_on_vec_items.rs b/clippy_lints/src/matches/match_on_vec_items.rs index bd53ebd48c8..d15ecce34f1 100644 --- a/clippy_lints/src/matches/match_on_vec_items.rs +++ b/clippy_lints/src/matches/match_on_vec_items.rs @@ -10,39 +10,35 @@ use rustc_span::sym; use super::MATCH_ON_VEC_ITEMS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { - if_chain! { - if let Some(idx_expr) = is_vec_indexing(cx, scrutinee); - if let ExprKind::Index(vec, idx, _) = idx_expr.kind; - - then { - // FIXME: could be improved to suggest surrounding every pattern with Some(_), - // but only when `or_patterns` are stabilized. - span_lint_and_sugg( - cx, - MATCH_ON_VEC_ITEMS, - scrutinee.span, - "indexing into a vector may panic", - "try", - format!( - "{}.get({})", - snippet(cx, vec.span, ".."), - snippet(cx, idx.span, "..") - ), - Applicability::MaybeIncorrect - ); - } + if let Some(idx_expr) = is_vec_indexing(cx, scrutinee) + && let ExprKind::Index(vec, idx, _) = idx_expr.kind + + { + // FIXME: could be improved to suggest surrounding every pattern with Some(_), + // but only when `or_patterns` are stabilized. + span_lint_and_sugg( + cx, + MATCH_ON_VEC_ITEMS, + scrutinee.span, + "indexing into a vector may panic", + "try", + format!( + "{}.get({})", + snippet(cx, vec.span, ".."), + snippet(cx, idx.span, "..") + ), + Applicability::MaybeIncorrect + ); } } fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if_chain! { - if let ExprKind::Index(array, index, _) = expr.kind; - if is_vector(cx, array); - if !is_full_range(cx, index); - - then { - return Some(expr); - } + if let ExprKind::Index(array, index, _) = expr.kind + && is_vector(cx, array) + && !is_full_range(cx, index) + + { + return Some(expr); } None diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 6fc79faddbe..745be671b86 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -66,25 +66,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let mut local_map: HirIdMap = HirIdMap::default(); let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - if_chain! { - if let Some(a_id) = path_to_local(a); - if let Some(b_id) = path_to_local(b); - let entry = match local_map.entry(a_id) { + if let Some(a_id) = path_to_local(a) + && let Some(b_id) = path_to_local(b) + && let entry = match local_map.entry(a_id) { HirIdMapEntry::Vacant(entry) => entry, // check if using the same bindings as before HirIdMapEntry::Occupied(entry) => return *entry.get() == b_id, - }; - // the names technically don't have to match; this makes the lint more conservative - if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id); - if cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b); - if pat_contains_local(lhs.pat, a_id); - if pat_contains_local(rhs.pat, b_id); - then { - entry.insert(b_id); - true - } else { - false } + // the names technically don't have to match; this makes the lint more conservative + && cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id) + && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b) + && pat_contains_local(lhs.pat, a_id) + && pat_contains_local(rhs.pat, b_id) + { + entry.insert(b_id); + true + } else { + false } }; // Arms with a guard are ignored, those can’t always be merged together diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 675a85ae555..3d920e9537f 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -20,21 +20,19 @@ enum CaseMethod { } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { - if_chain! { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind(); - if let ty::Str = ty.kind(); - then { - let mut visitor = MatchExprVisitor { - cx, - case_method: None, - }; - - visitor.visit_expr(scrutinee); - - if let Some(case_method) = visitor.case_method { - if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) { - lint(cx, &case_method, bad_case_span, bad_case_sym.as_str()); - } + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind() + && let ty::Str = ty.kind() + { + let mut visitor = MatchExprVisitor { + cx, + case_method: None, + }; + + visitor.visit_expr(scrutinee); + + if let Some(case_method) = visitor.case_method { + if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) { + lint(cx, &case_method, bad_case_span, bad_case_sym.as_str()); } } } @@ -88,17 +86,15 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( }; for arm in arms { - if_chain! { - if let PatKind::Lit(Expr { + if let PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. - }) = arm.pat.kind; - if let LitKind::Str(symbol, _) = lit.node; - let input = symbol.as_str(); - if !case_check(input); - then { - return Some((lit.span, symbol)); - } + }) = arm.pat.kind + && let LitKind::Str(symbol, _) = lit.node + && let input = symbol.as_str() + && !case_check(input) + { + return Some((lit.span, symbol)); } } diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index a2903e52ae0..f2fa404db5a 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -34,20 +34,18 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' } } } - if_chain! { - if matching_wild; - if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span); - if is_panic(cx, macro_call.def_id); - then { - // `Err(_)` or `Err(_e)` arm with `panic!` found - span_lint_and_note(cx, - MATCH_WILD_ERR_ARM, - arm.pat.span, - &format!("`Err({ident_bind_name})` matches all errors"), - None, - "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", - ); - } + if matching_wild + && let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span) + && is_panic(cx, macro_call.def_id) + { + // `Err(_)` or `Err(_e)` arm with `panic!` found + span_lint_and_note(cx, + MATCH_WILD_ERR_ARM, + arm.pat.span, + &format!("`Err({ident_bind_name})` matches all errors"), + None, + "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", + ); } } } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 9a7c00823b6..9ce9c2e8381 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -35,15 +35,13 @@ pub(super) fn check_if_let<'tcx>( // Extract the generic arguments out of a type fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option> { - if_chain! { - if let ty::Adt(_, subs) = ty.kind(); - if let Some(sub) = subs.get(index); - if let GenericArgKind::Type(sub_ty) = sub.unpack(); - then { - Some(sub_ty) - } else { - None - } + if let ty::Adt(_, subs) = ty.kind() + && let Some(sub) = subs.get(index) + && let GenericArgKind::Type(sub_ty) = sub.unpack() + { + Some(sub_ty) + } else { + None } } @@ -142,14 +140,12 @@ fn find_sugg_for_if_let<'tcx>( let needs_drop = needs_ordered_drop(cx, check_ty) || any_temporaries_need_ordered_drop(cx, let_expr); // check that `while_let_on_iterator` lint does not trigger - if_chain! { - if keyword == "while"; - if let ExprKind::MethodCall(method_path, ..) = let_expr.kind; - if method_path.ident.name == sym::next; - if is_trait_method(cx, let_expr, sym::Iterator); - then { - return; - } + if keyword == "while" + && let ExprKind::MethodCall(method_path, ..) = let_expr.kind + && method_path.ident.name == sym::next + && is_trait_method(cx, let_expr, sym::Iterator) + { + return; } let result_expr = match &let_expr.kind { diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 4efe93d4b54..2e19bbe42e4 100644 --- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -6,25 +6,23 @@ use rustc_middle::ty; use super::REST_PAT_IN_FULLY_BOUND_STRUCTS; pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { - if_chain! { - if !pat.span.from_expansion(); - if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind; - if let Some(def_id) = path.res.opt_def_id(); - let ty = cx.tcx.type_of(def_id).instantiate_identity(); - if let ty::Adt(def, _) = ty.kind(); - if def.is_struct() || def.is_union(); - if fields.len() == def.non_enum_variant().fields.len(); - if !def.non_enum_variant().is_field_list_non_exhaustive(); + if !pat.span.from_expansion() + && let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind + && let Some(def_id) = path.res.opt_def_id() + && let ty = cx.tcx.type_of(def_id).instantiate_identity() + && let ty::Adt(def, _) = ty.kind() + && (def.is_struct() || def.is_union()) + && fields.len() == def.non_enum_variant().fields.len() + && !def.non_enum_variant().is_field_list_non_exhaustive() - then { - span_lint_and_help( - cx, - REST_PAT_IN_FULLY_BOUND_STRUCTS, - pat.span, - "unnecessary use of `..` pattern in struct binding. All fields were already bound", - None, - "consider removing `..` from this binding", - ); - } + { + span_lint_and_help( + cx, + REST_PAT_IN_FULLY_BOUND_STRUCTS, + pat.span, + "unnecessary use of `..` pattern in struct binding. All fields were already bound", + None, + "consider removing `..` from this binding", + ); } } diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 48efd023017..bbf59643aad 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -89,50 +89,48 @@ fn report_single_pattern( }); let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); - let (msg, sugg) = if_chain! { - if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind; - let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex)); - if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait(); - if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait(); - if ty.is_integral() || ty.is_char() || ty.is_str() + let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind + && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex)) + && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait() + && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait() + && (ty.is_integral() || ty.is_char() || ty.is_str() || (implements_trait(cx, ty, spe_trait_id, &[]) - && implements_trait(cx, ty, pe_trait_id, &[ty.into()])); - then { - // scrutinee derives PartialEq and the pattern is a constant. - let pat_ref_count = match pat.kind { - // string literals are already a reference. - PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1, - _ => pat_ref_count, - }; - // References are only implicitly added to the pattern, so no overflow here. - // e.g. will work: match &Some(_) { Some(_) => () } - // will not: match Some(_) { &Some(_) => () } - let ref_count_diff = ty_ref_count - pat_ref_count; - - // Try to remove address of expressions first. - let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff); - let ref_count_diff = ref_count_diff - removed; - - let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`"; - let sugg = format!( - "if {} == {}{} {}{els_str}", - snippet(cx, ex.span, ".."), - // PartialEq for different reference counts may not exist. - "&".repeat(ref_count_diff), - snippet(cx, arms[0].pat.span, ".."), - expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), - ); - (msg, sugg) - } else { - let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"; - let sugg = format!( - "if let {} = {} {}{els_str}", - snippet(cx, arms[0].pat.span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), - ); - (msg, sugg) - } + && implements_trait(cx, ty, pe_trait_id, &[ty.into()]))) + { + // scrutinee derives PartialEq and the pattern is a constant. + let pat_ref_count = match pat.kind { + // string literals are already a reference. + PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1, + _ => pat_ref_count, + }; + // References are only implicitly added to the pattern, so no overflow here. + // e.g. will work: match &Some(_) { Some(_) => () } + // will not: match Some(_) { &Some(_) => () } + let ref_count_diff = ty_ref_count - pat_ref_count; + + // Try to remove address of expressions first. + let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff); + let ref_count_diff = ref_count_diff - removed; + + let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`"; + let sugg = format!( + "if {} == {}{} {}{els_str}", + snippet(cx, ex.span, ".."), + // PartialEq for different reference counts may not exist. + "&".repeat(ref_count_diff), + snippet(cx, arms[0].pat.span, ".."), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), + ); + (msg, sugg) + } else { + let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"; + let sugg = format!( + "if let {} = {} {}{els_str}", + snippet(cx, arms[0].pat.span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), + ); + (msg, sugg) }; span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app); diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 0fd6f533db0..7e573aafef9 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -22,59 +22,57 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine // #[allow(unreachable_code)] // val, // }; - if_chain! { - if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind; - if let ExprKind::Path(ref match_fun_path) = match_fun.kind; - if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); - if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind; - if is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr); - if let Some(return_ty) = find_return_type(cx, &expr.kind); - then { - let prefix; - let suffix; - let err_ty; + if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind + && let ExprKind::Path(ref match_fun_path) = match_fun.kind + && matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)) + && let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind + && is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr) + && let Some(return_ty) = find_return_type(cx, &expr.kind) + { + let prefix; + let suffix; + let err_ty; - if let Some(ty) = result_error_type(cx, return_ty) { - prefix = "Err("; - suffix = ")"; - err_ty = ty; - } else if let Some(ty) = poll_result_error_type(cx, return_ty) { - prefix = "Poll::Ready(Err("; - suffix = "))"; - err_ty = ty; - } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) { - prefix = "Poll::Ready(Some(Err("; - suffix = ")))"; - err_ty = ty; - } else { - return; - }; + if let Some(ty) = result_error_type(cx, return_ty) { + prefix = "Err("; + suffix = ")"; + err_ty = ty; + } else if let Some(ty) = poll_result_error_type(cx, return_ty) { + prefix = "Poll::Ready(Err("; + suffix = "))"; + err_ty = ty; + } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) { + prefix = "Poll::Ready(Some(Err("; + suffix = ")))"; + err_ty = ty; + } else { + return; + }; - let expr_err_ty = cx.typeck_results().expr_ty(err_arg); - let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt()); - let mut applicability = Applicability::MachineApplicable; - let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability); - let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) { - "" // already returns - } else { - "return " - }; - let suggestion = if err_ty == expr_err_ty { - format!("{ret_prefix}{prefix}{origin_snippet}{suffix}") - } else { - format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}") - }; + let expr_err_ty = cx.typeck_results().expr_ty(err_arg); + let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt()); + let mut applicability = Applicability::MachineApplicable; + let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability); + let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) { + "" // already returns + } else { + "return " + }; + let suggestion = if err_ty == expr_err_ty { + format!("{ret_prefix}{prefix}{origin_snippet}{suffix}") + } else { + format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}") + }; - span_lint_and_sugg( - cx, - TRY_ERR, - expr.span, - "returning an `Err(_)` with the `?` operator", - "try", - suggestion, - applicability, - ); - } + span_lint_and_sugg( + cx, + TRY_ERR, + expr.span, + "returning an `Err(_)` with the `?` operator", + "try", + suggestion, + applicability, + ); } } @@ -92,51 +90,45 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O /// Extracts the error type from Result. fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { - if_chain! { - if let ty::Adt(_, subst) = ty.kind(); - if is_type_diagnostic_item(cx, ty, sym::Result); - then { - Some(subst.type_at(1)) - } else { - None - } + if let ty::Adt(_, subst) = ty.kind() + && is_type_diagnostic_item(cx, ty, sym::Result) + { + Some(subst.type_at(1)) + } else { + None } } /// Extracts the error type from Poll>. fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { - if_chain! { - if let ty::Adt(def, subst) = ty.kind(); - if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()); - let ready_ty = subst.type_at(0); + if let ty::Adt(def, subst) = ty.kind() + && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()) + && let ready_ty = subst.type_at(0) - if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did()); - then { - Some(ready_subst.type_at(1)) - } else { - None - } + && let ty::Adt(ready_def, ready_subst) = ready_ty.kind() + && cx.tcx.is_diagnostic_item(sym::Result, ready_def.did()) + { + Some(ready_subst.type_at(1)) + } else { + None } } /// Extracts the error type from Poll>>. fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { - if_chain! { - if let ty::Adt(def, subst) = ty.kind(); - if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()); - let ready_ty = subst.type_at(0); + if let ty::Adt(def, subst) = ty.kind() + && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()) + && let ready_ty = subst.type_at(0) - if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did()); - let some_ty = ready_subst.type_at(0); + && let ty::Adt(ready_def, ready_subst) = ready_ty.kind() + && cx.tcx.is_diagnostic_item(sym::Option, ready_def.did()) + && let some_ty = ready_subst.type_at(0) - if let ty::Adt(some_def, some_subst) = some_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::Result, some_def.did()); - then { - Some(some_subst.type_at(1)) - } else { - None - } + && let ty::Adt(some_def, some_subst) = some_ty.kind() + && cx.tcx.is_diagnostic_item(sym::Result, some_def.did()) + { + Some(some_subst.type_at(1)) + } else { + None } } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index c6a1b45a9fa..0377af3f5db 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -125,17 +125,37 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_sp } fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - if_chain! { + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(src.hir_id) // check if replacement is mem::MaybeUninit::uninit().assume_init() - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(src.hir_id); - if cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id); - then { + && cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_WITH_UNINIT, + expr_span, + "replacing with `mem::MaybeUninit::uninit().assume_init()`", + "consider using", + format!( + "std::ptr::read({})", + snippet_with_applicability(cx, dest.span, "", &mut applicability) + ), + applicability, + ); + return; + } + + if let ExprKind::Call(repl_func, []) = src.kind + && let ExprKind::Path(ref repl_func_qpath) = repl_func.kind + && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() + { + if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, MEM_REPLACE_WITH_UNINIT, expr_span, - "replacing with `mem::MaybeUninit::uninit().assume_init()`", + "replacing with `mem::uninitialized()`", "consider using", format!( "std::ptr::read({})", @@ -143,40 +163,16 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' ), applicability, ); - return; - } - } - - if_chain! { - if let ExprKind::Call(repl_func, []) = src.kind; - if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - then { - if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_WITH_UNINIT, - expr_span, - "replacing with `mem::uninitialized()`", - "consider using", - format!( - "std::ptr::read({})", - snippet_with_applicability(cx, dest.span, "", &mut applicability) - ), - applicability, - ); - } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) && - !cx.typeck_results().expr_ty(src).is_primitive() { - span_lint_and_help( - cx, - MEM_REPLACE_WITH_UNINIT, - expr_span, - "replacing with `mem::zeroed()`", - None, - "consider using a default value or the `take_mut` crate instead", - ); - } + } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) && + !cx.typeck_results().expr_ty(src).is_primitive() { + span_lint_and_help( + cx, + MEM_REPLACE_WITH_UNINIT, + expr_span, + "replacing with `mem::zeroed()`", + None, + "consider using a default value or the `take_mut` crate instead", + ); } } } @@ -222,21 +218,19 @@ impl MemReplace { impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { + if let ExprKind::Call(func, [dest, src]) = expr.kind // Check that `expr` is a call to `mem::replace()` - if let ExprKind::Call(func, [dest, src]) = expr.kind; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); - then { - // Check that second argument is `Option::None` - if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { - check_replace_option_with_none(cx, dest, expr.span); - } else if self.msrv.meets(msrvs::MEM_TAKE) { - check_replace_with_default(cx, src, dest, expr.span); - } - check_replace_with_uninit(cx, src, dest, expr.span); + && let ExprKind::Path(ref func_qpath) = func.kind + && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::mem_replace, def_id) + { + // Check that second argument is `Option::None` + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + check_replace_option_with_none(cx, dest, expr.span); + } else if self.msrv.meets(msrvs::MEM_TAKE) { + check_replace_with_default(cx, src, dest, expr.span); } + check_replace_with_uninit(cx, src, dest, expr.span); } } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 3a8cc41748e..4e6a8c58bef 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -70,58 +70,52 @@ pub(crate) trait BindInsteadOfMap { closure_expr: &hir::Expr<'_>, closure_args_span: Span, ) -> bool { - if_chain! { - if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind; - if let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind; - if Self::is_variant(cx, path.res); - if !contains_return(inner_expr); - if let Some(msg) = Self::lint_msg(cx); - then { - let mut app = Applicability::MachineApplicable; - let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; - - let closure_args_snip = snippet(cx, closure_args_span, ".."); - let option_snip = snippet(cx, recv.span, ".."); - let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME); - span_lint_and_sugg( - cx, - BIND_INSTEAD_OF_MAP, - expr.span, - &msg, - "try", - note, - app, - ); - true - } else { - false - } + if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind + && let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind + && Self::is_variant(cx, path.res) + && !contains_return(inner_expr) + && let Some(msg) = Self::lint_msg(cx) + { + let mut app = Applicability::MachineApplicable; + let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; + + let closure_args_snip = snippet(cx, closure_args_span, ".."); + let option_snip = snippet(cx, recv.span, ".."); + let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME); + span_lint_and_sugg( + cx, + BIND_INSTEAD_OF_MAP, + expr.span, + &msg, + "try", + note, + app, + ); + true + } else { + false } } fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool { let mut suggs = Vec::new(); let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| { - if_chain! { - if !ret_expr.span.from_expansion(); - if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind; - if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind; - if Self::is_variant(cx, path.res); - if !contains_return(arg); - then { - suggs.push((ret_expr.span, arg.span.source_callsite())); - true - } else { - false - } + if !ret_expr.span.from_expansion() + && let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind + && let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind + && Self::is_variant(cx, path.res) + && !contains_return(arg) + { + suggs.push((ret_expr.span, arg.span.source_callsite())); + true + } else { + false } }); - let (span, msg) = if_chain! { - if can_sugg; - if let hir::ExprKind::MethodCall(segment, ..) = expr.kind; - if let Some(msg) = Self::lint_msg(cx); - then { (segment.ident.span, msg) } else { return false; } - }; + let (span, msg) = if can_sugg + && let hir::ExprKind::MethodCall(segment, ..) = expr.kind + && let Some(msg) = Self::lint_msg(cx) + { (segment.ident.span, msg) } else { return false; }; span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| { multispan_sugg_with_applicability( diag, @@ -139,12 +133,10 @@ pub(crate) trait BindInsteadOfMap { /// Lint use of `_.and_then(|x| Some(y))` for `Option`s fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool { - if_chain! { - if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def(); - if let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM); - if adt.did() == cx.tcx.parent(vid); - then {} else { return false; } - } + if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + && let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM) + && adt.did() == cx.tcx.parent(vid) + {} else { return false; } match arg.kind { hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => { diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs index 35370355f83..039b92da1e1 100644 --- a/clippy_lints/src/methods/bytecount.rs +++ b/clippy_lints/src/methods/bytecount.rs @@ -18,53 +18,51 @@ pub(super) fn check<'tcx>( filter_recv: &'tcx Expr<'_>, filter_arg: &'tcx Expr<'_>, ) { - if_chain! { - if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; - let body = cx.tcx.hir().body(body); - if let [param] = body.params; - if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; - if let ExprKind::Binary(ref op, l, r) = body.value.kind; - if op.node == BinOpKind::Eq; - if is_type_diagnostic_item(cx, + if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind + && let body = cx.tcx.hir().body(body) + && let [param] = body.params + && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind + && let ExprKind::Binary(ref op, l, r) = body.value.kind + && op.node == BinOpKind::Eq + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), - sym::SliceIter); - let operand_is_arg = |expr| { + sym::SliceIter) + && let operand_is_arg = (|expr| { let expr = peel_ref_operators(cx, peel_blocks(expr)); path_to_local_id(expr, arg_id) - }; - let needle = if operand_is_arg(l) { + }) + && let needle = if operand_is_arg(l) { r } else if operand_is_arg(r) { l } else { return; - }; - if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); - if !is_local_used(cx, needle, arg_id); - then { - let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = - filter_recv.kind { - let p = path.ident.name; - if p == sym::iter || p == sym::iter_mut { - receiver - } else { - filter_recv - } + } + && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind() + && !is_local_used(cx, needle, arg_id) + { + let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = + filter_recv.kind { + let p = path.ident.name; + if p == sym::iter || p == sym::iter_mut { + receiver } else { filter_recv - }; - let mut applicability = Applicability::MaybeIncorrect; - span_lint_and_sugg( - cx, - NAIVE_BYTECOUNT, - expr.span, - "you appear to be counting bytes the naive way", - "consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet_with_applicability(cx, haystack.span, "..", &mut applicability), - snippet_with_applicability(cx, needle.span, "..", &mut applicability)), - applicability, - ); - } + } + } else { + filter_recv + }; + let mut applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + NAIVE_BYTECOUNT, + expr.span, + "you appear to be counting bytes the naive way", + "consider using the bytecount crate", + format!("bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + applicability, + ); }; } diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs index 649fc46e4ad..eebd8428cff 100644 --- a/clippy_lints/src/methods/bytes_count_to_len.rs +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -14,23 +14,21 @@ pub(super) fn check<'tcx>( count_recv: &'tcx hir::Expr<'_>, bytes_recv: &'tcx hir::Expr<'_>, ) { - if_chain! { - if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); - if cx.tcx.type_of(impl_id).instantiate_identity().is_str(); - let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); - if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_COUNT_TO_LEN, - expr.span, - "using long and hard to read `.bytes().count()`", - "consider calling `.len()` instead", - format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)), - applicability - ); - } + if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(bytes_id) + && cx.tcx.type_of(impl_id).instantiate_identity().is_str() + && let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs() + && (ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String)) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_COUNT_TO_LEN, + expr.span, + "using long and hard to read `.bytes().count()`", + "consider calling `.len()` instead", + format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)), + applicability + ); }; } diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index d5897822eda..b773e762d93 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -27,51 +27,49 @@ pub(super) fn check<'tcx>( } } - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).instantiate_identity().is_str(); - if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind; - if (2..=6).contains(&ext_literal.as_str().len()); - let ext_str = ext_literal.as_str(); - if ext_str.starts_with('.'); - if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) - || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); - let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String); - then { - span_lint_and_then( - cx, - CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - recv.span.to(call_span), - "case-sensitive file extension comparison", - |diag| { - diag.help("consider using a case-insensitive comparison instead"); - if let Some(mut recv_source) = snippet_opt(cx, recv.span) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && cx.tcx.type_of(impl_id).instantiate_identity().is_str() + && let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind + && (2..=6).contains(&ext_literal.as_str().len()) + && let ext_str = ext_literal.as_str() + && ext_str.starts_with('.') + && (ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) + || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit())) + && let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs() + && (recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String)) + { + span_lint_and_then( + cx, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + recv.span.to(call_span), + "case-sensitive file extension comparison", + |diag| { + diag.help("consider using a case-insensitive comparison instead"); + if let Some(mut recv_source) = snippet_opt(cx, recv.span) { - if !cx.typeck_results().expr_ty(recv).is_ref() { - recv_source = format!("&{recv_source}"); - } + if !cx.typeck_results().expr_ty(recv).is_ref() { + recv_source = format!("&{recv_source}"); + } - let suggestion_source = reindent_multiline( - format!( - "std::path::Path::new({}) - .extension() - .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_source, ext_str.strip_prefix('.').unwrap()).into(), - true, - Some(indent_of(cx, call_span).unwrap_or(0) + 4) - ); + let suggestion_source = reindent_multiline( + format!( + "std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_source, ext_str.strip_prefix('.').unwrap()).into(), + true, + Some(indent_of(cx, call_span).unwrap_or(0) + 4) + ); - diag.span_suggestion( - recv.span.to(call_span), - "use std::path::Path", - suggestion_source, - Applicability::MaybeIncorrect, - ); - } + diag.span_suggestion( + recv.span.to(call_span), + "use std::path::Path", + suggestion_source, + Applicability::MaybeIncorrect, + ); } - ); - } + } + ); } } diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 0e41f3c2107..06c0ee2e691 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -15,34 +15,32 @@ pub(super) fn check( lint: &'static Lint, suggest: &str, ) -> bool { - if_chain! { - if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind; - if let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id)); - if Some(id) == cx.tcx.lang_items().option_some_variant(); - then { - let mut applicability = Applicability::MachineApplicable; - let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs(); + if let Some(args) = method_chain_args(info.chain, chain_methods) + && let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind + && let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id)) + && Some(id) == cx.tcx.lang_items().option_some_variant() + { + let mut applicability = Applicability::MachineApplicable; + let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs(); - if *self_ty.kind() != ty::Str { - return false; - } + if *self_ty.kind() != ty::Str { + return false; + } - span_lint_and_sugg( - cx, - lint, - info.expr.span, - &format!("you should use the `{suggest}` method"), - "like this", - format!("{}{}.{suggest}({})", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), - applicability, - ); + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{suggest}` method"), + "like this", + format!("{}{}.{suggest}({})", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), + snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), + applicability, + ); - return true; - } + return true; } false diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index c9d50a5b03d..a364bc9e525 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -15,28 +15,26 @@ pub(super) fn check( lint: &'static Lint, suggest: &str, ) -> bool { - if_chain! { - if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Lit(lit) = info.other.kind; - if let ast::LitKind::Char(c) = lit.node; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - lint, - info.expr.span, - &format!("you should use the `{suggest}` method"), - "like this", - format!("{}{}.{suggest}('{}')", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - c.escape_default()), - applicability, - ); + if let Some(args) = method_chain_args(info.chain, chain_methods) + && let hir::ExprKind::Lit(lit) = info.other.kind + && let ast::LitKind::Char(c) = lit.node + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{suggest}` method"), + "like this", + format!("{}{}.{suggest}('{}')", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), + c.escape_default()), + applicability, + ); - true - } else { - false - } + true + } else { + false } } diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index a8d4dd5e4f3..89df0652855 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -16,30 +16,28 @@ pub(super) fn check( err_span: Span, msrv: &Msrv, ) { - if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) // Test the version to make sure the lint can be showed (expect_err has been // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) - if msrv.meets(msrvs::EXPECT_ERR); + && msrv.meets(msrvs::EXPECT_ERR) // Grabs the `Result` type - let result_type = cx.typeck_results().expr_ty(recv); + && let result_type = cx.typeck_results().expr_ty(recv) // Tests if the T type in a `Result` is not None - if let Some(data_type) = get_data_type(cx, result_type); + && let Some(data_type) = get_data_type(cx, result_type) // Tests if the T type in a `Result` implements debug - if has_debug_impl(cx, data_type); + && has_debug_impl(cx, data_type) - then { - span_lint_and_sugg( - cx, - ERR_EXPECT, - err_span.to(expect_span), - "called `.err().expect()` on a `Result` value", - "try", - "expect_err".to_string(), - Applicability::MachineApplicable - ); - } + { + span_lint_and_sugg( + cx, + ERR_EXPECT, + err_span.to(expect_span), + "called `.err().expect()` on a `Result` value", + "try", + "expect_err".to_string(), + Applicability::MachineApplicable + ); }; } diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index 495b266529b..43a85f6e8a6 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -11,35 +11,33 @@ use super::EXTEND_WITH_DRAIN; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if_chain! { - if is_type_diagnostic_item(cx, ty, sym::Vec); + if is_type_diagnostic_item(cx, ty, sym::Vec) //check source object - if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind; - if src_method.ident.as_str() == "drain"; - let src_ty = cx.typeck_results().expr_ty(drain_vec); + && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind + && src_method.ident.as_str() == "drain" + && let src_ty = cx.typeck_results().expr_ty(drain_vec) //check if actual src type is mutable for code suggestion - let immutable = src_ty.is_mutable_ptr(); - let src_ty = src_ty.peel_refs(); - if is_type_diagnostic_item(cx, src_ty, sym::Vec); + && let immutable = src_ty.is_mutable_ptr() + && let src_ty = src_ty.peel_refs() + && is_type_diagnostic_item(cx, src_ty, sym::Vec) //check drain range - if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs(); - if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - EXTEND_WITH_DRAIN, - expr.span, - "use of `extend` instead of `append` for adding the full range of a second vector", - "try", - format!( - "{}.append({}{})", - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - if immutable { "" } else { "&mut " }, - snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability) - ), - applicability, - ); - } + && let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs() + && is_type_lang_item(cx, src_ty_range, LangItem::RangeFull) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + EXTEND_WITH_DRAIN, + expr.span, + "use of `extend` instead of `append` for adding the full range of a second vector", + "try", + format!( + "{}.append({}{})", + snippet_with_applicability(cx, recv.span, "..", &mut applicability), + if immutable { "" } else { "&mut " }, + snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability) + ), + applicability, + ); } } diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 3fef53739fb..362f2589329 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -20,21 +20,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let verb: &str; let lint_unary: &str; let help_unary: &str; - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(op, _) = parent.kind; - if op == hir::UnOp::Not; - then { - lint_unary = "!"; - verb = "denies"; - help_unary = ""; - span = parent.span; - } else { - lint_unary = ""; - verb = "covers"; - help_unary = "!"; - span = expr.span; - } + if let Some(parent) = get_parent_expr(cx, expr) + && let hir::ExprKind::Unary(op, _) = parent.kind + && op == hir::UnOp::Not + { + lint_unary = "!"; + verb = "denies"; + help_unary = ""; + span = parent.span; + } else { + lint_unary = ""; + verb = "covers"; + help_unary = "!"; + span = expr.span; } let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files"); let help_msg = format!("use `{help_unary}FileType::is_dir()` instead"); diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 22b67923e50..ee7a1538a5f 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -29,13 +29,11 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { - if_chain! { - if ident.name == method_name; - if let hir::ExprKind::Path(path) = &receiver.kind; - if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); - then { - return arg_id == *local - } + if ident.name == method_name + && let hir::ExprKind::Path(path) = &receiver.kind + && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) + { + return arg_id == *local } false }, @@ -139,11 +137,9 @@ impl<'tcx> OffendingFilterExpr<'tcx> { && path_to_local_id(map_arg_peeled, map_param_id)) && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| { // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; + let a_path = if !is_filter_param_ref + && let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind + { expr_path } else { a }; // let the filter closure arg and the map closure arg be equal path_to_local_id(a_path, filter_param_id) && path_to_local_id(b, map_param_id) @@ -305,87 +301,85 @@ pub(super) fn check( return; } - if_chain! { - if is_trait_method(cx, map_recv, sym::Iterator); + if is_trait_method(cx, map_recv, sym::Iterator) // filter(|x| ...is_some())... - if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; - let filter_body = cx.tcx.hir().body(filter_body_id); - if let [filter_param] = filter_body.params; + && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind + && let filter_body = cx.tcx.hir().body(filter_body_id) + && let [filter_param] = filter_body.params // optional ref pattern: `filter(|&x| ..)` - let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { (ref_pat, true) } else { (filter_param.pat, false) - }; + } - if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id); + && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind + && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) - if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; - let map_body = cx.tcx.hir().body(map_body_id); - if let [map_param] = map_body.params; - if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind + && let map_body = cx.tcx.hir().body(map_body_id) + && let [map_param] = map_body.params + && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind - if let Some(check_result) = - offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref); + && let Some(check_result) = + offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref) - then { - let span = filter_span.with_hi(expr.span.hi()); - let (filter_name, lint) = if is_find { - ("find", MANUAL_FIND_MAP) - } else { - ("filter", MANUAL_FILTER_MAP) - }; - let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); + { + let span = filter_span.with_hi(expr.span.hi()); + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) + } else { + ("filter", MANUAL_FILTER_MAP) + }; + let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); - let (sugg, note_and_span, applicability) = match check_result { - CheckResult::Method { map_arg, method, side_effect_expr_span } => { - let (to_opt, deref) = match method { - CalledMethod::ResultIsOk => (".ok()", String::new()), - CalledMethod::OptionIsSome => { - let derefs = cx.typeck_results() - .expr_adjustments(map_arg) - .iter() - .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) - .count(); + let (sugg, note_and_span, applicability) = match check_result { + CheckResult::Method { map_arg, method, side_effect_expr_span } => { + let (to_opt, deref) = match method { + CalledMethod::ResultIsOk => (".ok()", String::new()), + CalledMethod::OptionIsSome => { + let derefs = cx.typeck_results() + .expr_adjustments(map_arg) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); - ("", "*".repeat(derefs)) - } - }; + ("", "*".repeat(derefs)) + } + }; - let sugg = format!( - "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", - snippet(cx, map_arg.span, ".."), - ); - let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span { - let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \ - because this expression potentially contains side effects and will only execute once"; + let sugg = format!( + "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", + snippet(cx, map_arg.span, ".."), + ); + let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span { + let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \ + because this expression potentially contains side effects and will only execute once"; - (Some((note, span)), Applicability::MaybeIncorrect) - } else { - (None, Applicability::MachineApplicable) - }; + (Some((note, span)), Applicability::MaybeIncorrect) + } else { + (None, Applicability::MachineApplicable) + }; - (sugg, note_and_span, applicability) - } - CheckResult::PatternMatching { variant_span, variant_ident } => { - let pat = snippet(cx, variant_span, ""); + (sugg, note_and_span, applicability) + } + CheckResult::PatternMatching { variant_span, variant_ident } => { + let pat = snippet(cx, variant_span, ""); - (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \ - {pat} => Some({variant_ident}), \ - _ => None \ - }})"), None, Applicability::MachineApplicable) - } - }; - span_lint_and_then(cx, lint, span, &msg, |diag| { - diag.span_suggestion(span, "try", sugg, applicability); + (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \ + {pat} => Some({variant_ident}), \ + _ => None \ + }})"), None, Applicability::MachineApplicable) + } + }; + span_lint_and_then(cx, lint, span, &msg, |diag| { + diag.span_suggestion(span, "try", sugg, applicability); - if let Some((note, span)) = note_and_span { - diag.span_note(span, note); - } - }); - } + if let Some((note, span)) = note_and_span { + diag.span_note(span, note); + } + }); } } diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 4040d3a5fe1..cee8d8eb029 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -12,28 +12,26 @@ use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { - if_chain! { - if is_path_diagnostic_item(cx, func, sym::from_iter_fn); - let ty = cx.typeck_results().expr_ty(expr); - let arg_ty = cx.typeck_results().expr_ty(&args[0]); - if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + if is_path_diagnostic_item(cx, func, sym::from_iter_fn) + && let ty = cx.typeck_results().expr_ty(expr) + && let arg_ty = cx.typeck_results().expr_ty(&args[0]) + && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) - if implements_trait(cx, arg_ty, iter_id, &[]); - then { - // `expr` implements `FromIterator` trait - let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - let turbofish = extract_turbofish(cx, expr, ty); - let sugg = format!("{iter_expr}.collect::<{turbofish}>()"); - span_lint_and_sugg( - cx, - FROM_ITER_INSTEAD_OF_COLLECT, - expr.span, - "usage of `FromIterator::from_iter`", - "use `.collect()` instead of `::from_iter()`", - sugg, - Applicability::MaybeIncorrect, - ); - } + && implements_trait(cx, arg_ty, iter_id, &[]) + { + // `expr` implements `FromIterator` trait + let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); + let turbofish = extract_turbofish(cx, expr, ty); + let sugg = format!("{iter_expr}.collect::<{turbofish}>()"); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + sugg, + Applicability::MaybeIncorrect, + ); } } @@ -43,41 +41,37 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> } let call_site = expr.span.source_callsite(); - if_chain! { - if let Some(snippet) = snippet_opt(cx, call_site); - let snippet_split = snippet.split("::").collect::>(); - if let Some((_, elements)) = snippet_split.split_last(); + if let Some(snippet) = snippet_opt(cx, call_site) + && let snippet_split = snippet.split("::").collect::>() + && let Some((_, elements)) = snippet_split.split_last() - then { - if_chain! { - if let [type_specifier, _] = snippet_split.as_slice(); - if let Some(type_specifier) = strip_angle_brackets(type_specifier); - if let Some((type_specifier, ..)) = type_specifier.split_once(" as "); - then { - type_specifier.to_string() - } else { - // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) - if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) { - // remove the type specifier from the path elements - let without_ts = elements.iter().filter_map(|e| { - if e == type_specifier { None } else { Some((*e).to_string()) } - }).collect::>(); - // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) - format!("{}{type_specifier}", without_ts.join("::")) - } else { - // type is not explicitly specified so wildcards are needed - // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` - let ty_str = ty.to_string(); - let start = ty_str.find('<').unwrap_or(0); - let end = ty_str.find('>').unwrap_or(ty_str.len()); - let nb_wildcard = ty_str[start..end].split(',').count(); - let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{wildcards}>", elements.join("::")) - } - } - } + { + if let [type_specifier, _] = snippet_split.as_slice() + && let Some(type_specifier) = strip_angle_brackets(type_specifier) + && let Some((type_specifier, ..)) = type_specifier.split_once(" as ") + { + type_specifier.to_string() } else { - ty.to_string() + // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) + format!("{}{type_specifier}", without_ts.join("::")) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or(ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{wildcards}>", elements.join("::")) + } } + } else { + ty.to_string() } } diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index 2e1dd3ec649..9b6f76f0f42 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -17,13 +17,24 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, ) { - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - let identity = cx.tcx.type_of(impl_id).instantiate_identity(); - if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; - then { - if identity.is_slice() { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && let identity = cx.tcx.type_of(impl_id).instantiate_identity() + && let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind + { + if identity.is_slice() { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.first()"), + app, + ); + } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){ let mut app = Applicability::MachineApplicable; let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); span_lint_and_sugg( @@ -32,22 +43,9 @@ pub(super) fn check<'tcx>( expr.span, &format!("accessing first element with `{slice_name}.get(0)`"), "try", - format!("{slice_name}.first()"), + format!("{slice_name}.front()"), app, ); - } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){ - let mut app = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), - "try", - format!("{slice_name}.front()"), - app, - ); - } } } } diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index e91ce64d8c8..73747340ef1 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -11,34 +11,32 @@ use rustc_span::sym; use super::IMPLICIT_CLONE; pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { - if_chain! { - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_clone_like(cx, method_name, method_def_id); - let return_type = cx.typeck_results().expr_ty(expr); - let input_type = cx.typeck_results().expr_ty(recv); - let (input_type, ref_count) = peel_mid_ty_refs(input_type); - if !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned)); - if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())); - if return_type == input_type; - if let Some(clone_trait) = cx.tcx.lang_items().clone_trait(); - if implements_trait(cx, return_type, clone_trait, &[]); - then { - let mut app = Applicability::MachineApplicable; - let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; - span_lint_and_sugg( - cx, - IMPLICIT_CLONE, - expr.span, - &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), - "consider using", - if ref_count > 1 { - format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1)) - } else { - format!("{recv_snip}.clone()") - }, - app, - ); - } + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && is_clone_like(cx, method_name, method_def_id) + && let return_type = cx.typeck_results().expr_ty(expr) + && let input_type = cx.typeck_results().expr_ty(recv) + && let (input_type, ref_count) = peel_mid_ty_refs(input_type) + && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned)) + && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())) + && return_type == input_type + && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() + && implements_trait(cx, return_type, clone_trait, &[]) + { + let mut app = Applicability::MachineApplicable; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; + span_lint_and_sugg( + cx, + IMPLICIT_CLONE, + expr.span, + &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), + "consider using", + if ref_count > 1 { + format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1)) + } else { + format!("{recv_snip}.clone()") + }, + app, + ); } } diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 6686d42c95f..c0b7b3ae972 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -18,37 +18,35 @@ pub fn check( receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>], ) { - if_chain! { - if args.is_empty() && method_name == sym::to_string; - if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did); - if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id); - let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver); - let self_ty = args.type_at(0); - let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); - if deref_count >= 1; - if specializes_tostring(cx, deref_self_ty); - then { - span_lint_and_then( - cx, - INEFFICIENT_TO_STRING, - expr.span, - &format!("calling `to_string` on `{arg_ty}`"), - |diag| { - diag.help(format!( - "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" - )); - let mut applicability = Applicability::MachineApplicable; - let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability); - diag.span_suggestion( - expr.span, - "try dereferencing the receiver", - format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)), - applicability, - ); - }, - ); - } + if args.is_empty() && method_name == sym::to_string + && let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did) + && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id) + && let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver) + && let self_ty = args.type_at(0) + && let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty) + && deref_count >= 1 + && specializes_tostring(cx, deref_self_ty) + { + span_lint_and_then( + cx, + INEFFICIENT_TO_STRING, + expr.span, + &format!("calling `to_string` on `{arg_ty}`"), + |diag| { + diag.help(format!( + "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" + )); + let mut applicability = Applicability::MachineApplicable; + let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability); + diag.span_suggestion( + expr.span, + "try dereferencing the receiver", + format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)), + applicability, + ); + }, + ); } } diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 8adf9e37059..7bb32d6ea65 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -19,24 +19,22 @@ pub(super) fn check( receiver: &hir::Expr<'_>, ) { let self_ty = cx.typeck_results().expr_ty_adjusted(receiver); - if_chain! { - if let ty::Ref(..) = self_ty.kind(); - if method_name == sym::into_iter; - if is_trait_method(cx, expr, sym::IntoIterator); - if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty); - then { - span_lint_and_sugg( - cx, - INTO_ITER_ON_REF, - method_span, - &format!( - "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`", - ), - "call directly", - method_name.to_string(), - Applicability::MachineApplicable, - ); - } + if let ty::Ref(..) = self_ty.kind() + && method_name == sym::into_iter + && is_trait_method(cx, expr, sym::IntoIterator) + && let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty) + { + span_lint_and_sugg( + cx, + INTO_ITER_ON_REF, + method_span, + &format!( + "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`", + ), + "call directly", + method_name.to_string(), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index bde6f92b076..da841ca50f4 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -10,22 +10,20 @@ use rustc_span::sym; use super::ITER_CLONED_COLLECT; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) { - if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec); - if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)); - if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) + && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)) + && let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) - then { - span_lint_and_sugg( - cx, - ITER_CLONED_COLLECT, - to_replace, - &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable"), - "try", - ".to_vec()".to_string(), - Applicability::MachineApplicable, - ); - } + { + span_lint_and_sugg( + cx, + ITER_CLONED_COLLECT, + to_replace, + &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable"), + "try", + ".to_vec()".to_string(), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 625325d4cf5..687aee267fa 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -22,64 +22,60 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v ) { - if_chain! { - if !expr.span.from_expansion(); - if let ExprKind::Closure(c) = m_arg.kind; - if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body); - if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; + if !expr.span.from_expansion() + && let ExprKind::Closure(c) = m_arg.kind + && let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body) + && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind - let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { + && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, - }; + } - let ty = cx.typeck_results().expr_ty(recv); - if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); + && let ty = cx.typeck_results().expr_ty(recv) + && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)) - then { - let mut applicability = rustc_errors::Applicability::MachineApplicable; - let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); - let into_prefix = if map_type == "into_iter" {"into_"} else {""}; + { + let mut applicability = rustc_errors::Applicability::MachineApplicable; + let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); + let into_prefix = if map_type == "into_iter" {"into_"} else {""}; - if_chain! { - if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind; - if let [local_ident] = path.segments; - if local_ident.ident.as_str() == bound_ident.as_str(); + if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind + && let [local_ident] = path.segments + && local_ident.ident.as_str() == bound_ident.as_str() - then { - span_lint_and_sugg( - cx, - ITER_KV_MAP, - expr.span, - &format!("iterating on a map's {replacement_kind}s"), - "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"), - applicability, - ); - } else { - let ref_annotation = if annotation.0 == ByRef::Yes { - "ref " - } else { - "" - }; - let mut_annotation = if annotation.1 == Mutability::Mut { - "mut " - } else { - "" - }; - span_lint_and_sugg( - cx, - ITER_KV_MAP, - expr.span, - &format!("iterating on a map's {replacement_kind}s"), - "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", - snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), - applicability, - ); - } - } + { + span_lint_and_sugg( + cx, + ITER_KV_MAP, + expr.span, + &format!("iterating on a map's {replacement_kind}s"), + "try", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"), + applicability, + ); + } else { + let ref_annotation = if annotation.0 == ByRef::Yes { + "ref " + } else { + "" + }; + let mut_annotation = if annotation.1 == Mutability::Mut { + "mut " + } else { + "" + }; + span_lint_and_sugg( + cx, + ITER_KV_MAP, + expr.span, + &format!("iterating on a map's {replacement_kind}s"), + "try", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", + snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), + applicability, + ); } } } diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index 8f885e9f729..9d97370116e 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -26,29 +26,27 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() { // caller is a Slice - if_chain! { - if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind; - if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) - = higher::Range::hir(index_expr); - if let hir::ExprKind::Lit(start_lit) = &start_expr.kind; - if let ast::LitKind::Int(start_idx, _) = start_lit.node; - then { - let mut applicability = Applicability::MachineApplicable; - let suggest = if start_idx == 0 { - format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) - } else { - format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) - }; - span_lint_and_sugg( - cx, - ITER_NEXT_SLICE, - expr.span, - "using `.iter().next()` on a Slice without end index", - "try calling", - suggest, - applicability, - ); - } + if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind + && let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) + = higher::Range::hir(index_expr) + && let hir::ExprKind::Lit(start_lit) = &start_expr.kind + && let ast::LitKind::Int(start_idx, _) = start_lit.node + { + let mut applicability = Applicability::MachineApplicable; + let suggest = if start_idx == 0 { + format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) + } else { + format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) + }; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "using `.iter().next()` on a Slice without end index", + "try calling", + suggest, + applicability, + ); } } else if is_vec_or_array(cx, caller_expr) { // caller is a Vec or an Array diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index 39af52141bb..872476a314c 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -19,18 +19,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr expr.span.trim_start(recv.span).unwrap(), "called `skip(..).next()` on an iterator", |diag| { - if_chain! { - if let Some(id) = path_to_local(recv); - if let Node::Pat(pat) = cx.tcx.hir().get(id); - if let PatKind::Binding(ann, _, _, _) = pat.kind; - if ann != BindingAnnotation::MUT; - then { - application = Applicability::Unspecified; - diag.span_help( - pat.span, - format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), - ); - } + if let Some(id) = path_to_local(recv) + && let Node::Pat(pat) = cx.tcx.hir().get(id) + && let PatKind::Binding(ann, _, _, _) = pat.kind + && ann != BindingAnnotation::MUT + { + application = Applicability::Unspecified; + diag.span_help( + pat.span, + format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), + ); } diag.span_suggestion( diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index 3031193e531..35d5e090cc8 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -18,30 +18,28 @@ pub(super) fn check<'tcx>( or_expr: &'tcx Expr<'_>, map_expr: &'tcx Expr<'_>, ) { - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option); - if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind; - if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr); - if is_ok_wrapping(cx, map_expr); - if let Some(recv_snippet) = snippet_opt(cx, recv.span); - if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); - if let Some(indent) = indent_of(cx, expr.span); - then { - let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); - span_lint_and_sugg( - cx, - MANUAL_OK_OR, - expr.span, - "this pattern reimplements `Option::ok_or`", - "replace with", - format!( - "{recv_snippet}.ok_or({reindented_err_arg_snippet})" - ), - Applicability::MachineApplicable, - ); - } + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option) + && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind + && is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr) + && is_ok_wrapping(cx, map_expr) + && let Some(recv_snippet) = snippet_opt(cx, recv.span) + && let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span) + && let Some(indent) = indent_of(cx, expr.span) + { + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + span_lint_and_sugg( + cx, + MANUAL_OK_OR, + expr.span, + "this pattern reimplements `Option::ok_or`", + "replace with", + format!( + "{recv_snippet}.ok_or({reindented_err_arg_snippet})" + ), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 540425eef8c..464d4c37a87 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -69,16 +69,14 @@ enum MinMax { fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { // `T::max_value()` `T::min_value()` inherent methods - if_chain! { - if let hir::ExprKind::Call(func, args) = &expr.kind; - if args.is_empty(); - if let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind; - then { - match segment.ident.as_str() { - "max_value" => return Some(MinMax::Max), - "min_value" => return Some(MinMax::Min), - _ => {} - } + if let hir::ExprKind::Call(func, args) = &expr.kind + && args.is_empty() + && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind + { + match segment.ident.as_str() { + "max_value" => return Some(MinMax::Max), + "min_value" => return Some(MinMax::Min), + _ => {} } } diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index ab13d30d845..5b4517f3d6c 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -55,43 +55,41 @@ pub(super) fn check( take_self_arg: &Expr<'_>, take_arg: &Expr<'_>, ) { - if_chain! { - if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; - if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat); - if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String); - if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); - if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id); - if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg); - let ctxt = collect_expr.span.ctxt(); - if ctxt == take_expr.span.ctxt(); - if ctxt == take_self_arg.span.ctxt(); - then { - let mut app = Applicability::MachineApplicable; - let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0; + if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind + && is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat) + && is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String) + && let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id) + && let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator) + && cx.tcx.trait_of_item(take_id) == Some(iter_trait_id) + && let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg) + && let ctxt = collect_expr.span.ctxt() + && ctxt == take_expr.span.ctxt() + && ctxt == take_self_arg.span.ctxt() + { + let mut app = Applicability::MachineApplicable; + let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0; - let val_str = match repeat_kind { - RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return, - RepeatKind::Char('\'') => r#""'""#.into(), - RepeatKind::Char('"') => r#""\"""#.into(), - RepeatKind::Char(_) => - match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) { - Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])), - s @ Cow::Borrowed(_) => s, - }, - RepeatKind::String => - Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(), - }; + let val_str = match repeat_kind { + RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return, + RepeatKind::Char('\'') => r#""'""#.into(), + RepeatKind::Char('"') => r#""\"""#.into(), + RepeatKind::Char(_) => + match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) { + Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])), + s @ Cow::Borrowed(_) => s, + }, + RepeatKind::String => + Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(), + }; - span_lint_and_sugg( - cx, - MANUAL_STR_REPEAT, - collect_expr.span, - "manual implementation of `str::repeat` using iterators", - "try", - format!("{val_str}.repeat({count_snip})"), - app - ) - } + span_lint_and_sugg( + cx, + MANUAL_STR_REPEAT, + collect_expr.span, + "manual implementation of `str::repeat` using iterators", + "try", + format!("{val_str}.repeat({count_snip})"), + app + ) } } diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index e0f8cb1b955..417bcc41a28 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -16,57 +16,53 @@ use rustc_span::{sym, Span}; use super::MAP_CLONE; pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) { - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); - if cx.tcx.impl_of_method(method_id) + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && (cx.tcx.impl_of_method(method_id) .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option)) - || is_diag_trait_item(cx, method_id, sym::Iterator); - if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; - then { - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(closure_body.value); - match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::NONE, .., name, None - ) = inner.kind { - if ident_eq(name, closure_expr) { - lint_explicit_closure(cx, e.span, recv.span, true, msrv); - } - }, - hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { - match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { - if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { - lint_explicit_closure(cx, e.span, recv.span, true, msrv); - } + || is_diag_trait_item(cx, method_id, sym::Iterator)) + && let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind + { + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(closure_body.value); + match closure_body.params[0].pat.kind { + hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( + hir::BindingAnnotation::NONE, .., name, None + ) = inner.kind { + if ident_eq(name, closure_expr) { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + }, + hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { + match closure_expr.kind { + hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { + if ident_eq(name, inner) { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); } - }, - hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! { - if ident_eq(name, obj) && method.ident.name == sym::clone; - if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); - if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); - if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); - // no autoderefs - if !cx.typeck_results().expr_adjustments(obj).iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); - then { - let obj_ty = cx.typeck_results().expr_ty(obj); - if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, *ty); - lint_explicit_closure(cx, e.span, recv.span, copy, msrv); - } - } else { - lint_needless_cloning(cx, e.span, recv.span); - } + } + }, + hir::ExprKind::MethodCall(method, obj, [], _) => if ident_eq(name, obj) && method.ident.name == sym::clone + && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) + && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) + && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) + // no autoderefs + && !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) + { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, *ty); + lint_explicit_closure(cx, e.span, recv.span, copy, msrv); } - }, - _ => {}, - } - }, - _ => {}, - } + } else { + lint_needless_cloning(cx, e.span, recv.span); + } + }, + _ => {}, + } + }, + _ => {}, } } } diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index 01cdd02e602..0f8cacc3435 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -13,26 +13,24 @@ use super::MAP_COLLECT_RESULT_UNIT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) { // return of collect `Result<(),_>` let collect_ret_ty = cx.typeck_results().expr_ty(expr); - if_chain! { - if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result); - if let ty::Adt(_, args) = collect_ret_ty.kind(); - if let Some(result_t) = args.types().next(); - if result_t.is_unit(); + if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result) + && let ty::Adt(_, args) = collect_ret_ty.kind() + && let Some(result_t) = args.types().next() + && result_t.is_unit() // get parts for snippet - then { - span_lint_and_sugg( - cx, - MAP_COLLECT_RESULT_UNIT, - expr.span, - "`.map().collect()` can be replaced with `.try_for_each()`", - "try", - format!( - "{}.try_for_each({})", - snippet(cx, iter.span, ".."), - snippet(cx, map_fn.span, "..") - ), - Applicability::MachineApplicable, - ); - } + { + span_lint_and_sugg( + cx, + MAP_COLLECT_RESULT_UNIT, + expr.span, + "`.map().collect()` can be replaced with `.try_for_each()`", + "try", + format!( + "{}.try_for_each({})", + snippet(cx, iter.span, ".."), + snippet(cx, map_fn.span, "..") + ), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 57581363cfa..88545b7286c 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -19,22 +19,20 @@ pub(super) fn check( ) { let caller_ty = cx.typeck_results().expr_ty(caller); - if_chain! { - if is_trait_method(cx, expr, sym::Iterator) + if (is_trait_method(cx, expr, sym::Iterator) || is_type_diagnostic_item(cx, caller_ty, sym::Result) - || is_type_diagnostic_item(cx, caller_ty, sym::Option); - if is_expr_untyped_identity_function(cx, map_arg); - if let Some(sugg_span) = expr.span.trim_start(caller.span); - then { - span_lint_and_sugg( - cx, - MAP_IDENTITY, - sugg_span, - "unnecessary map of the identity function", - &format!("remove the call to `{name}`"), - String::new(), - Applicability::MachineApplicable, - ) - } + || is_type_diagnostic_item(cx, caller_ty, sym::Option)) + && is_expr_untyped_identity_function(cx, map_arg) + && let Some(sugg_span) = expr.span.trim_start(caller.span) + { + span_lint_and_sugg( + cx, + MAP_IDENTITY, + sugg_span, + "unnecessary map of the identity function", + &format!("remove the call to `{name}`"), + String::new(), + Applicability::MachineApplicable, + ) } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a71a136eba5..1664a313fa9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3977,44 +3977,40 @@ impl<'tcx> LateLintPass<'tcx> for Methods { return; } - if_chain! { - if let TraitItemKind::Fn(ref sig, _) = item.kind; - if sig.decl.implicit_self.has_implicit_self(); - if let Some(first_arg_hir_ty) = sig.decl.inputs.first(); - if let Some(&first_arg_ty) = cx.tcx.fn_sig(item.owner_id) + if let TraitItemKind::Fn(ref sig, _) = item.kind + && sig.decl.implicit_self.has_implicit_self() + && let Some(first_arg_hir_ty) = sig.decl.inputs.first() + && let Some(&first_arg_ty) = cx.tcx.fn_sig(item.owner_id) .instantiate_identity() .inputs() .skip_binder() - .first(); - then { - let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); - wrong_self_convention::check( - cx, - item.ident.name.as_str(), - self_ty, - first_arg_ty, - first_arg_hir_ty.span, - false, - true, - ); - } - } - - if_chain! { - if item.ident.name == sym::new; - if let TraitItemKind::Fn(_, _) = item.kind; - let ret_ty = return_ty(cx, item.owner_id); + .first() + { let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty(); - if !ret_ty.contains(self_ty); + wrong_self_convention::check( + cx, + item.ident.name.as_str(), + self_ty, + first_arg_ty, + first_arg_hir_ty.span, + false, + true, + ); + } - then { - span_lint( - cx, - NEW_RET_NO_SELF, - item.span, - "methods called `new` usually return `Self`", - ); - } + if item.ident.name == sym::new + && let TraitItemKind::Fn(_, _) = item.kind + && let ret_ty = return_ty(cx, item.owner_id) + && let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty() + && !ret_ty.contains(self_ty) + + { + span_lint( + cx, + NEW_RET_NO_SELF, + item.span, + "methods called `new` usually return `Self`", + ); } } diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index 2855e23bf5b..15ce7c2eee6 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -11,22 +11,20 @@ use rustc_span::{sym, Span}; use super::MUT_MUTEX_LOCK; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { - if_chain! { - if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)); - if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex); - then { - span_lint_and_sugg( - cx, - MUT_MUTEX_LOCK, - name_span, - "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", - "change this to", - "get_mut".to_owned(), - Applicability::MaybeIncorrect, - ); - } + if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)) + && let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind() + && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex) + { + span_lint_and_sugg( + cx, + MUT_MUTEX_LOCK, + name_span, + "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", + "change this to", + "get_mut".to_owned(), + Applicability::MaybeIncorrect, + ); } } diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs index 01655e860c4..f6ba165a9a1 100644 --- a/clippy_lints/src/methods/no_effect_replace.rs +++ b/clippy_lints/src/methods/no_effect_replace.rs @@ -19,17 +19,15 @@ pub(super) fn check<'tcx>( return; } - if_chain! { - if let ExprKind::Lit(spanned) = &arg1.kind; - if let Some(param1) = lit_string_value(&spanned.node); + if let ExprKind::Lit(spanned) = &arg1.kind + && let Some(param1) = lit_string_value(&spanned.node) - if let ExprKind::Lit(spanned) = &arg2.kind; - if let LitKind::Str(param2, _) = &spanned.node; - if param1 == param2.as_str(); + && let ExprKind::Lit(spanned) = &arg2.kind + && let LitKind::Str(param2, _) = &spanned.node + && param1 == param2.as_str() - then { - span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself"); - } + { + span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself"); } if SpanlessEq::new(cx).eq_expr(arg1, arg2) { diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index f2ef42933df..7c86c820a42 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -10,23 +10,21 @@ use super::OK_EXPECT; /// lint use of `ok().expect()` for `Result`s pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { - if_chain! { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) // lint if the caller of `ok()` is a `Result` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - let result_type = cx.typeck_results().expr_ty(recv); - if let Some(error_type) = get_error_type(cx, result_type); - if has_debug_impl(cx, error_type); + && let result_type = cx.typeck_results().expr_ty(recv) + && let Some(error_type) = get_error_type(cx, result_type) + && has_debug_impl(cx, error_type) - then { - span_lint_and_help( - cx, - OK_EXPECT, - expr.span, - "called `ok().expect()` on a `Result` value", - None, - "you can call `expect()` directly on the `Result`", - ); - } + { + span_lint_and_help( + cx, + OK_EXPECT, + expr.span, + "called `ok().expect()` on a `Result` value", + None, + "you can call `expect()` directly on the `Result`", + ); } } diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 7b81d4571b2..9463c39229d 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -58,34 +58,30 @@ pub(super) fn check( match &closure_expr.kind { hir::ExprKind::MethodCall(_, receiver, [], _) => { - if_chain! { - if path_to_local_id(receiver, closure_body.params[0].pat.hir_id); - let adj = cx + if path_to_local_id(receiver, closure_body.params[0].pat.hir_id) + && let adj = cx .typeck_results() .expr_adjustments(receiver) .iter() .map(|x| &x.kind) - .collect::>(); - if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj; - then { - let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); - cx.tcx.is_diagnostic_item(sym::deref_method, method_did) - || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) - || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) - } else { - false - } + .collect::>() + && let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj + { + let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); + cx.tcx.is_diagnostic_item(sym::deref_method, method_did) + || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) + || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) + } else { + false } }, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, inner) if same_mutability(m) => { - if_chain! { - if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind; - if let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind; - then { - path_to_local_id(inner2, closure_body.params[0].pat.hir_id) - } else { - false - } + if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind + && let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind + { + path_to_local_id(inner2, closure_body.params[0].pat.hir_id) + } else { + false } }, _ => false, diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index cb6a2306857..418e6a7d6a0 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -58,27 +58,25 @@ pub(super) fn check<'tcx>( if is_option { let self_snippet = snippet(cx, recv.span, ".."); - if_chain! { - if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind; - let arg_snippet = snippet(cx, fn_decl_span, ".."); - let body = cx.tcx.hir().body(body); - if let Some((func, [arg_char])) = reduce_unit_expression(body.value); - if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id)); - if Some(id) == cx.tcx.lang_items().option_some_variant(); - then { - let func_snippet = snippet(cx, arg_char.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `map(..)` instead"; - return span_lint_and_sugg( - cx, - OPTION_MAP_OR_NONE, - expr.span, - msg, - "try using `map` instead", - format!("{self_snippet}.map({arg_snippet} {func_snippet})"), - Applicability::MachineApplicable, - ); - } + if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind + && let arg_snippet = snippet(cx, fn_decl_span, "..") + && let body = cx.tcx.hir().body(body) + && let Some((func, [arg_char])) = reduce_unit_expression(body.value) + && let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id)) + && Some(id) == cx.tcx.lang_items().option_some_variant() + { + let func_snippet = snippet(cx, arg_char.span, ".."); + let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ + `map(..)` instead"; + return span_lint_and_sugg( + cx, + OPTION_MAP_OR_NONE, + expr.span, + msg, + "try using `map` instead", + format!("{self_snippet}.map({arg_snippet} {func_snippet})"), + Applicability::MachineApplicable, + ); } let func_snippet = snippet(cx, map_arg.span, ".."); diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b942346d5c3..6d970dbfab2 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -131,54 +131,52 @@ pub(super) fn check<'tcx>( (sym::Result, true, &["or", "unwrap_or"], "else"), ]; - if_chain! { - if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); - - if switch_to_lazy_eval(cx, arg); - if !contains_return(arg); - - let self_ty = cx.typeck_results().expr_ty(self_expr); - - if let Some(&(_, fn_has_arguments, poss, suffix)) = - KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0)); - - if poss.contains(&name); - - then { - let ctxt = span.ctxt(); - let mut app = Applicability::HasPlaceholders; - let sugg = { - let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { - (false, Some(fun_span)) => (fun_span, false), - _ => (arg.span, true), - }; - - let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0; - let snip = if use_lambda { - let l_arg = if fn_has_arguments { "_" } else { "" }; - format!("|{l_arg}| {snip}") - } else { - snip.into_owned() - }; - - if let Some(f) = second_arg { - let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0; - format!("{snip}, {f}") - } else { - snip - } + if KNOW_TYPES.iter().any(|k| k.2.contains(&name)) + + && switch_to_lazy_eval(cx, arg) + && !contains_return(arg) + + && let self_ty = cx.typeck_results().expr_ty(self_expr) + + && let Some(&(_, fn_has_arguments, poss, suffix)) = + KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0)) + + && poss.contains(&name) + + { + let ctxt = span.ctxt(); + let mut app = Applicability::HasPlaceholders; + let sugg = { + let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { + (false, Some(fun_span)) => (fun_span, false), + _ => (arg.span, true), }; - let span_replace_word = method_span.with_hi(span.hi()); - span_lint_and_sugg( - cx, - OR_FUN_CALL, - span_replace_word, - &format!("use of `{name}` followed by a function call"), - "try", - format!("{name}_{suffix}({sugg})"), - app, - ); - } + + let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0; + let snip = if use_lambda { + let l_arg = if fn_has_arguments { "_" } else { "" }; + format!("|{l_arg}| {snip}") + } else { + snip.into_owned() + }; + + if let Some(f) = second_arg { + let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0; + format!("{snip}, {f}") + } else { + snip + } + }; + let span_replace_word = method_span.with_hi(span.hi()); + span_lint_and_sugg( + cx, + OR_FUN_CALL, + span_replace_word, + &format!("use of `{name}` followed by a function call"), + "try", + format!("{name}_{suffix}({sugg})"), + app, + ); } } diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs index 1c07d2a3a59..c292b93843b 100644 --- a/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -11,27 +11,25 @@ use std::path::{Component, Path}; use super::PATH_BUF_PUSH_OVERWRITE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf); - if let ExprKind::Lit(lit) = arg.kind; - if let LitKind::Str(ref path_lit, _) = lit.node; - if let pushed_path = Path::new(path_lit.as_str()); - if let Some(pushed_path_lit) = pushed_path.to_str(); - if pushed_path.has_root(); - if let Some(root) = pushed_path.components().next(); - if root == Component::RootDir; - then { - span_lint_and_sugg( - cx, - PATH_BUF_PUSH_OVERWRITE, - lit.span, - "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", - "try", - format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), - Applicability::MachineApplicable, - ); - } + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf) + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Str(ref path_lit, _) = lit.node + && let pushed_path = Path::new(path_lit.as_str()) + && let Some(pushed_path_lit) = pushed_path.to_str() + && pushed_path.has_root() + && let Some(root) = pushed_path.components().next() + && root == Component::RootDir + { + span_lint_and_sugg( + cx, + PATH_BUF_PUSH_OVERWRITE, + lit.span, + "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", + "try", + format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index f253d8de91f..dabeba0b3c3 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -9,25 +9,23 @@ use rustc_span::sym; use super::RANGE_ZIP_WITH_LEN; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) { - if_chain! { - if is_trait_method(cx, expr, sym::Iterator); + if is_trait_method(cx, expr, sym::Iterator) // range expression in `.zip()` call: `0..x.len()` - if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); - if is_integer_const(cx, start, 0); + && let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg) + && is_integer_const(cx, start, 0) // `.len()` call - if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind; - if len_path.ident.name == sym::len; + && let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind + && len_path.ident.name == sym::len // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind; - if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); - then { - span_lint(cx, - RANGE_ZIP_WITH_LEN, - expr.span, - &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, recv.span, "_")) - ); - } + && let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind + && let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind + && SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments) + { + span_lint(cx, + RANGE_ZIP_WITH_LEN, + expr.span, + &format!("it is more idiomatic to use `{}.iter().enumerate()`", + snippet(cx, recv.span, "_")) + ); } } diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 04ddaaa2f46..01dc28a4076 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -35,29 +35,27 @@ pub(super) fn check<'tcx>( // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; - let any_search_snippet = if_chain! { - if search_method == "find"; - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind; - let closure_body = cx.tcx.hir().body(body); - if let Some(closure_arg) = closure_body.params.first(); - then { - if let hir::PatKind::Ref(..) = closure_arg.pat.kind { - Some(search_snippet.replacen('&', "", 1)) - } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { - // `find()` provides a reference to the item, but `any` does not, - // so we should fix item usages for suggestion - if let Some(closure_sugg) = deref_closure_args(cx, search_arg) { - applicability = closure_sugg.applicability; - Some(closure_sugg.suggestion) - } else { - Some(search_snippet.to_string()) - } + let any_search_snippet = if search_method == "find" + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind + && let closure_body = cx.tcx.hir().body(body) + && let Some(closure_arg) = closure_body.params.first() + { + if let hir::PatKind::Ref(..) = closure_arg.pat.kind { + Some(search_snippet.replacen('&', "", 1)) + } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { + // `find()` provides a reference to the item, but `any` does not, + // so we should fix item usages for suggestion + if let Some(closure_sugg) = deref_closure_args(cx, search_arg) { + applicability = closure_sugg.applicability; + Some(closure_sugg.suggestion) } else { - None + Some(search_snippet.to_string()) } } else { None } + } else { + None }; // add note if not multi-line if is_some { @@ -110,41 +108,39 @@ pub(super) fn check<'tcx>( self_ty.is_str() } }; - if_chain! { - if is_string_or_str_slice(search_recv); - if is_string_or_str_slice(search_arg); - then { - let msg = format!("called `{option_check_method}()` after calling `find()` on a string"); - match option_check_method { - "is_some" => { - let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - method_span.with_hi(expr.span.hi()), - &msg, - "use `contains()` instead", - format!("contains({find_arg})"), - applicability, - ); - }, - "is_none" => { - let string = snippet(cx, search_recv.span, ".."); - let mut applicability = Applicability::MachineApplicable; - let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); - span_lint_and_sugg( - cx, - SEARCH_IS_SOME, - expr.span, - &msg, - "use `!_.contains()` instead", - format!("!{string}.contains({find_arg})"), - applicability, - ); - }, - _ => (), - } + if is_string_or_str_slice(search_recv) + && is_string_or_str_slice(search_arg) + { + let msg = format!("called `{option_check_method}()` after calling `find()` on a string"); + match option_check_method { + "is_some" => { + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "use `contains()` instead", + format!("contains({find_arg})"), + applicability, + ); + }, + "is_none" => { + let string = snippet(cx, search_recv.span, ".."); + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + "use `!_.contains()` instead", + format!("!{string}.contains({find_arg})"), + applicability, + ); + }, + _ => (), } } } diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index 4d704ec39eb..d0b57bbf94e 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -45,24 +45,22 @@ pub(super) fn check( args: &[hir::Expr<'_>], ) { for &(method, pos) in &PATTERN_METHODS { - if_chain! { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind(); - if ty.is_str(); - if method_name.as_str() == method && args.len() > pos; - let arg = &args[pos]; - let mut applicability = Applicability::MachineApplicable; - if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability); - then { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "try using a `char` instead", - hint, - applicability, - ); - } + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() + && ty.is_str() + && method_name.as_str() == method && args.len() > pos + && let arg = &args[pos] + && let mut applicability = Applicability::MachineApplicable + && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) + { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "try using a `char` instead", + hint, + applicability, + ); } } } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 9da61bca52c..c6b79876115 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -286,21 +286,19 @@ fn parse_iter_usage<'tcx>( match (name.ident.as_str(), args) { ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), ("next_tuple", []) => { - return if_chain! { - if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); - if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); - if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()); - if let ty::Tuple(subs) = subs.type_at(0).kind(); - if subs.len() == 2; - then { - Some(IterUsage { - kind: IterUsageKind::NextTuple, - span: e.span, - unwrap_kind: None - }) - } else { - None - } + return if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE) + && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind() + && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) + && let ty::Tuple(subs) = subs.type_at(0).kind() + && subs.len() == 2 + { + Some(IterUsage { + kind: IterUsageKind::NextTuple, + span: e.span, + unwrap_kind: None + }) + } else { + None }; }, ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { @@ -308,18 +306,16 @@ fn parse_iter_usage<'tcx>( let span = if name.ident.as_str() == "nth" { e.span } else { - if_chain! { - if let Some((_, Node::Expr(next_expr))) = iter.next(); - if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind; - if next_name.ident.name == sym::next; - if next_expr.span.ctxt() == ctxt; - if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); - if cx.tcx.trait_of_item(next_id) == Some(iter_id); - then { - next_expr.span - } else { - return None; - } + if let Some((_, Node::Expr(next_expr))) = iter.next() + && let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind + && next_name.ident.name == sym::next + && next_expr.span.ctxt() == ctxt + && let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id) + && cx.tcx.trait_of_item(next_id) == Some(iter_id) + { + next_expr.span + } else { + return None; } }; (IterUsageKind::Nth(idx), span) diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 0dc7fe2a2c5..909f2fa6bfc 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -9,26 +9,24 @@ use rustc_span::sym; use super::SUSPICIOUS_MAP; pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) { - if_chain! { - if is_trait_method(cx, count_recv, sym::Iterator); - if let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind; - let closure_body = cx.tcx.hir().body(closure.body); - if !cx.typeck_results().expr_ty(closure_body.value).is_unit(); - then { - if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) { - // A variable is used mutably inside of the closure. Suppress the lint. - if !map_mutated_vars.is_empty() { - return; - } + if is_trait_method(cx, count_recv, sym::Iterator) + && let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind + && let closure_body = cx.tcx.hir().body(closure.body) + && !cx.typeck_results().expr_ty(closure_body.value).is_unit() + { + if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) { + // A variable is used mutably inside of the closure. Suppress the lint. + if !map_mutated_vars.is_empty() { + return; } - span_lint_and_help( - cx, - SUSPICIOUS_MAP, - expr.span, - "this call to `map()` won't have an effect on the call to `count()`", - None, - "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`", - ); } + span_lint_and_help( + cx, + SUSPICIOUS_MAP, + expr.span, + "this call to `map()` won't have an effect on the call to `count()`", + None, + "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`", + ); } } diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 3cb2719e4a0..873968b6417 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -8,41 +8,39 @@ use rustc_span::source_map::Spanned; use super::SUSPICIOUS_SPLITN; pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) { - if_chain! { - if count <= 1; - if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(call_id); - if cx.tcx.impl_trait_ref(impl_id).is_none(); - let self_ty = cx.tcx.type_of(impl_id).instantiate_identity(); - if self_ty.is_slice() || self_ty.is_str(); - then { - // Ignore empty slice and string literals when used with a literal count. - if matches!(self_arg.kind, ExprKind::Array([])) - || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) - { - return; - } + if count <= 1 + && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(call_id) + && cx.tcx.impl_trait_ref(impl_id).is_none() + && let self_ty = cx.tcx.type_of(impl_id).instantiate_identity() + && (self_ty.is_slice() || self_ty.is_str()) + { + // Ignore empty slice and string literals when used with a literal count. + if matches!(self_arg.kind, ExprKind::Array([])) + || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) + { + return; + } - let (msg, note_msg) = if count == 0 { - (format!("`{method_name}` called with `0` splits"), - "the resulting iterator will always return `None`") + let (msg, note_msg) = if count == 0 { + (format!("`{method_name}` called with `0` splits"), + "the resulting iterator will always return `None`") + } else { + (format!("`{method_name}` called with `1` split"), + if self_ty.is_slice() { + "the resulting iterator will always return the entire slice followed by `None`" } else { - (format!("`{method_name}` called with `1` split"), - if self_ty.is_slice() { - "the resulting iterator will always return the entire slice followed by `None`" - } else { - "the resulting iterator will always return the entire string followed by `None`" - }) - }; + "the resulting iterator will always return the entire string followed by `None`" + }) + }; - span_lint_and_note( - cx, - SUSPICIOUS_SPLITN, - expr.span, - &msg, - None, - note_msg, - ); - } + span_lint_and_note( + cx, + SUSPICIOUS_SPLITN, + expr.span, + &msg, + None, + note_msg, + ); } } diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 9eb8d6e6e78..f1ffa8fd808 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -12,40 +12,38 @@ use rustc_span::sym; use super::SUSPICIOUS_TO_OWNED; pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool { - if_chain! { - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diag_trait_item(cx, method_def_id, sym::ToOwned); - let input_type = cx.typeck_results().expr_ty(expr); - if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind(); - if cx.tcx.is_diagnostic_item(sym::Cow, adt.did()); + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && is_diag_trait_item(cx, method_def_id, sym::ToOwned) + && let input_type = cx.typeck_results().expr_ty(expr) + && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind() + && cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) - then { - let mut app = Applicability::MaybeIncorrect; - let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; - span_lint_and_then( - cx, - SUSPICIOUS_TO_OWNED, - expr.span, - &with_forced_trimmed_paths!(format!( - "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" - )), - |diag| { - diag.span_suggestion( - expr.span, - "depending on intent, either make the Cow an Owned variant", - format!("{recv_snip}.into_owned()"), - app - ); - diag.span_suggestion( - expr.span, - "or clone the Cow itself", - format!("{recv_snip}.clone()"), - app - ); - } - ); - return true; - } + { + let mut app = Applicability::MaybeIncorrect; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; + span_lint_and_then( + cx, + SUSPICIOUS_TO_OWNED, + expr.span, + &with_forced_trimmed_paths!(format!( + "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" + )), + |diag| { + diag.span_suggestion( + expr.span, + "depending on intent, either make the Cow an Owned variant", + format!("{recv_snip}.into_owned()"), + app + ); + diag.span_suggestion( + expr.span, + "or clone the Cow itself", + format!("{recv_snip}.clone()"), + app + ); + } + ); + return true; } false } diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index bc9c518dbcf..fef309db462 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -10,18 +10,16 @@ use super::UNINIT_ASSUMED_INIT; /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter) pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::Call(callee, args) = recv.kind; - if args.is_empty(); - if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); - if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); - then { - span_lint( - cx, - UNINIT_ASSUMED_INIT, - expr.span, - "this call for this type may be undefined behavior" - ); - } + if let hir::ExprKind::Call(callee, args) = recv.kind + && args.is_empty() + && is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit) + && !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)) + { + span_lint( + cx, + UNINIT_ASSUMED_INIT, + expr.span, + "this call for this type may be undefined behavior" + ); } } diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 6e23754bf46..7694cd42beb 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -61,57 +61,55 @@ fn check_fold_with_op( op: hir::BinOpKind, replacement: Replacement, ) { - if_chain! { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind // Extract the body of the closure passed to fold - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(closure_body.value); + && let closure_body = cx.tcx.hir().body(body) + && let closure_expr = peel_blocks(closure_body.value) // Check if the closure body is of the form `acc some_expr(x)` - if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; - if bin_op.node == op; + && let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind + && bin_op.node == op // Extract the names of the two arguments to the closure - if let [param_a, param_b] = closure_body.params; - if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind; - if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; - - if path_to_local_id(left_expr, first_arg_id); - if replacement.has_args || path_to_local_id(right_expr, second_arg_id); - - then { - let mut applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) - } else { - String::new() - }; - - let sugg = if replacement.has_args { - format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", - method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!( - "{method}{turbofish}()", - method = replacement.method_name, - ) - }; - - span_lint_and_sugg( - cx, - UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), - // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) - "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, - ); - } + && let [param_a, param_b] = closure_body.params + && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind + && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind + + && path_to_local_id(left_expr, first_arg_id) + && (replacement.has_args || path_to_local_id(right_expr, second_arg_id)) + + { + let mut applicability = Applicability::MachineApplicable; + + let turbofish = if replacement.has_generic_return { + format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) + } else { + String::new() + }; + + let sugg = if replacement.has_args { + format!( + "{method}{turbofish}(|{second_arg_ident}| {r})", + method = replacement.method_name, + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), + ) + } else { + format!( + "{method}{turbofish}()", + method = replacement.method_name, + ) + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FOLD, + fold_span.with_hi(expr.span.hi()), + // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) + "this `.fold` can be written more succinctly using another method", + "try", + sugg, + applicability, + ); } } diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 0c72c13a3ca..f55de39c10d 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -13,15 +13,13 @@ use rustc_span::{sym, Symbol}; use super::UNNECESSARY_TO_OWNED; pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let Some(callee_def_id) = fn_def_id(cx, parent); - if is_into_iter(cx, callee_def_id); - then { - check_for_loop_iter(cx, parent, method_name, receiver, false) - } else { - false - } + if let Some(parent) = get_parent_expr(cx, expr) + && let Some(callee_def_id) = fn_def_id(cx, parent) + && is_into_iter(cx, callee_def_id) + { + check_for_loop_iter(cx, parent, method_name, receiver, false) + } else { + false } } @@ -36,65 +34,61 @@ pub fn check_for_loop_iter( receiver: &Expr<'_>, cloned_before_iter: bool, ) -> bool { - if_chain! { - if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent)); - if let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent); - let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body); - if !clone_or_copy_needed; - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); - then { - let snippet = if_chain! { - if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind; - if maybe_iter_method_name.ident.name == sym::iter; + if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent)) + && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) + && let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body) + && !clone_or_copy_needed + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + { + let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind + && maybe_iter_method_name.ident.name == sym::iter - if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - let receiver_ty = cx.typeck_results().expr_ty(receiver); - if implements_trait(cx, receiver_ty, iterator_trait_id, &[]); - if let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty); + && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let receiver_ty = cx.typeck_results().expr_ty(receiver) + && implements_trait(cx, receiver_ty, iterator_trait_id, &[]) + && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty) - if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator); - let collection_ty = cx.typeck_results().expr_ty(collection); - if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]); - if let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item"); + && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let collection_ty = cx.typeck_results().expr_ty(collection) + && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) + && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") - if iter_item_ty == into_iter_item_ty; - if let Some(collection_snippet) = snippet_opt(cx, collection.span); - then { - collection_snippet + && iter_item_ty == into_iter_item_ty + && let Some(collection_snippet) = snippet_opt(cx, collection.span) + { + collection_snippet + } else { + receiver_snippet + }; + span_lint_and_then( + cx, + UNNECESSARY_TO_OWNED, + expr.span, + &format!("unnecessary use of `{method_name}`"), + |diag| { + // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to + // a `to_owned`-like function was removed, then the next suggestion may be + // incorrect. This is because the iterator that results from the call's removal + // could hold a reference to a resource that is used mutably. See + // https://github.com/rust-lang/rust-clippy/issues/8148. + let applicability = if cloned_before_iter { + Applicability::MaybeIncorrect } else { - receiver_snippet - } - }; - span_lint_and_then( - cx, - UNNECESSARY_TO_OWNED, - expr.span, - &format!("unnecessary use of `{method_name}`"), - |diag| { - // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to - // a `to_owned`-like function was removed, then the next suggestion may be - // incorrect. This is because the iterator that results from the call's removal - // could hold a reference to a resource that is used mutably. See - // https://github.com/rust-lang/rust-clippy/issues/8148. - let applicability = if cloned_before_iter { - Applicability::MaybeIncorrect - } else { - Applicability::MachineApplicable - }; - diag.span_suggestion(expr.span, "use", snippet, applicability); - for addr_of_expr in addr_of_exprs { - match addr_of_expr.kind { - ExprKind::AddrOf(_, _, referent) => { - let span = addr_of_expr.span.with_hi(referent.span.lo()); - diag.span_suggestion(span, "remove this `&`", "", applicability); - } - _ => unreachable!(), + Applicability::MachineApplicable + }; + diag.span_suggestion(expr.span, "use", snippet, applicability); + for addr_of_expr in addr_of_exprs { + match addr_of_expr.kind { + ExprKind::AddrOf(_, _, referent) => { + let span = addr_of_expr.span.with_hi(referent.span.lo()); + diag.span_suggestion(span, "remove this `&`", "", applicability); } + _ => unreachable!(), } } - ); - return true; - } + } + ); + return true; } false } diff --git a/clippy_lints/src/methods/unnecessary_join.rs b/clippy_lints/src/methods/unnecessary_join.rs index d0c62fb56dc..e2b389e96da 100644 --- a/clippy_lints/src/methods/unnecessary_join.rs +++ b/clippy_lints/src/methods/unnecessary_join.rs @@ -18,25 +18,23 @@ pub(super) fn check<'tcx>( ) { let applicability = Applicability::MachineApplicable; let collect_output_adjusted_type = cx.typeck_results().expr_ty_adjusted(join_self_arg); - if_chain! { + if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind() // the turbofish for collect is ::> - if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind(); - if let Slice(slice) = ref_type.kind(); - if is_type_lang_item(cx, *slice, LangItem::String); + && let Slice(slice) = ref_type.kind() + && is_type_lang_item(cx, *slice, LangItem::String) // the argument for join is "" - if let ExprKind::Lit(spanned) = &join_arg.kind; - if let LitKind::Str(symbol, _) = spanned.node; - if symbol.is_empty(); - then { - span_lint_and_sugg( - cx, - UNNECESSARY_JOIN, - span.with_hi(expr.span.hi()), - r#"called `.collect::>().join("")` on an iterator"#, - "try using", - "collect::()".to_owned(), - applicability, - ); - } + && let ExprKind::Lit(spanned) = &join_arg.kind + && let LitKind::Str(symbol, _) = spanned.node + && symbol.is_empty() + { + span_lint_and_sugg( + cx, + UNNECESSARY_JOIN, + span.with_hi(expr.span.hi()), + r#"called `.collect::>().join("")` on an iterator"#, + "try using", + "collect::()".to_owned(), + applicability, + ); } } diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 79bff39379c..b66e962017c 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -116,55 +116,51 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident } fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option { - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).instantiate_identity().is_slice(); - if let ExprKind::Closure(&Closure { body, .. }) = arg.kind; - if let closure_body = cx.tcx.hir().body(body); - if let &[ + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && cx.tcx.type_of(impl_id).instantiate_identity().is_slice() + && let ExprKind::Closure(&Closure { body, .. }) = arg.kind + && let closure_body = cx.tcx.hir().body(body) + && let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } - ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind; - if method_path.ident.name == sym::cmp; - if is_trait_method(cx, closure_body.value, sym::Ord); - then { - let (closure_body, closure_arg, reverse) = if mirrored_exprs( - left_expr, - left_ident, - right_expr, - right_ident - ) { - (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false) - } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { - (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true) - } else { - return None; - }; - let vec_name = Sugg::hir(cx, recv, "..").to_string(); + ] = &closure_body.params + && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind + && method_path.ident.name == sym::cmp + && is_trait_method(cx, closure_body.value, sym::Ord) + { + let (closure_body, closure_arg, reverse) = if mirrored_exprs( + left_expr, + left_ident, + right_expr, + right_ident + ) { + (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false) + } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { + (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true) + } else { + return None; + }; + let vec_name = Sugg::hir(cx, recv, "..").to_string(); - if_chain! { - if let ExprKind::Path(QPath::Resolved(_, Path { - segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind; - if left_name == left_ident; - if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) - }); - then { - return Some(LintTrigger::Sort(SortDetection { vec_name })); - } - } + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind + && left_name == left_ident + && cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) + }) + { + return Some(LintTrigger::Sort(SortDetection { vec_name })); + } - if !expr_borrows(cx, left_expr) { - return Some(LintTrigger::SortByKey(SortByKeyDetection { - vec_name, - closure_arg, - closure_body, - reverse, - })); - } + if !expr_borrows(cx, left_expr) { + return Some(LintTrigger::SortByKey(SortByKeyDetection { + vec_name, + closure_arg, + closure_body, + reverse, + })); } } diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 772686d93dd..395b22ebc5d 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -32,25 +32,23 @@ pub fn check<'tcx>( args: &'tcx [Expr<'_>], msrv: &Msrv, ) { - if_chain! { - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if args.is_empty(); - then { - if is_cloned_or_copied(cx, method_name, method_def_id) { - unnecessary_iter_cloned::check(cx, expr, method_name, receiver); - } else if is_to_owned_like(cx, expr, method_name, method_def_id) { - // At this point, we know the call is of a `to_owned`-like function. The functions - // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary - // based on its context, that is, whether it is a referent in an `AddrOf` expression, an - // argument in a `into_iter` call, or an argument in the call of some other function. - if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) { - return; - } - if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { - return; - } - check_other_call_arg(cx, expr, method_name, receiver); + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && args.is_empty() + { + if is_cloned_or_copied(cx, method_name, method_def_id) { + unnecessary_iter_cloned::check(cx, expr, method_name, receiver); + } else if is_to_owned_like(cx, expr, method_name, method_def_id) { + // At this point, we know the call is of a `to_owned`-like function. The functions + // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary + // based on its context, that is, whether it is a referent in an `AddrOf` expression, an + // argument in a `into_iter` call, or an argument in the call of some other function. + if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) { + return; } + if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { + return; + } + check_other_call_arg(cx, expr, method_name, receiver); } } } @@ -65,11 +63,10 @@ fn check_addr_of_expr( method_def_id: DefId, receiver: &Expr<'_>, ) -> bool { - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind; - let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::>(); - if let + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind + && let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::>() + && let // For matching uses of `Cow::from` [ Adjustment { @@ -110,10 +107,10 @@ fn check_addr_of_expr( kind: Adjust::Borrow(_), target: target_ty, }, - ] = adjustments[..]; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty); - let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); + ] = adjustments[..] + && let receiver_ty = cx.typeck_results().expr_ty(receiver) + && let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty) + && let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty) // Only flag cases satisfying at least one of the following three conditions: // * the referent and receiver types are distinct // * the referent/receiver type is a copyable array @@ -123,77 +120,72 @@ fn check_addr_of_expr( // https://github.com/rust-lang/rust-clippy/issues/8759 // Arrays are a bit of a corner case. Non-copyable arrays are handled by // `redundant_clone`, but copyable arrays are not. - if *referent_ty != receiver_ty + && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) - || is_cow_into_owned(cx, method_name, method_def_id); - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); - then { - if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { + || is_cow_into_owned(cx, method_name, method_def_id)) + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + { + if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{method_name}`"), + "use", + format!( + "{:&>width$}{receiver_snippet}", + "", + width = n_target_refs - n_receiver_refs + ), + Applicability::MachineApplicable, + ); + return true; + } + if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) + && implements_trait(cx, receiver_ty, deref_trait_id, &[]) + && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty) + // Make sure that it's actually calling the right `.to_string()`, (#10033) + // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) + // but that's ok for Cow::into_owned specifically) + && (cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty + || is_cow_into_owned(cx, method_name, method_def_id)) + { + if n_receiver_refs > 0 { span_lint_and_sugg( cx, UNNECESSARY_TO_OWNED, parent.span, &format!("unnecessary use of `{method_name}`"), "use", - format!( - "{:&>width$}{receiver_snippet}", - "", - width = n_target_refs - n_receiver_refs - ), + receiver_snippet, + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + expr.span.with_lo(receiver.span.hi()), + &format!("unnecessary use of `{method_name}`"), + "remove this", + String::new(), Applicability::MachineApplicable, ); - return true; - } - if_chain! { - if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); - if implements_trait(cx, receiver_ty, deref_trait_id, &[]); - if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty); - // Make sure that it's actually calling the right `.to_string()`, (#10033) - // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) - // but that's ok for Cow::into_owned specifically) - if cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty - || is_cow_into_owned(cx, method_name, method_def_id); - then { - if n_receiver_refs > 0 { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - parent.span, - &format!("unnecessary use of `{method_name}`"), - "use", - receiver_snippet, - Applicability::MachineApplicable, - ); - } else { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{method_name}`"), - "remove this", - String::new(), - Applicability::MachineApplicable, - ); - } - return true; - } - } - if_chain! { - if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); - if implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]); - then { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - parent.span, - &format!("unnecessary use of `{method_name}`"), - "use", - format!("{receiver_snippet}.as_ref()"), - Applicability::MachineApplicable, - ); - return true; - } } + return true; + } + if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) + && implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]) + { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{method_name}`"), + "use", + format!("{receiver_snippet}.as_ref()"), + Applicability::MachineApplicable, + ); + return true; } } false @@ -208,38 +200,36 @@ fn check_into_iter_call_arg( receiver: &Expr<'_>, msrv: &Msrv, ) -> bool { - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let Some(callee_def_id) = fn_def_id(cx, parent); - if is_into_iter(cx, callee_def_id); - if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - let parent_ty = cx.typeck_results().expr_ty(parent); - if implements_trait(cx, parent_ty, iterator_trait_id, &[]); - if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty); - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); - then { - if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { - return true; - } - let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) { - "copied" - } else { - "cloned" - }; - // The next suggestion may be incorrect because the removal of the `to_owned`-like - // function could cause the iterator to hold a reference to a resource that is used - // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - parent.span, - &format!("unnecessary use of `{method_name}`"), - "use", - format!("{receiver_snippet}.iter().{cloned_or_copied}()"), - Applicability::MaybeIncorrect, - ); + if let Some(parent) = get_parent_expr(cx, expr) + && let Some(callee_def_id) = fn_def_id(cx, parent) + && is_into_iter(cx, callee_def_id) + && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let parent_ty = cx.typeck_results().expr_ty(parent) + && implements_trait(cx, parent_ty, iterator_trait_id, &[]) + && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + { + if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; } + let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) { + "copied" + } else { + "cloned" + }; + // The next suggestion may be incorrect because the removal of the `to_owned`-like + // function could cause the iterator to hold a reference to a resource that is used + // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{method_name}`"), + "use", + format!("{receiver_snippet}.iter().{cloned_or_copied}()"), + Applicability::MaybeIncorrect, + ); + return true; } false } @@ -252,26 +242,25 @@ fn check_other_call_arg<'tcx>( method_name: Symbol, receiver: &'tcx Expr<'tcx>, ) -> bool { - if_chain! { - if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); - if let Some((callee_def_id, _, recv, call_args)) = get_callee_generic_args_and_args(cx, maybe_call); - let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder(); - if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id); - if let Some(input) = fn_sig.inputs().get(i); - let (input, n_refs) = peel_mid_ty_refs(*input); - if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input); - if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait(); - if let [trait_predicate] = trait_predicates + if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr) + && let Some((callee_def_id, _, recv, call_args)) = get_callee_generic_args_and_args(cx, maybe_call) + && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder() + && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id) + && let Some(input) = fn_sig.inputs().get(i) + && let (input, n_refs) = peel_mid_ty_refs(*input) + && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input) + && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait() + && let [trait_predicate] = trait_predicates .iter() .filter(|trait_predicate| trait_predicate.def_id() != sized_def_id) - .collect::>()[..]; - if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); - if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); - if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id; - let receiver_ty = cx.typeck_results().expr_ty(receiver); + .collect::>()[..] + && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) + && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) + && (trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id) + && let receiver_ty = cx.typeck_results().expr_ty(receiver) // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. - if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) { + && let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) { Some((n_refs, receiver_ty)) } else if trait_predicate.def_id() != deref_trait_id { Some((1, Ty::new_ref(cx.tcx, @@ -283,21 +272,20 @@ fn check_other_call_arg<'tcx>( ))) } else { None - }; - if can_change_type(cx, maybe_arg, receiver_ty); - if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); - then { - span_lint_and_sugg( - cx, - UNNECESSARY_TO_OWNED, - maybe_arg.span, - &format!("unnecessary use of `{method_name}`"), - "use", - format!("{:&>n_refs$}{receiver_snippet}", ""), - Applicability::MachineApplicable, - ); - return true; } + && can_change_type(cx, maybe_arg, receiver_ty) + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + { + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + maybe_arg.span, + &format!("unnecessary use of `{method_name}`"), + "use", + format!("{:&>n_refs$}{receiver_snippet}", ""), + Applicability::MachineApplicable, + ); + return true; } false } @@ -329,22 +317,18 @@ fn get_callee_generic_args_and_args<'tcx>( Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>], )> { - if_chain! { - if let ExprKind::Call(callee, args) = expr.kind; - let callee_ty = cx.typeck_results().expr_ty(callee); - if let ty::FnDef(callee_def_id, _) = callee_ty.kind(); - then { - let generic_args = cx.typeck_results().node_args(callee.hir_id); - return Some((*callee_def_id, generic_args, None, args)); - } + if let ExprKind::Call(callee, args) = expr.kind + && let callee_ty = cx.typeck_results().expr_ty(callee) + && let ty::FnDef(callee_def_id, _) = callee_ty.kind() + { + let generic_args = cx.typeck_results().node_args(callee.hir_id); + return Some((*callee_def_id, generic_args, None, args)); } - if_chain! { - if let ExprKind::MethodCall(_, recv, args, _) = expr.kind; - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - then { - let generic_args = cx.typeck_results().node_args(expr.hir_id); - return Some((method_def_id, generic_args, Some(recv), args)); - } + if let ExprKind::MethodCall(_, recv, args, _) = expr.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + { + let generic_args = cx.typeck_results().node_args(expr.hir_id); + return Some((method_def_id, generic_args, Some(recv), args)); } None } diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index b5f810eddf4..c23966f95e9 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -22,13 +22,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty); if base_rcv_ty == base_res_ty && rcv_depth >= res_depth { // allow the `as_ref` or `as_mut` if it is followed by another method call - if_chain! { - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::MethodCall(segment, ..) = parent.kind; - if segment.ident.span != expr.span; - then { - return; - } + if let Some(parent) = get_parent_expr(cx, expr) + && let hir::ExprKind::MethodCall(segment, ..) = parent.kind + && segment.ident.span != expr.span + { + return; } let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 9f1f73e6021..f776e055833 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -55,32 +55,30 @@ pub(super) fn get_hint_if_single_char_arg( arg: &hir::Expr<'_>, applicability: &mut Applicability, ) -> Option { - if_chain! { - if let hir::ExprKind::Lit(lit) = &arg.kind; - if let ast::LitKind::Str(r, style) = lit.node; - let string = r.as_str(); - if string.chars().count() == 1; - then { - let snip = snippet_with_applicability(cx, arg.span, string, applicability); - let ch = if let ast::StrStyle::Raw(nhash) = style { - let nhash = nhash as usize; - // for raw string: r##"a"## - &snip[(nhash + 2)..(snip.len() - 1 - nhash)] - } else { - // for regular string: "a" - &snip[1..(snip.len() - 1)] - }; + if let hir::ExprKind::Lit(lit) = &arg.kind + && let ast::LitKind::Str(r, style) = lit.node + && let string = r.as_str() + && string.chars().count() == 1 + { + let snip = snippet_with_applicability(cx, arg.span, string, applicability); + let ch = if let ast::StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; - let hint = format!("'{}'", match ch { - "'" => "\\'" , - r"\" => "\\\\", - _ => ch, - }); + let hint = format!("'{}'", match ch { + "'" => "\\'" , + r"\" => "\\\\", + _ => ch, + }); - Some(hint) - } else { - None - } + Some(hint) + } else { + None } } @@ -140,15 +138,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { return; }, ExprKind::MethodCall(.., args, _) => { - if_chain! { - if args.iter().all(|arg| !self.is_binding(arg)); - if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); - let method_ty = self.cx.tcx.type_of(method_def_id).instantiate_identity(); - let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); - if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)); - then { - return; - } + if args.iter().all(|arg| !self.is_binding(arg)) + && let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id) + && let method_ty = self.cx.tcx.type_of(method_def_id).instantiate_identity() + && let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder() + && matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)) + { + return; } }, _ => {}, diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs index 73072718678..9f0507916e1 100644 --- a/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -17,29 +17,27 @@ pub(super) fn check<'tcx>( default_arg: &'tcx Expr<'_>, name_span: Span, ) { - if_chain! { - if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec); - if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind; - if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind; - then { - let method_call_span = expr.span.with_lo(name_span.lo()); - span_lint_and_then( - cx, - VEC_RESIZE_TO_ZERO, - expr.span, - "emptying a vector with `resize`", - |db| { - db.help("the arguments may be inverted..."); - db.span_suggestion( - method_call_span, - "...or you can empty the vector with", - "clear()".to_string(), - Applicability::MaybeIncorrect, - ); - }, - ); - } + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec) + && let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind + && let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind + { + let method_call_span = expr.span.with_lo(name_span.lo()); + span_lint_and_then( + cx, + VEC_RESIZE_TO_ZERO, + expr.span, + "emptying a vector with `resize`", + |db| { + db.help("the arguments may be inverted..."); + db.span_suggestion( + method_call_span, + "...or you can empty the vector with", + "clear()".to_string(), + Applicability::MaybeIncorrect, + ); + }, + ); } } diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index e9f268da691..4f5cf734fa4 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -7,12 +7,10 @@ use rustc_middle::ty; use super::ZST_OFFSET; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { - if_chain! { - if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind(); - if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty)); - if layout.is_zst(); - then { - span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); - } + if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind() + && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty)) + && layout.is_zst() + { + span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 01eace6c48c..ee58a47743d 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -143,73 +143,69 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if_chain! { - if !in_external_macro(cx.tcx.sess, stmt.span); - if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; - if let Some(init) = local.init; + if !in_external_macro(cx.tcx.sess, stmt.span) + && let StmtKind::Local(local) = stmt.kind + && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind + && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. - if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id); - then { - let ctxt = local.span.ctxt(); - let mut app = Applicability::MachineApplicable; - let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); - let (mutopt, initref) = if mutabl == Mutability::Mut { - ("mut ", sugg_init.mut_addr()) - } else { - ("", sugg_init.addr()) - }; - let tyopt = if let Some(ty) = local.ty { - let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; - format!(": &{mutopt}{ty_snip}") - } else { - String::new() - }; - span_lint_hir_and_then( - cx, - TOPLEVEL_REF_ARG, - init.hir_id, - local.pat.span, - "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead", - |diag| { - diag.span_suggestion( - stmt.span, - "try", - format!( - "let {name}{tyopt} = {initref};", - name=snippet(cx, name.span, ".."), - ), - app, - ); - } - ); - } + && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) + { + let ctxt = local.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); + let (mutopt, initref) = if mutabl == Mutability::Mut { + ("mut ", sugg_init.mut_addr()) + } else { + ("", sugg_init.addr()) + }; + let tyopt = if let Some(ty) = local.ty { + let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; + format!(": &{mutopt}{ty_snip}") + } else { + String::new() + }; + span_lint_hir_and_then( + cx, + TOPLEVEL_REF_ARG, + init.hir_id, + local.pat.span, + "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead", + |diag| { + diag.span_suggestion( + stmt.span, + "try", + format!( + "let {name}{tyopt} = {initref};", + name=snippet(cx, name.span, ".."), + ), + app, + ); + } + ); }; - if_chain! { - if let StmtKind::Semi(expr) = stmt.kind; - if let ExprKind::Binary(ref binop, a, b) = expr.kind; - if binop.node == BinOpKind::And || binop.node == BinOpKind::Or; - if let Some(sugg) = Sugg::hir_opt(cx, a); - then { - span_lint_hir_and_then( - cx, - SHORT_CIRCUIT_STATEMENT, - expr.hir_id, - stmt.span, - "boolean short circuit operator in statement may be clearer using an explicit test", - |diag| { - let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg }; - diag.span_suggestion( - stmt.span, - "replace it with", - format!( - "if {sugg} {{ {}; }}", - &snippet(cx, b.span, ".."), - ), - Applicability::MachineApplicable, // snippet - ); - }); - } + if let StmtKind::Semi(expr) = stmt.kind + && let ExprKind::Binary(ref binop, a, b) = expr.kind + && (binop.node == BinOpKind::And || binop.node == BinOpKind::Or) + && let Some(sugg) = Sugg::hir_opt(cx, a) + { + span_lint_hir_and_then( + cx, + SHORT_CIRCUIT_STATEMENT, + expr.hir_id, + stmt.span, + "boolean short circuit operator in statement may be clearer using an explicit test", + |diag| { + let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg }; + diag.span_suggestion( + stmt.span, + "replace it with", + format!( + "if {sugg} {{ {}; }}", + &snippet(cx, b.span, ".."), + ), + Applicability::MachineApplicable, // snippet + ); + }); }; } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 0d79ece087f..724f2c8e597 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -49,59 +49,57 @@ declare_lint_pass!(TypeParamMismatch => [MISMATCHING_TYPE_PARAM_ORDER]); impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if_chain! { - if !item.span.from_expansion(); - if let ItemKind::Impl(imp) = &item.kind; - if let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind; - if let Some(segment) = path.segments.iter().next(); - if let Some(generic_args) = segment.args; - if !generic_args.args.is_empty(); - then { - // get the name and span of the generic parameters in the Impl - let mut impl_params = Vec::new(); - for p in generic_args.args { - match p { - GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) => - impl_params.push((path.segments[0].ident.to_string(), path.span)), - GenericArg::Type(_) => return, - _ => (), - }; - } - - // find the type that the Impl is for - // only lint on struct/enum/union for now - let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else { - return + if !item.span.from_expansion() + && let ItemKind::Impl(imp) = &item.kind + && let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind + && let Some(segment) = path.segments.iter().next() + && let Some(generic_args) = segment.args + && !generic_args.args.is_empty() + { + // get the name and span of the generic parameters in the Impl + let mut impl_params = Vec::new(); + for p in generic_args.args { + match p { + GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) => + impl_params.push((path.segments[0].ident.to_string(), path.span)), + GenericArg::Type(_) => return, + _ => (), }; + } - // get the names of the generic parameters in the type - let type_params = &cx.tcx.generics_of(defid).params; - let type_param_names: Vec<_> = type_params.iter() - .filter_map(|p| - match p.kind { - GenericParamDefKind::Type {..} => Some(p.name.to_string()), - _ => None, - } - ).collect(); - // hashmap of name -> index for mismatch_param_name - let type_param_names_hashmap: FxHashMap<&String, usize> = - type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect(); + // find the type that the Impl is for + // only lint on struct/enum/union for now + let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else { + return + }; + + // get the names of the generic parameters in the type + let type_params = &cx.tcx.generics_of(defid).params; + let type_param_names: Vec<_> = type_params.iter() + .filter_map(|p| + match p.kind { + GenericParamDefKind::Type {..} => Some(p.name.to_string()), + _ => None, + } + ).collect(); + // hashmap of name -> index for mismatch_param_name + let type_param_names_hashmap: FxHashMap<&String, usize> = + type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect(); - let type_name = segment.ident; - for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { - if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { - let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order"); - let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params", - type_param_names[i]); - span_lint_and_help( - cx, - MISMATCHING_TYPE_PARAM_ORDER, - *impl_param_span, - &msg, - None, - &help - ); - } + let type_name = segment.ident; + for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { + if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { + let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order"); + let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params", + type_param_names[i]); + span_lint_and_help( + cx, + MISMATCHING_TYPE_PARAM_ORDER, + *impl_param_span, + &msg, + None, + &help + ); } } } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 0629dee4f72..cfc4af35f33 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -64,16 +64,14 @@ impl MissingDoc { } fn has_include(meta: Option) -> bool { - if_chain! { - if let Some(meta) = meta; - if let MetaItemKind::List(list) = meta.kind; - if let Some(meta) = list.first(); - if let Some(name) = meta.ident(); - then { - name.name == sym::include - } else { - false - } + if let Some(meta) = meta + && let MetaItemKind::List(list) = meta.kind + && let Some(meta) = list.first() + && let Some(name) = meta.ident() + { + name.name == sym::include + } else { + false } } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 16ff98a5922..1d07727f1c0 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -72,13 +72,12 @@ impl LateLintPass<'_> for ImportRename { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Use(path, UseKind::Single) = &item.kind { for &res in &path.res { - if_chain! { - if let Res::Def(_, id) = res; - if let Some(name) = self.renames.get(&id); + if let Res::Def(_, id) = res + && let Some(name) = self.renames.get(&id) // Remove semicolon since it is not present for nested imports - let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';'); - if let Some(snip) = snippet_opt(cx, span_without_semi); - if let Some(import) = match snip.split_once(" as ") { + && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') + && let Some(snip) = snippet_opt(cx, span_without_semi) + && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { if rename.trim() == name.as_str() { @@ -87,20 +86,19 @@ impl LateLintPass<'_> for ImportRename { Some(import.trim()) } }, - }; - then { - span_lint_and_sugg( - cx, - MISSING_ENFORCED_IMPORT_RENAMES, - span_without_semi, - "this import should be renamed", - "try", - format!( - "{import} as {name}", - ), - Applicability::MachineApplicable, - ); } + { + span_lint_and_sugg( + cx, + MISSING_ENFORCED_IMPORT_RENAMES, + span_without_semi, + "this import should be renamed", + "try", + format!( + "{import} as {name}", + ), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 215161b04c7..9634b4357c2 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -80,12 +80,10 @@ declare_lint_pass!(EvalOrderDependence => [MIXED_READ_WRITE_IN_EXPRESSION, DIVER impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Find a write to a local variable. - let var = if_chain! { - if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind; - if let Some(var) = path_to_local(lhs); - if expr.span.desugaring_kind().is_none(); - then { var } else { return; } - }; + let var = if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind + && let Some(var) = path_to_local(lhs) + && expr.span.desugaring_kind().is_none() + { var } else { return; }; let mut visitor = ReadVisitor { cx, var, diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 97e8f1c030a..b6aafd35b58 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -66,48 +66,46 @@ enum Mode { } fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) { - if_chain! { - if let [segment] = &path.segments[..]; - if segment.ident.name == kw::SelfUpper; - then { - // In case we have a named lifetime, we check if the name comes from expansion. - // If it does, at this point we know the rest of the parameter was written by the user, - // so let them decide what the name of the lifetime should be. - // See #6089 for more details. - let mut applicability = Applicability::MachineApplicable; - let self_param = match (binding_mode, mutbl) { - (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(), - (Mode::Ref(Some(lifetime)), Mutability::Mut) => { - if lifetime.ident.span.from_expansion() { - applicability = Applicability::HasPlaceholders; - "&'_ mut self".to_string() - } else { - format!("&{} mut self", &lifetime.ident.name) - } - }, - (Mode::Ref(None), Mutability::Not) => "&self".to_string(), - (Mode::Ref(Some(lifetime)), Mutability::Not) => { - if lifetime.ident.span.from_expansion() { - applicability = Applicability::HasPlaceholders; - "&'_ self".to_string() - } else { - format!("&{} self", &lifetime.ident.name) - } - }, - (Mode::Value, Mutability::Mut) => "mut self".to_string(), - (Mode::Value, Mutability::Not) => "self".to_string(), - }; + if let [segment] = &path.segments[..] + && segment.ident.name == kw::SelfUpper + { + // In case we have a named lifetime, we check if the name comes from expansion. + // If it does, at this point we know the rest of the parameter was written by the user, + // so let them decide what the name of the lifetime should be. + // See #6089 for more details. + let mut applicability = Applicability::MachineApplicable; + let self_param = match (binding_mode, mutbl) { + (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(), + (Mode::Ref(Some(lifetime)), Mutability::Mut) => { + if lifetime.ident.span.from_expansion() { + applicability = Applicability::HasPlaceholders; + "&'_ mut self".to_string() + } else { + format!("&{} mut self", &lifetime.ident.name) + } + }, + (Mode::Ref(None), Mutability::Not) => "&self".to_string(), + (Mode::Ref(Some(lifetime)), Mutability::Not) => { + if lifetime.ident.span.from_expansion() { + applicability = Applicability::HasPlaceholders; + "&'_ self".to_string() + } else { + format!("&{} self", &lifetime.ident.name) + } + }, + (Mode::Value, Mutability::Mut) => "mut self".to_string(), + (Mode::Value, Mutability::Not) => "self".to_string(), + }; - span_lint_and_sugg( - cx, - NEEDLESS_ARBITRARY_SELF_TYPE, - span, - "the type of the `self` parameter does not need to be arbitrary", - "consider to change this parameter to", - self_param, - applicability, - ) - } + span_lint_and_sugg( + cx, + NEEDLESS_ARBITRARY_SELF_TYPE, + span, + "the type of the `self` parameter does not need to be arbitrary", + "consider to change this parameter to", + self_param, + applicability, + ) } } @@ -125,12 +123,10 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { } }, TyKind::Ref(lifetime, mut_ty) => { - if_chain! { - if let TyKind::Path(None, path) = &mut_ty.ty.kind; - if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind; - then { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); - } + if let TyKind::Path(None, path) = &mut_ty.ty.kind + && let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind + { + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } }, _ => {}, diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index cb2738947d4..6803034f475 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -362,21 +362,19 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin } fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { - if_chain! { - if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind; - if let Some(last_stmt) = loop_block.stmts.last(); - if let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind; - if let ast::ExprKind::Continue(_) = inner_expr.kind; - then { - span_lint_and_help( - cx, - NEEDLESS_CONTINUE, - last_stmt.span, - MSG_REDUNDANT_CONTINUE_EXPRESSION, - None, - DROP_CONTINUE_EXPRESSION_MSG, - ); - } + if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind + && let Some(last_stmt) = loop_block.stmts.last() + && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind + && let ast::ExprKind::Continue(_) = inner_expr.kind + { + span_lint_and_help( + cx, + NEEDLESS_CONTINUE, + last_stmt.span, + MSG_REDUNDANT_CONTINUE_EXPRESSION, + None, + DROP_CONTINUE_EXPRESSION_MSG, + ); } with_loop_block(expr, |loop_block, label| { for (i, stmt) in loop_block.stmts.iter().enumerate() { diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 086c8e6fffe..42bce1ee276 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -52,65 +52,63 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { return; }; - if_chain! { + if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind // Check the method name is `for_each`. - if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind; - if method_name.ident.name == Symbol::intern("for_each"); + && method_name.ident.name == Symbol::intern("for_each") // Check `for_each` is an associated function of `Iterator`. - if is_trait_method(cx, expr, sym::Iterator); + && is_trait_method(cx, expr, sym::Iterator) // Checks the receiver of `for_each` is also a method call. - if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind; + && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. - if matches!( + && matches!( iter_recv.kind, ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..) - ); + ) // Checks the type of the `iter` method receiver is NOT a user defined type. - if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some(); + && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some() // Skip the lint if the body is not block because this is simpler than `for` loop. // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. - if let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind; - let body = cx.tcx.hir().body(body); - if let ExprKind::Block(..) = body.value.kind; - then { - let mut ret_collector = RetCollector::default(); - ret_collector.visit_expr(body.value); - - // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. - if ret_collector.ret_in_loop { - return; - } - - let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() { - (Applicability::MachineApplicable, None) - } else { - ( - Applicability::MaybeIncorrect, - Some( - ret_collector - .spans - .into_iter() - .map(|span| (span, "continue".to_string())) - .collect(), - ), - ) - }; - - let sugg = format!( - "for {} in {} {}", - snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability), - snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability), - snippet_with_applicability(cx, body.value.span, "..", &mut applicability), - ); - - span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { - diag.span_suggestion(stmt.span, "try", sugg, applicability); - if let Some(ret_suggs) = ret_suggs { - diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability); - } - }) + && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind + && let body = cx.tcx.hir().body(body) + && let ExprKind::Block(..) = body.value.kind + { + let mut ret_collector = RetCollector::default(); + ret_collector.visit_expr(body.value); + + // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. + if ret_collector.ret_in_loop { + return; } + + let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() { + (Applicability::MachineApplicable, None) + } else { + ( + Applicability::MaybeIncorrect, + Some( + ret_collector + .spans + .into_iter() + .map(|span| (span, "continue".to_string())) + .collect(), + ), + ) + }; + + let sugg = format!( + "for {} in {} {}", + snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability), + snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability), + snippet_with_applicability(cx, body.value.span, "..", &mut applicability), + ); + + span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { + diag.span_suggestion(stmt.span, "try", sugg, applicability); + if let Some(ret_suggs) = ret_suggs { + diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability); + } + }) } } } diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index c8888c744b6..886c0f3a430 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -128,21 +128,19 @@ impl LocalAssign { let assign = match expr.kind { ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span), ExprKind::Block(block, _) => { - if_chain! { - if let Some((last, other_stmts)) = block.stmts.split_last(); - if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind; + if let Some((last, other_stmts)) = block.stmts.split_last() + && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind - let assign = Self::from_expr(expr, last.span)?; + && let assign = Self::from_expr(expr, last.span)? // avoid visiting if not needed - if assign.lhs_id == binding_id; - if other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt)); + && assign.lhs_id == binding_id + && other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt)) - then { - Some(assign) - } else { - None - } + { + Some(assign) + } else { + None } }, ExprKind::Assign(..) => Self::from_expr(expr, expr.span), @@ -368,8 +366,7 @@ fn check<'tcx>( impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { let mut parents = cx.tcx.hir().parent_iter(local.hir_id); - if_chain! { - if let Local { + if let Local { init: None, pat: &Pat { kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None), @@ -377,13 +374,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { }, source: LocalSource::Normal, .. - } = local; - if let Some((_, Node::Stmt(local_stmt))) = parents.next(); - if let Some((_, Node::Block(block))) = parents.next(); + } = local + && let Some((_, Node::Stmt(local_stmt))) = parents.next() + && let Some((_, Node::Block(block))) = parents.next() - then { - check(cx, local, local_stmt, block, binding_id); - } + { + check(cx, local, local_stmt, block, binding_id); } } } diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index 7bbf1fb4cd9..6d4a4ee603e 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -53,21 +53,19 @@ fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { // don't check floating point literals on the start expression of a range return; } - if_chain! { - if let ExprKind::Lit(literal) = e.kind; + if let ExprKind::Lit(literal) = e.kind // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ - if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo); + && (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo) // inspect the source code of the expression for parenthesis - if snippet_enclosed_in_parenthesis(&snippet(cx, e.span, "")); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERALS, e.span, - "needless parenthesis on range literals can be removed", - |diag| { - let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability); - diag.span_suggestion(e.span, "try", suggestion, applicability); - }); - } + && snippet_enclosed_in_parenthesis(&snippet(cx, e.span, "")) + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERALS, e.span, + "needless parenthesis on range literals can be removed", + |diag| { + let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability); + diag.span_suggestion(e.span, "try", suggestion, applicability); + }); } } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 8fa461ac12c..24b9eaac088 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -177,118 +177,114 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ) }; - if_chain! { - if !is_self(arg); - if !ty.is_mutable_ptr(); - if !is_copy(cx, ty); - if ty.is_sized(cx.tcx, cx.param_env); - if !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter( + if !is_self(arg) + && !ty.is_mutable_ptr() + && !is_copy(cx, ty) + && ty.is_sized(cx.tcx, cx.param_env) + && !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter( cx.tcx, cx.param_env, ty, t, [Option::>::None], - )); - if !implements_borrow_trait; - if !all_borrowable_trait; - - if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind; - if !moved_vars.contains(&canonical_id); - then { - // Dereference suggestion - let sugg = |diag: &mut Diagnostic| { - if let ty::Adt(def, ..) = ty.kind() { - if let Some(span) = cx.tcx.hir().span_if_local(def.did()) { - if type_allowed_to_implement_copy( - cx.tcx, - cx.param_env, - ty, - traits::ObligationCause::dummy_with_span(span), - ).is_ok() { - diag.span_help(span, "consider marking this type as `Copy`"); - } + )) + && !implements_borrow_trait + && !all_borrowable_trait + + && let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind + && !moved_vars.contains(&canonical_id) + { + // Dereference suggestion + let sugg = |diag: &mut Diagnostic| { + if let ty::Adt(def, ..) = ty.kind() { + if let Some(span) = cx.tcx.hir().span_if_local(def.did()) { + if type_allowed_to_implement_copy( + cx.tcx, + cx.param_env, + ty, + traits::ObligationCause::dummy_with_span(span), + ).is_ok() { + diag.span_help(span, "consider marking this type as `Copy`"); } } + } - if_chain! { - if is_type_diagnostic_item(cx, ty, sym::Vec); - if let Some(clone_spans) = - get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]); - if let TyKind::Path(QPath::Resolved(_, path)) = input.kind; - if let Some(elem_ty) = path.segments.iter() - .find(|seg| seg.ident.name == sym::Vec) - .and_then(|ps| ps.args.as_ref()) - .map(|params| params.args.iter().find_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }).unwrap()); - then { - let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_")); - diag.span_suggestion( - input.span, - "consider changing the type to", - slice_ty, - Applicability::Unspecified, - ); - - for (span, suggestion) in clone_spans { - diag.span_suggestion( - span, - snippet_opt(cx, span) - .map_or( - "change the call to".into(), - |x| format!("change `{x}` to"), - ), - suggestion, - Applicability::Unspecified, - ); - } - - // cannot be destructured, no need for `*` suggestion - return; - } + if is_type_diagnostic_item(cx, ty, sym::Vec) + && let Some(clone_spans) = + get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]) + && let TyKind::Path(QPath::Resolved(_, path)) = input.kind + && let Some(elem_ty) = path.segments.iter() + .find(|seg| seg.ident.name == sym::Vec) + .and_then(|ps| ps.args.as_ref()) + .map(|params| params.args.iter().find_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }).unwrap()) + { + let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_")); + diag.span_suggestion( + input.span, + "consider changing the type to", + slice_ty, + Applicability::Unspecified, + ); + + for (span, suggestion) in clone_spans { + diag.span_suggestion( + span, + snippet_opt(cx, span) + .map_or( + "change the call to".into(), + |x| format!("change `{x}` to"), + ), + suggestion, + Applicability::Unspecified, + ); } - if is_type_lang_item(cx, ty, LangItem::String) { - if let Some(clone_spans) = - get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { + // cannot be destructured, no need for `*` suggestion + return; + } + + if is_type_lang_item(cx, ty, LangItem::String) { + if let Some(clone_spans) = + get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { + diag.span_suggestion( + input.span, + "consider changing the type to", + "&str", + Applicability::Unspecified, + ); + + for (span, suggestion) in clone_spans { diag.span_suggestion( - input.span, - "consider changing the type to", - "&str", + span, + snippet_opt(cx, span) + .map_or( + "change the call to".into(), + |x| format!("change `{x}` to") + ), + suggestion, Applicability::Unspecified, ); - - for (span, suggestion) in clone_spans { - diag.span_suggestion( - span, - snippet_opt(cx, span) - .map_or( - "change the call to".into(), - |x| format!("change `{x}` to") - ), - suggestion, - Applicability::Unspecified, - ); - } - - return; } + + return; } + } - let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))]; + let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))]; - multispan_sugg(diag, "consider taking a reference instead", spans); - }; + multispan_sugg(diag, "consider taking a reference instead", spans); + }; - span_lint_and_then( - cx, - NEEDLESS_PASS_BY_VALUE, - input.span, - "this argument is passed by value, but not consumed in the function body", - sugg, - ); - } + span_lint_and_then( + cx, + NEEDLESS_PASS_BY_VALUE, + input.span, + "this argument is passed by value, but not consumed in the function body", + sugg, + ); } } } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 074c9fef1b2..66ad45e1cb8 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -111,34 +111,32 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Call(path, [arg]) = expr.kind; - if let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path); - if let Some(variant_id) = cx.tcx.opt_parent(ctor_id); - let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path) + && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) + && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { "Some()" } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) { "Ok()" } else { return; - }; - if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind; - if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; - if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; - if expr.span.eq_ctxt(inner_expr.span); - let expr_ty = cx.typeck_results().expr_ty(expr); - let inner_ty = cx.typeck_results().expr_ty(inner_expr); - if expr_ty == inner_ty; - then { - span_lint_and_sugg( - cx, - NEEDLESS_QUESTION_MARK, - expr.span, - "question mark operator is useless here", - &format!("try removing question mark and `{sugg_remove}`"), - format!("{}", snippet(cx, inner_expr.span, r#""...""#)), - Applicability::MachineApplicable, - ); } + && let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind + && let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind + && expr.span.eq_ctxt(inner_expr.span) + && let expr_ty = cx.typeck_results().expr_ty(expr) + && let inner_ty = cx.typeck_results().expr_ty(inner_expr) + && expr_ty == inner_ty + { + span_lint_and_sugg( + cx, + NEEDLESS_QUESTION_MARK, + expr.span, + "question mark operator is useless here", + &format!("try removing question mark and `{sugg_remove}`"), + format!("{}", snippet(cx, inner_expr.span, r#""...""#)), + Applicability::MachineApplicable, + ); } } diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 56c67406d6f..5e692d7d205 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -46,42 +46,40 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]); impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if !in_external_macro(cx.sess(), expr.span); - if let ExprKind::Unary(UnOp::Not, inner) = expr.kind; - if let ExprKind::Binary(ref op, left, _) = inner.kind; - if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node; + if !in_external_macro(cx.sess(), expr.span) + && let ExprKind::Unary(UnOp::Not, inner) = expr.kind + && let ExprKind::Binary(ref op, left, _) = inner.kind + && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node - then { - let ty = cx.typeck_results().expr_ty(left); + { + let ty = cx.typeck_results().expr_ty(left); - let implements_ord = { - if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) { - implements_trait(cx, ty, id, &[]) - } else { - return; - } - }; - - let implements_partial_ord = { - if let Some(id) = cx.tcx.lang_items().partial_ord_trait() { - implements_trait(cx, ty, id, &[ty.into()]) - } else { - return; - } - }; + let implements_ord = { + if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) { + implements_trait(cx, ty, id, &[]) + } else { + return; + } + }; - if implements_partial_ord && !implements_ord { - span_lint( - cx, - NEG_CMP_OP_ON_PARTIAL_ORD, - expr.span, - "the use of negated comparison operators on partially ordered \ - types produces code that is hard to read and refactor, please \ - consider using the `partial_cmp` method instead, to make it \ - clear that the two values could be incomparable", - ); + let implements_partial_ord = { + if let Some(id) = cx.tcx.lang_items().partial_ord_trait() { + implements_trait(cx, ty, id, &[ty.into()]) + } else { + return; } + }; + + if implements_partial_ord && !implements_ord { + span_lint( + cx, + NEG_CMP_OP_ON_PARTIAL_ORD, + expr.span, + "the use of negated comparison operators on partially ordered \ + types produces code that is hard to read and refactor, please \ + consider using the `partial_cmp` method instead, to make it \ + clear that the two values could be incomparable", + ); } } } diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index db0e22842d1..62a8f04bf17 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -53,28 +53,26 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply { } fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { - if_chain! { - if let ExprKind::Lit(l) = lit.kind; - if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); - if cx.typeck_results().expr_ty(exp).is_integral(); + if let ExprKind::Lit(l) = lit.kind + && consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1) + && cx.typeck_results().expr_ty(exp).is_integral() - then { - let mut applicability = Applicability::MachineApplicable; - let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); - let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { - format!("-({snip})") - } else { - format!("-{snip}") - }; - span_lint_and_sugg( - cx, - NEG_MULTIPLY, - span, - "this multiplication by -1 can be written more succinctly", - "consider using", - suggestion, - applicability, - ); - } + { + let mut applicability = Applicability::MachineApplicable; + let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); + let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { + format!("-({snip})") + } else { + format!("-{snip}") + }; + span_lint_and_sugg( + cx, + NEG_MULTIPLY, + span, + "this multiplication by -1 can be written more succinctly", + "consider using", + suggestion, + applicability, + ); } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index f7f9dccfbce..bd75a8c2a98 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -93,73 +93,69 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // an impl of `Default` return; } - if_chain! { - if sig.decl.inputs.is_empty(); - if name == sym::new; - if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id); - let self_def_id = cx.tcx.hir().get_parent_item(id.into()); - let self_ty = cx.tcx.type_of(self_def_id).instantiate_identity(); - if self_ty == return_ty(cx, id); - if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); - then { - if self.impling_types.is_none() { - let mut impls = HirIdSet::default(); - cx.tcx.for_each_impl(default_trait_id, |d| { - let ty = cx.tcx.type_of(d).instantiate_identity(); - if let Some(ty_def) = ty.ty_adt_def() { - if let Some(local_def_id) = ty_def.did().as_local() { - impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id)); - } + if sig.decl.inputs.is_empty() + && name == sym::new + && cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id) + && let self_def_id = cx.tcx.hir().get_parent_item(id.into()) + && let self_ty = cx.tcx.type_of(self_def_id).instantiate_identity() + && self_ty == return_ty(cx, id) + && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default) + { + if self.impling_types.is_none() { + let mut impls = HirIdSet::default(); + cx.tcx.for_each_impl(default_trait_id, |d| { + let ty = cx.tcx.type_of(d).instantiate_identity(); + if let Some(ty_def) = ty.ty_adt_def() { + if let Some(local_def_id) = ty_def.did().as_local() { + impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id)); } - }); - self.impling_types = Some(impls); - } - - // Check if a Default implementation exists for the Self type, regardless of - // generics - if_chain! { - if let Some(ref impling_types) = self.impling_types; - let self_def = cx.tcx.type_of(self_def_id).instantiate_identity(); - if let Some(self_def) = self_def.ty_adt_def(); - if let Some(self_local_did) = self_def.did().as_local(); - let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); - if impling_types.contains(&self_id); - then { - return; } - } + }); + self.impling_types = Some(impls); + } - let generics_sugg = snippet(cx, generics.span, ""); - let where_clause_sugg = if generics.has_where_clause_predicates { - format!("\n{}\n", snippet(cx, generics.where_clause_span, "")) - } else { - String::new() - }; - let self_ty_fmt = self_ty.to_string(); - let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt); - span_lint_hir_and_then( - cx, - NEW_WITHOUT_DEFAULT, - id.into(), - impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{self_type_snip}`" - ), - |diag| { - diag.suggest_prepend_item( - cx, - item.span, - "try adding this", - &create_new_without_default_suggest_msg( - &self_type_snip, - &generics_sugg, - &where_clause_sugg - ), - Applicability::MachineApplicable, - ); - }, - ); + // Check if a Default implementation exists for the Self type, regardless of + // generics + if let Some(ref impling_types) = self.impling_types + && let self_def = cx.tcx.type_of(self_def_id).instantiate_identity() + && let Some(self_def) = self_def.ty_adt_def() + && let Some(self_local_did) = self_def.did().as_local() + && let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did) + && impling_types.contains(&self_id) + { + return; } + + let generics_sugg = snippet(cx, generics.span, ""); + let where_clause_sugg = if generics.has_where_clause_predicates { + format!("\n{}\n", snippet(cx, generics.where_clause_span, "")) + } else { + String::new() + }; + let self_ty_fmt = self_ty.to_string(); + let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt); + span_lint_hir_and_then( + cx, + NEW_WITHOUT_DEFAULT, + id.into(), + impl_item.span, + &format!( + "you should consider adding a `Default` implementation for `{self_type_snip}`" + ), + |diag| { + diag.suggest_prepend_item( + cx, + item.span, + "try adding this", + &create_new_without_default_suggest_msg( + &self_type_snip, + &generics_sugg, + &where_clause_sugg + ), + Applicability::MachineApplicable, + ); + }, + ); } } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 3a28e511fdd..c5d6ff9b2f5 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -132,24 +132,22 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { return true; } } else if let StmtKind::Local(local) = stmt.kind { - if_chain! { - if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id); - if let Some(init) = local.init; - if local.els.is_none(); - if !local.pat.span.from_expansion(); - if has_no_effect(cx, init); - if let PatKind::Binding(_, _, ident, _) = local.pat.kind; - if ident.name.to_ident_string().starts_with('_'); - then { - span_lint_hir( - cx, - NO_EFFECT_UNDERSCORE_BINDING, - init.hir_id, - stmt.span, - "binding to `_` prefixed variable with no side-effect" - ); - return true; - } + if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id) + && let Some(init) = local.init + && local.els.is_none() + && !local.pat.span.from_expansion() + && has_no_effect(cx, init) + && let PatKind::Binding(_, _, ident, _) = local.pat.kind + && ident.name.to_ident_string().starts_with('_') + { + span_lint_hir( + cx, + NO_EFFECT_UNDERSCORE_BINDING, + init.hir_id, + stmt.span, + "binding to `_` prefixed variable with no side-effect" + ); + return true; } } false @@ -199,63 +197,61 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if_chain! { - if let StmtKind::Semi(expr) = stmt.kind; - let ctxt = stmt.span.ctxt(); - if expr.span.ctxt() == ctxt; - if let Some(reduced) = reduce_expression(cx, expr); - if !in_external_macro(cx.sess(), stmt.span); - if reduced.iter().all(|e| e.span.ctxt() == ctxt); - then { - if let ExprKind::Index(..) = &expr.kind { - let snippet = if let (Some(arr), Some(func)) = - (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) - { - format!("assert!({}.len() > {});", &arr, &func) + if let StmtKind::Semi(expr) = stmt.kind + && let ctxt = stmt.span.ctxt() + && expr.span.ctxt() == ctxt + && let Some(reduced) = reduce_expression(cx, expr) + && !in_external_macro(cx.sess(), stmt.span) + && reduced.iter().all(|e| e.span.ctxt() == ctxt) + { + if let ExprKind::Index(..) = &expr.kind { + let snippet = if let (Some(arr), Some(func)) = + (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) + { + format!("assert!({}.len() > {});", &arr, &func) + } else { + return; + }; + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be written as", + snippet, + Applicability::MaybeIncorrect, + ); + }, + ); + } else { + let mut snippet = String::new(); + for e in reduced { + if let Some(snip) = snippet_opt(cx, e.span) { + snippet.push_str(&snip); + snippet.push(';'); } else { return; - }; - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be written as", - snippet, - Applicability::MaybeIncorrect, - ); - }, - ); - } else { - let mut snippet = String::new(); - for e in reduced { - if let Some(snip) = snippet_opt(cx, e.span) { - snippet.push_str(&snip); - snippet.push(';'); - } else { - return; - } } - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be reduced to", - snippet, - Applicability::MachineApplicable, - ); - }, - ); } + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be reduced to", + snippet, + Applicability::MachineApplicable, + ); + }, + ); } } } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 54cec066ba1..5a91468a214 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -386,15 +386,14 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { of_trait: Some(of_trait_ref), .. }) => { - if_chain! { + if let Some(of_trait_def_id) = of_trait_ref.trait_def_id() // Lint a trait impl item only when the definition is a generic type, // assuming an assoc const is not meant to be an interior mutable type. - if let Some(of_trait_def_id) = of_trait_ref.trait_def_id(); - if let Some(of_assoc_item) = cx + && let Some(of_assoc_item) = cx .tcx .associated_item(impl_item.owner_id) - .trait_item_def_id; - if cx + .trait_item_def_id + && cx .tcx .layout_of(cx.tcx.param_env(of_trait_def_id).and( // Normalize assoc types because ones originated from generic params @@ -405,23 +404,22 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.tcx.type_of(of_assoc_item).instantiate_identity(), ), )) - .is_err(); + .is_err() // If there were a function like `has_frozen_variant` described above, // we should use here as a frozen variant is a potential to be frozen // similar to unknown layouts. // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` - let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); - let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized); - if self.is_value_unfrozen_poly(cx, *body_id, normalized); - then { - lint( - cx, - Source::Assoc { - item: impl_item.span, - }, - ); - } + && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() + && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty) + && !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) + && self.is_value_unfrozen_poly(cx, *body_id, normalized) + { + lint( + cx, + Source::Assoc { + item: impl_item.span, + }, + ); } }, ItemKind::Impl(Impl { of_trait: None, .. }) => { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index e94e4589966..ab52ed5a7ca 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -44,38 +44,34 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { - if_chain! { - if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def(); - if (path.ident.name == sym!(mode) + if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() + && ((path.ident.name == sym!(mode) && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder))) || (path.ident.name == sym!(set_mode) - && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); - if let ExprKind::Lit(_) = param.kind; - if param.span.eq_ctxt(expr.span); + && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) + && let ExprKind::Lit(_) = param.kind + && param.span.eq_ctxt(expr.span) - then { - let Some(snip) = snippet_opt(cx, param.span) else { - return - }; + { + let Some(snip) = snippet_opt(cx, param.span) else { + return + }; - if !snip.starts_with("0o") { - show_error(cx, param); - } + if !snip.starts_with("0o") { + show_error(cx, param); } } }, ExprKind::Call(func, [param]) => { - if_chain! { - if let ExprKind::Path(ref path) = func.kind; - if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); - if let ExprKind::Lit(_) = param.kind; - if param.span.eq_ctxt(expr.span); - if let Some(snip) = snippet_opt(cx, param.span); - if !snip.starts_with("0o"); - then { - show_error(cx, param); - } + if let ExprKind::Path(ref path) = func.kind + && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE) + && let ExprKind::Lit(_) = param.kind + && param.span.eq_ctxt(expr.span) + && let Some(snip) = snippet_opt(cx, param.span) + && !snip.starts_with("0o") + { + show_error(cx, param); } }, _ => {}, diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 62ef48c8a90..23e756c850f 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -81,73 +81,69 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { // We start from `Send` impl instead of `check_field_def()` because // single `AdtDef` may have multiple `Send` impls due to generic // parameters, and the lint is much easier to implement in this way. - if_chain! { - if !in_external_macro(cx.tcx.sess, item.span); - if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send); - if let ItemKind::Impl(hir_impl) = &item.kind; - if let Some(trait_ref) = &hir_impl.of_trait; - if let Some(trait_id) = trait_ref.trait_def_id(); - if send_trait == trait_id; - if hir_impl.polarity == ImplPolarity::Positive; - if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id); - if let self_ty = ty_trait_ref.instantiate_identity().self_ty(); - if let ty::Adt(adt_def, impl_trait_args) = self_ty.kind(); - then { - let mut non_send_fields = Vec::new(); - - let hir_map = cx.tcx.hir(); - for variant in adt_def.variants() { - for field in &variant.fields { - if_chain! { - if let Some(field_hir_id) = field - .did - .as_local() - .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)); - if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id); - if let field_ty = field.ty(cx.tcx, impl_trait_args); - if !ty_allowed_in_send(cx, field_ty, send_trait); - if let Node::Field(field_def) = hir_map.get(field_hir_id); - then { - non_send_fields.push(NonSendField { - def: field_def, - ty: field_ty, - generic_params: collect_generic_params(field_ty), - }) - } - } + if !in_external_macro(cx.tcx.sess, item.span) + && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send) + && let ItemKind::Impl(hir_impl) = &item.kind + && let Some(trait_ref) = &hir_impl.of_trait + && let Some(trait_id) = trait_ref.trait_def_id() + && send_trait == trait_id + && hir_impl.polarity == ImplPolarity::Positive + && let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) + && let self_ty = ty_trait_ref.instantiate_identity().self_ty() + && let ty::Adt(adt_def, impl_trait_args) = self_ty.kind() + { + let mut non_send_fields = Vec::new(); + + let hir_map = cx.tcx.hir(); + for variant in adt_def.variants() { + for field in &variant.fields { + if let Some(field_hir_id) = field + .did + .as_local() + .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)) + && !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id) + && let field_ty = field.ty(cx.tcx, impl_trait_args) + && !ty_allowed_in_send(cx, field_ty, send_trait) + && let Node::Field(field_def) = hir_map.get(field_hir_id) + { + non_send_fields.push(NonSendField { + def: field_def, + ty: field_ty, + generic_params: collect_generic_params(field_ty), + }) } } + } - if !non_send_fields.is_empty() { - span_lint_and_then( - cx, - NON_SEND_FIELDS_IN_SEND_TY, - item.span, - &format!( - "some fields in `{}` are not safe to be sent to another thread", - snippet(cx, hir_impl.self_ty.span, "Unknown") - ), - |diag| { - for field in non_send_fields { - diag.span_note( - field.def.span, - format!("it is not safe to send field `{}` to another thread", field.def.ident.name), - ); - - match field.generic_params.len() { - 0 => diag.help("use a thread-safe type that implements `Send`"), - 1 if is_ty_param(field.ty) => diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)), - _ => diag.help(format!( - "add bounds on type parameter{} `{}` that satisfy `{}: Send`", - if field.generic_params.len() > 1 { "s" } else { "" }, - field.generic_params_string(), - snippet(cx, field.def.ty.span, "Unknown"), - )), - }; - } - }, - ); - } + if !non_send_fields.is_empty() { + span_lint_and_then( + cx, + NON_SEND_FIELDS_IN_SEND_TY, + item.span, + &format!( + "some fields in `{}` are not safe to be sent to another thread", + snippet(cx, hir_impl.self_ty.span, "Unknown") + ), + |diag| { + for field in non_send_fields { + diag.span_note( + field.def.span, + format!("it is not safe to send field `{}` to another thread", field.def.ident.name), + ); + + match field.generic_params.len() { + 0 => diag.help("use a thread-safe type that implements `Send`"), + 1 if is_ty_param(field.ty) => diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)), + _ => diag.help(format!( + "add bounds on type parameter{} `{}` that satisfy `{}: Send`", + if field.generic_params.len() > 1 { "s" } else { "" }, + field.generic_params_string(), + snippet(cx, field.def.ty.span, "Unknown"), + )), + }; + } + }, + ); } } } diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 11c3a5417b5..87359086512 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -93,24 +93,22 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac .map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local)) }; let span_call_site = span.ctxt().outer_expn_data().call_site; - if_chain! { - if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind; - let name = mac_name.as_str(); - if let Some(braces) = mac_braces.macro_braces.get(name); - if let Some(snip) = snippet_opt(cx, span_call_site); + if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind + && let name = mac_name.as_str() + && let Some(braces) = mac_braces.macro_braces.get(name) + && let Some(snip) = snippet_opt(cx, span_call_site) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 - if snip.starts_with(&format!("{name}!")); - if unnested_or_local(); + && snip.starts_with(&format!("{name}!")) + && unnested_or_local() // make formatting consistent - let c = snip.replace(' ', ""); - if !c.starts_with(&format!("{name}!{}", braces.0)); - if !mac_braces.done.contains(&span_call_site); - then { - Some((span_call_site, braces, snip)) - } else { - None - } + && let c = snip.replace(' ', "") + && !c.starts_with(&format!("{name}!{}", braces.0)) + && !mac_braces.done.contains(&span_call_site) + { + Some((span_call_site, braces, snip)) + } else { + None } } diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index c4572a09db6..bc7ad151aee 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -25,43 +25,41 @@ pub(super) fn check<'tcx>( let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { let ty = cx.typeck_results().expr_ty(assignee); let rty = cx.typeck_results().expr_ty(rhs); - if_chain! { - if let Some((_, lang_item)) = binop_traits(op.node); - if let Some(trait_id) = cx.tcx.lang_items().get(lang_item); - let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id; - if trait_ref_of_method(cx, parent_fn) - .map_or(true, |t| t.path.res.def_id() != trait_id); - if implements_trait(cx, ty, trait_id, &[rty.into()]); - then { - // Primitive types execute assign-ops right-to-left. Every other type is left-to-right. - if !(ty.is_primitive() && rty.is_primitive()) { - // TODO: This will have false negatives as it doesn't check if the borrows are - // actually live at the end of their respective expressions. - let mut_borrows = mut_borrows_in_expr(cx, assignee); - let imm_borrows = imm_borrows_in_expr(cx, rhs); - if mut_borrows.iter().any(|id| imm_borrows.contains(id)) { - return; - } + if let Some((_, lang_item)) = binop_traits(op.node) + && let Some(trait_id) = cx.tcx.lang_items().get(lang_item) + && let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id + && trait_ref_of_method(cx, parent_fn) + .map_or(true, |t| t.path.res.def_id() != trait_id) + && implements_trait(cx, ty, trait_id, &[rty.into()]) + { + // Primitive types execute assign-ops right-to-left. Every other type is left-to-right. + if !(ty.is_primitive() && rty.is_primitive()) { + // TODO: This will have false negatives as it doesn't check if the borrows are + // actually live at the end of their respective expressions. + let mut_borrows = mut_borrows_in_expr(cx, assignee); + let imm_borrows = imm_borrows_in_expr(cx, rhs); + if mut_borrows.iter().any(|id| imm_borrows.contains(id)) { + return; } - span_lint_and_then( - cx, - ASSIGN_OP_PATTERN, - expr.span, - "manual implementation of an assign operation", - |diag| { - if let (Some(snip_a), Some(snip_r)) = - (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) - { - diag.span_suggestion( - expr.span, - "replace it with", - format!("{snip_a} {}= {snip_r}", op.node.as_str()), - Applicability::MachineApplicable, - ); - } - }, - ); } + span_lint_and_then( + cx, + ASSIGN_OP_PATTERN, + expr.span, + "manual implementation of an assign operation", + |diag| { + if let (Some(snip_a), Some(snip_r)) = + (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) + { + diag.span_suggestion( + expr.span, + "replace it with", + format!("{snip_a} {}= {snip_r}", op.node.as_str()), + Applicability::MachineApplicable, + ); + } + }, + ); } }; diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index abe8df19543..408c9a2cf29 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -23,19 +23,17 @@ fn comparison_to_const<'tcx>( typeck: &TypeckResults<'tcx>, expr: &'tcx Expr<'tcx>, ) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> { - if_chain! { - if let ExprKind::Binary(operator, left, right) = expr.kind; - if let Ok(cmp_op) = CmpOp::try_from(operator.node); - then { - match (constant(cx, typeck, left), constant(cx, typeck, right)) { - (Some(_), Some(_)) => None, - (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))), - (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))), - _ => None, - } - } else { - None + if let ExprKind::Binary(operator, left, right) = expr.kind + && let Ok(cmp_op) = CmpOp::try_from(operator.node) + { + match (constant(cx, typeck, left), constant(cx, typeck, right)) { + (Some(_), Some(_)) => None, + (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))), + (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))), + _ => None, } + } else { + None } } @@ -46,87 +44,85 @@ pub(super) fn check<'tcx>( right_cond: &'tcx Expr<'tcx>, span: Span, ) { - if_chain! { + if and_op.node == BinOpKind::And // Ensure that the binary operator is && - if and_op.node == BinOpKind::And; // Check that both operands to '&&' are themselves a binary operation // The `comparison_to_const` step also checks this, so this step is just an optimization - if let ExprKind::Binary(_, _, _) = left_cond.kind; - if let ExprKind::Binary(_, _, _) = right_cond.kind; + && let ExprKind::Binary(_, _, _) = left_cond.kind + && let ExprKind::Binary(_, _, _) = right_cond.kind - let typeck = cx.typeck_results(); + && let typeck = cx.typeck_results() // Check that both operands to '&&' compare a non-literal to a literal - if let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) = - comparison_to_const(cx, typeck, left_cond); - if let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) = - comparison_to_const(cx, typeck, right_cond); + && let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) = + comparison_to_const(cx, typeck, left_cond) + && let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) = + comparison_to_const(cx, typeck, right_cond) - if left_type == right_type; + && left_type == right_type // Check that the same expression is compared in both comparisons - if SpanlessEq::new(cx).eq_expr(left_expr, right_expr); + && SpanlessEq::new(cx).eq_expr(left_expr, right_expr) - if !left_expr.can_have_side_effects(); + && !left_expr.can_have_side_effects() // Compare the two constant expressions - if let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const); + && let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const) // Rule out the `x >= 42 && x <= 42` corner case immediately // Mostly to simplify the implementation, but it is also covered by `clippy::double_comparisons` - if !matches!( + && !matches!( (&left_cmp_op, &right_cmp_op, ordering), (CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal) - ); - - then { - if left_cmp_op.direction() == right_cmp_op.direction() { - let lhs_str = snippet(cx, left_cond.span, ""); - let rhs_str = snippet(cx, right_cond.span, ""); - // We already know that either side of `&&` has no effect, - // but emit a different error message depending on which side it is - if left_side_is_useless(left_cmp_op, ordering) { - span_lint_and_note( - cx, - REDUNDANT_COMPARISONS, - span, - "left-hand side of `&&` operator has no effect", - Some(left_cond.span.until(right_cond.span)), - &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), - ); - } else { - span_lint_and_note( - cx, - REDUNDANT_COMPARISONS, - span, - "right-hand side of `&&` operator has no effect", - Some(and_op.span.to(right_cond.span)), - &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), - ); - } - // We could autofix this error but choose not to, - // because code triggering this lint probably not behaving correctly in the first place - } - else if !comparison_is_possible(left_cmp_op.direction(), ordering) { - let expr_str = snippet(cx, left_expr.span, ".."); - let lhs_str = snippet(cx, left_const_expr.span, ""); - let rhs_str = snippet(cx, right_const_expr.span, ""); - let note = match ordering { - Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"), - Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"), - Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"), - }; + ) + + { + if left_cmp_op.direction() == right_cmp_op.direction() { + let lhs_str = snippet(cx, left_cond.span, ""); + let rhs_str = snippet(cx, right_cond.span, ""); + // We already know that either side of `&&` has no effect, + // but emit a different error message depending on which side it is + if left_side_is_useless(left_cmp_op, ordering) { span_lint_and_note( cx, - IMPOSSIBLE_COMPARISONS, + REDUNDANT_COMPARISONS, span, - "boolean expression will never evaluate to 'true'", - None, - ¬e, + "left-hand side of `&&` operator has no effect", + Some(left_cond.span.until(right_cond.span)), + &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), ); - }; + } else { + span_lint_and_note( + cx, + REDUNDANT_COMPARISONS, + span, + "right-hand side of `&&` operator has no effect", + Some(and_op.span.to(right_cond.span)), + &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), + ); + } + // We could autofix this error but choose not to, + // because code triggering this lint probably not behaving correctly in the first place } + else if !comparison_is_possible(left_cmp_op.direction(), ordering) { + let expr_str = snippet(cx, left_expr.span, ".."); + let lhs_str = snippet(cx, left_const_expr.span, ""); + let rhs_str = snippet(cx, right_const_expr.span, ""); + let note = match ordering { + Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"), + Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"), + Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"), + }; + span_lint_and_note( + cx, + IMPOSSIBLE_COMPARISONS, + span, + "boolean expression will never evaluate to 'true'", + None, + ¬e, + ); + }; } } diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index bce6bdcaf61..fecaf14bf5e 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -105,14 +105,12 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { return is_signum(cx, child_expr); } - if_chain! { - if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind; - if sym!(signum) == method_name.ident.name; + if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind + && sym!(signum) == method_name.ident.name // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) - then { - return is_float(cx, self_arg); - } + { + return is_float(cx, self_arg); } false } diff --git a/clippy_lints/src/operators/float_equality_without_abs.rs b/clippy_lints/src/operators/float_equality_without_abs.rs index a0a8b6aabd9..91eaa296f14 100644 --- a/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/clippy_lints/src/operators/float_equality_without_abs.rs @@ -24,48 +24,46 @@ pub(crate) fn check<'tcx>( _ => return, }; - if_chain! { + if let ExprKind::Binary( // left hand side is a subtraction - if let ExprKind::Binary( Spanned { node: BinOpKind::Sub, .. }, val_l, val_r, - ) = lhs.kind; + ) = lhs.kind // right hand side matches either f32::EPSILON or f64::EPSILON - if let ExprKind::Path(ref epsilon_path) = rhs.kind; - if let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id); - if match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON); + && let ExprKind::Path(ref epsilon_path) = rhs.kind + && let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id) + && (match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON)) // values of the subtractions on the left hand side are of the type float - let t_val_l = cx.typeck_results().expr_ty(val_l); - let t_val_r = cx.typeck_results().expr_ty(val_r); - if let ty::Float(_) = t_val_l.kind(); - if let ty::Float(_) = t_val_r.kind(); + && let t_val_l = cx.typeck_results().expr_ty(val_l) + && let t_val_r = cx.typeck_results().expr_ty(val_r) + && let ty::Float(_) = t_val_l.kind() + && let ty::Float(_) = t_val_r.kind() - then { - let sug_l = sugg::Sugg::hir(cx, val_l, ".."); - let sug_r = sugg::Sugg::hir(cx, val_r, ".."); - // format the suggestion - let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); - // spans the lint - span_lint_and_then( - cx, - FLOAT_EQUALITY_WITHOUT_ABS, - expr.span, - "float equality check without `.abs()`", - | diag | { - diag.span_suggestion( - lhs.span, - "add `.abs()`", - suggestion, - Applicability::MaybeIncorrect, - ); - } - ); - } + { + let sug_l = sugg::Sugg::hir(cx, val_l, ".."); + let sug_r = sugg::Sugg::hir(cx, val_r, ".."); + // format the suggestion + let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); + // spans the lint + span_lint_and_then( + cx, + FLOAT_EQUALITY_WITHOUT_ABS, + expr.span, + "float equality check without `.abs()`", + | diag | { + diag.span_suggestion( + lhs.span, + "add `.abs()`", + suggestion, + Applicability::MaybeIncorrect, + ); + } + ); } } diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index a2c3a4d8ba7..2c7eebc5ae9 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -19,15 +19,13 @@ pub(super) fn check<'tcx>( if op == BinOpKind::Rem { let lhs_operand = analyze_operand(lhs, cx, e); let rhs_operand = analyze_operand(rhs, cx, e); - if_chain! { - if let Some(lhs_operand) = lhs_operand; - if let Some(rhs_operand) = rhs_operand; - then { - check_const_operands(cx, e, &lhs_operand, &rhs_operand); - } - else { - check_non_const_operands(cx, e, lhs); - } + if let Some(lhs_operand) = lhs_operand + && let Some(rhs_operand) = rhs_operand + { + check_const_operands(cx, e, &lhs_operand, &rhs_operand); + } + else { + check_non_const_operands(cx, e, lhs); } }; } diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs index 932dd470f9e..77ef4a43497 100644 --- a/clippy_lints/src/operators/op_ref.rs +++ b/clippy_lints/src/operators/op_ref.rs @@ -180,41 +180,37 @@ fn in_impl<'tcx>( e: &'tcx Expr<'_>, bin_op: DefId, ) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { - if_chain! { - if let Some(block) = get_enclosing_block(cx, e.hir_id); - if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()); - let item = cx.tcx.hir().expect_item(impl_def_id.expect_local()); - if let ItemKind::Impl(item) = &item.kind; - if let Some(of_trait) = &item.of_trait; - if let Some(seg) = of_trait.path.segments.last(); - if let Res::Def(_, trait_id) = seg.res; - if trait_id == bin_op; - if let Some(generic_args) = seg.args; - if let Some(GenericArg::Type(other_ty)) = generic_args.args.last(); + if let Some(block) = get_enclosing_block(cx, e.hir_id) + && let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()) + && let item = cx.tcx.hir().expect_item(impl_def_id.expect_local()) + && let ItemKind::Impl(item) = &item.kind + && let Some(of_trait) = &item.of_trait + && let Some(seg) = of_trait.path.segments.last() + && let Res::Def(_, trait_id) = seg.res + && trait_id == bin_op + && let Some(generic_args) = seg.args + && let Some(GenericArg::Type(other_ty)) = generic_args.args.last() - then { - Some((item.self_ty, other_ty)) - } - else { - None - } + { + Some((item.self_ty, other_ty)) + } + else { + None } } fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { - if_chain! { - if let ty::Adt(adt_def, _) = middle_ty.kind(); - if let Some(local_did) = adt_def.did().as_local(); - let item = cx.tcx.hir().expect_item(local_did); - let middle_ty_id = item.owner_id.to_def_id(); - if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; - if let Res::Def(_, hir_ty_id) = path.res; + if let ty::Adt(adt_def, _) = middle_ty.kind() + && let Some(local_did) = adt_def.did().as_local() + && let item = cx.tcx.hir().expect_item(local_did) + && let middle_ty_id = item.owner_id.to_def_id() + && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind + && let Res::Def(_, hir_ty_id) = path.res - then { - hir_ty_id == middle_ty_id - } - else { - false - } + { + hir_ty_id == middle_ty_id + } + else { + false } } diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 1229c202f5a..7ae269655c6 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -22,22 +22,20 @@ pub(super) fn check<'tcx>( _ => (left, right), }; - if_chain! { - if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); - if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); - if let Some(left_snip) = snippet_opt(cx, left_var.span); - if let Some(right_snip) = snippet_opt(cx, right_var.span); - then { - span_lint_and_sugg( - cx, - PTR_EQ, - expr.span, - LINT_MSG, - "try", - format!("std::ptr::eq({left_snip}, {right_snip})"), - Applicability::MachineApplicable, - ); - } + if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left) + && let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right) + && let Some(left_snip) = snippet_opt(cx, left_var.span) + && let Some(right_snip) = snippet_opt(cx, right_var.span) + { + span_lint_and_sugg( + cx, + PTR_EQ, + expr.span, + LINT_MSG, + "try", + format!("std::ptr::eq({left_snip}, {right_snip})"), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index d7cbbe13a26..b69d374fbfd 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -122,73 +122,71 @@ fn try_get_option_occurrence<'tcx>( _ => expr, }; let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?; - if_chain! { - if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind; - if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); - if let Some(none_captures) = can_move_expr_to_closure(cx, if_else); - if some_captures + if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind + && let Some(some_captures) = can_move_expr_to_closure(cx, if_then) + && let Some(none_captures) = can_move_expr_to_closure(cx, if_else) + && some_captures .iter() .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) - .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()); - then { - let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" }; - let some_body = peel_blocks(if_then); - let none_body = peel_blocks(if_else); - let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; - let capture_name = id.name.to_ident_string(); - let (as_ref, as_mut) = match &expr.kind { - ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), - ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), - _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => { - (mutb == Mutability::Not, mutb == Mutability::Mut) - } - _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT), - }; + .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()) + { + let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" }; + let some_body = peel_blocks(if_then); + let none_body = peel_blocks(if_else); + let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; + let capture_name = id.name.to_ident_string(); + let (as_ref, as_mut) = match &expr.kind { + ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), + ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), + _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => { + (mutb == Mutability::Not, mutb == Mutability::Mut) + } + _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT), + }; - // Check if captures the closure will need conflict with borrows made in the scrutinee. - // TODO: check all the references made in the scrutinee expression. This will require interacting - // with the borrow checker. Currently only `[.]*` is checked for. - if as_ref || as_mut { - let e = peel_hir_expr_while(cond_expr, |e| match e.kind { - ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e), - _ => None, - }); - if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind { - match some_captures.get(local_id) - .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id))) - { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, - Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, - Some(CaptureKind::Ref(Mutability::Not)) | None => (), - } + // Check if captures the closure will need conflict with borrows made in the scrutinee. + // TODO: check all the references made in the scrutinee expression. This will require interacting + // with the borrow checker. Currently only `[.]*` is checked for. + if as_ref || as_mut { + let e = peel_hir_expr_while(cond_expr, |e| match e.kind { + ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e), + _ => None, + }); + if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind { + match some_captures.get(local_id) + .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id))) + { + Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, + Some(CaptureKind::Ref(Mutability::Not)) | None => (), } } + } - let mut app = Applicability::Unspecified; + let mut app = Applicability::Unspecified; - let (none_body, is_argless_call) = match none_body.kind { - ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true), - _ => (none_body, false), - }; + let (none_body, is_argless_call) = match none_body.kind { + ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true), + _ => (none_body, false), + }; - return Some(OptionOccurrence { - option: format_option_in_sugg( - Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), - as_ref, - as_mut, - ), - method_sugg: method_sugg.to_string(), - some_expr: format!( - "|{capture_mut}{capture_name}| {}", - Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app), - ), - none_expr: format!( - "{}{}", - if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "}, - Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), - ), - }); - } + return Some(OptionOccurrence { + option: format_option_in_sugg( + Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), + as_ref, + as_mut, + ), + method_sugg: method_sugg.to_string(), + some_expr: format!( + "|{capture_mut}{capture_name}| {}", + Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app), + ), + none_expr: format!( + "{}{}", + if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "}, + Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), + ), + }); } None diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 38cd5043adc..36ad6cf5f9b 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -34,41 +34,37 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r); - if_chain! { - if let ExprKind::Binary(ref op, first, second) = expr.kind; - if let ExprKind::Binary(ref op2, ident1, ident2) = first.kind; - if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind; - if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind; - if let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind; - if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]); - if cx.typeck_results().expr_ty(ident1).is_integral(); - if cx.typeck_results().expr_ty(ident2).is_integral(); - then { - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } + if let ExprKind::Binary(ref op, first, second) = expr.kind + && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind + && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind + && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind + && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind + && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) + && cx.typeck_results().expr_ty(ident1).is_integral() + && cx.typeck_results().expr_ty(ident2).is_integral() + { + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); + } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } - if_chain! { - if let ExprKind::Binary(ref op, first, second) = expr.kind; - if let ExprKind::Binary(ref op2, ident1, ident2) = second.kind; - if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind; - if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind; - if let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind; - if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]); - if cx.typeck_results().expr_ty(ident1).is_integral(); - if cx.typeck_results().expr_ty(ident2).is_integral(); - then { - if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); - } - if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); - } + if let ExprKind::Binary(ref op, first, second) = expr.kind + && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind + && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind + && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind + && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind + && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0])) + && cx.typeck_results().expr_ty(ident1).is_integral() + && cx.typeck_results().expr_ty(ident2).is_integral() + { + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); + } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 68d3d00ac16..105af98f1aa 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -34,22 +34,20 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]); impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if_chain! { - if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); - if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); - if trait_ref.path.res.def_id() == eq_trait; - then { - for impl_item in *impl_items { - if impl_item.ident.name == sym::ne { - span_lint_hir( - cx, - PARTIALEQ_NE_IMPL, - impl_item.id.hir_id(), - impl_item.span, - "re-implementing `PartialEq::ne` is unnecessary", - ); - } + if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind + && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) + && let Some(eq_trait) = cx.tcx.lang_items().eq_trait() + && trait_ref.path.res.def_id() == eq_trait + { + for impl_item in *impl_items { + if impl_item.ident.name == sym::ne { + span_lint_hir( + cx, + PARTIALEQ_NE_IMPL, + impl_item.id.hir_id(), + impl_item.span, + "re-implementing `PartialEq::ne` is unnecessary", + ); } } }; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 4d7a055dae1..3a6f37f01a8 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -229,22 +229,20 @@ impl<'tcx> PassByRefOrValue { } let ty = cx.tcx.erase_late_bound_regions(ty); - if_chain! { - if is_copy(cx, ty); - if !is_self_ty(input); - if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()); - if size > self.value_max_size; - then { - span_lint_and_sugg( - cx, - LARGE_TYPES_PASSED_BY_VALUE, - input.span, - &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size), - "consider passing by reference instead", - format!("&{}", snippet(cx, input.span, "_")), - Applicability::MaybeIncorrect, - ); - } + if is_copy(cx, ty) + && !is_self_ty(input) + && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) + && size > self.value_max_size + { + span_lint_and_sugg( + cx, + LARGE_TYPES_PASSED_BY_VALUE, + input.span, + &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size), + "consider passing by reference instead", + format!("&{}", snippet(cx, input.span, "_")), + Applicability::MaybeIncorrect, + ); } }, diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 057b7e30642..0aebd9a6df3 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -118,25 +118,23 @@ impl EarlyLintPass for Precedence { arg = receiver; } - if_chain! { - if !all_odd; - if let ExprKind::Lit(lit) = &arg.kind; - if let token::LitKind::Integer | token::LitKind::Float = &lit.kind; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - PRECEDENCE, - expr.span, - "unary minus has lower precedence than method call", - "consider adding parentheses to clarify your intent", - format!( - "-({})", - snippet_with_applicability(cx, operand.span, "..", &mut applicability) - ), - applicability, - ); - } + if !all_odd + && let ExprKind::Lit(lit) = &arg.kind + && let token::LitKind::Integer | token::LitKind::Float = &lit.kind + { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + PRECEDENCE, + expr.span, + "unary minus has lower precedence than method call", + "consider adding parentheses to clarify your intent", + format!( + "-({})", + snippet_with_applicability(cx, operand.span, "..", &mut applicability) + ), + applicability, + ); } } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index b133635e883..0c01934433a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -179,17 +179,15 @@ fn expr_return_none_or_err( _ => false, }, ExprKind::Call(call_expr, args_expr) => { - if_chain! { - if smbl == sym::Result; - if let ExprKind::Path(QPath::Resolved(_, path)) = &call_expr.kind; - if let Some(segment) = path.segments.first(); - if let Some(err_sym) = err_sym; - if let Some(arg) = args_expr.first(); - if let ExprKind::Path(QPath::Resolved(_, arg_path)) = &arg.kind; - if let Some(PathSegment { ident, .. }) = arg_path.segments.first(); - then { - return segment.ident.name == sym::Err && err_sym == ident.name; - } + if smbl == sym::Result + && let ExprKind::Path(QPath::Resolved(_, path)) = &call_expr.kind + && let Some(segment) = path.segments.first() + && let Some(err_sym) = err_sym + && let Some(arg) = args_expr.first() + && let ExprKind::Path(QPath::Resolved(_, arg_path)) = &arg.kind + && let Some(PathSegment { ident, .. }) = arg_path.segments.first() + { + return segment.ident.name == sym::Err && err_sym == ident.name; } false }, @@ -218,81 +216,77 @@ impl QuestionMark { /// /// If it matches, it will suggest to use the question mark operator instead fn check_is_none_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if_chain! { - if !self.inside_try_block(); - if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); - if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind; - let caller_ty = cx.typeck_results().expr_ty(caller); - let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); - if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); - then { - let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) && - !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); - let sugg = if let Some(else_inner) = r#else { - if eq_expr_value(cx, caller, peel_blocks(else_inner)) { - format!("Some({receiver_str}?)") - } else { - return; - } + if !self.inside_try_block() + && let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) + && !is_else_clause(cx.tcx, expr) + && let ExprKind::MethodCall(segment, caller, ..) = &cond.kind + && let caller_ty = cx.typeck_results().expr_ty(caller) + && let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else) + && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block)) + { + let mut applicability = Applicability::MachineApplicable; + let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) && + !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); + let sugg = if let Some(else_inner) = r#else { + if eq_expr_value(cx, caller, peel_blocks(else_inner)) { + format!("Some({receiver_str}?)") } else { - format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) - }; + return; + } + } else { + format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) + }; - span_lint_and_sugg( - cx, - QUESTION_MARK, - expr.span, - "this block may be rewritten with the `?` operator", - "replace it with", - sugg, - applicability, - ); - } + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this block may be rewritten with the `?` operator", + "replace it with", + sugg, + applicability, + ); } } fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if_chain! { - if !self.inside_try_block(); - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); - if !is_else_clause(cx.tcx, expr); - if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind; - if ddpos.as_opt_usize().is_none(); - if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; - let caller_ty = cx.typeck_results().expr_ty(let_expr); - let if_block = IfBlockType::IfLet( + if !self.inside_try_block() + && let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr) + && !is_else_clause(cx.tcx, expr) + && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind + && ddpos.as_opt_usize().is_none() + && let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind + && let caller_ty = cx.typeck_results().expr_ty(let_expr) + && let if_block = IfBlockType::IfLet( cx.qpath_res(path1, let_pat.hir_id), caller_ty, ident.name, let_expr, if_then, if_else + ) + && ((is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) + || is_early_return(sym::Result, cx, &if_block)) + && if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none() + { + let mut applicability = Applicability::MachineApplicable; + let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); + let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); + let sugg = format!( + "{receiver_str}{}?{}", + if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, + if requires_semi { ";" } else { "" } + ); + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this block may be rewritten with the `?` operator", + "replace it with", + sugg, + applicability, ); - if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) - || is_early_return(sym::Result, cx, &if_block); - if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none(); - then { - let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); - let sugg = format!( - "{receiver_str}{}?{}", - if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, - if requires_semi { ";" } else { "" } - ); - span_lint_and_sugg( - cx, - QUESTION_MARK, - expr.span, - "this block may be rewritten with the `?` operator", - "replace it with", - sugg, - applicability, - ); - } } } } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index ffd49de3820..f62acc79b03 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -282,16 +282,14 @@ fn check_possible_range_contains( // If the LHS is the same operator, we have to recurse to get the "real" RHS, since they have // the same operator precedence - if_chain! { - if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind; - if op == lhs_op.node; - let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()); - if let Some(snip) = &snippet_opt(cx, new_span); + if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind + && op == lhs_op.node + && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) + && let Some(snip) = &snippet_opt(cx, new_span) // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong - if snip.matches('(').count() == snip.matches(')').count(); - then { - check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); - } + && snip.matches('(').count() == snip.matches(')').count() + { + check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); } } @@ -348,71 +346,67 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> // exclusive range plus one: `x..(y+1)` fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if expr.span.can_be_used_for_suggestions(); - if let Some(higher::Range { + if expr.span.can_be_used_for_suggestions() + && let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen - }) = higher::Range::hir(expr); - if let Some(y) = y_plus_one(cx, end); - then { - let span = expr.span; - span_lint_and_then( - cx, - RANGE_PLUS_ONE, - span, - "an inclusive range would be more readable", - |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); - let end = Sugg::hir(cx, y, "y").maybe_par(); - if let Some(is_wrapped) = &snippet_opt(cx, span) { - if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { - diag.span_suggestion( - span, - "use", - format!("({start}..={end})"), - Applicability::MaybeIncorrect, - ); - } else { - diag.span_suggestion( - span, - "use", - format!("{start}..={end}"), - Applicability::MachineApplicable, // snippet - ); - } + }) = higher::Range::hir(expr) + && let Some(y) = y_plus_one(cx, end) + { + let span = expr.span; + span_lint_and_then( + cx, + RANGE_PLUS_ONE, + span, + "an inclusive range would be more readable", + |diag| { + let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); + let end = Sugg::hir(cx, y, "y").maybe_par(); + if let Some(is_wrapped) = &snippet_opt(cx, span) { + if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { + diag.span_suggestion( + span, + "use", + format!("({start}..={end})"), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_suggestion( + span, + "use", + format!("{start}..={end}"), + Applicability::MachineApplicable, // snippet + ); } - }, - ); - } + } + }, + ); } } // inclusive range minus one: `x..=(y-1)` fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if expr.span.can_be_used_for_suggestions(); - if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr); - if let Some(y) = y_minus_one(cx, end); - then { - span_lint_and_then( - cx, - RANGE_MINUS_ONE, - expr.span, - "an exclusive range would be more readable", - |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); - let end = Sugg::hir(cx, y, "y").maybe_par(); - diag.span_suggestion( - expr.span, - "use", - format!("{start}..{end}"), - Applicability::MachineApplicable, // snippet - ); - }, - ); - } + if expr.span.can_be_used_for_suggestions() + && let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr) + && let Some(y) = y_minus_one(cx, end) + { + span_lint_and_then( + cx, + RANGE_MINUS_ONE, + expr.span, + "an exclusive range would be more readable", + |diag| { + let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); + let end = Sugg::hir(cx, y, "y").maybe_par(); + diag.span_suggestion( + expr.span, + "use", + format!("{start}..{end}"), + Applicability::MachineApplicable, // snippet + ); + }, + ); } } @@ -446,52 +440,50 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { } } - if_chain! { - if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr); - let ty = cx.typeck_results().expr_ty(start); - if let ty::Int(_) | ty::Uint(_) = ty.kind(); - if let Some(start_idx) = constant(cx, cx.typeck_results(), start); - if let Some(end_idx) = constant(cx, cx.typeck_results(), end); - if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); - if is_empty_range(limits, ordering); - then { - if inside_indexing_expr(cx, expr) { - // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ... - if ordering != Ordering::Equal { - span_lint( - cx, - REVERSED_EMPTY_RANGES, - expr.span, - "this range is reversed and using it to index a slice will panic at run-time", - ); - } - // ... except in for loop arguments for backwards compatibility with `reverse_range_loop` - } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) { - span_lint_and_then( + if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr) + && let ty = cx.typeck_results().expr_ty(start) + && let ty::Int(_) | ty::Uint(_) = ty.kind() + && let Some(start_idx) = constant(cx, cx.typeck_results(), start) + && let Some(end_idx) = constant(cx, cx.typeck_results(), end) + && let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx) + && is_empty_range(limits, ordering) + { + if inside_indexing_expr(cx, expr) { + // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ... + if ordering != Ordering::Equal { + span_lint( cx, REVERSED_EMPTY_RANGES, expr.span, - "this range is empty so it will yield no values", - |diag| { - if ordering != Ordering::Equal { - let start_snippet = snippet(cx, start.span, "_"); - let end_snippet = snippet(cx, end.span, "_"); - let dots = match limits { - RangeLimits::HalfOpen => "..", - RangeLimits::Closed => "..=" - }; - - diag.span_suggestion( - expr.span, - "consider using the following if you are attempting to iterate over this \ - range in reverse", - format!("({end_snippet}{dots}{start_snippet}).rev()"), - Applicability::MaybeIncorrect, - ); - } - }, + "this range is reversed and using it to index a slice will panic at run-time", ); } + // ... except in for loop arguments for backwards compatibility with `reverse_range_loop` + } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) { + span_lint_and_then( + cx, + REVERSED_EMPTY_RANGES, + expr.span, + "this range is empty so it will yield no values", + |diag| { + if ordering != Ordering::Equal { + let start_snippet = snippet(cx, start.span, "_"); + let end_snippet = snippet(cx, end.span, "_"); + let dots = match limits { + RangeLimits::HalfOpen => "..", + RangeLimits::Closed => "..=" + }; + + diag.span_suggestion( + expr.span, + "consider using the following if you are attempting to iterate over this \ + range in reverse", + format!("({end_snippet}{dots}{start_snippet}).rev()"), + Applicability::MaybeIncorrect, + ); + } + }, + ); } } } diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 59ce289e7d2..7d86252e6c5 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -118,26 +118,24 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr< /// Checks whether the given `expr` is a call to `Arc::new`, `Rc::new`, or evaluates to a `Weak` fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { - if_chain! { - if let ExprKind::Call(func, _args) = expr.kind; - if let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind; - if let TyKind::Path(ref ty_path) = ty.kind; - if let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id(); + if let ExprKind::Call(func, _args) = expr.kind + && let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind + && let TyKind::Path(ref ty_path) = ty.kind + && let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id() - then { - if last_path_segment(func_path).ident.name == sym::new - && let Some(symbol) = cx - .tcx - .get_diagnostic_name(def_id) - .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) { - return Some((symbol, func.span)); - } + { + if last_path_segment(func_path).ident.name == sym::new + && let Some(symbol) = cx + .tcx + .get_diagnostic_name(def_id) + .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) { + return Some((symbol, func.span)); + } - if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() - && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) - { - return Some((Symbol::intern("Weak"), func.span)); - } + if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) + { + return Some((Symbol::intern("Weak"), func.span)); } } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index ef14e68967e..ecc5a28519b 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -146,18 +146,16 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let pred_terminator = mir[ps[0]].terminator(); // receiver of the `deref()` call - let (pred_arg, deref_clone_ret) = if_chain! { - if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) = - is_call_with_ref_arg(cx, mir, &pred_terminator.kind); - if res == cloned; - if cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id); - if is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf) - || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString); - then { - (pred_arg, res) - } else { - continue; - } + let (pred_arg, deref_clone_ret) = if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) = + is_call_with_ref_arg(cx, mir, &pred_terminator.kind) + && res == cloned + && cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id) + && (is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf) + || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString)) + { + (pred_arg, res) + } else { + continue; }; let (local, cannot_move_out) = @@ -212,45 +210,43 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { .assert_crate_local() .lint_root; - if_chain! { - if let Some(snip) = snippet_opt(cx, span); - if let Some(dot) = snip.rfind('.'); - then { - let sugg_span = span.with_lo( - span.lo() + BytePos(u32::try_from(dot).unwrap()) - ); - let mut app = Applicability::MaybeIncorrect; - - let call_snip = &snip[dot + 1..]; - // Machine applicable when `call_snip` looks like `foobar()` - if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) { - if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') { - app = Applicability::MachineApplicable; - } + if let Some(snip) = snippet_opt(cx, span) + && let Some(dot) = snip.rfind('.') + { + let sugg_span = span.with_lo( + span.lo() + BytePos(u32::try_from(dot).unwrap()) + ); + let mut app = Applicability::MaybeIncorrect; + + let call_snip = &snip[dot + 1..]; + // Machine applicable when `call_snip` looks like `foobar()` + if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) { + if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') { + app = Applicability::MachineApplicable; } + } - span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| { - diag.span_suggestion( - sugg_span, - "remove this", - "", - app, + span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| { + diag.span_suggestion( + sugg_span, + "remove this", + "", + app, + ); + if clone_usage.cloned_used { + diag.span_note( + span, + "cloned value is neither consumed nor mutated", ); - if clone_usage.cloned_used { - diag.span_note( - span, - "cloned value is neither consumed nor mutated", - ); - } else { - diag.span_note( - span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())), - "this value is dropped without further use", - ); - } - }); - } else { - span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone"); - } + } else { + diag.span_note( + span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())), + "this value is dropped without further use", + ); + } + }); + } else { + span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone"); } } } @@ -262,18 +258,16 @@ fn is_call_with_ref_arg<'tcx>( mir: &'tcx mir::Body<'tcx>, kind: &'tcx mir::TerminatorKind<'tcx>, ) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, mir::Local)> { - if_chain! { - if let mir::TerminatorKind::Call { func, args, destination, .. } = kind; - if args.len() == 1; - if let mir::Operand::Move(mir::Place { local, .. }) = &args[0]; - if let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind(); - if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx)); - if !is_copy(cx, inner_ty); - then { - Some((def_id, *local, inner_ty, destination.as_local()?)) - } else { - None - } + if let mir::TerminatorKind::Call { func, args, destination, .. } = kind + && args.len() == 1 + && let mir::Operand::Move(mir::Place { local, .. }) = &args[0] + && let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind() + && let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx)) + && !is_copy(cx, inner_ty) + { + Some((def_id, *local, inner_ty, destination.as_local()?)) + } else { + None } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index e679fab5323..e8906d51e88 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -201,14 +201,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if_chain! { - if let hir::ExprKind::Call(closure, _) = expr.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind; - if self.path.segments[0].ident == path.segments[0].ident; - if self.path.res == path.res; - then { - self.count += 1; - } + if let hir::ExprKind::Call(closure, _) = expr.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind + && self.path.segments[0].ident == path.segments[0].ident + && self.path.res == path.res + { + self.count += 1; } hir_visit::walk_expr(self, expr); } @@ -223,25 +221,23 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { } for w in block.stmts.windows(2) { - if_chain! { - if let hir::StmtKind::Local(local) = w[0].kind; - if let Option::Some(t) = local.init; - if let hir::ExprKind::Closure { .. } = t.kind; - if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind; - if let hir::StmtKind::Semi(second) = w[1].kind; - if let hir::ExprKind::Assign(_, call, _) = second.kind; - if let hir::ExprKind::Call(closure, _) = call.kind; - if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind; - if ident == path.segments[0].ident; - if count_closure_usage(cx, block, path) == 1; - then { - span_lint( - cx, - REDUNDANT_CLOSURE_CALL, - second.span, - "closure called just once immediately after it was declared", - ); - } + if let hir::StmtKind::Local(local) = w[0].kind + && let Option::Some(t) = local.init + && let hir::ExprKind::Closure { .. } = t.kind + && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind + && let hir::StmtKind::Semi(second) = w[1].kind + && let hir::ExprKind::Assign(_, call, _) = second.kind + && let hir::ExprKind::Call(closure, _) = call.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind + && ident == path.segments[0].ident + && count_closure_usage(cx, block, path) == 1 + { + span_lint( + cx, + REDUNDANT_CLOSURE_CALL, + second.span, + "closure called just once immediately after it was declared", + ); } } } diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 6bc0d06183f..15b784039b6 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -46,40 +46,38 @@ declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]); impl<'tcx> LateLintPass<'tcx> for RedundantLocals { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { - if_chain! { - if !local.span.is_desugaring(DesugaringKind::Async); + if !local.span.is_desugaring(DesugaringKind::Async) // the pattern is a single by-value binding - if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind; + && let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind // the binding is not type-ascribed - if local.ty.is_none(); + && local.ty.is_none() // the expression is a resolved path - if let Some(expr) = local.init; - if let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind; + && let Some(expr) = local.init + && let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind // the path is a single segment equal to the local's name - if let [last_segment] = path.segments; - if last_segment.ident == ident; + && let [last_segment] = path.segments + && last_segment.ident == ident // resolve the path to its defining binding pattern - if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id); - if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id); + && let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id) + && let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id) // the previous binding has the same mutability - if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability); + && find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability) // the local does not change the effect of assignments to the binding. see #11290 - if !affects_assignments(cx, mutability, binding_id, local.hir_id); + && !affects_assignments(cx, mutability, binding_id, local.hir_id) // the local does not affect the code's drop behavior - if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr)); + && !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr)) // the local is user-controlled - if !in_external_macro(cx.sess(), local.span); - if !is_from_proc_macro(cx, expr); - then { - span_lint_and_help( - cx, - REDUNDANT_LOCALS, - local.span, - &format!("redundant redefinition of a binding `{ident}`"), - Some(binding_pat.span), - &format!("`{ident}` is initially defined here"), - ); - } + && !in_external_macro(cx.sess(), local.span) + && !is_from_proc_macro(cx, expr) + { + span_lint_and_help( + cx, + REDUNDANT_LOCALS, + local.span, + &format!("redundant redefinition of a binding `{ident}`"), + Some(binding_pat.span), + &format!("`{ident}` is initially defined here"), + ); } } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 03673eb27f8..d25e8c2de03 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -45,28 +45,26 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]); impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if_chain! { - if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()); - if !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false); - if is_not_macro_export(item); - then { - let span = item.span.with_hi(item.ident.span.hi()); - let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id()); - span_lint_and_then( - cx, - REDUNDANT_PUB_CRATE, - span, - &format!("pub(crate) {descr} inside private module"), - |diag| { - diag.span_suggestion( - item.vis_span, - "consider using", - "pub".to_string(), - Applicability::MachineApplicable, - ); - }, - ); - } + if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) + && is_not_macro_export(item) + { + let span = item.span.with_hi(item.ident.span.hi()); + let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id()); + span_lint_and_then( + cx, + REDUNDANT_PUB_CRATE, + span, + &format!("pub(crate) {descr} inside private module"), + |diag| { + diag.span_suggestion( + item.vis_span, + "consider using", + "pub".to_string(), + Applicability::MachineApplicable, + ); + }, + ); } if let ItemKind::Mod { .. } = item.kind { diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 7adbd67912c..48bcd676ab9 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -78,92 +78,90 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } let ctxt = expr.span.ctxt(); - if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind; - if addressee.span.ctxt() == ctxt; - if let ExprKind::Index(indexed, range, _) = addressee.kind; - if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull); - then { - let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); - let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed)); - let parent_expr = get_parent_expr(cx, expr); - let needs_parens_for_prefix = parent_expr.map_or(false, |parent| { - parent.precedence().order() > PREC_PREFIX - }); - let mut app = Applicability::MachineApplicable; + if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind + && addressee.span.ctxt() == ctxt + && let ExprKind::Index(indexed, range, _) = addressee.kind + && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull) + { + let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); + let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed)); + let parent_expr = get_parent_expr(cx, expr); + let needs_parens_for_prefix = parent_expr.map_or(false, |parent| { + parent.precedence().order() > PREC_PREFIX + }); + let mut app = Applicability::MachineApplicable; - let ((lint, msg), help, sugg) = if expr_ty == indexed_ty { - if expr_ref_count > indexed_ref_count { - // Indexing takes self by reference and can't return a reference to that - // reference as it's a local variable. The only way this could happen is if - // `self` contains a reference to the `Self` type. If this occurs then the - // lint no longer applies as it's essentially a field access, which is not - // redundant. - return; - } - let deref_count = indexed_ref_count - expr_ref_count; + let ((lint, msg), help, sugg) = if expr_ty == indexed_ty { + if expr_ref_count > indexed_ref_count { + // Indexing takes self by reference and can't return a reference to that + // reference as it's a local variable. The only way this could happen is if + // `self` contains a reference to the `Self` type. If this occurs then the + // lint no longer applies as it's essentially a field access, which is not + // redundant. + return; + } + let deref_count = indexed_ref_count - expr_ref_count; - let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut { - // The slice was used to reborrow the mutable reference. - (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead") - } else if matches!( - parent_expr, - Some(Expr { - kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _), - .. - }) - ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| { - matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))) - }) { - // The slice was used to make a temporary reference. - (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead") - } else if deref_count != 0 { - (DEREF_BY_SLICING_LINT, "", "dereference the original value instead") - } else { - (REDUNDANT_SLICING_LINT, "", "use the original value instead") - }; + let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut { + // The slice was used to reborrow the mutable reference. + (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead") + } else if matches!( + parent_expr, + Some(Expr { + kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _), + .. + }) + ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| { + matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))) + }) { + // The slice was used to make a temporary reference. + (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead") + } else if deref_count != 0 { + (DEREF_BY_SLICING_LINT, "", "dereference the original value instead") + } else { + (REDUNDANT_SLICING_LINT, "", "use the original value instead") + }; - let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; - let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix { - format!("({reborrow_str}{}{snip})", "*".repeat(deref_count)) - } else { - format!("{reborrow_str}{}{snip}", "*".repeat(deref_count)) - }; + let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; + let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix { + format!("({reborrow_str}{}{snip})", "*".repeat(deref_count)) + } else { + format!("{reborrow_str}{}{snip}", "*".repeat(deref_count)) + }; - (lint, help_str, sugg) - } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { - if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( - cx.param_env, - Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), - ) { - if deref_ty == expr_ty { - let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; - let sugg = if needs_parens_for_prefix { - format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count)) - } else { - format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count)) - }; - (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg) + (lint, help_str, sugg) + } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { + if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( + cx.param_env, + Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), + ) { + if deref_ty == expr_ty { + let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; + let sugg = if needs_parens_for_prefix { + format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count)) } else { - return; - } + format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count)) + }; + (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg) } else { return; } } else { return; - }; + } + } else { + return; + }; - span_lint_and_sugg( - cx, - lint, - expr.span, - msg, - help, - sugg, - app, - ); - } + span_lint_and_sugg( + cx, + lint, + expr.span, + msg, + help, + sugg, + app, + ); } } } diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index c984a8286eb..472cde7cd15 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -38,34 +38,32 @@ declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]); impl<'tcx> LateLintPass<'tcx> for RefOptionRef { fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { - if_chain! { - if let TyKind::Ref(_, ref mut_ty) = ty.kind; - if mut_ty.mutbl == Mutability::Not; - if let TyKind::Path(ref qpath) = &mut_ty.ty.kind; - let last = last_path_segment(qpath); - if let Some(def_id) = last.res.opt_def_id(); + if let TyKind::Ref(_, ref mut_ty) = ty.kind + && mut_ty.mutbl == Mutability::Not + && let TyKind::Path(ref qpath) = &mut_ty.ty.kind + && let last = last_path_segment(qpath) + && let Some(def_id) = last.res.opt_def_id() - if cx.tcx.is_diagnostic_item(sym::Option, def_id); - if let Some(params) = last_path_segment(qpath).args ; - if params.parenthesized == GenericArgsParentheses::No; - if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { + && cx.tcx.is_diagnostic_item(sym::Option, def_id) + && let Some(params) = last_path_segment(qpath).args + && params.parenthesized == GenericArgsParentheses::No + && let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(inner_ty) => Some(inner_ty), _ => None, - }); - if let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind; - if inner_mut_ty.mutbl == Mutability::Not; + }) + && let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind + && inner_mut_ty.mutbl == Mutability::Not - then { - span_lint_and_sugg( - cx, - REF_OPTION_REF, - ty.span, - "since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`", - "try", - format!("Option<{}>", &snippet(cx, inner_ty.span, "..")), - Applicability::MaybeIncorrect, - ); - } + { + span_lint_and_sugg( + cx, + REF_OPTION_REF, + ty.span, + "since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`", + "try", + format!("Option<{}>", &snippet(cx, inner_ty.span, "..")), + Applicability::MaybeIncorrect, + ); } } } diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 12da29f1108..74d2814f91e 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -47,58 +47,56 @@ fn without_parens(mut e: &Expr) -> &Expr { impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if_chain! { - if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; - if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; - if deref_target.span.eq_ctxt(e.span); - if !addrof_target.span.from_expansion(); - then { - let mut applicability = Applicability::MachineApplicable; - let sugg = if e.span.from_expansion() { - if let Some(macro_source) = snippet_opt(cx, e.span) { - // Remove leading whitespace from the given span - // e.g: ` $visitor` turns into `$visitor` - let trim_leading_whitespaces = |span| { - snippet_opt(cx, span).and_then(|snip| { - #[expect(clippy::cast_possible_truncation)] - snip.find(|c: char| !c.is_whitespace()).map(|pos| { - span.lo() + BytePos(pos as u32) - }) - }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) - }; - - let mut generate_snippet = |pattern: &str| { + if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind + && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind + && deref_target.span.eq_ctxt(e.span) + && !addrof_target.span.from_expansion() + { + let mut applicability = Applicability::MachineApplicable; + let sugg = if e.span.from_expansion() { + if let Some(macro_source) = snippet_opt(cx, e.span) { + // Remove leading whitespace from the given span + // e.g: ` $visitor` turns into `$visitor` + let trim_leading_whitespaces = |span| { + snippet_opt(cx, span).and_then(|snip| { #[expect(clippy::cast_possible_truncation)] - macro_source.rfind(pattern).map(|pattern_pos| { - let rpos = pattern_pos + pattern.len(); - let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); - let span = trim_leading_whitespaces(span_after_ref); - snippet_with_applicability(cx, span, "_", &mut applicability) + snip.find(|c: char| !c.is_whitespace()).map(|pos| { + span.lo() + BytePos(pos as u32) }) - }; + }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) + }; + + let mut generate_snippet = |pattern: &str| { + #[expect(clippy::cast_possible_truncation)] + macro_source.rfind(pattern).map(|pattern_pos| { + let rpos = pattern_pos + pattern.len(); + let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); + let span = trim_leading_whitespaces(span_after_ref); + snippet_with_applicability(cx, span, "_", &mut applicability) + }) + }; - if *mutability == Mutability::Mut { - generate_snippet("mut") - } else { - generate_snippet("&") - } + if *mutability == Mutability::Mut { + generate_snippet("mut") } else { - Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) + generate_snippet("&") } } else { - Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)) - }; - if let Some(sugg) = sugg { - span_lint_and_sugg( - cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try", - sugg.to_string(), - applicability, - ); + Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) } + } else { + Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)) + }; + if let Some(sugg) = sugg { + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try", + sugg.to_string(), + applicability, + ); } } } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index b795e4b15ba..3571b9bfb8d 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -191,13 +191,11 @@ fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { } fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { - if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; - if let ExprKind::Array(exprs) = expr.kind; - then { - for expr in exprs { - check_regex(cx, expr, utf8); - } + if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind + && let ExprKind::Array(exprs) = expr.kind + { + for expr in exprs { + check_regex(cx, expr, utf8); } } } diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 245029a066d..8913f4a2e7e 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -69,35 +69,33 @@ declare_clippy_lint! { declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]); fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) { - if_chain! { + if !in_external_macro(cx.sess(), span) // If it comes from an external macro, better ignore it. - if !in_external_macro(cx.sess(), span); - if decl.implicit_self.has_implicit_self(); + && decl.implicit_self.has_implicit_self() // We only show this warning for public exported methods. - if cx.effective_visibilities.is_exported(fn_def); + && cx.effective_visibilities.is_exported(fn_def) // We don't want to emit this lint if the `#[must_use]` attribute is already there. - if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)); - if cx.tcx.visibility(fn_def.to_def_id()).is_public(); - let ret_ty = return_ty(cx, owner_id); - let self_arg = nth_arg(cx, owner_id, 0); + && !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)) + && cx.tcx.visibility(fn_def.to_def_id()).is_public() + && let ret_ty = return_ty(cx, owner_id) + && let self_arg = nth_arg(cx, owner_id, 0) // If `Self` has the same type as the returned type, then we want to warn. // // For this check, we don't want to remove the reference on the returned type because if // there is one, we shouldn't emit a warning! - if self_arg.peel_refs() == ret_ty; + && self_arg.peel_refs() == ret_ty // If `Self` is already marked as `#[must_use]`, no need for the attribute here. - if !is_must_use_ty(cx, ret_ty); + && !is_must_use_ty(cx, ret_ty) - then { - span_lint_and_help( - cx, - RETURN_SELF_NOT_MUST_USE, - span, - "missing `#[must_use]` attribute on a method returning `Self`", - None, - "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type" - ); - } + { + span_lint_and_help( + cx, + RETURN_SELF_NOT_MUST_USE, + span, + "missing `#[must_use]` attribute on a method returning `Self`", + None, + "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type" + ); } } @@ -111,18 +109,16 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse { span: Span, fn_def: LocalDefId, ) { - if_chain! { + if matches!(kind, FnKind::Method(_, _)) // We are only interested in methods, not in functions or associated functions. - if matches!(kind, FnKind::Method(_, _)); - if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id()); + && let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id()) // We don't want this method to be te implementation of a trait because the // `#[must_use]` should be put on the trait definition directly. - if cx.tcx.trait_id_of_impl(impl_def).is_none(); + && cx.tcx.trait_id_of_impl(impl_def).is_none() - then { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def); - check_method(cx, decl, fn_def, span, hir_id.expect_owner()); - } + { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def); + check_method(cx, decl, fn_def, span, hir_id.expect_owner()); } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 72235a954ba..bab20d0e1f6 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -189,50 +189,48 @@ impl<'tcx> LateLintPass<'tcx> for Return { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { // we need both a let-binding stmt and an expr - if_chain! { - if let Some(retexpr) = block.expr; - if let Some(stmt) = block.stmts.iter().last(); - if let StmtKind::Local(local) = &stmt.kind; - if local.ty.is_none(); - if cx.tcx.hir().attrs(local.hir_id).is_empty(); - if let Some(initexpr) = &local.init; - if let PatKind::Binding(_, local_id, _, _) = local.pat.kind; - if path_to_local_id(retexpr, local_id); - if !last_statement_borrows(cx, initexpr); - if !in_external_macro(cx.sess(), initexpr.span); - if !in_external_macro(cx.sess(), retexpr.span); - if !local.span.from_expansion(); - then { - span_lint_hir_and_then( - cx, - LET_AND_RETURN, - retexpr.hir_id, - retexpr.span, - "returning the result of a `let` binding from a block", - |err| { - err.span_label(local.span, "unnecessary `let` binding"); + if let Some(retexpr) = block.expr + && let Some(stmt) = block.stmts.iter().last() + && let StmtKind::Local(local) = &stmt.kind + && local.ty.is_none() + && cx.tcx.hir().attrs(local.hir_id).is_empty() + && let Some(initexpr) = &local.init + && let PatKind::Binding(_, local_id, _, _) = local.pat.kind + && path_to_local_id(retexpr, local_id) + && !last_statement_borrows(cx, initexpr) + && !in_external_macro(cx.sess(), initexpr.span) + && !in_external_macro(cx.sess(), retexpr.span) + && !local.span.from_expansion() + { + span_lint_hir_and_then( + cx, + LET_AND_RETURN, + retexpr.hir_id, + retexpr.span, + "returning the result of a `let` binding from a block", + |err| { + err.span_label(local.span, "unnecessary `let` binding"); - if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { - if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { - if !has_enclosing_paren(&snippet) { - snippet = format!("({snippet})"); - } - snippet.push_str(" as _"); + if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { + if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { + if !has_enclosing_paren(&snippet) { + snippet = format!("({snippet})"); } - err.multipart_suggestion( - "return the expression directly", - vec![ - (local.span, String::new()), - (retexpr.span, snippet), - ], - Applicability::MachineApplicable, - ); - } else { - err.span_help(initexpr.span, "this expression can be directly returned"); + snippet.push_str(" as _"); } - }, - ); - } + err.multipart_suggestion( + "return the expression directly", + vec![ + (local.span, String::new()), + (retexpr.span, snippet), + ], + Applicability::MachineApplicable, + ); + } else { + err.span_help(initexpr.span, "this expression can be directly returned"); + } + }, + ); } } diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 9587326ca00..a6ad0b5cc1e 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -75,26 +75,24 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { match of_trait { Some(trait_ref) => { - let mut methods_in_trait: BTreeSet = if_chain! { - if let Some(Node::TraitRef(TraitRef { path, .. })) = - cx.tcx.hir().find(trait_ref.hir_ref_id); - if let Res::Def(DefKind::Trait, did) = path.res; - then{ - // FIXME: if - // `rustc_middle::ty::assoc::AssocItems::items` is public, - // we can iterate its keys instead of `in_definition_order`, - // which's more efficient - cx.tcx - .associated_items(did) - .in_definition_order() - .filter(|assoc_item| { - matches!(assoc_item.kind, AssocKind::Fn) - }) - .map(|assoc_item| assoc_item.name) - .collect() - }else{ - BTreeSet::new() - } + let mut methods_in_trait: BTreeSet = if let Some(Node::TraitRef(TraitRef { path, .. })) = + cx.tcx.hir().find(trait_ref.hir_ref_id) + && let Res::Def(DefKind::Trait, did) = path.res + { + // FIXME: if + // `rustc_middle::ty::assoc::AssocItems::items` is public, + // we can iterate its keys instead of `in_definition_order`, + // which's more efficient + cx.tcx + .associated_items(did) + .in_definition_order() + .filter(|assoc_item| { + matches!(assoc_item.kind, AssocKind::Fn) + }) + .map(|assoc_item| assoc_item.name) + .collect() + }else{ + BTreeSet::new() }; let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| { diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index b92014f68b3..578188a66af 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -70,22 +70,20 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { return; } - if_chain! { - if let Some(self_def) = self_ty.ty_adt_def(); - if let Some(self_local_did) = self_def.did().as_local(); - let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); - if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id); - let type_name = x.ident.name.as_str().to_lowercase(); - if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name; + if let Some(self_def) = self_ty.ty_adt_def() + && let Some(self_local_did) = self_def.did().as_local() + && let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did) + && let Some(Node::Item(x)) = cx.tcx.hir().find(self_id) + && let type_name = x.ident.name.as_str().to_lowercase() + && (impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name) - then { - span_lint( - cx, - SELF_NAMED_CONSTRUCTORS, - impl_item.span, - &format!("constructor `{}` has the same name as the type", impl_item.ident.name), - ); - } + { + span_lint( + cx, + SELF_NAMED_CONSTRUCTORS, + impl_item.span, + &format!("constructor `{}` has the same name as the type", impl_item.ident.name), + ); } } } diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index ccf8b997705..dc606e90707 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -38,30 +38,28 @@ declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED] impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { - if_chain! { - if !block.span.from_expansion(); - if let Some(expr) = block.expr; - let t_expr = cx.typeck_results().expr_ty(expr); - if t_expr.is_unit(); - let mut app = Applicability::MachineApplicable; - if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0; - if !snippet.ends_with('}') && !snippet.ends_with(';'); - if cx.sess().source_map().is_multiline(block.span); - then { - // filter out the desugared `for` loop - if let ExprKind::DropTemps(..) = &expr.kind { - return; - } - span_lint_and_sugg( - cx, - SEMICOLON_IF_NOTHING_RETURNED, - expr.span.source_callsite(), - "consider adding a `;` to the last statement for consistent formatting", - "add a `;` here", - format!("{snippet};"), - app, - ); + if !block.span.from_expansion() + && let Some(expr) = block.expr + && let t_expr = cx.typeck_results().expr_ty(expr) + && t_expr.is_unit() + && let mut app = Applicability::MachineApplicable + && let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0 + && !snippet.ends_with('}') && !snippet.ends_with(';') + && cx.sess().source_map().is_multiline(block.span) + { + // filter out the desugared `for` loop + if let ExprKind::DropTemps(..) = &expr.kind { + return; } + span_lint_and_sugg( + cx, + SEMICOLON_IF_NOTHING_RETURNED, + expr.span.source_callsite(), + "consider adding a `;` to the last statement for consistent formatting", + "add a `;` here", + format!("{snippet};"), + app, + ); } } } diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index b940cac6047..2ea9122cfc4 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -39,16 +39,14 @@ declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option> { match expr.kind { ExprKind::Call(count_func, _func_args) => { - if_chain! { - if !inverted; - if let ExprKind::Path(ref count_func_qpath) = count_func.kind; - if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); - if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::mem_size_of | sym::mem_size_of_val)); - then { - cx.typeck_results().node_args(count_func.hir_id).types().next() - } else { - None - } + if !inverted + && let ExprKind::Path(ref count_func_qpath) = count_func.kind + && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id() + && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::mem_size_of | sym::mem_size_of_val)) + { + cx.typeck_results().node_args(count_func.hir_id).types().next() + } else { + None } }, ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node => { @@ -80,13 +78,12 @@ fn get_pointee_ty_and_count_expr<'tcx>( "wrapping_offset", ]; - if_chain! { + if let ExprKind::Call(func, [.., count]) = expr.kind // Find calls to ptr::{copy, copy_nonoverlapping} // and ptr::{swap_nonoverlapping, write_bytes}, - if let ExprKind::Call(func, [.., count]) = expr.kind; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if matches!(cx.tcx.get_diagnostic_name(def_id), Some( + && let ExprKind::Path(ref func_qpath) = func.kind + && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() + && matches!(cx.tcx.get_diagnostic_name(def_id), Some( sym::ptr_copy | sym::ptr_copy_nonoverlapping | sym::ptr_slice_from_raw_parts @@ -95,26 +92,23 @@ fn get_pointee_ty_and_count_expr<'tcx>( | sym::ptr_write_bytes | sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut - )); + )) // Get the pointee type - if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next(); - then { - return Some((pointee_ty, count)); - } + && let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next() + { + return Some((pointee_ty, count)); }; - if_chain! { + if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods - if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind; - let method_ident = method_path.ident.as_str(); - if METHODS.iter().any(|m| *m == method_ident); + && let method_ident = method_path.ident.as_str() + && METHODS.iter().any(|m| *m == method_ident) // Get the pointee type - if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = - cx.typeck_results().expr_ty(ptr_self).kind(); - then { - return Some((*pointee_ty, count)); - } + && let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = + cx.typeck_results().expr_ty(ptr_self).kind() + { + return Some((*pointee_ty, count)); }; None } @@ -127,25 +121,23 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { const LINT_MSG: &str = "found a count of bytes \ instead of a count of elements of `T`"; - if_chain! { + if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr) // Find calls to functions with an element count parameter and get // the pointee type and count parameter expression - if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr); // Find a size_of call in the count parameter expression and // check that it's the same type - if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false); - if pointee_ty == ty_used_for_size_of; - then { - span_lint_and_help( - cx, - SIZE_OF_IN_ELEMENT_COUNT, - count_expr.span, - LINT_MSG, - None, - HELP_MSG - ); - } + && let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false) + && pointee_ty == ty_used_for_size_of + { + span_lint_and_help( + cx, + SIZE_OF_IN_ELEMENT_COUNT, + count_expr.span, + LINT_MSG, + None, + HELP_MSG + ); }; } } diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 2244eab96ca..7de0beb1292 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -103,41 +103,37 @@ enum InitializationType<'tcx> { impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)` - if_chain! { - if let ExprKind::Assign(left, right, _) = expr.kind; - if let Some(local_id) = path_to_local(left); - if let Some(size_expr) = Self::as_vec_initializer(cx, right); - - then { - let vi = VecAllocation { - local_id, - allocation_expr: right, - size_expr, - }; - - Self::search_initialization(cx, vi, expr.hir_id); - } + if let ExprKind::Assign(left, right, _) = expr.kind + && let Some(local_id) = path_to_local(left) + && let Some(size_expr) = Self::as_vec_initializer(cx, right) + + { + let vi = VecAllocation { + local_id, + allocation_expr: right, + size_expr, + }; + + Self::search_initialization(cx, vi, expr.hir_id); } } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` // or `Vec::new()` - if_chain! { - if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind; - if let Some(init) = local.init; - if let Some(size_expr) = Self::as_vec_initializer(cx, init); - - then { - let vi = VecAllocation { - local_id, - allocation_expr: init, - size_expr, - }; - - Self::search_initialization(cx, vi, stmt.hir_id); - } + if let StmtKind::Local(local) = stmt.kind + && let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind + && let Some(init) = local.init + && let Some(size_expr) = Self::as_vec_initializer(cx, init) + + { + let vi = VecAllocation { + local_id, + allocation_expr: init, + size_expr, + }; + + Self::search_initialization(cx, vi, stmt.hir_id); } } } @@ -242,16 +238,14 @@ struct VectorInitializationVisitor<'a, 'tcx> { impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Checks if the given expression is extending a vector with `repeat(0).take(..)` fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { - if_chain! { - if self.initialization_found; - if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind; - if path_to_local_id(self_arg, self.vec_alloc.local_id); - if path.ident.name == sym!(extend); - if self.is_repeat_take(extend_arg); - - then { - self.slow_expression = Some(InitializationType::Extend(expr)); - } + if self.initialization_found + && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind + && path_to_local_id(self_arg, self.vec_alloc.local_id) + && path.ident.name == sym!(extend) + && self.is_repeat_take(extend_arg) + + { + self.slow_expression = Some(InitializationType::Extend(expr)); } } @@ -281,21 +275,19 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool { - if_chain! { - if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind; - if take_path.ident.name == sym!(take); + if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind + && take_path.ident.name == sym!(take) // Check that take is applied to `repeat(0)` - if self.is_repeat_zero(recv); - then { - if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { - // Check that len expression is equals to `with_capacity` expression - return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) - || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity") - } - - self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); - return true; + && self.is_repeat_zero(recv) + { + if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { + // Check that len expression is equals to `with_capacity` expression + return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) + || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity") } + + self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); + return true; } false @@ -303,15 +295,13 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if given expression is `repeat(0)` fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool { - if_chain! { - if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; - if is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat); - if is_integer_literal(repeat_arg, 0); - then { - true - } else { - false - } + if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind + && is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat) + && is_integer_literal(repeat_arg, 0) + { + true + } else { + false } } } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index a44adc93855..f4f0d0ac551 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -255,124 +255,118 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use rustc_ast::LitKind; - if_chain! { + if let ExprKind::Call(fun, args) = e.kind // Find std::str::converts::from_utf8 - if let ExprKind::Call(fun, args) = e.kind; - if is_path_diagnostic_item(cx, fun, sym::str_from_utf8); + && is_path_diagnostic_item(cx, fun, sym::str_from_utf8) // Find string::as_bytes - if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind; - if let ExprKind::Index(left, right, _) = args.kind; - let (method_names, expressions, _) = method_calls(left, 1); - if method_names.len() == 1; - if expressions.len() == 1; - if expressions[0].1.is_empty(); - if method_names[0] == sym!(as_bytes); + && let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind + && let ExprKind::Index(left, right, _) = args.kind + && let (method_names, expressions, _) = method_calls(left, 1) + && method_names.len() == 1 + && expressions.len() == 1 + && expressions[0].1.is_empty() + && method_names[0] == sym!(as_bytes) // Check for slicer - if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind; + && let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind - then { - let mut applicability = Applicability::MachineApplicable; - let string_expression = &expressions[0].0; + { + let mut applicability = Applicability::MachineApplicable; + let string_expression = &expressions[0].0; - let snippet_app = snippet_with_applicability( - cx, - string_expression.span, "..", - &mut applicability, - ); + let snippet_app = snippet_with_applicability( + cx, + string_expression.span, "..", + &mut applicability, + ); + + span_lint_and_sugg( + cx, + STRING_FROM_UTF8_AS_BYTES, + e.span, + "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", + "try", + format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), + applicability + ) + } + if !in_external_macro(cx.sess(), e.span) + && let ExprKind::MethodCall(path, receiver, ..) = &e.kind + && path.ident.name == sym!(as_bytes) + && let ExprKind::Lit(lit) = &receiver.kind + && let LitKind::Str(lit_content, _) = &lit.node + { + let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#); + let mut applicability = Applicability::MachineApplicable; + if callsite.starts_with("include_str!") { span_lint_and_sugg( cx, - STRING_FROM_UTF8_AS_BYTES, + STRING_LIT_AS_BYTES, e.span, - "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", - "try", - format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), - applicability - ) - } - } - - if_chain! { - if !in_external_macro(cx.sess(), e.span); - if let ExprKind::MethodCall(path, receiver, ..) = &e.kind; - if path.ident.name == sym!(as_bytes); - if let ExprKind::Lit(lit) = &receiver.kind; - if let LitKind::Str(lit_content, _) = &lit.node; - then { - let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#); - let mut applicability = Applicability::MachineApplicable; - if callsite.starts_with("include_str!") { + "calling `as_bytes()` on `include_str!(..)`", + "consider using `include_bytes!(..)` instead", + snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen( + "include_str", + "include_bytes", + 1, + ), + applicability, + ); + } else if lit_content.as_str().is_ascii() + && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT + && !receiver.span.from_expansion() + { + if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e) + && let Node::Expr(parent) = parent + && let ExprKind::Match(scrutinee, ..) = parent.kind + && scrutinee.hir_id == id + { + // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces + // `&[u8]`. This change would prevent matching with different sized slices. + } else if !callsite.starts_with("env!") { span_lint_and_sugg( cx, STRING_LIT_AS_BYTES, e.span, - "calling `as_bytes()` on `include_str!(..)`", - "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen( - "include_str", - "include_bytes", - 1, + "calling `as_bytes()` on a string literal", + "consider using a byte string literal instead", + format!( + "b{}", + snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability) ), applicability, ); - } else if lit_content.as_str().is_ascii() - && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT - && !receiver.span.from_expansion() - { - if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e) - && let Node::Expr(parent) = parent - && let ExprKind::Match(scrutinee, ..) = parent.kind - && scrutinee.hir_id == id - { - // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces - // `&[u8]`. This change would prevent matching with different sized slices. - } else if !callsite.starts_with("env!") { - span_lint_and_sugg( - cx, - STRING_LIT_AS_BYTES, - e.span, - "calling `as_bytes()` on a string literal", - "consider using a byte string literal instead", - format!( - "b{}", - snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability) - ), - applicability, - ); - } } } } - if_chain! { - if let ExprKind::MethodCall(path, recv, [], _) = &e.kind; - if path.ident.name == sym!(into_bytes); - if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind; - if matches!(path.ident.name.as_str(), "to_owned" | "to_string"); - if let ExprKind::Lit(lit) = &recv.kind; - if let LitKind::Str(lit_content, _) = &lit.node; + if let ExprKind::MethodCall(path, recv, [], _) = &e.kind + && path.ident.name == sym!(into_bytes) + && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind + && matches!(path.ident.name.as_str(), "to_owned" | "to_string") + && let ExprKind::Lit(lit) = &recv.kind + && let LitKind::Str(lit_content, _) = &lit.node - if lit_content.as_str().is_ascii(); - if lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT; - if !recv.span.from_expansion(); - then { - let mut applicability = Applicability::MachineApplicable; + && lit_content.as_str().is_ascii() + && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT + && !recv.span.from_expansion() + { + let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - STRING_LIT_AS_BYTES, - e.span, - "calling `into_bytes()` on a string literal", - "consider using a byte string literal instead", - format!( - "b{}.to_vec()", - snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability) - ), - applicability, - ); - } + span_lint_and_sugg( + cx, + STRING_LIT_AS_BYTES, + e.span, + "calling `into_bytes()` on a string literal", + "consider using a byte string literal instead", + format!( + "b{}.to_vec()", + snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability) + ), + applicability, + ); } } } @@ -406,22 +400,20 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; - if path.ident.name == sym::to_string; - let ty = cx.typeck_results().expr_ty(self_arg); - if let ty::Ref(_, ty, ..) = ty.kind(); - if ty.is_str(); - then { - span_lint_and_help( - cx, - STR_TO_STRING, - expr.span, - "`to_string()` called on a `&str`", - None, - "consider using `.to_owned()`", - ); - } + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind + && path.ident.name == sym::to_string + && let ty = cx.typeck_results().expr_ty(self_arg) + && let ty::Ref(_, ty, ..) = ty.kind() + && ty.is_str() + { + span_lint_and_help( + cx, + STR_TO_STRING, + expr.span, + "`to_string()` called on a `&str`", + None, + "consider using `.to_owned()`", + ); } } } @@ -456,21 +448,19 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; - if path.ident.name == sym::to_string; - let ty = cx.typeck_results().expr_ty(self_arg); - if is_type_lang_item(cx, ty, LangItem::String); - then { - span_lint_and_help( - cx, - STRING_TO_STRING, - expr.span, - "`to_string()` called on a `String`", - None, - "consider using `.clone()`", - ); - } + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind + && path.ident.name == sym::to_string + && let ty = cx.typeck_results().expr_ty(self_arg) + && is_type_lang_item(cx, ty, LangItem::String) + { + span_lint_and_help( + cx, + STRING_TO_STRING, + expr.span, + "`to_string()` called on a `String`", + None, + "consider using `.clone()`", + ); } } } @@ -500,26 +490,24 @@ declare_lint_pass!(TrimSplitWhitespace => [TRIM_SPLIT_WHITESPACE]); impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); - if_chain! { - if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind; - if path.ident.name == sym!(split_whitespace); - if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id); - if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id); - if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind; - if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str(); - if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id); - if is_one_of_trim_diagnostic_items(cx, trim_def_id); - then { - span_lint_and_sugg( - cx, - TRIM_SPLIT_WHITESPACE, - trim_span.with_hi(split_ws_span.lo()), - &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), - &format!("remove `{trim_fn_name}()`"), - String::new(), - Applicability::MachineApplicable, - ); - } + if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind + && path.ident.name == sym!(split_whitespace) + && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id) + && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id) + && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind + && let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str() + && let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id) + && is_one_of_trim_diagnostic_items(cx, trim_def_id) + { + span_lint_and_sugg( + cx, + TRIM_SPLIT_WHITESPACE, + trim_span.with_hi(split_ws_span.lo()), + &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), + &format!("remove `{trim_fn_name}()`"), + String::new(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index b3db5e9a422..23aa1f76d2d 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -41,48 +41,46 @@ declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]); impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if !expr.span.from_expansion(); - if let ExprKind::Call(func, [recv]) = expr.kind; - if let ExprKind::Path(path) = &func.kind; - if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if match_libc_symbol(cx, did, "strlen"); - if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind; - if !recv.span.from_expansion(); - if path.ident.name == sym::as_ptr; - then { - let ctxt = expr.span.ctxt(); - let span = match get_parent_node(cx.tcx, expr.hir_id) { - Some(Node::Block(&Block { - rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), span, .. - })) - if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => { - span - } - _ => expr.span, - }; + if !expr.span.from_expansion() + && let ExprKind::Call(func, [recv]) = expr.kind + && let ExprKind::Path(path) = &func.kind + && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id() + && match_libc_symbol(cx, did, "strlen") + && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind + && !recv.span.from_expansion() + && path.ident.name == sym::as_ptr + { + let ctxt = expr.span.ctxt(); + let span = match get_parent_node(cx.tcx, expr.hir_id) { + Some(Node::Block(&Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), span, .. + })) + if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => { + span + } + _ => expr.span, + }; - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - let mut app = Applicability::MachineApplicable; - let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; - let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) { - "as_bytes" - } else if is_type_lang_item(cx, ty, LangItem::CStr) { - "to_bytes" - } else { - return; - }; + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); + let mut app = Applicability::MachineApplicable; + let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; + let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) { + "as_bytes" + } else if is_type_lang_item(cx, ty, LangItem::CStr) { + "to_bytes" + } else { + return; + }; - span_lint_and_sugg( - cx, - STRLEN_ON_C_STRINGS, - span, - "using `libc::strlen` on a `CString` or `CStr` value", - "try", - format!("{val_name}.{method_name}().len()"), - app, - ); - } + span_lint_and_sugg( + cx, + STRLEN_ON_C_STRINGS, + span, + "using `libc::strlen` on a `CString` or `CStr` value", + "try", + format!("{val_name}.{method_name}().len()"), + app, + ); } } } diff --git a/clippy_lints/src/suspicious_doc_comments.rs b/clippy_lints/src/suspicious_doc_comments.rs index 0abc199da16..dd799d24ca3 100644 --- a/clippy_lints/src/suspicious_doc_comments.rs +++ b/clippy_lints/src/suspicious_doc_comments.rs @@ -76,19 +76,17 @@ fn collect_doc_comment_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> attrs .iter() .filter_map(|attr| { - if_chain! { - if let AttrKind::DocComment(com_kind, sym) = attr.kind; - if let AttrStyle::Outer = attr.style; - if let Some(com) = sym.as_str().strip_prefix('!'); - then { - let sugg = match com_kind { - CommentKind::Line => format!("//!{com}"), - CommentKind::Block => format!("/*!{com}*/") - }; - Some((attr.span, sugg)) - } else { - None - } + if let AttrKind::DocComment(com_kind, sym) = attr.kind + && let AttrStyle::Outer = attr.style + && let Some(com) = sym.as_str().strip_prefix('!') + { + let sugg = match com_kind { + CommentKind::Line => format!("//!{com}"), + CommentKind::Block => format!("/*!{com}*/") + }; + Some((attr.span, sugg)) + } else { + None } }) .collect() diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index bb8cde5b94d..eff0c8cd561 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -155,34 +155,32 @@ fn check_binops(cx: &EarlyContext<'_>, binops: &[&BinaryOp<'_>]) { match (no_difference_info, double_difference_info) { (Some(i), None) => attempt_to_emit_no_difference_lint(cx, binops, i, expected_loc), (None, Some((double_difference_index, ident_loc1, ident_loc2))) => { - if_chain! { - if one_ident_difference_count == binop_count - 1; - if let Some(binop) = binops.get(double_difference_index); - then { - let changed_loc = if ident_loc1 == expected_loc { - ident_loc2 - } else if ident_loc2 == expected_loc { - ident_loc1 - } else { - // This expression doesn't match the form we're - // looking for. - return; - }; - - if let Some(sugg) = ident_swap_sugg( + if one_ident_difference_count == binop_count - 1 + && let Some(binop) = binops.get(double_difference_index) + { + let changed_loc = if ident_loc1 == expected_loc { + ident_loc2 + } else if ident_loc2 == expected_loc { + ident_loc1 + } else { + // This expression doesn't match the form we're + // looking for. + return; + }; + + if let Some(sugg) = ident_swap_sugg( + cx, + &paired_identifiers, + binop, + changed_loc, + &mut applicability, + ) { + emit_suggestion( cx, - &paired_identifiers, - binop, - changed_loc, - &mut applicability, - ) { - emit_suggestion( - cx, - binop.span, - sugg, - applicability, - ); - } + binop.span, + sugg, + applicability, + ); } } }, @@ -212,48 +210,44 @@ fn attempt_to_emit_no_difference_lint( let old_right_ident = get_ident(binop.right, expected_loc); for b in skip_index(binops.iter(), i) { - if_chain! { - if let (Some(old_ident), Some(new_ident)) = - (old_left_ident, get_ident(b.left, expected_loc)); - if old_ident != new_ident; - if let Some(sugg) = suggestion_with_swapped_ident( + if let (Some(old_ident), Some(new_ident)) = + (old_left_ident, get_ident(b.left, expected_loc)) + && old_ident != new_ident + && let Some(sugg) = suggestion_with_swapped_ident( cx, binop.left, expected_loc, new_ident, &mut applicability, + ) + { + emit_suggestion( + cx, + binop.span, + replace_left_sugg(cx, binop, &sugg, &mut applicability), + applicability, ); - then { - emit_suggestion( - cx, - binop.span, - replace_left_sugg(cx, binop, &sugg, &mut applicability), - applicability, - ); - return; - } + return; } - if_chain! { - if let (Some(old_ident), Some(new_ident)) = - (old_right_ident, get_ident(b.right, expected_loc)); - if old_ident != new_ident; - if let Some(sugg) = suggestion_with_swapped_ident( + if let (Some(old_ident), Some(new_ident)) = + (old_right_ident, get_ident(b.right, expected_loc)) + && old_ident != new_ident + && let Some(sugg) = suggestion_with_swapped_ident( cx, binop.right, expected_loc, new_ident, &mut applicability, + ) + { + emit_suggestion( + cx, + binop.span, + replace_right_sugg(cx, binop, &sugg, &mut applicability), + applicability, ); - then { - emit_suggestion( - cx, - binop.span, - replace_right_sugg(cx, binop, &sugg, &mut applicability), - applicability, - ); - return; - } + return; } } } diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 6271ea02731..b2badd7b2ac 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -57,37 +57,35 @@ declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind; - if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node); - if let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang); - if let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang); + if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind + && let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node) + && let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang) + && let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang) // Check for more than one binary operation in the implemented function // Linting when multiple operations are involved can result in false positives - let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id; - if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn); - if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind; - let body = cx.tcx.hir().body(body_id); - let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id; - if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn); - let trait_id = trait_ref.path.res.def_id(); - if ![binop_trait_id, op_assign_trait_id].contains(&trait_id); - if let Some(&(_, lint)) = [ + && let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id + && let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn) + && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind + && let body = cx.tcx.hir().body(body_id) + && let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id + && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn) + && let trait_id = trait_ref.path.res.def_id() + && ![binop_trait_id, op_assign_trait_id].contains(&trait_id) + && let Some(&(_, lint)) = [ (&BINOP_TRAITS, SUSPICIOUS_ARITHMETIC_IMPL), (&OP_ASSIGN_TRAITS, SUSPICIOUS_OP_ASSIGN_IMPL), ] .iter() - .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t))); - if count_binops(body.value) == 1; - then { - span_lint( - cx, - lint, - binop.span, - &format!("suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id)), - ); - } + .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t))) + && count_binops(body.value) == 1 + { + span_lint( + cx, + lint, + binop.span, + &format!("suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id)), + ); } } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 660e6835e46..29f85907f9e 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -149,36 +149,34 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { } for [s1, s2, s3] in block.stmts.array_windows::<3>() { - if_chain! { + if let StmtKind::Local(tmp) = s1.kind // let t = foo(); - if let StmtKind::Local(tmp) = s1.kind; - if let Some(tmp_init) = tmp.init; - if let PatKind::Binding(.., ident, None) = tmp.pat.kind; + && let Some(tmp_init) = tmp.init + && let PatKind::Binding(.., ident, None) = tmp.pat.kind // foo() = bar(); - if let StmtKind::Semi(first) = s2.kind; - if let ExprKind::Assign(lhs1, rhs1, _) = first.kind; + && let StmtKind::Semi(first) = s2.kind + && let ExprKind::Assign(lhs1, rhs1, _) = first.kind // bar() = t; - if let StmtKind::Semi(second) = s3.kind; - if let ExprKind::Assign(lhs2, rhs2, _) = second.kind; - if let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind; - if rhs2.segments.len() == 1; + && let StmtKind::Semi(second) = s3.kind + && let ExprKind::Assign(lhs2, rhs2, _) = second.kind + && let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind + && rhs2.segments.len() == 1 - if ident.name == rhs2.segments[0].ident.name; - if eq_expr_value(cx, tmp_init, lhs1); - if eq_expr_value(cx, rhs1, lhs2); + && ident.name == rhs2.segments[0].ident.name + && eq_expr_value(cx, tmp_init, lhs1) + && eq_expr_value(cx, rhs1, lhs2) - let ctxt = s1.span.ctxt(); - if s2.span.ctxt() == ctxt; - if s3.span.ctxt() == ctxt; - if first.span.ctxt() == ctxt; - if second.span.ctxt() == ctxt; + && let ctxt = s1.span.ctxt() + && s2.span.ctxt() == ctxt + && s3.span.ctxt() == ctxt + && first.span.ctxt() == ctxt + && second.span.ctxt() == ctxt - then { - let span = s1.span.to(s3.span); - generate_swap_warning(cx, lhs1, lhs2, span, false); - } + { + let span = s1.span.to(s3.span); + generate_swap_warning(cx, lhs1, lhs2, span, false); } } } @@ -261,20 +259,18 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { for [s1, s2, s3] in block.stmts.array_windows::<3>() { let ctxt = s1.span.ctxt(); - if_chain! { - if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt); - if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt); - if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt); - if eq_expr_value(cx, lhs0, rhs1); - if eq_expr_value(cx, lhs2, rhs1); - if eq_expr_value(cx, lhs1, rhs0); - if eq_expr_value(cx, lhs1, rhs2); - if s2.span.ctxt() == ctxt; - if s3.span.ctxt() == ctxt; - then { - let span = s1.span.to(s3.span); - generate_swap_warning(cx, lhs0, rhs0, span, true); - } + if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt) + && let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt) + && let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt) + && eq_expr_value(cx, lhs0, rhs1) + && eq_expr_value(cx, lhs2, rhs1) + && eq_expr_value(cx, lhs1, rhs0) + && eq_expr_value(cx, lhs1, rhs2) + && s2.span.ctxt() == ctxt + && s3.span.ctxt() == ctxt + { + let span = s1.span.to(s3.span); + generate_swap_warning(cx, lhs0, rhs0, span, true); }; } } diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index 0cfb1c1253c..9481c78a505 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -55,20 +55,18 @@ impl LateLintPass<'_> for TestsOutsideTestModule { sp: Span, _: LocalDefId, ) { - if_chain! { - if !matches!(kind, FnKind::Closure); - if is_in_test_function(cx.tcx, body.id().hir_id); - if !is_in_cfg_test(cx.tcx, body.id().hir_id); - then { - span_lint_and_note( - cx, - TESTS_OUTSIDE_TEST_MODULE, - sp, - "this function marked with #[test] is outside a #[cfg(test)] module", - None, - "move it to a testing module marked with #[cfg(test)]", - ); - } + if !matches!(kind, FnKind::Closure) + && is_in_test_function(cx.tcx, body.id().hir_id) + && !is_in_cfg_test(cx.tcx, body.id().hir_id) + { + span_lint_and_note( + cx, + TESTS_OUTSIDE_TEST_MODULE, + sp, + "this function marked with #[test] is outside a #[cfg(test)] module", + None, + "move it to a testing module marked with #[cfg(test)]", + ); } } } diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index a171d225f1e..6990e7468f8 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -38,59 +38,53 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind; - if is_some_path.ident.name.as_str() == "is_some"; - then { - let match_result = match &to_digit_expr.kind { - hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { - if_chain! { - if to_digits_path.ident.name.as_str() == "to_digit"; - let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg); - if *char_arg_ty.kind() == ty::Char; - then { - Some((true, *char_arg, radix_arg)) - } else { - None - } - } + if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind + && is_some_path.ident.name.as_str() == "is_some" + { + let match_result = match &to_digit_expr.kind { + hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { + if to_digits_path.ident.name.as_str() == "to_digit" + && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg) + && *char_arg_ty.kind() == ty::Char + { + Some((true, *char_arg, radix_arg)) + } else { + None } - hir::ExprKind::Call(to_digits_call, to_digit_args) => { - if_chain! { - if let [char_arg, radix_arg] = *to_digit_args; - if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind; - if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id); - if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id(); - if match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "", "to_digit"]); - then { - Some((false, char_arg, radix_arg)) - } else { - None - } - } + } + hir::ExprKind::Call(to_digits_call, to_digit_args) => { + if let [char_arg, radix_arg] = *to_digit_args + && let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind + && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id) + && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id() + && match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "", "to_digit"]) + { + Some((false, char_arg, radix_arg)) + } else { + None } - _ => None - }; + } + _ => None + }; - if let Some((is_method_call, char_arg, radix_arg)) = match_result { - let mut applicability = Applicability::MachineApplicable; - let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability); - let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability); + if let Some((is_method_call, char_arg, radix_arg)) = match_result { + let mut applicability = Applicability::MachineApplicable; + let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability); + let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability); - span_lint_and_sugg( - cx, - TO_DIGIT_IS_SOME, - expr.span, - "use of `.to_digit(..).is_some()`", - "try", - if is_method_call { - format!("{char_arg_snip}.is_digit({radix_snip})") - } else { - format!("char::is_digit({char_arg_snip}, {radix_snip})") - }, - applicability, - ); - } + span_lint_and_sugg( + cx, + TO_DIGIT_IS_SOME, + expr.span, + "use of `.to_digit(..).is_some()`", + "try", + if is_method_call { + format!("{char_arg_snip}.is_digit({radix_snip})") + } else { + format!("char::is_digit({char_arg_snip}, {radix_snip})") + }, + applicability, + ); } } } diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 87181adc24b..7eef02b3c65 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -54,20 +54,18 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if_chain! { + if let ItemKind::Struct(data, _) = &item.kind // First check if last field is an array - if let ItemKind::Struct(data, _) = &item.kind; - if let Some(last_field) = data.fields().last(); - if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind; + && let Some(last_field) = data.fields().last() + && let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind // Then check if that array is zero-sized - let length = Const::from_anon_const(cx.tcx, length.def_id); - let length = length.try_eval_target_usize(cx.tcx, cx.param_env); - if let Some(length) = length; - then { - length == 0 - } else { - false - } + && let length = Const::from_anon_const(cx.tcx, length.def_id) + && let length = length.try_eval_target_usize(cx.tcx, cx.param_env) + && let Some(length) = length + { + length == 0 + } else { + false } } diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index f065d215e48..0bcb1afeea2 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -124,103 +124,99 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { let mut self_bounds_map = FxHashMap::default(); for predicate in item.generics.predicates { - if_chain! { - if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; - if bound_predicate.origin != PredicateOrigin::ImplTrait; - if !bound_predicate.span.from_expansion(); - if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; - if let Some(PathSegment { + if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate + && bound_predicate.origin != PredicateOrigin::ImplTrait + && !bound_predicate.span.from_expansion() + && let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind + && let Some(PathSegment { res: Res::SelfTyParam { trait_: def_id }, .. - }) = segments.first(); - if let Some( + }) = segments.first() + && let Some( Node::Item( Item { kind: ItemKind::Trait(_, _, _, self_bounds, _), .. } ) - ) = cx.tcx.hir().get_if_local(*def_id); - then { - if self_bounds_map.is_empty() { - for bound in *self_bounds { - let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue }; - self_bounds_map.insert(self_res, self_segments); - } + ) = cx.tcx.hir().get_if_local(*def_id) + { + if self_bounds_map.is_empty() { + for bound in *self_bounds { + let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue }; + self_bounds_map.insert(self_res, self_segments); } + } - bound_predicate - .bounds - .iter() - .filter_map(get_trait_info_from_bound) - .for_each(|(trait_item_res, trait_item_segments, span)| { - if let Some(self_segments) = self_bounds_map.get(&trait_item_res) { - if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) { - span_lint_and_help( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - span, - "this trait bound is already specified in trait declaration", - None, - "consider removing this trait bound", - ); - } + bound_predicate + .bounds + .iter() + .filter_map(get_trait_info_from_bound) + .for_each(|(trait_item_res, trait_item_segments, span)| { + if let Some(self_segments) = self_bounds_map.get(&trait_item_res) { + if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) { + span_lint_and_help( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + span, + "this trait bound is already specified in trait declaration", + None, + "consider removing this trait bound", + ); } - }); - } + } + }); } } } fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { - if_chain! { - if let TyKind::Ref(.., mut_ty) = &ty.kind; - if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind; - if bounds.len() > 2; - then { + if let TyKind::Ref(.., mut_ty) = &ty.kind + && let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind + && bounds.len() > 2 + { - // Build up a hash of every trait we've seen - // When we see a trait for the first time, add it to unique_traits - // so we can later use it to build a string of all traits exactly once, without duplicates + // Build up a hash of every trait we've seen + // When we see a trait for the first time, add it to unique_traits + // so we can later use it to build a string of all traits exactly once, without duplicates - let mut seen_def_ids = FxHashSet::default(); - let mut unique_traits = Vec::new(); + let mut seen_def_ids = FxHashSet::default(); + let mut unique_traits = Vec::new(); - // Iterate the bounds and add them to our seen hash - // If we haven't yet seen it, add it to the fixed traits - for bound in bounds { - let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; + // Iterate the bounds and add them to our seen hash + // If we haven't yet seen it, add it to the fixed traits + for bound in bounds { + let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; - let new_trait = seen_def_ids.insert(def_id); + let new_trait = seen_def_ids.insert(def_id); - if new_trait { - unique_traits.push(bound); - } + if new_trait { + unique_traits.push(bound); } + } - // If the number of unique traits isn't the same as the number of traits in the bounds, - // there must be 1 or more duplicates - if bounds.len() != unique_traits.len() { - let mut bounds_span = bounds[0].span; - - for bound in bounds.iter().skip(1) { - bounds_span = bounds_span.to(bound.span); - } - - let fixed_trait_snippet = unique_traits - .iter() - .filter_map(|b| snippet_opt(cx, b.span)) - .collect::>() - .join(" + "); + // If the number of unique traits isn't the same as the number of traits in the bounds, + // there must be 1 or more duplicates + if bounds.len() != unique_traits.len() { + let mut bounds_span = bounds[0].span; - span_lint_and_sugg( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - bounds_span, - "this trait bound is already specified in trait declaration", - "try", - fixed_trait_snippet, - Applicability::MaybeIncorrect, - ); + for bound in bounds.iter().skip(1) { + bounds_span = bounds_span.to(bound.span); } + + let fixed_trait_snippet = unique_traits + .iter() + .filter_map(|b| snippet_opt(cx, b.span)) + .collect::>() + .join(" + "); + + span_lint_and_sugg( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + bounds_span, + "this trait bound is already specified in trait declaration", + "try", + fixed_trait_snippet, + Applicability::MaybeIncorrect, + ); } } } @@ -267,36 +263,34 @@ impl TraitBounds { let mut map: UnhashMap, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; for bound in gen.predicates { - if_chain! { - if let WherePredicate::BoundPredicate(ref p) = bound; - if p.origin != PredicateOrigin::ImplTrait; - if p.bounds.len() as u64 <= self.max_trait_bounds; - if !p.span.from_expansion(); - let bounds = p.bounds.iter().filter(|b| !self.cannot_combine_maybe_bound(cx, b)).collect::>(); - if !bounds.is_empty(); - if let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds); - if !is_from_proc_macro(cx, p.bounded_ty); - then { - let trait_bounds = v - .iter() - .copied() - .chain(p.bounds.iter()) - .filter_map(get_trait_info_from_bound) - .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability)) - .join(" + "); - let hint_string = format!( - "consider combining the bounds: `{}: {trait_bounds}`", - snippet(cx, p.bounded_ty.span, "_"), - ); - span_lint_and_help( - cx, - TYPE_REPETITION_IN_BOUNDS, - p.span, - "this type has already been used as a bound predicate", - None, - &hint_string, - ); - } + if let WherePredicate::BoundPredicate(ref p) = bound + && p.origin != PredicateOrigin::ImplTrait + && p.bounds.len() as u64 <= self.max_trait_bounds + && !p.span.from_expansion() + && let bounds = p.bounds.iter().filter(|b| !self.cannot_combine_maybe_bound(cx, b)).collect::>() + && !bounds.is_empty() + && let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds) + && !is_from_proc_macro(cx, p.bounded_ty) + { + let trait_bounds = v + .iter() + .copied() + .chain(p.bounds.iter()) + .filter_map(get_trait_info_from_bound) + .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability)) + .join(" + "); + let hint_string = format!( + "consider combining the bounds: `{}: {trait_bounds}`", + snippet(cx, p.bounded_ty.span, "_"), + ); + span_lint_and_help( + cx, + TYPE_REPETITION_IN_BOUNDS, + p.span, + "this type has already been used as a bound predicate", + None, + &hint_string, + ); } } } @@ -318,15 +312,13 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { .predicates .iter() .filter_map(|pred| { - if_chain! { - if pred.in_where_clause(); - if let WherePredicate::BoundPredicate(bound_predicate) = pred; - if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind; - then { - return Some( - rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements") - .into_iter().map(|(trait_ref, _)| (path.res, trait_ref))) - } + if pred.in_where_clause() + && let WherePredicate::BoundPredicate(bound_predicate) = pred + && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind + { + return Some( + rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements") + .into_iter().map(|(trait_ref, _)| (path.res, trait_ref))) } None }) @@ -340,25 +332,23 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { // compare trait bounds keyed by generic name and comparable trait to collected where // predicates eg. (T, Clone) for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) { - if_chain! { - if let WherePredicate::BoundPredicate(bound_predicate) = predicate; - if bound_predicate.origin != PredicateOrigin::ImplTrait; - if !bound_predicate.span.from_expansion(); - if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind; - then { - let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements"); - for (trait_ref, span) in traits { - let key = (path.res, trait_ref); - if where_predicates.contains(&key) { - span_lint_and_help( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - span, - "this trait bound is already specified in the where clause", - None, - "consider removing this trait bound", - ); - } + if let WherePredicate::BoundPredicate(bound_predicate) = predicate + && bound_predicate.origin != PredicateOrigin::ImplTrait + && !bound_predicate.span.from_expansion() + && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind + { + let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements"); + for (trait_ref, span) in traits { + let key = (path.res, trait_ref); + if where_predicates.contains(&key) { + span_lint_and_help( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + span, + "this trait bound is already specified in the where clause", + None, + "consider removing this trait bound", + ); } } } @@ -401,11 +391,9 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { .filter_map(|segment| { // get trait bound type arguments Some(segment.args?.args.iter().filter_map(|arg| { - if_chain! { - if let GenericArg::Type(ty) = arg; - if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind; - then { return Some(path.res) } - } + if let GenericArg::Type(ty) = arg + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + { return Some(path.res) } None })) }) @@ -444,27 +432,25 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) - comparable_bounds[i] = (k, v); } - if_chain! { - if repeated_res; - if let [first_trait, .., last_trait] = bounds; - then { - let all_trait_span = first_trait.span().to(last_trait.span()); - - let traits = comparable_bounds.iter() - .filter_map(|&(_, span)| snippet_opt(cx, span)) - .collect::>(); - let traits = traits.join(" + "); - - span_lint_and_sugg( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - all_trait_span, - msg, - "try", - traits, - Applicability::MachineApplicable - ); - } + if repeated_res + && let [first_trait, .., last_trait] = bounds + { + let all_trait_span = first_trait.span().to(last_trait.span()); + + let traits = comparable_bounds.iter() + .filter_map(|&(_, span)| snippet_opt(cx, span)) + .collect::>(); + let traits = traits.join(" + "); + + span_lint_and_sugg( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + all_trait_span, + msg, + "try", + traits, + Applicability::MachineApplicable + ); } comparable_bounds diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 6eec40cb529..89580005c52 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -494,51 +494,49 @@ impl Transmute { } impl<'tcx> LateLintPass<'tcx> for Transmute { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(path_expr, [arg]) = e.kind; - if let ExprKind::Path(QPath::Resolved(None, path)) = path_expr.kind; - if let Some(def_id) = path.res.opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::transmute, def_id); - then { - // Avoid suggesting non-const operations in const contexts: - // - from/to bits (https://github.com/rust-lang/rust/issues/73736) - // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911) - // - char conversions (https://github.com/rust-lang/rust/issues/89259) - let const_context = in_constant(cx, e.hir_id); + if let ExprKind::Call(path_expr, [arg]) = e.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = path_expr.kind + && let Some(def_id) = path.res.opt_def_id() + && cx.tcx.is_diagnostic_item(sym::transmute, def_id) + { + // Avoid suggesting non-const operations in const contexts: + // - from/to bits (https://github.com/rust-lang/rust/issues/73736) + // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911) + // - char conversions (https://github.com/rust-lang/rust/issues/89259) + let const_context = in_constant(cx, e.hir_id); - let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) { - [] => (cx.typeck_results().expr_ty(arg), false), - [.., a] => (a.target, true), - }; - // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them. - let to_ty = cx.typeck_results().expr_ty(e); + let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) { + [] => (cx.typeck_results().expr_ty(arg), false), + [.., a] => (a.target, true), + }; + // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them. + let to_ty = cx.typeck_results().expr_ty(e); - // If useless_transmute is triggered, the other lints can be skipped. - if useless_transmute::check(cx, e, from_ty, to_ty, arg) { - return; - } + // If useless_transmute is triggered, the other lints can be skipped. + if useless_transmute::check(cx, e, from_ty, to_ty, arg) { + return; + } - let linted = wrong_transmute::check(cx, e, from_ty, to_ty) - | crosspointer_transmute::check(cx, e, from_ty, to_ty) - | transmuting_null::check(cx, e, arg, to_ty) - | transmute_null_to_fn::check(cx, e, arg, to_ty) - | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) - | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) - | ( - unsound_collection_transmute::check(cx, e, from_ty, to_ty) - || transmute_undefined_repr::check(cx, e, from_ty, to_ty) - ); + let linted = wrong_transmute::check(cx, e, from_ty, to_ty) + | crosspointer_transmute::check(cx, e, from_ty, to_ty) + | transmuting_null::check(cx, e, arg, to_ty) + | transmute_null_to_fn::check(cx, e, arg, to_ty) + | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) + | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) + | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) + | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) + | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) + | ( + unsound_collection_transmute::check(cx, e, from_ty, to_ty) + || transmute_undefined_repr::check(cx, e, from_ty, to_ty) + ); - if !linted { - transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg); - } + if !linted { + transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg); } } } diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index 5ecba512b0f..fe30a585da0 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -32,17 +32,15 @@ pub(super) fn check<'tcx>( arg = inner_expr; } - if_chain! { + if let ExprKind::Lit(lit) = &arg.kind // if the expression is a float literal and it is unsuffixed then // add a suffix so the suggestion is valid and unambiguous - if let ExprKind::Lit(lit) = &arg.kind; - if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node; - then { - let op = format!("{sugg}{}", float_ty.name_str()).into(); - match sugg { - sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op), - _ => sugg = sugg::Sugg::NonParen(op) - } + && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node + { + let op = format!("{sugg}{}", float_ty.name_str()).into(); + match sugg { + sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op), + _ => sugg = sugg::Sugg::NonParen(op) } } diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index ea9ad99618a..52bb68845db 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -21,67 +21,65 @@ pub(super) fn check<'tcx>( let mut triggered = false; if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) { - if_chain! { - if let ty::Slice(slice_ty) = *ty_from.kind(); - if ty_to.is_str(); - if let ty::Uint(ty::UintTy::U8) = slice_ty.kind(); - if from_mutbl == to_mutbl; - then { - let postfix = if *from_mutbl == Mutability::Mut { - "_mut" - } else { - "" - }; + if let ty::Slice(slice_ty) = *ty_from.kind() + && ty_to.is_str() + && let ty::Uint(ty::UintTy::U8) = slice_ty.kind() + && from_mutbl == to_mutbl + { + let postfix = if *from_mutbl == Mutability::Mut { + "_mut" + } else { + "" + }; - let snippet = snippet(cx, arg.span, ".."); + let snippet = snippet(cx, arg.span, ".."); - span_lint_and_sugg( + span_lint_and_sugg( + cx, + TRANSMUTE_BYTES_TO_STR, + e.span, + &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + "consider using", + if const_context { + format!("std::str::from_utf8_unchecked{postfix}({snippet})") + } else { + format!("std::str::from_utf8{postfix}({snippet}).unwrap()") + }, + Applicability::MaybeIncorrect, + ); + triggered = true; + } else { + if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) + && !const_context { + span_lint_and_then( cx, - TRANSMUTE_BYTES_TO_STR, + TRANSMUTE_PTR_TO_PTR, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), - "consider using", - if const_context { - format!("std::str::from_utf8_unchecked{postfix}({snippet})") - } else { - format!("std::str::from_utf8{postfix}({snippet}).unwrap()") + "transmute from a reference to a reference", + |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { + let ty_from_and_mut = ty::TypeAndMut { + ty: *ty_from, + mutbl: *from_mutbl + }; + let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl }; + let sugg_paren = arg + .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut)) + .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut)); + let sugg = if *to_mutbl == Mutability::Mut { + sugg_paren.mut_addr_deref() + } else { + sugg_paren.addr_deref() + }; + diag.span_suggestion( + e.span, + "try", + sugg, + Applicability::Unspecified, + ); }, - Applicability::MaybeIncorrect, ); - triggered = true; - } else { - if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) - && !const_context { - span_lint_and_then( - cx, - TRANSMUTE_PTR_TO_PTR, - e.span, - "transmute from a reference to a reference", - |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let ty_from_and_mut = ty::TypeAndMut { - ty: *ty_from, - mutbl: *from_mutbl - }; - let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl }; - let sugg_paren = arg - .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut)) - .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut)); - let sugg = if *to_mutbl == Mutability::Mut { - sugg_paren.mut_addr_deref() - } else { - sugg_paren.addr_deref() - }; - diag.span_suggestion( - e.span, - "try", - sugg, - Applicability::Unspecified, - ); - }, - ); - triggered = true; - } + triggered = true; } } } diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 7c2223ca3ab..a65bc0ce458 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -299,14 +299,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> } fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if_chain! { - if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty); - if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); - then { - layout.layout.size().bytes() == 0 - } else { - false - } + if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) + && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + { + layout.layout.size().bytes() == 0 + } else { + false } } diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 306ca5724da..a67431123ad 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -15,66 +15,64 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m TyKind::Path(ref qpath) => { let hir_id = mut_ty.ty.hir_id; let def = cx.qpath_res(qpath, hir_id); - if_chain! { - if let Some(def_id) = def.opt_def_id(); - if Some(def_id) == cx.tcx.lang_items().owned_box(); - if let QPath::Resolved(None, path) = *qpath; - if let [ref bx] = *path.segments; - if let Some(params) = bx.args; - if params.parenthesized == hir::GenericArgsParentheses::No; - if let Some(inner) = params.args.iter().find_map(|arg| match arg { + if let Some(def_id) = def.opt_def_id() + && Some(def_id) == cx.tcx.lang_items().owned_box() + && let QPath::Resolved(None, path) = *qpath + && let [ref bx] = *path.segments + && let Some(params) = bx.args + && params.parenthesized == hir::GenericArgsParentheses::No + && let Some(inner) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, - }); - then { - if is_any_trait(cx, inner) { - // Ignore `Box` types; see issue #1884 for details. - return false; - } - - let ltopt = if lt.is_anonymous() { - String::new() - } else { - format!("{} ", lt.ident.as_str()) - }; + }) + { + if is_any_trait(cx, inner) { + // Ignore `Box` types; see issue #1884 for details. + return false; + } - if mut_ty.mutbl == Mutability::Mut { - // Ignore `&mut Box` types; see issue #2907 for - // details. - return false; - } + let ltopt = if lt.is_anonymous() { + String::new() + } else { + format!("{} ", lt.ident.as_str()) + }; - // When trait objects or opaque types have lifetime or auto-trait bounds, - // we need to add parentheses to avoid a syntax error due to its ambiguity. - // Originally reported as the issue #3128. - let inner_snippet = snippet(cx, inner.span, ".."); - let suggestion = match &inner.kind { - TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => { - format!("&{ltopt}({})", &inner_snippet) - }, - TyKind::Path(qpath) - if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) - .map_or(false, |bounds| bounds.len() > 1) => - { - format!("&{ltopt}({})", &inner_snippet) - }, - _ => format!("&{ltopt}{}", &inner_snippet), - }; - span_lint_and_sugg( - cx, - BORROWED_BOX, - hir_ty.span, - "you seem to be trying to use `&Box`. Consider using just `&T`", - "try", - suggestion, - // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item - // because the trait impls of it will break otherwise; - // and there may be other cases that result in invalid code. - // For example, type coercion doesn't work nicely. - Applicability::Unspecified, - ); - return true; + if mut_ty.mutbl == Mutability::Mut { + // Ignore `&mut Box` types; see issue #2907 for + // details. + return false; } + + // When trait objects or opaque types have lifetime or auto-trait bounds, + // we need to add parentheses to avoid a syntax error due to its ambiguity. + // Originally reported as the issue #3128. + let inner_snippet = snippet(cx, inner.span, ".."); + let suggestion = match &inner.kind { + TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => { + format!("&{ltopt}({})", &inner_snippet) + }, + TyKind::Path(qpath) + if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) + .map_or(false, |bounds| bounds.len() > 1) => + { + format!("&{ltopt}({})", &inner_snippet) + }, + _ => format!("&{ltopt}{}", &inner_snippet), + }; + span_lint_and_sugg( + cx, + BORROWED_BOX, + hir_ty.span, + "you seem to be trying to use `&Box`. Consider using just `&T`", + "try", + suggestion, + // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item + // because the trait impls of it will break otherwise; + // and there may be other cases that result in invalid code. + // For example, type coercion doesn't work nicely. + Applicability::Unspecified, + ); + return true; }; false }, @@ -84,33 +82,29 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m // Returns true if given type is `Any` trait. fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { - if_chain! { - if let TyKind::TraitObject(traits, ..) = t.kind; - if !traits.is_empty(); - if let Some(trait_did) = traits[0].trait_ref.trait_def_id(); + if let TyKind::TraitObject(traits, ..) = t.kind + && !traits.is_empty() + && let Some(trait_did) = traits[0].trait_ref.trait_def_id() // Only Send/Sync can be used as additional traits, so it is enough to // check only the first trait. - if cx.tcx.is_diagnostic_item(sym::Any, trait_did); - then { - return true; - } + && cx.tcx.is_diagnostic_item(sym::Any, trait_did) + { + return true; } false } fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option> { - if_chain! { - if let Some(did) = cx.qpath_res(qpath, id).opt_def_id(); - if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did); - if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; - if synthetic; - if let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id); - if let Some(pred) = generics.bounds_for_param(did.expect_local()).next(); - then { - Some(pred.bounds) - } else { - None - } + if let Some(did) = cx.qpath_res(qpath, id).opt_def_id() + && let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did) + && let GenericParamKind::Type { synthetic, .. } = generic_param.kind + && synthetic + && let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id) + && let Some(pred) = generics.bounds_for_param(did.expect_local()).next() + { + Some(pred.bounds) + } else { + None } } diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index 4a5a94f2630..badd8acbc90 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -8,30 +8,28 @@ use rustc_span::{sym, Symbol}; use super::BOX_COLLECTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if_chain! { - if Some(def_id) == cx.tcx.lang_items().owned_box(); - if let Some(item_type) = get_std_collection(cx, qpath); - then { - let generic = match item_type { - sym::String => "", - _ => "<..>", - }; + if Some(def_id) == cx.tcx.lang_items().owned_box() + && let Some(item_type) = get_std_collection(cx, qpath) + { + let generic = match item_type { + sym::String => "", + _ => "<..>", + }; - let box_content = format!("{item_type}{generic}"); - span_lint_and_help( - cx, - BOX_COLLECTION, - hir_ty.span, - &format!( - "you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), - None, - &format!( - "`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation") - ); - true - } else { - false - } + let box_content = format!("{item_type}{generic}"); + span_lint_and_help( + cx, + BOX_COLLECTION, + hir_ty.span, + &format!( + "you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), + None, + &format!( + "`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation") + ); + true + } else { + false } } diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index 60622903af1..98284031344 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -9,21 +9,19 @@ use rustc_span::symbol::sym; use super::OPTION_OPTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if_chain! { - if cx.tcx.is_diagnostic_item(sym::Option, def_id); - if let Some(arg) = qpath_generic_tys(qpath).next(); - if path_def_id(cx, arg) == Some(def_id); - then { - span_lint( - cx, - OPTION_OPTION, - hir_ty.span, - "consider using `Option` instead of `Option>` or a custom \ - enum if you need to distinguish all 3 cases", - ); - true - } else { - false - } + if cx.tcx.is_diagnostic_item(sym::Option, def_id) + && let Some(arg) = qpath_generic_tys(qpath).next() + && path_def_id(cx, arg) == Some(def_id) + { + span_lint( + cx, + OPTION_OPTION, + hir_ty.span, + "consider using `Option` instead of `Option>` or a custom \ + enum if you need to distinguish all 3 cases", + ); + true + } else { + false } } diff --git a/clippy_lints/src/types/rc_mutex.rs b/clippy_lints/src/types/rc_mutex.rs index a616c3e4ea8..1ab4d233ff7 100644 --- a/clippy_lints/src/types/rc_mutex.rs +++ b/clippy_lints/src/types/rc_mutex.rs @@ -9,22 +9,20 @@ use rustc_span::symbol::sym; use super::RC_MUTEX; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if_chain! { - if cx.tcx.is_diagnostic_item(sym::Rc, def_id) ; - if let Some(arg) = qpath_generic_tys(qpath).next(); - if let Some(id) = path_def_id(cx, arg); - if cx.tcx.is_diagnostic_item(sym::Mutex, id); - then { - span_lint_and_help( - cx, - RC_MUTEX, - hir_ty.span, - "usage of `Rc>`", - None, - "consider using `Rc>` or `Arc>` instead", - ); - return true; - } + if cx.tcx.is_diagnostic_item(sym::Rc, def_id) + && let Some(arg) = qpath_generic_tys(qpath).next() + && let Some(id) = path_def_id(cx, arg) + && cx.tcx.is_diagnostic_item(sym::Mutex, id) + { + span_lint_and_help( + cx, + RC_MUTEX, + hir_ty.span, + "usage of `Rc>`", + None, + "consider using `Rc>` or `Arc>` instead", + ); + return true; } false diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index a30748db88f..7278447a70e 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -6,17 +6,15 @@ use rustc_span::source_map::Span; pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option { let last = last_path_segment(qpath); - if_chain! { - if let Some(params) = last.args; - if params.parenthesized == GenericArgsParentheses::No; - if let Some(ty) = params.args.iter().find_map(|arg| match arg { + if let Some(params) = last.args + && params.parenthesized == GenericArgsParentheses::No + && let Some(ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, - }); - if let TyKind::Ref(..) = ty.kind; - then { - return Some(ty.span); - } + }) + && let TyKind::Ref(..) = ty.kind + { + return Some(ty.span); } None } diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 72569e10f05..ff616805d08 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -83,41 +83,39 @@ fn handle_uninit_vec_pair<'tcx>( maybe_init_or_reserve: &'tcx Stmt<'tcx>, maybe_set_len: &'tcx Expr<'tcx>, ) { - if_chain! { - if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve); - if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len); - if vec.location.eq_expr(cx, set_len_self); - if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); - if let ty::Adt(_, args) = vec_ty.kind(); + if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve) + && let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len) + && vec.location.eq_expr(cx, set_len_self) + && let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind() + && let ty::Adt(_, args) = vec_ty.kind() // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()` - if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id); - then { - if vec.has_capacity() { - // with_capacity / reserve -> set_len + && !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id) + { + if vec.has_capacity() { + // with_capacity / reserve -> set_len - // Check T of Vec - if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) { - // FIXME: #7698, false positive of the internal lints - #[expect(clippy::collapsible_span_lint_calls)] - span_lint_and_then( - cx, - UNINIT_VEC, - vec![call_span, maybe_init_or_reserve.span], - "calling `set_len()` immediately after reserving a buffer creates uninitialized values", - |diag| { - diag.help("initialize the buffer or wrap the content in `MaybeUninit`"); - }, - ); - } - } else { - // new / default -> set_len - span_lint( + // Check T of Vec + if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) { + // FIXME: #7698, false positive of the internal lints + #[expect(clippy::collapsible_span_lint_calls)] + span_lint_and_then( cx, UNINIT_VEC, vec![call_span, maybe_init_or_reserve.span], - "calling `set_len()` on empty `Vec` creates out-of-bound values", + "calling `set_len()` immediately after reserving a buffer creates uninitialized values", + |diag| { + diag.help("initialize the buffer or wrap the content in `MaybeUninit`"); + }, ); } + } else { + // new / default -> set_len + span_lint( + cx, + UNINIT_VEC, + vec![call_span, maybe_init_or_reserve.span], + "calling `set_len()` on empty `Vec` creates out-of-bound values", + ); } } } @@ -156,16 +154,14 @@ impl<'tcx> VecLocation<'tcx> { fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { match stmt.kind { StmtKind::Local(local) => { - if_chain! { - if let Some(init_expr) = local.init; - if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; - if let Some(init_kind) = get_vec_init_kind(cx, init_expr); - then { - return Some(TargetVec { - location: VecLocation::Local(hir_id), - init_kind: Some(init_kind), - }) - } + if let Some(init_expr) = local.init + && let PatKind::Binding(_, hir_id, _, None) = local.pat.kind + && let Some(init_kind) = get_vec_init_kind(cx, init_expr) + { + return Some(TargetVec { + location: VecLocation::Local(hir_id), + init_kind: Some(init_kind), + }) } }, StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind { diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index e76cc65fd46..8145c4e5108 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -44,14 +44,12 @@ fn get_trait_predicates_for_trait_id<'tcx>( ) -> Vec> { let mut preds = Vec::new(); for (pred, _) in generics.predicates { - if_chain! { - if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder(); - let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred)); - if let Some(trait_def_id) = trait_id; - if trait_def_id == trait_pred.trait_ref.def_id; - then { - preds.push(trait_pred); - } + if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder() + && let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred)) + && let Some(trait_def_id) = trait_id + && trait_def_id == trait_pred.trait_ref.def_id + { + preds.push(trait_pred); } } preds @@ -94,21 +92,19 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve .enumerate() .for_each(|(i, inp)| { for trait_pred in &fn_mut_preds { - if_chain! { - if trait_pred.self_ty() == inp; - if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred); - then { - if ord_preds - .iter() - .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) - { - args_to_check.push((i, "Ord".to_string())); - } else if partial_ord_preds - .iter() - .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) - { - args_to_check.push((i, "PartialOrd".to_string())); - } + if trait_pred.self_ty() == inp + && let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred) + { + if ord_preds + .iter() + .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) + { + args_to_check.push((i, "Ord".to_string())); + } else if partial_ord_preds + .iter() + .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) + { + args_to_check.push((i, "PartialOrd".to_string())); } } } @@ -118,30 +114,26 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve } fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option)> { - if_chain! { - if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind; - if let ty::Closure(_def_id, args) = &cx.typeck_results().node_type(arg.hir_id).kind(); - let ret_ty = args.as_closure().sig().output(); - let ty = cx.tcx.erase_late_bound_regions(ret_ty); - if ty.is_unit(); - then { - let body = cx.tcx.hir().body(body); - if_chain! { - if let ExprKind::Block(block, _) = body.value.kind; - if block.expr.is_none(); - if let Some(stmt) = block.stmts.last(); - if let StmtKind::Semi(_) = stmt.kind; - then { - let data = stmt.span.data(); - // Make a span out of the semicolon for the help message - Some((fn_decl_span, Some(data.with_lo(data.hi-BytePos(1))))) - } else { - Some((fn_decl_span, None)) - } - } + if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind + && let ty::Closure(_def_id, args) = &cx.typeck_results().node_type(arg.hir_id).kind() + && let ret_ty = args.as_closure().sig().output() + && let ty = cx.tcx.erase_late_bound_regions(ret_ty) + && ty.is_unit() + { + let body = cx.tcx.hir().body(body); + if let ExprKind::Block(block, _) = body.value.kind + && block.expr.is_none() + && let Some(stmt) = block.stmts.last() + && let StmtKind::Semi(_) = stmt.kind + { + let data = stmt.span.data(); + // Make a span out of the semicolon for the help message + Some((fn_decl_span, Some(data.with_lo(data.hi-BytePos(1))))) } else { - None + Some((fn_decl_span, None)) } + } else { + None } } diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 462b1aa8153..76d07f77f46 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -22,12 +22,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { } let map = &cx.tcx.hir(); let opt_parent_node = map.find_parent(expr.hir_id); - if_chain! { - if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node; - if is_questionmark_desugar_marked_call(parent_expr); - then { - return; - } + if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node + && is_questionmark_desugar_marked_call(parent_expr) + { + return; } let args: Vec<_> = match expr.kind { @@ -80,21 +78,19 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp args_to_recover .iter() .filter_map(|arg| { - if_chain! { - if let ExprKind::Block(block, _) = arg.kind; - if block.expr.is_none(); - if let Some(last_stmt) = block.stmts.iter().last(); - if let StmtKind::Semi(last_expr) = last_stmt.kind; - if let Some(snip) = snippet_opt(cx, last_expr.span); - then { - Some(( - last_stmt.span, - snip, - )) - } - else { - None - } + if let ExprKind::Block(block, _) = arg.kind + && block.expr.is_none() + && let Some(last_stmt) = block.stmts.iter().last() + && let StmtKind::Semi(last_expr) = last_stmt.kind + && let Some(snip) = snippet_opt(cx, last_expr.span) + { + Some(( + last_stmt.span, + snip, + )) + } + else { + None } }) .for_each(|(span, sugg)| { diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index e7355f92304..bc217ac2906 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -76,55 +76,49 @@ impl LateLintPass<'_> for UnnamedAddress { matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..)) } - if_chain! { - if let ExprKind::Binary(binop, left, right) = expr.kind; - if is_comparison(binop.node); - if is_trait_ptr(cx, left) && is_trait_ptr(cx, right); - then { - span_lint_and_help( - cx, - VTABLE_ADDRESS_COMPARISONS, - expr.span, - "comparing trait object pointers compares a non-unique vtable address", - None, - "consider extracting and comparing data pointers only", - ); - } + if let ExprKind::Binary(binop, left, right) = expr.kind + && is_comparison(binop.node) + && is_trait_ptr(cx, left) && is_trait_ptr(cx, right) + { + span_lint_and_help( + cx, + VTABLE_ADDRESS_COMPARISONS, + expr.span, + "comparing trait object pointers compares a non-unique vtable address", + None, + "consider extracting and comparing data pointers only", + ); } - if_chain! { - if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id); - let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0); - if ty_param.is_trait(); - then { - span_lint_and_help( - cx, - VTABLE_ADDRESS_COMPARISONS, - expr.span, - "comparing trait object pointers compares a non-unique vtable address", - None, - "consider extracting and comparing data pointers only", - ); - } + if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind + && let ExprKind::Path(ref func_qpath) = func.kind + && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id) + && let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0) + && ty_param.is_trait() + { + span_lint_and_help( + cx, + VTABLE_ADDRESS_COMPARISONS, + expr.span, + "comparing trait object pointers compares a non-unique vtable address", + None, + "consider extracting and comparing data pointers only", + ); } - if_chain! { - if let ExprKind::Binary(binop, left, right) = expr.kind; - if is_comparison(binop.node); - if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr(); - if cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr(); - if is_fn_def(cx, left) || is_fn_def(cx, right); - then { - span_lint( - cx, - FN_ADDRESS_COMPARISONS, - expr.span, - "comparing with a non-unique address of a function item", - ); - } + if let ExprKind::Binary(binop, left, right) = expr.kind + && is_comparison(binop.node) + && cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() + && cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr() + && (is_fn_def(cx, left) || is_fn_def(cx, right)) + { + span_lint( + cx, + FN_ADDRESS_COMPARISONS, + expr.span, + "comparing with a non-unique address of a function item", + ); } } } diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 28ea02e4d9a..70c276fe1ce 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -36,45 +36,41 @@ declare_lint_pass!(UnnecessaryOwnedEmptyStrings => [UNNECESSARY_OWNED_EMPTY_STRI impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner_expr) = expr.kind; - if let ExprKind::Call(fun, args) = inner_expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - if let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind(); - if inner_str.is_str(); - then { - if match_def_path(cx, fun_def_id, &paths::STRING_NEW) { - span_lint_and_sugg( - cx, - UNNECESSARY_OWNED_EMPTY_STRINGS, - expr.span, - "usage of `&String::new()` for a function expecting a `&str` argument", - "try", - "\"\"".to_owned(), - Applicability::MachineApplicable, - ); - } else { - if_chain! { - if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id); - if let [.., last_arg] = args; - if let ExprKind::Lit(spanned) = &last_arg.kind; - if let LitKind::Str(symbol, _) = spanned.node; - if symbol.is_empty(); - let inner_expr_type = cx.typeck_results().expr_ty(inner_expr); - if is_type_lang_item(cx, inner_expr_type, LangItem::String); - then { - span_lint_and_sugg( - cx, - UNNECESSARY_OWNED_EMPTY_STRINGS, - expr.span, - "usage of `&String::from(\"\")` for a function expecting a `&str` argument", - "try", - "\"\"".to_owned(), - Applicability::MachineApplicable, - ); - } - } + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner_expr) = expr.kind + && let ExprKind::Call(fun, args) = inner_expr.kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind() + && inner_str.is_str() + { + if match_def_path(cx, fun_def_id, &paths::STRING_NEW) { + span_lint_and_sugg( + cx, + UNNECESSARY_OWNED_EMPTY_STRINGS, + expr.span, + "usage of `&String::new()` for a function expecting a `&str` argument", + "try", + "\"\"".to_owned(), + Applicability::MachineApplicable, + ); + } else { + if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id) + && let [.., last_arg] = args + && let ExprKind::Lit(spanned) = &last_arg.kind + && let LitKind::Str(symbol, _) = spanned.node + && symbol.is_empty() + && let inner_expr_type = cx.typeck_results().expr_ty(inner_expr) + && is_type_lang_item(cx, inner_expr_type, LangItem::String) + { + span_lint_and_sugg( + cx, + UNNECESSARY_OWNED_EMPTY_STRINGS, + expr.span, + "usage of `&String::from(\"\")` for a function expecting a `&str` argument", + "try", + "\"\"".to_owned(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index a1083a0a68e..338a4daf6c1 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -36,35 +36,33 @@ declare_lint_pass!(UnnecessarySelfImports => [UNNECESSARY_SELF_IMPORTS]); impl EarlyLintPass for UnnecessarySelfImports { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if_chain! { - if let ItemKind::Use(use_tree) = &item.kind; - if let UseTreeKind::Nested(nodes) = &use_tree.kind; - if let [(self_tree, _)] = &**nodes; - if let [self_seg] = &*self_tree.prefix.segments; - if self_seg.ident.name == kw::SelfLower; - if let Some(last_segment) = use_tree.prefix.segments.last(); + if let ItemKind::Use(use_tree) = &item.kind + && let UseTreeKind::Nested(nodes) = &use_tree.kind + && let [(self_tree, _)] = &**nodes + && let [self_seg] = &*self_tree.prefix.segments + && self_seg.ident.name == kw::SelfLower + && let Some(last_segment) = use_tree.prefix.segments.last() - then { - span_lint_and_then( - cx, - UNNECESSARY_SELF_IMPORTS, - item.span, - "import ending with `::{self}`", - |diag| { - diag.span_suggestion( - last_segment.span().with_hi(item.span.hi()), - "consider omitting `::{self}`", - format!( - "{}{};", - last_segment.ident, - if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() }, - ), - Applicability::MaybeIncorrect, - ); - diag.note("this will slightly change semantics; any non-module items at the same path will also be imported"); - }, - ); - } + { + span_lint_and_then( + cx, + UNNECESSARY_SELF_IMPORTS, + item.span, + "import ending with `::{self}`", + |diag| { + diag.span_suggestion( + last_segment.span().with_hi(item.span.hi()), + "consider omitting `::{self}`", + format!( + "{}{};", + last_segment.ident, + if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() }, + ), + Applicability::MaybeIncorrect, + ); + diag.note("this will slightly change semantics; any non-module items at the same path will also be imported"); + }, + ); } } } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index ab8de17b091..8b1d9d4a739 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -119,28 +119,26 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Check if all return expression respect the following condition and collect them. let mut suggs = Vec::new(); let can_sugg = find_all_ret_expressions(cx, body.value, |ret_expr| { - if_chain! { - if !ret_expr.span.from_expansion(); + if !ret_expr.span.from_expansion() // Check if a function call. - if let ExprKind::Call(func, [arg]) = ret_expr.kind; - if is_res_lang_ctor(cx, path_res(cx, func), lang_item); + && let ExprKind::Call(func, [arg]) = ret_expr.kind + && is_res_lang_ctor(cx, path_res(cx, func), lang_item) // Make sure the function argument does not contain a return expression. - if !contains_return(arg); - then { - suggs.push( - ( - ret_expr.span, - if inner_type.is_unit() { - String::new() - } else { - snippet(cx, arg.span.source_callsite(), "..").to_string() - } - ) - ); - true - } else { - false - } + && !contains_return(arg) + { + suggs.push( + ( + ret_expr.span, + if inner_type.is_unit() { + String::new() + } else { + snippet(cx, arg.span.source_callsite(), "..").to_string() + } + ) + ); + true + } else { + false } }); diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index f864c520302..1ecce18c9ae 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -73,25 +73,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { }) .is_some() }; - if_chain! { - if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind; - if assoc_item.fn_has_self_parameter; - if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; - if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api; - let body = cx.tcx.hir().body(*body_id); - if let [self_param, ..] = body.params; - if !is_local_used(cx, body, self_param.pat.hir_id); - if !contains_todo(cx, body); - then { - span_lint_and_help( - cx, - UNUSED_SELF, - self_param.span, - "unused `self` argument", - None, - "consider refactoring to an associated function", - ); - } + if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind + && assoc_item.fn_has_self_parameter + && let ImplItemKind::Fn(.., body_id) = &impl_item.kind + && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api) + && let body = cx.tcx.hir().body(*body_id) + && let [self_param, ..] = body.params + && !is_local_used(cx, body, self_param.pat.hir_id) + && !contains_todo(cx, body) + { + span_lint_and_help( + cx, + UNUSED_SELF, + self_param.span, + "unused `self` argument", + None, + "consider refactoring to an associated function", + ); } } } diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index ae844673b15..7ceb6df9c44 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -38,40 +38,36 @@ declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]); impl EarlyLintPass for UnusedUnit { fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { - if_chain! { - if let ast::FnRetTy::Ty(ref ty) = kind.decl().output; - if let ast::TyKind::Tup(ref vals) = ty.kind; - if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span); - then { - // implicit types in closure signatures are forbidden when `for<...>` is present - if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind { - return; - } - - lint_unneeded_unit_return(cx, ty, span); + if let ast::FnRetTy::Ty(ref ty) = kind.decl().output + && let ast::TyKind::Tup(ref vals) = ty.kind + && vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span) + { + // implicit types in closure signatures are forbidden when `for<...>` is present + if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind { + return; } + + lint_unneeded_unit_return(cx, ty, span); } } fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - if_chain! { - if let Some(stmt) = block.stmts.last(); - if let ast::StmtKind::Expr(ref expr) = stmt.kind; - if is_unit_expr(expr); - let ctxt = block.span.ctxt(); - if stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt; - then { - let sp = expr.span; - span_lint_and_sugg( - cx, - UNUSED_UNIT, - sp, - "unneeded unit expression", - "remove the final `()`", - String::new(), - Applicability::MachineApplicable, - ); - } + if let Some(stmt) = block.stmts.last() + && let ast::StmtKind::Expr(ref expr) = stmt.kind + && is_unit_expr(expr) + && let ctxt = block.span.ctxt() + && stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt + { + let sp = expr.span; + span_lint_and_sugg( + cx, + UNUSED_UNIT, + sp, + "unneeded unit expression", + "remove the final `()`", + String::new(), + Applicability::MachineApplicable, + ); } } @@ -97,16 +93,14 @@ impl EarlyLintPass for UnusedUnit { fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) { let segments = &poly.trait_ref.path.segments; - if_chain! { - if segments.len() == 1; - if ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()); - if let Some(args) = &segments[0].args; - if let ast::GenericArgs::Parenthesized(generic_args) = &**args; - if let ast::FnRetTy::Ty(ty) = &generic_args.output; - if ty.kind.is_unit(); - then { - lint_unneeded_unit_return(cx, ty, generic_args.span); - } + if segments.len() == 1 + && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) + && let Some(args) = &segments[0].args + && let ast::GenericArgs::Parenthesized(generic_args) = &**args + && let ast::FnRetTy::Ty(ty) = &generic_args.output + && ty.kind.is_unit() + { + lint_unneeded_unit_return(cx, ty, generic_args.span); } } } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index e52cfb29fe5..8b7429d8e38 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -157,39 +157,37 @@ fn collect_unwrap_info<'tcx>( } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind { return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); } else { - if_chain! { - if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind; - if let Some(local_id) = path_to_local(receiver); - let ty = cx.typeck_results().expr_ty(receiver); - let name = method_name.ident.as_str(); - if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name); - then { - assert!(args.is_empty()); - let unwrappable = match name { - "is_some" | "is_ok" => true, - "is_err" | "is_none" => false, - _ => unreachable!(), - }; - let safe_to_unwrap = unwrappable != invert; - let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { - UnwrappableKind::Option - } else { - UnwrappableKind::Result - }; + if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind + && let Some(local_id) = path_to_local(receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && let name = method_name.ident.as_str() + && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) + { + assert!(args.is_empty()); + let unwrappable = match name { + "is_some" | "is_ok" => true, + "is_err" | "is_none" => false, + _ => unreachable!(), + }; + let safe_to_unwrap = unwrappable != invert; + let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { + UnwrappableKind::Option + } else { + UnwrappableKind::Result + }; - return vec![ - UnwrapInfo { - local_id, - if_expr, - check: expr, - check_name: method_name, - branch, - safe_to_unwrap, - kind, - is_entire_condition, - } - ] - } + return vec![ + UnwrapInfo { + local_id, + if_expr, + check: expr, + check_name: method_name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + } + ] } } Vec::new() @@ -320,73 +318,71 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { } } else { // find `unwrap[_err]()` calls: - if_chain! { - if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind; - let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg); - if let Some(id) = path_to_local(self_arg); - if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name); - let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name); - if let Some(unwrappable) = self.unwrappables.iter() - .find(|u| u.local_id == id); + if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind + && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg) + && let Some(id) = path_to_local(self_arg) + && [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name) + && let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name) + && let Some(unwrappable) = self.unwrappables.iter() + .find(|u| u.local_id == id) // Span contexts should not differ with the conditional branch - let span_ctxt = expr.span.ctxt(); - if unwrappable.branch.span.ctxt() == span_ctxt; - if unwrappable.check.span.ctxt() == span_ctxt; - then { - if call_to_unwrap == unwrappable.safe_to_unwrap { - let is_entire_condition = unwrappable.is_entire_condition; - let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id); - let suggested_pattern = if call_to_unwrap { - unwrappable.kind.success_variant_pattern() - } else { - unwrappable.kind.error_variant_pattern() - }; - - span_lint_hir_and_then( - self.cx, - UNNECESSARY_UNWRAP, - expr.hir_id, - expr.span, - &format!( - "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", - method_name.ident.name, - unwrappable.check_name.ident.as_str(), - ), - |diag| { - if is_entire_condition { - diag.span_suggestion( - unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), - "try", - format!( - "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}", - borrow_prefix = match as_ref_kind { - Some(AsRefKind::AsRef) => "&", - Some(AsRefKind::AsMut) => "&mut ", - None => "", - }, - ), - // We don't track how the unwrapped value is used inside the - // block or suggest deleting the unwrap, so we can't offer a - // fixable solution. - Applicability::Unspecified, - ); - } else { - diag.span_label(unwrappable.check.span, "the check is happening here"); - diag.help("try using `if let` or `match`"); - } - }, - ); + && let span_ctxt = expr.span.ctxt() + && unwrappable.branch.span.ctxt() == span_ctxt + && unwrappable.check.span.ctxt() == span_ctxt + { + if call_to_unwrap == unwrappable.safe_to_unwrap { + let is_entire_condition = unwrappable.is_entire_condition; + let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id); + let suggested_pattern = if call_to_unwrap { + unwrappable.kind.success_variant_pattern() } else { - span_lint_hir_and_then( - self.cx, - PANICKING_UNWRAP, - expr.hir_id, - expr.span, - &format!("this call to `{}()` will always panic", - method_name.ident.name), - |diag| { diag.span_label(unwrappable.check.span, "because of this check"); }, - ); - } + unwrappable.kind.error_variant_pattern() + }; + + span_lint_hir_and_then( + self.cx, + UNNECESSARY_UNWRAP, + expr.hir_id, + expr.span, + &format!( + "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", + method_name.ident.name, + unwrappable.check_name.ident.as_str(), + ), + |diag| { + if is_entire_condition { + diag.span_suggestion( + unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()), + "try", + format!( + "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}", + borrow_prefix = match as_ref_kind { + Some(AsRefKind::AsRef) => "&", + Some(AsRefKind::AsMut) => "&mut ", + None => "", + }, + ), + // We don't track how the unwrapped value is used inside the + // block or suggest deleting the unwrap, so we can't offer a + // fixable solution. + Applicability::Unspecified, + ); + } else { + diag.span_label(unwrappable.check.span, "the check is happening here"); + diag.help("try using `if let` or `match`"); + } + }, + ); + } else { + span_lint_hir_and_then( + self.cx, + PANICKING_UNWRAP, + expr.hir_id, + expr.span, + &format!("this call to `{}()` will always panic", + method_name.ident.name), + |diag| { diag.span_label(unwrappable.check.span, "because of this check"); }, + ); } } walk_expr(self, expr); diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 21592abbf16..a3977f1b6c8 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -60,15 +60,13 @@ declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if_chain! { + if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind // first check if it's a method or function - if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option); - then { - lint_impl_body(cx, impl_item.span, impl_item); - } + && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option)) + { + lint_impl_body(cx, impl_item.span, impl_item); } } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index c3fe16ad5c3..4bfd4d22c70 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -93,32 +93,30 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { // relevant for linting, since this is the self type of the `impl` we're currently in. To // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that // we're in an `impl` or nested item, that we don't want to lint - let stack_item = if_chain! { - if let ItemKind::Impl(Impl { self_ty, generics,.. }) = item.kind; - if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind; - let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; - if parameters.as_ref().map_or(true, |params| { + let stack_item = if let ItemKind::Impl(Impl { self_ty, generics,.. }) = item.kind + && let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind + && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args + && parameters.as_ref().map_or(true, |params| { params.parenthesized == GenericArgsParentheses::No && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) - }); - if !item.span.from_expansion(); - if !is_from_proc_macro(cx, item); // expensive, should be last check - then { - // Self cannot be used inside const generic parameters - let types_to_skip = generics.params.iter().filter_map(|param| { - match param { - GenericParam { kind: GenericParamKind::Const { ty: Ty { hir_id, ..}, ..}, ..} => Some(*hir_id), - _ => None, - } - }).chain(std::iter::once(self_ty.hir_id)).collect(); - StackItem::Check { - impl_id: item.owner_id.def_id, - in_body: 0, - types_to_skip, + }) + && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) // expensive, should be last check + { + // Self cannot be used inside const generic parameters + let types_to_skip = generics.params.iter().filter_map(|param| { + match param { + GenericParam { kind: GenericParamKind::Const { ty: Ty { hir_id, ..}, ..}, ..} => Some(*hir_id), + _ => None, } - } else { - StackItem::NoCheck + }).chain(std::iter::once(self_ty.hir_id)).collect(); + StackItem::Check { + impl_id: item.owner_id.def_id, + in_body: 0, + types_to_skip, } + } else { + StackItem::NoCheck }; self.stack.push(stack_item); } @@ -132,56 +130,54 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait // declaration. The collection of those types is all this method implementation does. - if_chain! { - if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind; - if let Some(&mut StackItem::Check { + if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind + && let Some(&mut StackItem::Check { impl_id, ref mut types_to_skip, .. - }) = self.stack.last_mut(); - if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id); - then { - // `self_ty` is the semantic self type of `impl for `. This cannot be - // `Self`. - let self_ty = impl_trait_ref.instantiate_identity().self_ty(); + }) = self.stack.last_mut() + && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id) + { + // `self_ty` is the semantic self type of `impl for `. This cannot be + // `Self`. + let self_ty = impl_trait_ref.instantiate_identity().self_ty(); - // `trait_method_sig` is the signature of the function, how it is declared in the - // trait, not in the impl of the trait. - let trait_method = cx - .tcx - .associated_item(impl_item.owner_id) - .trait_item_def_id - .expect("impl method matches a trait method"); - let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity(); - let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig); + // `trait_method_sig` is the signature of the function, how it is declared in the + // trait, not in the impl of the trait. + let trait_method = cx + .tcx + .associated_item(impl_item.owner_id) + .trait_item_def_id + .expect("impl method matches a trait method"); + let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity(); + let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig); - // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the - // implementation of the trait. - let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output { - Some(&**ty) - } else { - None - }; - let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty); + // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the + // implementation of the trait. + let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output { + Some(&**ty) + } else { + None + }; + let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty); - // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature. - // - // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the - // trait declaration. This is used to check if `Self` was used in the trait - // declaration. - // - // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed - // to `Self`), we want to skip linting that type and all subtypes of it. This - // avoids suggestions to e.g. replace `Vec` with `Vec`, in an `impl Trait - // for u8`, when the trait always uses `Vec`. - // - // See also https://github.com/rust-lang/rust-clippy/issues/2894. - for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) { - if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) { - let mut visitor = SkipTyCollector::default(); - visitor.visit_ty(impl_hir_ty); - types_to_skip.extend(visitor.types_to_skip); - } + // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature. + // + // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the + // trait declaration. This is used to check if `Self` was used in the trait + // declaration. + // + // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed + // to `Self`), we want to skip linting that type and all subtypes of it. This + // avoids suggestions to e.g. replace `Vec` with `Vec`, in an `impl Trait + // for u8`, when the trait always uses `Vec`. + // + // See also https://github.com/rust-lang/rust-clippy/issues/2894. + for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) { + if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) { + let mut visitor = SkipTyCollector::default(); + visitor.visit_ty(impl_hir_ty); + types_to_skip.extend(visitor.types_to_skip); } } } @@ -203,42 +199,38 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { - if_chain! { - if !hir_ty.span.from_expansion(); - if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); - if let Some(&StackItem::Check { + if !hir_ty.span.from_expansion() + && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) + && let Some(&StackItem::Check { impl_id, in_body, ref types_to_skip, - }) = self.stack.last(); - if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; - if !matches!( + }) = self.stack.last() + && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind + && !matches!( path.res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _) - ); - if !types_to_skip.contains(&hir_ty.hir_id); - let ty = if in_body > 0 { + ) + && !types_to_skip.contains(&hir_ty.hir_id) + && let ty = if in_body > 0 { cx.typeck_results().node_type(hir_ty.hir_id) } else { hir_ty_to_ty(cx.tcx, hir_ty) - }; - if same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity()); - then { - span_lint(cx, hir_ty.span); } + && same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity()) + { + span_lint(cx, hir_ty.span); } } fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if !expr.span.from_expansion(); - if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); - if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); - if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity(); - then {} else { return; } - } + if !expr.span.from_expansion() + && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) + && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last() + && cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity() + {} else { return; } match expr.kind { ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path), ExprKind::Call(fun, _) => { @@ -252,18 +244,16 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { - if_chain! { - if !pat.span.from_expansion(); - if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); - if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); + if !pat.span.from_expansion() + && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) + && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last() // get the path from the pattern - if let PatKind::Path(QPath::Resolved(_, path)) + && let PatKind::Path(QPath::Resolved(_, path)) | PatKind::TupleStruct(QPath::Resolved(_, path), _, _) - | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind; - if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity(); - then { - check_path(cx, path); - } + | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind + && cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity() + { + check_path(cx, path); } } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 28f1d487eb5..bc83fddcc53 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -311,76 +311,68 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if_chain! { - if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into; + if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into + && let a = cx.typeck_results().expr_ty(e) + && let b = cx.typeck_results().expr_ty(recv) + && is_type_diagnostic_item(cx, a, sym::Result) + && let ty::Adt(_, args) = a.kind() + && let Some(a_type) = args.types().next() + && same_type_and_consts(a_type, b) + + { + span_lint_and_help( + cx, + USELESS_CONVERSION, + e.span, + &format!("useless conversion to the same type: `{b}`"), + None, + "consider removing `.try_into()`", + ); + } + }, + + ExprKind::Call(path, [arg]) => { + if let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && !is_ty_alias(qpath) + { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(recv); - if is_type_diagnostic_item(cx, a, sym::Result); - if let ty::Adt(_, args) = a.kind(); - if let Some(a_type) = args.types().next(); - if same_type_and_consts(a_type, b); + let b = cx.typeck_results().expr_ty(arg); + if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id) + && is_type_diagnostic_item(cx, a, sym::Result) + && let ty::Adt(_, args) = a.kind() + && let Some(a_type) = args.types().next() + && same_type_and_consts(a_type, b) - then { + { + let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); span_lint_and_help( cx, USELESS_CONVERSION, e.span, &format!("useless conversion to the same type: `{b}`"), None, - "consider removing `.try_into()`", + &hint, ); } - } - }, - ExprKind::Call(path, [arg]) => { - if_chain! { - if let ExprKind::Path(ref qpath) = path.kind; - if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - if !is_ty_alias(qpath); - then { - let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(arg); - if_chain! { - if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id); - if is_type_diagnostic_item(cx, a, sym::Result); - if let ty::Adt(_, args) = a.kind(); - if let Some(a_type) = args.types().next(); - if same_type_and_consts(a_type, b); + if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) + && same_type_and_consts(a, b) - then { - let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); - span_lint_and_help( - cx, - USELESS_CONVERSION, - e.span, - &format!("useless conversion to the same type: `{b}`"), - None, - &hint, - ); - } - } - - if_chain! { - if cx.tcx.is_diagnostic_item(sym::from_fn, def_id); - if same_type_and_consts(a, b); - - then { - let mut app = Applicability::MachineApplicable; - let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); - let sugg_msg = - format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); - span_lint_and_sugg( - cx, - USELESS_CONVERSION, - e.span, - &format!("useless conversion to the same type: `{b}`"), - &sugg_msg, - sugg.to_string(), - app, - ); - } - } + { + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); + let sugg_msg = + format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); + span_lint_and_sugg( + cx, + USELESS_CONVERSION, + e.span, + &format!("useless conversion to the same type: `{b}`"), + &sugg_msg, + sugg.to_string(), + app, + ); } } }, diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index d7666b77f6e..1ed74982486 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -78,45 +78,43 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { return; } - if_chain! { - if let ExprKind::Call(func, and_then_args) = expr.kind; - if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]); - if and_then_args.len() == 5; - if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind; - let body = cx.tcx.hir().body(body); - let only_expr = peel_blocks_with_stmt(body.value); - if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind; - if let ExprKind::Path(..) = recv.kind; - then { - let and_then_snippets = get_and_then_snippets(cx, and_then_args); - let mut sle = SpanlessEq::new(cx).deny_side_effects(); - match ps.ident.as_str() { - "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { - suggest_suggestion( - cx, - expr, - &and_then_snippets, - &span_suggestion_snippets(cx, span_call_args), - ); - }, - "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { - let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); - }, - "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { - let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); - suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); - }, - "help" => { - let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); - suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); - }, - "note" => { - let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); - suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); - }, - _ => (), - } + if let ExprKind::Call(func, and_then_args) = expr.kind + && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]) + && and_then_args.len() == 5 + && let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind + && let body = cx.tcx.hir().body(body) + && let only_expr = peel_blocks_with_stmt(body.value) + && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind + && let ExprKind::Path(..) = recv.kind + { + let and_then_snippets = get_and_then_snippets(cx, and_then_args); + let mut sle = SpanlessEq::new(cx).deny_side_effects(); + match ps.ident.as_str() { + "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + suggest_suggestion( + cx, + expr, + &and_then_snippets, + &span_suggestion_snippets(cx, span_call_args), + ); + }, + "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true); + }, + "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => { + let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#); + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true); + }, + "help" => { + let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#); + suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false); + }, + "note" => { + let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#); + suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false); + }, + _ => (), } } } diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index cacd05262a2..6781c1aef3e 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -56,22 +56,20 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { return; } - if_chain! { - if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind; - let fn_name = path.ident; - if let Some(sugg) = self.map.get(fn_name.as_str()); - let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); - then { - span_lint_and_help( - cx, - COMPILER_LINT_FUNCTIONS, - path.ident.span, - "usage of a compiler lint function", - None, - &format!("please use the Clippy variant of this function: `{sugg}`"), - ); - } + if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind + && let fn_name = path.ident + && let Some(sugg) = self.map.get(fn_name.as_str()) + && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() + && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT)) + { + span_lint_and_help( + cx, + COMPILER_LINT_FUNCTIONS, + path.ident.span, + "usage of a compiler lint function", + None, + &format!("please use the Clippy variant of this function: `{sugg}`"), + ); } } } diff --git a/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/clippy_lints/src/utils/internal_lints/if_chain_style.rs index 8cdd5ea8903..873e136136f 100644 --- a/clippy_lints/src/utils/internal_lints/if_chain_style.rs +++ b/clippy_lints/src/utils/internal_lints/if_chain_style.rs @@ -18,11 +18,9 @@ declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]); impl<'tcx> LateLintPass<'tcx> for IfChainStyle { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - let (local, after, if_chain_span) = if_chain! { - if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts; - if let Some(if_chain_span) = is_expn_of(block.span, "if_chain"); - then { (local, after, if_chain_span) } else { return } - }; + let (local, after, if_chain_span) = if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts + && let Some(if_chain_span) = is_expn_of(block.span, "if_chain") + { (local, after, if_chain_span) } else { return }; if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) { span_lint( cx, @@ -55,13 +53,11 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { } let Some(if_chain_span) = if_chain_span else { return }; // check for `if a && b;` - if_chain! { - if let ExprKind::Binary(op, _, _) = cond.kind; - if op.node == BinOpKind::And; - if cx.sess().source_map().is_multiline(cond.span); - then { - span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`"); - } + if let ExprKind::Binary(op, _, _) = cond.kind + && op.node == BinOpKind::And + && cx.sess().source_map().is_multiline(cond.span) + { + span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`"); } if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span) && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span) @@ -89,17 +85,15 @@ fn check_nested_if_chains( } => (head, tail), _ => return, }; - if_chain! { - if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail); - let sm = cx.sess().source_map(); - if head + if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail) + && let sm = cx.sess().source_map() + && head .iter() - .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span)); - if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr); - then { - } else { - return; - } + .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span)) + && (if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr)) + { + } else { + return; } let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) { (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"), diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index fc9afe5ca8b..c2b36fc28f7 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -77,15 +77,13 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { for def_id in def_path_def_ids(cx, module) { for item in cx.tcx.module_children(def_id) { - if_chain! { - if let Res::Def(DefKind::Const, item_def_id) = item.res; - let ty = cx.tcx.type_of(item_def_id).instantiate_identity(); - if match_type(cx, ty, &paths::SYMBOL); - if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id); - if let Ok(value) = value.to_u32(); - then { - self.symbol_map.insert(value, item_def_id); - } + if let Res::Def(DefKind::Const, item_def_id) = item.res + && let ty = cx.tcx.type_of(item_def_id).instantiate_identity() + && match_type(cx, ty, &paths::SYMBOL) + && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id) + && let Ok(value) = value.to_u32() + { + self.symbol_map.insert(value, item_def_id); } } } @@ -93,24 +91,22 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(func, [arg]) = &expr.kind; - if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind(); - if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN); - if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg); - let value = Symbol::intern(&arg).as_u32(); - if let Some(&def_id) = self.symbol_map.get(&value); - then { - span_lint_and_sugg( - cx, - INTERNING_DEFINED_SYMBOL, - is_expn_of(expr.span, "sym").unwrap_or(expr.span), - "interning a defined symbol", - "try", - cx.tcx.def_path_str(def_id), - Applicability::MachineApplicable, - ); - } + if let ExprKind::Call(func, [arg]) = &expr.kind + && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() + && match_def_path(cx, *def_id, &paths::SYMBOL_INTERN) + && let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg) + && let value = Symbol::intern(&arg).as_u32() + && let Some(&def_id) = self.symbol_map.get(&value) + { + span_lint_and_sugg( + cx, + INTERNING_DEFINED_SYMBOL, + is_expn_of(expr.span, "sym").unwrap_or(expr.span), + "interning a defined symbol", + "try", + cx.tcx.def_path_str(def_id), + Applicability::MachineApplicable, + ); } if let ExprKind::Binary(op, left, right) = expr.kind { if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) { @@ -163,27 +159,24 @@ impl InterningDefinedSymbol { fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option> { static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR]; static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; - let call = if_chain! { - if let ExprKind::AddrOf(_, _, e) = expr.kind; - if let ExprKind::Unary(UnOp::Deref, e) = e.kind; - then { e } else { expr } - }; - if_chain! { + let call = if let ExprKind::AddrOf(_, _, e) = expr.kind + && let ExprKind::Unary(UnOp::Deref, e) = e.kind + { e } else { expr }; + if let ExprKind::MethodCall(_, item, [], _) = call.kind // is a method call - if let ExprKind::MethodCall(_, item, [], _) = call.kind; - if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id); - let ty = cx.typeck_results().expr_ty(item); + && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id) + && let ty = cx.typeck_results().expr_ty(item) // ...on either an Ident or a Symbol - if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) { + && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) { Some(false) } else if match_type(cx, ty, &paths::IDENT) { Some(true) } else { None - }; + } // ...which converts it to a string - let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS }; - if let Some(is_to_owned) = paths + && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS } + && let Some(is_to_owned) = paths .iter() .find_map(|path| if match_def_path(cx, did, path) { Some(path == &paths::SYMBOL_TO_IDENT_STRING) @@ -194,14 +187,13 @@ impl InterningDefinedSymbol { Some(true) } else { None - }); - then { - return Some(SymbolStrExpr::Expr { - item, - is_ident, - is_to_owned, - }); - } + }) + { + return Some(SymbolStrExpr::Expr { + item, + is_ident, + is_to_owned, + }); } // is a string constant if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) { diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 25077223885..b5a4787175a 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -31,13 +31,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let local_def_id = &cx.tcx.parent_module(item.hir_id()); let mod_name = &cx.tcx.item_name(local_def_id.to_def_id()); - if_chain! { - if mod_name.as_str() == "paths"; - if let hir::ItemKind::Const(.., body_id) = item.kind; - let body = cx.tcx.hir().body(body_id); - let typeck_results = cx.tcx.typeck_body(body_id); - if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value); - if let Some(path) = path + if mod_name.as_str() == "paths" + && let hir::ItemKind::Const(.., body_id) = item.kind + && let body = cx.tcx.hir().body(body_id) + && let typeck_results = cx.tcx.typeck_body(body_id) + && let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value) + && let Some(path) = path .iter() .map(|x| { if let Constant::Str(s) = x { @@ -46,11 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { None } }) - .collect::>>(); - if !check_path(cx, &path[..]); - then { - span_lint(cx, INVALID_PATHS, item.span, "invalid path"); - } + .collect::>>() + && !check_path(cx, &path[..]) + { + span_lint(cx, INVALID_PATHS, item.span, "invalid path"); } } } diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 00e352961bd..871c8f99ebf 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -309,15 +309,13 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option { let attrs = cx.tcx.hir().attrs(item.hir_id()); attrs.iter().find_map(|attr| { - if_chain! { + if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind // Identify attribute - if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind; - if let [tool_name, attr_name] = &attr_kind.item.path.segments[..]; - if tool_name.ident.name == sym::clippy; - if attr_name.ident.name == sym::version; - if let Some(version) = attr.value_str(); - then { Some(version) } else { None } - } + && let [tool_name, attr_name] = &attr_kind.item.path.segments[..] + && tool_name.ident.name == sym::clippy + && attr_name.ident.name == sym::version + && let Some(version) = attr.value_str() + { Some(version) } else { None } }) } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 51abe0c1dc3..e4e72bbc388 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -543,49 +543,45 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) { if let ItemKind::Static(ty, Mutability::Not, _) = item.kind { // Normal lint - if_chain! { + if is_lint_ref_type(cx, ty) // item validation - if is_lint_ref_type(cx, ty); // disallow check - let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); + && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase() // metadata extraction - if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item); - if let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item); - then { - if let Some(configuration_section) = self.get_lint_configs(&lint_name) { - raw_docs.push_str(&configuration_section); - } - let version = get_lint_version(cx, item); - - self.lints.push(LintMetadata::new( - lint_name, - SerializableSpan::from_item(cx, item), - group, - level, - version, - raw_docs, - )); + && let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item) + && let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item) + { + if let Some(configuration_section) = self.get_lint_configs(&lint_name) { + raw_docs.push_str(&configuration_section); } + let version = get_lint_version(cx, item); + + self.lints.push(LintMetadata::new( + lint_name, + SerializableSpan::from_item(cx, item), + group, + level, + version, + raw_docs, + )); } - if_chain! { - if is_deprecated_lint(cx, ty); + if is_deprecated_lint(cx, ty) // disallow check - let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); + && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase() // Metadata the little we can get from a deprecated lint - if let Some(raw_docs) = extract_attr_docs_or_lint(cx, item); - then { - let version = get_lint_version(cx, item); - - self.lints.push(LintMetadata::new( - lint_name, - SerializableSpan::from_item(cx, item), - DEPRECATED_LINT_GROUP_STR.to_string(), - DEPRECATED_LINT_LEVEL, - version, - raw_docs, - )); - } + && let Some(raw_docs) = extract_attr_docs_or_lint(cx, item) + { + let version = get_lint_version(cx, item); + + self.lints.push(LintMetadata::new( + lint_name, + SerializableSpan::from_item(cx, item), + DEPRECATED_LINT_GROUP_STR.to_string(), + DEPRECATED_LINT_LEVEL, + version, + raw_docs, + )); } } } @@ -789,15 +785,13 @@ fn collect_renames(lints: &mut Vec) { loop { if let Some(lint_name) = names.pop() { for (k, v) in RENAMED_LINTS { - if_chain! { - if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX); - if name == lint_name; - if let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX); - then { - lint.former_ids.insert(past_name.to_owned()); - writeln!(collected, "* `{past_name}`").unwrap(); - names.push(past_name.to_string()); - } + if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX) + && name == lint_name + && let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX) + { + lint.former_ids.insert(past_name.to_owned()); + writeln!(collected, "* `{past_name}`").unwrap(); + names.push(past_name.to_string()); } } @@ -927,20 +921,18 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { } fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if_chain! { - if let ExprKind::Path(qpath) = &expr.kind; - if let QPath::Resolved(_, path) = qpath; - - let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)); - if match_type(self.cx, expr_ty, &paths::LINT); - then { - if let hir::def::Res::Def(DefKind::Static(..), _) = path.res { - let lint_name = last_path_segment(qpath).ident.name; - self.lints.push(sym_to_string(lint_name).to_ascii_lowercase()); - } else if let Some(local) = get_parent_local(self.cx, expr) { - if let Some(local_init) = local.init { - intravisit::walk_expr(self, local_init); - } + if let ExprKind::Path(qpath) = &expr.kind + && let QPath::Resolved(_, path) = qpath + + && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)) + && match_type(self.cx, expr_ty, &paths::LINT) + { + if let hir::def::Res::Def(DefKind::Static(..), _) = path.res { + let lint_name = last_path_segment(qpath).ident.name; + self.lints.push(sym_to_string(lint_name).to_ascii_lowercase()); + } else if let Some(local) = get_parent_local(self.cx, expr) { + if let Some(local_init) = local.init { + intravisit::walk_expr(self, local_init); } } } @@ -992,13 +984,11 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)); - if_chain! { - if match_type(self.cx, expr_ty, &paths::APPLICABILITY); - if let Some(local) = get_parent_local(self.cx, expr); - if let Some(local_init) = local.init; - then { - intravisit::walk_expr(self, local_init); - } + if match_type(self.cx, expr_ty, &paths::APPLICABILITY) + && let Some(local) = get_parent_local(self.cx, expr) + && let Some(local_init) = local.init + { + intravisit::walk_expr(self, local_init); }; intravisit::walk_expr(self, expr); diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 86b77a77f17..1c09695c9dd 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -22,40 +22,38 @@ declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]); impl LateLintPass<'_> for MsrvAttrImpl { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if_chain! { - if let hir::ItemKind::Impl(hir::Impl { + if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), items, .. - }) = &item.kind; - if let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity); - let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS); - if is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS); - if let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind(); - if self_ty_def.is_struct(); - if self_ty_def.all_fields().any(|f| { + }) = &item.kind + && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity) + && let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS) + && (is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS)) + && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind() + && self_ty_def.is_struct() + && self_ty_def.all_fields().any(|f| { cx.tcx .type_of(f.did) .instantiate_identity() .walk() .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV)) - }); - if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs)); - then { - let context = if is_late_pass { "LateContext" } else { "EarlyContext" }; - let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" }; - let span = cx.sess().source_map().span_through_char(item.span, '{'); - span_lint_and_sugg( - cx, - MISSING_MSRV_ATTR_IMPL, - span, - &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), - &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), - format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")), - Applicability::MachineApplicable, - ); - } + }) + && !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs)) + { + let context = if is_late_pass { "LateContext" } else { "EarlyContext" }; + let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" }; + let span = cx.sess().source_map().span_through_char(item.span, '{'); + span_lint_and_sugg( + cx, + MISSING_MSRV_ATTR_IMPL, + span, + &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), + &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), + format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs index 2b13fad8066..78eeb04d58d 100644 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs @@ -40,23 +40,21 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let (method_names, arg_lists, spans) = method_calls(expr, 2); let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); - if_chain! { - if let ["expn_data", "outer_expn"] = method_names.as_slice(); - let (self_arg, args) = arg_lists[1]; - if args.is_empty(); - let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); - then { - span_lint_and_sugg( - cx, - OUTER_EXPN_EXPN_DATA, - spans[1].with_hi(expr.span.hi()), - "usage of `outer_expn().expn_data()`", - "try", - "outer_expn_data()".to_string(), - Applicability::MachineApplicable, - ); - } + if let ["expn_data", "outer_expn"] = method_names.as_slice() + && let (self_arg, args) = arg_lists[1] + && args.is_empty() + && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs() + && match_type(cx, self_ty, &paths::SYNTAX_CONTEXT) + { + span_lint_and_sugg( + cx, + OUTER_EXPN_EXPN_DATA, + spans[1].with_hi(expr.span.hi()), + "usage of `outer_expn().expn_data()`", + "try", + "outer_expn_data()".to_string(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 81be04659b9..3ad02afd88a 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -102,108 +102,106 @@ impl UnnecessaryDefPath { &["clippy_utils", "is_expr_path_def_path"], ]; - if_chain! { - if let [cx_arg, def_arg, args @ ..] = args; - if let ExprKind::Path(path) = &func.kind; - if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if let Some(which_path) = match_any_def_paths(cx, id, PATHS); - let item_arg = if which_path == 4 { &args[1] } else { &args[0] }; + if let [cx_arg, def_arg, args @ ..] = args + && let ExprKind::Path(path) = &func.kind + && let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && let Some(which_path) = match_any_def_paths(cx, id, PATHS) + && let item_arg = if which_path == 4 { &args[1] } else { &args[0] } // Extract the path to the matched type - if let Some(segments) = path_to_matched_type(cx, item_arg); - let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); - if let Some(def_id) = def_path_def_ids(cx, &segments[..]).next(); - then { - // Check if the target item is a diagnostic item or LangItem. - #[rustfmt::skip] - let (msg, item) = if let Some(item_name) - = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) - { - ( - "use of a def path to a diagnostic item", - Item::DiagnosticItem(*item_name), - ) - } else if let Some(item_name) = get_lang_item_name(cx, def_id) { - ( - "use of a def path to a `LangItem`", - Item::LangItem(item_name), - ) - } else { - return; - }; + && let Some(segments) = path_to_matched_type(cx, item_arg) + && let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect() + && let Some(def_id) = def_path_def_ids(cx, &segments[..]).next() + { + // Check if the target item is a diagnostic item or LangItem. + #[rustfmt::skip] + let (msg, item) = if let Some(item_name) + = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id) + { + ( + "use of a def path to a diagnostic item", + Item::DiagnosticItem(*item_name), + ) + } else if let Some(item_name) = get_lang_item_name(cx, def_id) { + ( + "use of a def path to a `LangItem`", + Item::LangItem(item_name), + ) + } else { + return; + }; - let has_ctor = match cx.tcx.def_kind(def_id) { - DefKind::Struct => { - let variant = cx.tcx.adt_def(def_id).non_enum_variant(); - variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - }, - DefKind::Variant => { - let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); - variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) - }, - _ => false, - }; + let has_ctor = match cx.tcx.def_kind(def_id) { + DefKind::Struct => { + let variant = cx.tcx.adt_def(def_id).non_enum_variant(); + variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + }, + DefKind::Variant => { + let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id); + variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public()) + }, + _ => false, + }; - let mut app = Applicability::MachineApplicable; - let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); - let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); - let (sugg, with_note) = match (which_path, item) { - // match_def_path - (0, Item::DiagnosticItem(item)) => ( - format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), - has_ctor, - ), - (0, Item::LangItem(item)) => ( - format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"), - has_ctor, - ), - // match_trait_method - (1, Item::DiagnosticItem(item)) => { - (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false) - }, - // match_type - (2, Item::DiagnosticItem(item)) => ( - format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), - false, - ), - (2, Item::LangItem(item)) => ( - format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), - false, - ), - // is_expr_path_def_path - (3, Item::DiagnosticItem(item)) if has_ctor => ( - format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",), - false, - ), - (3, Item::LangItem(item)) if has_ctor => ( - format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",), - false, - ), - (3, Item::DiagnosticItem(item)) => ( - format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), - false, - ), - (3, Item::LangItem(item)) => ( - format!( - "path_res({cx_snip}, {def_snip}).opt_def_id()\ - .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))", - ), - false, + let mut app = Applicability::MachineApplicable; + let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app); + let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app); + let (sugg, with_note) = match (which_path, item) { + // match_def_path + (0, Item::DiagnosticItem(item)) => ( + format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), + has_ctor, + ), + (0, Item::LangItem(item)) => ( + format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"), + has_ctor, + ), + // match_trait_method + (1, Item::DiagnosticItem(item)) => { + (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false) + }, + // match_type + (2, Item::DiagnosticItem(item)) => ( + format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), + false, + ), + (2, Item::LangItem(item)) => ( + format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), + false, + ), + // is_expr_path_def_path + (3, Item::DiagnosticItem(item)) if has_ctor => ( + format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",), + false, + ), + (3, Item::LangItem(item)) if has_ctor => ( + format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",), + false, + ), + (3, Item::DiagnosticItem(item)) => ( + format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), + false, + ), + (3, Item::LangItem(item)) => ( + format!( + "path_res({cx_snip}, {def_snip}).opt_def_id()\ + .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))", ), - _ => return, - }; + false, + ), + _ => return, + }; - span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| { - diag.span_suggestion(span, "try", sugg, app); - if with_note { - diag.help( - "if this `DefId` came from a constructor expression or pattern then the \ - parent `DefId` should be used instead", - ); - } - }); + span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| { + diag.span_suggestion(span, "try", sugg, app); + if with_note { + diag.help( + "if this `DefId` came from a constructor expression or pattern then the \ + parent `DefId` should be used instead", + ); + } + }); - self.linted_def_ids.insert(def_id); - } + self.linted_def_ids.insert(def_id); } } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index a9dd44afaf7..d215e6b5768 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -72,21 +72,19 @@ fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]` - if_chain! { - if adjusts_to_slice(cx, expr); - if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()); - then { - let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { - // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) - (SuggestedType::SliceRef(mutability), expr.span) - } else { - // `expr` is the `vec![_]` expansion, so suggest `[_]` - // and also use the span of the actual `vec![_]` expression - (SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site) - }; - - self.check_vec_macro(cx, &vec_args, span, suggest_slice); - } + if adjusts_to_slice(cx, expr) + && let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) + { + let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { + // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) + (SuggestedType::SliceRef(mutability), expr.span) + } else { + // `expr` is the `vec![_]` expansion, so suggest `[_]` + // and also use the span of the actual `vec![_]` expression + (SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site) + }; + + self.check_vec_macro(cx, &vec_args, span, suggest_slice); } // search for `let foo = vec![_]` expressions where all uses of `foo` @@ -124,15 +122,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } // search for `for _ in vec![…]` - if_chain! { - if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr); - if let Some(vec_args) = higher::VecArgs::hir(cx, arg); - if self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR); - then { - // report the error around the `vec!` not inside `:` - let span = arg.span.ctxt().outer_expn_data().call_site; - self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array); - } + if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) + && let Some(vec_args) = higher::VecArgs::hir(cx, arg) + && self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR) + { + // report the error around the `vec!` not inside `:` + let span = arg.span.ctxt().outer_expn_data().call_site; + self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array); } } diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index d88ede76398..c94ed82646e 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -127,70 +127,68 @@ impl LateLintPass<'_> for WildcardImports { if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) { return; } - if_chain! { - if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind; - if self.warn_on_all || !self.check_exceptions(item, use_path.segments); - let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id); - if !used_imports.is_empty(); // Already handled by `unused_imports` - if !used_imports.contains(&kw::Underscore); - then { - let mut applicability = Applicability::MachineApplicable; - let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability); - let (span, braced_glob) = if import_source_snippet.is_empty() { - // This is a `_::{_, *}` import - // In this case `use_path.span` is empty and ends directly in front of the `*`, - // so we need to extend it by one byte. - ( - use_path.span.with_hi(use_path.span.hi() + BytePos(1)), - true, - ) - } else { - // In this case, the `use_path.span` ends right before the `::*`, so we need to - // extend it up to the `*`. Since it is hard to find the `*` in weird - // formattings like `use _ :: *;`, we extend it up to, but not including the - // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we - // can just use the end of the item span - let mut span = use_path.span.with_hi(item.span.hi()); - if snippet(cx, span, "").ends_with(';') { - span = use_path.span.with_hi(item.span.hi() - BytePos(1)); - } - ( - span, false, - ) - }; + if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind + && (self.warn_on_all || !self.check_exceptions(item, use_path.segments)) + && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id) + && !used_imports.is_empty() // Already handled by `unused_imports` + && !used_imports.contains(&kw::Underscore) + { + let mut applicability = Applicability::MachineApplicable; + let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability); + let (span, braced_glob) = if import_source_snippet.is_empty() { + // This is a `_::{_, *}` import + // In this case `use_path.span` is empty and ends directly in front of the `*`, + // so we need to extend it by one byte. + ( + use_path.span.with_hi(use_path.span.hi() + BytePos(1)), + true, + ) + } else { + // In this case, the `use_path.span` ends right before the `::*`, so we need to + // extend it up to the `*`. Since it is hard to find the `*` in weird + // formattings like `use _ :: *;`, we extend it up to, but not including the + // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we + // can just use the end of the item span + let mut span = use_path.span.with_hi(item.span.hi()); + if snippet(cx, span, "").ends_with(';') { + span = use_path.span.with_hi(item.span.hi() - BytePos(1)); + } + ( + span, false, + ) + }; - let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(); - let imports_string = if imports.len() == 1 { - imports.pop().unwrap() - } else if braced_glob { - imports.join(", ") - } else { - format!("{{{}}}", imports.join(", ")) - }; + let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(); + let imports_string = if imports.len() == 1 { + imports.pop().unwrap() + } else if braced_glob { + imports.join(", ") + } else { + format!("{{{}}}", imports.join(", ")) + }; - let sugg = if braced_glob { - imports_string - } else { - format!("{import_source_snippet}::{imports_string}") - }; + let sugg = if braced_glob { + imports_string + } else { + format!("{import_source_snippet}::{imports_string}") + }; - // Glob imports always have a single resolution. - let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] { - (ENUM_GLOB_USE, "usage of wildcard import for enum variants") - } else { - (WILDCARD_IMPORTS, "usage of wildcard import") - }; + // Glob imports always have a single resolution. + let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] { + (ENUM_GLOB_USE, "usage of wildcard import for enum variants") + } else { + (WILDCARD_IMPORTS, "usage of wildcard import") + }; - span_lint_and_sugg( - cx, - lint, - span, - message, - "try", - sugg, - applicability, - ); - } + span_lint_and_sugg( + cx, + lint, + span, + message, + "try", + sugg, + applicability, + ); } } diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index f2f0699ef48..7f7d30d03ab 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -32,35 +32,33 @@ declare_lint_pass!(ZeroDiv => [ZERO_DIVIDED_BY_ZERO]); impl<'tcx> LateLintPass<'tcx> for ZeroDiv { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // check for instances of 0.0/0.0 - if_chain! { - if let ExprKind::Binary(ref op, left, right) = expr.kind; - if op.node == BinOpKind::Div; + if let ExprKind::Binary(ref op, left, right) = expr.kind + && op.node == BinOpKind::Div // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. - if let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left); - if let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right); - if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value; - if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value; - then { - // since we're about to suggest a use of f32::NAN or f64::NAN, - // match the precision of the literals that are given. - let float_type = match (lhs_value, rhs_value) { - (Constant::F64(_), _) - | (_, Constant::F64(_)) => "f64", - _ => "f32" - }; - span_lint_and_help( - cx, - ZERO_DIVIDED_BY_ZERO, - expr.span, - "constant division of `0.0` with `0.0` will always result in NaN", - None, - &format!( - "consider using `{float_type}::NAN` if you would like a constant representing NaN", - ), - ); - } + && let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left) + && let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right) + && (Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value) + && (Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value) + { + // since we're about to suggest a use of f32::NAN or f64::NAN, + // match the precision of the literals that are given. + let float_type = match (lhs_value, rhs_value) { + (Constant::F64(_), _) + | (_, Constant::F64(_)) => "f64", + _ => "f32" + }; + span_lint_and_help( + cx, + ZERO_DIVIDED_BY_ZERO, + expr.span, + "constant division of `0.0` with `0.0` will always result in NaN", + None, + &format!( + "consider using `{float_type}::NAN` if you would like a constant representing NaN", + ), + ); } } } diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index fee100fe1ea..6504b0fa5f9 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -46,23 +46,21 @@ declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]); impl LateLintPass<'_> for ZeroSizedMapValues { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { - if_chain! { - if !hir_ty.span.from_expansion(); - if !in_trait_impl(cx, hir_ty.hir_id); - let ty = ty_from_hir_ty(cx, hir_ty); - if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap); - if let Adt(_, args) = ty.kind(); - let ty = args.type_at(1); + if !hir_ty.span.from_expansion() + && !in_trait_impl(cx, hir_ty.hir_id) + && let ty = ty_from_hir_ty(cx, hir_ty) + && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)) + && let Adt(_, args) = ty.kind() + && let ty = args.type_at(1) // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968 - if !ty.has_escaping_bound_vars(); + && !ty.has_escaping_bound_vars() // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`. - if is_normalizable(cx, cx.param_env, ty); - if let Ok(layout) = cx.layout_of(ty); - if layout.is_zst(); - then { - span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, hir_ty.span, "map with zero-sized value type", None, "consider using a set instead"); - } + && is_normalizable(cx, cx.param_env, ty) + && let Ok(layout) = cx.layout_of(ty) + && layout.is_zst() + { + span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, hir_ty.span, "map with zero-sized value type", None, "consider using a set instead"); } } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index b7d8c0a8fd7..791f815c850 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -372,27 +372,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::Binary(op, left, right) => self.binop(op, left, right), ExprKind::Call(callee, args) => { // We only handle a few const functions for now. - if_chain! { - if args.is_empty(); - if let ExprKind::Path(qpath) = &callee.kind; - let res = self.typeck_results.qpath_res(qpath, callee.hir_id); - if let Some(def_id) = res.opt_def_id(); - let def_path = self.lcx.get_def_path(def_id); - let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect(); - if let ["core", "num", int_impl, "max_value"] = *def_path; - then { - let value = match int_impl { - "" => i8::MAX as u128, - "" => i16::MAX as u128, - "" => i32::MAX as u128, - "" => i64::MAX as u128, - "" => i128::MAX as u128, - _ => return None, - }; - Some(Constant::Int(value)) - } else { - None - } + if args.is_empty() + && let ExprKind::Path(qpath) = &callee.kind + && let res = self.typeck_results.qpath_res(qpath, callee.hir_id) + && let Some(def_id) = res.opt_def_id() + && let def_path = self.lcx.get_def_path(def_id) + && let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect() + && let ["core", "num", int_impl, "max_value"] = *def_path + { + let value = match int_impl { + "" => i8::MAX as u128, + "" => i16::MAX as u128, + "" => i32::MAX as u128, + "" => i64::MAX as u128, + "" => i128::MAX as u128, + _ => return None, + }; + Some(Constant::Int(value)) + } else { + None } }, ExprKind::Index(arr, index, _) => self.index(arr, index), diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index edea4b3667f..93cd5b3fe1e 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -30,24 +30,22 @@ pub struct ForLoop<'tcx> { impl<'tcx> ForLoop<'tcx> { /// Parses a desugared `for` loop pub fn hir(expr: &Expr<'tcx>) -> Option { - if_chain! { - if let hir::ExprKind::DropTemps(e) = expr.kind; - if let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind; - if let hir::ExprKind::Call(_, [arg]) = iterexpr.kind; - if let hir::ExprKind::Loop(block, ..) = arm.body.kind; - if let [stmt] = block.stmts; - if let hir::StmtKind::Expr(e) = stmt.kind; - if let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind; - if let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind; - then { - return Some(Self { - pat: field.pat, - arg, - body: some_arm.body, - loop_id: arm.body.hir_id, - span: expr.span.ctxt().outer_expn_data().call_site, - }); - } + if let hir::ExprKind::DropTemps(e) = expr.kind + && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind + && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind + && let hir::ExprKind::Loop(block, ..) = arm.body.kind + && let [stmt] = block.stmts + && let hir::StmtKind::Expr(e) = stmt.kind + && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind + && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind + { + return Some(Self { + pat: field.pat, + arg, + body: some_arm.body, + loop_id: arm.body.hir_id, + span: expr.span.ctxt().outer_expn_data().call_site, + }); } None } @@ -277,29 +275,27 @@ impl<'a> VecArgs<'a> { /// Returns the arguments of the `vec!` macro if this expression was expanded /// from `vec!`. pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option> { - if_chain! { - if let hir::ExprKind::Call(fun, args) = expr.kind; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - if is_expn_of(fun.span, "vec").is_some(); - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - then { - return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 { - // `vec![elem; size]` case - Some(VecArgs::Repeat(&args[0], &args[1])) - } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { - // `vec![a, b, c]` case - if let hir::ExprKind::Call(_, [arg]) = &args[0].kind - && let hir::ExprKind::Array(args) = arg.kind { - Some(VecArgs::Vec(args)) - } else { - None - } - } else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() { - Some(VecArgs::Vec(&[])) + if let hir::ExprKind::Call(fun, args) = expr.kind + && let hir::ExprKind::Path(ref qpath) = fun.kind + && is_expn_of(fun.span, "vec").is_some() + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + { + return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 { + // `vec![elem; size]` case + Some(VecArgs::Repeat(&args[0], &args[1])) + } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { + // `vec![a, b, c]` case + if let hir::ExprKind::Call(_, [arg]) = &args[0].kind + && let hir::ExprKind::Array(args) = arg.kind { + Some(VecArgs::Vec(args)) } else { None - }; - } + } + } else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() { + Some(VecArgs::Vec(&[])) + } else { + None + }; } None diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 1181dfc0ef9..e3c26525a6a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -176,14 +176,12 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr /// canonical binding `HirId`. pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { let hir = cx.tcx.hir(); - if_chain! { - if let Some(Node::Pat(pat)) = hir.find(hir_id); - if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)); - let parent = hir.parent_id(hir_id); - if let Some(Node::Local(local)) = hir.find(parent); - then { - return local.init; - } + if let Some(Node::Pat(pat)) = hir.find(hir_id) + && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)) + && let parent = hir.parent_id(hir_id) + && let Some(Node::Local(local)) = hir.find(parent) + { + return local.init; } None } @@ -713,13 +711,11 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> // Get the implemented trait for the current function let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); let parent_impl = cx.tcx.hir().get_parent_item(hir_id); - if_chain! { - if parent_impl != hir::CRATE_OWNER_ID; - if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id); - if let hir::ItemKind::Impl(impl_) = &item.kind; - then { - return impl_.of_trait.as_ref(); - } + if parent_impl != hir::CRATE_OWNER_ID + && let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id) + && let hir::ItemKind::Impl(impl_) = &item.kind + { + return impl_.of_trait.as_ref(); } None } @@ -823,13 +819,11 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< /// Returns true if the expr is equal to `Default::default` when evaluated. pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool { - if_chain! { - if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diag_trait_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); - then { true } else { false } - } + if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind + && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() + && (is_diag_trait_item(cx, repl_def_id, sym::Default) + || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath)) + { true } else { false } } /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. @@ -843,16 +837,14 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { _ => false, }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), - ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! { - if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind; - if let LitKind::Int(v, _) = const_lit.node; - if v <= 32 && is_default_equivalent(cx, x); - then { - true - } - else { - false - } + ExprKind::Repeat(x, ArrayLen::Body(len)) => if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind + && let LitKind::Int(v, _) = const_lit.node + && v <= 32 && is_default_equivalent(cx, x) + { + true + } + else { + false }, ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func), ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg), @@ -1736,15 +1728,13 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It /// operator or the `try` macro. pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { - if_chain! { - if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind; - if ddpos.as_opt_usize().is_none(); - if is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk); - if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; - if path_to_local_id(arm.body, hir_id); - then { - return true; - } + if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind + && ddpos.as_opt_usize().is_none() + && is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk) + && let PatKind::Binding(_, hir_id, _, None) = pat[0].kind + && path_to_local_id(arm.body, hir_id) + { + return true; } false } @@ -1763,14 +1753,12 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc return Some(expr); } - if_chain! { - if arms.len() == 2; - if arms[0].guard.is_none(); - if arms[1].guard.is_none(); - if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0])); - then { - return Some(expr); - } + if arms.len() == 2 + && arms[0].guard.is_none() + && arms[1].guard.is_none() + && ((is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]))) + { + return Some(expr); } } @@ -1887,14 +1875,12 @@ pub fn match_function_call<'tcx>( expr: &'tcx Expr<'_>, path: &[&str], ) -> Option<&'tcx [Expr<'tcx>]> { - if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - if match_def_path(cx, fun_def_id, path); - then { - return Some(args); - } + if let ExprKind::Call(fun, args) = expr.kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && match_def_path(cx, fun_def_id, path) + { + return Some(args); }; None } @@ -1904,13 +1890,11 @@ pub fn match_function_call_with_def_id<'tcx>( expr: &'tcx Expr<'_>, fun_def_id: DefId, ) -> Option<&'tcx [Expr<'tcx>]> { - if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id); - then { - return Some(args); - } + if let ExprKind::Call(fun, args) = expr.kind + && let ExprKind::Path(ref qpath) = fun.kind + && cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id) + { + return Some(args); }; None } @@ -2008,14 +1992,12 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t // check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { - ExprKind::Call(path, _) => if_chain! { - if let ExprKind::Path(ref qpath) = path.kind; - if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id); - then { - Some(did) - } else { - None - } + ExprKind::Call(path, _) => if let ExprKind::Path(ref qpath) = path.kind + && let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) + { + Some(did) + } else { + None }, ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), _ => None, @@ -2071,14 +2053,12 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { }, _, ) => { - if_chain! { - if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind; - if let ExprKind::Ret(Some(ret_val)) = e.kind; - then { - expr = ret_val; - } else { - return false; - } + if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind + && let ExprKind::Ret(Some(ret_val)) = e.kind + { + expr = ret_val; + } else { + return false; } }, _ => return check_pat(cx, param.pat, expr), -- cgit 1.4.1-3-g733a5 From 13b4bb12ad6ef84dea53c5a2547473b3d4ab93e3 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 2 Nov 2023 19:23:36 +0000 Subject: Clean up after if chain removal --- clippy_lints/Cargo.toml | 1 - clippy_lints/src/attrs.rs | 1 - clippy_lints/src/blocks_in_if_conditions.rs | 1 - clippy_lints/src/booleans.rs | 1 - clippy_lints/src/borrow_deref_ref.rs | 37 +++-- clippy_lints/src/cargo/multiple_crate_versions.rs | 11 +- clippy_lints/src/cargo/wildcard_dependencies.rs | 1 - clippy_lints/src/casts/cast_sign_loss.rs | 1 - .../src/casts/cast_slice_different_sizes.rs | 1 - .../src/casts/cast_slice_from_raw_parts.rs | 5 +- clippy_lints/src/casts/char_lit_as_u8.rs | 4 +- clippy_lints/src/casts/ptr_cast_constness.rs | 17 ++- clippy_lints/src/casts/unnecessary_cast.rs | 16 ++- clippy_lints/src/checked_conversions.rs | 15 +- clippy_lints/src/collapsible_if.rs | 43 +++--- clippy_lints/src/copy_iterator.rs | 8 +- clippy_lints/src/crate_in_macro_def.rs | 14 +- clippy_lints/src/create_dir.rs | 3 +- clippy_lints/src/declared_lints.rs | 2 - clippy_lints/src/default.rs | 1 - .../src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 80 +++++------ clippy_lints/src/derivable_impls.rs | 64 ++++----- clippy_lints/src/derive.rs | 35 ++--- clippy_lints/src/doc.rs | 33 ++--- clippy_lints/src/empty_drop.rs | 14 +- clippy_lints/src/exhaustive_items.rs | 28 ++-- clippy_lints/src/exit.rs | 1 - clippy_lints/src/explicit_write.rs | 1 - clippy_lints/src/fallible_impl_from.rs | 14 +- clippy_lints/src/float_literal.rs | 4 +- clippy_lints/src/floating_point_arithmetic.rs | 160 ++++++++++++++------- clippy_lints/src/format_args.rs | 9 +- clippy_lints/src/format_impl.rs | 15 +- clippy_lints/src/formatting.rs | 15 +- clippy_lints/src/from_str_radix_10.rs | 18 +-- clippy_lints/src/functions/misnamed_getters.rs | 2 +- clippy_lints/src/functions/result.rs | 21 +-- clippy_lints/src/if_let_mutex.rs | 1 - clippy_lints/src/implicit_hasher.rs | 8 +- clippy_lints/src/implicit_saturating_add.rs | 29 +++- clippy_lints/src/implicit_saturating_sub.rs | 8 +- .../src/inconsistent_struct_constructor.rs | 16 +-- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/instant_subtraction.rs | 20 +-- clippy_lints/src/large_const_arrays.rs | 4 +- clippy_lints/src/large_include_file.rs | 2 +- clippy_lints/src/len_zero.rs | 11 +- clippy_lints/src/let_if_seq.rs | 61 +++++--- clippy_lints/src/let_with_type_underscore.rs | 4 +- clippy_lints/src/lib.rs | 1 - clippy_lints/src/lifetimes.rs | 1 - clippy_lints/src/literal_representation.rs | 31 ++-- clippy_lints/src/loops/explicit_counter_loop.rs | 3 +- clippy_lints/src/loops/manual_find.rs | 21 +-- clippy_lints/src/loops/manual_flatten.rs | 38 ++--- clippy_lints/src/loops/manual_memcpy.rs | 26 +++- clippy_lints/src/loops/missing_spin_loop.rs | 12 +- clippy_lints/src/loops/mut_range_bound.rs | 9 +- clippy_lints/src/loops/needless_range_loop.rs | 1 - clippy_lints/src/loops/same_item_push.rs | 9 +- clippy_lints/src/loops/single_element_loop.rs | 13 +- clippy_lints/src/loops/utils.rs | 3 +- .../src/loops/while_immutable_condition.rs | 1 - clippy_lints/src/loops/while_let_on_iterator.rs | 73 +++++----- clippy_lints/src/macro_use.rs | 7 +- clippy_lints/src/main_recursion.rs | 5 +- clippy_lints/src/manual_async_fn.rs | 5 +- clippy_lints/src/manual_bits.rs | 8 +- clippy_lints/src/manual_strip.rs | 47 +++--- clippy_lints/src/map_unit_fn.rs | 1 - clippy_lints/src/match_result_ok.rs | 1 - clippy_lints/src/matches/collapsible_match.rs | 28 ++-- .../src/matches/infallible_destructuring_match.rs | 7 +- clippy_lints/src/matches/manual_filter.rs | 16 ++- clippy_lints/src/matches/manual_unwrap_or.rs | 39 +++-- clippy_lints/src/matches/match_as_ref.rs | 5 +- clippy_lints/src/matches/match_like_matches.rs | 15 +- clippy_lints/src/matches/match_on_vec_items.rs | 11 +- .../src/matches/match_str_case_mismatch.rs | 11 +- clippy_lints/src/matches/match_wild_err_arm.rs | 3 +- .../src/matches/redundant_pattern_match.rs | 1 - .../src/matches/rest_pat_in_fully_bound_struct.rs | 1 - clippy_lints/src/matches/single_match.rs | 12 +- clippy_lints/src/matches/try_err.rs | 4 - clippy_lints/src/mem_replace.rs | 6 +- clippy_lints/src/methods/bind_instead_of_map.rs | 25 ++-- clippy_lints/src/methods/bytecount.rs | 16 +-- clippy_lints/src/methods/bytes_count_to_len.rs | 8 +- .../case_sensitive_file_extension_comparisons.rs | 16 ++- clippy_lints/src/methods/chars_cmp.rs | 11 +- clippy_lints/src/methods/chars_cmp_with_unwrap.rs | 11 +- clippy_lints/src/methods/err_expect.rs | 5 +- clippy_lints/src/methods/extend_with_drain.rs | 1 - clippy_lints/src/methods/filetype_is_file.rs | 1 - clippy_lints/src/methods/filter_map.rs | 34 +++-- .../src/methods/from_iter_instead_of_collect.rs | 16 ++- clippy_lints/src/methods/get_first.rs | 30 ++-- clippy_lints/src/methods/implicit_clone.rs | 1 - clippy_lints/src/methods/inefficient_to_string.rs | 4 +- clippy_lints/src/methods/into_iter_on_ref.rs | 5 +- clippy_lints/src/methods/iter_cloned_collect.rs | 8 +- clippy_lints/src/methods/iter_kv_map.rs | 30 ++-- clippy_lints/src/methods/iter_next_slice.rs | 18 ++- clippy_lints/src/methods/iter_skip_next.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 5 +- .../src/methods/manual_saturating_arithmetic.rs | 3 +- clippy_lints/src/methods/manual_str_repeat.rs | 20 +-- clippy_lints/src/methods/map_clone.rs | 39 ++--- .../src/methods/map_collect_result_unit.rs | 3 +- clippy_lints/src/methods/map_identity.rs | 6 +- clippy_lints/src/methods/mod.rs | 6 +- clippy_lints/src/methods/mut_mutex_lock.rs | 1 - clippy_lints/src/methods/no_effect_replace.rs | 3 - clippy_lints/src/methods/ok_expect.rs | 2 - clippy_lints/src/methods/option_as_ref_deref.rs | 1 - clippy_lints/src/methods/or_fun_call.rs | 6 - .../src/methods/path_buf_push_overwrite.rs | 1 - clippy_lints/src/methods/range_zip_with_len.rs | 10 +- clippy_lints/src/methods/search_is_some.rs | 5 +- clippy_lints/src/methods/single_char_pattern.rs | 4 +- clippy_lints/src/methods/str_splitn.rs | 23 ++- clippy_lints/src/methods/suspicious_map.rs | 1 - clippy_lints/src/methods/suspicious_splitn.rs | 30 ++-- clippy_lints/src/methods/suspicious_to_owned.rs | 8 +- clippy_lints/src/methods/uninit_assumed_init.rs | 3 +- clippy_lints/src/methods/unnecessary_fold.rs | 7 +- .../src/methods/unnecessary_iter_cloned.rs | 7 +- clippy_lints/src/methods/unnecessary_sort_by.rs | 48 +++++-- clippy_lints/src/methods/useless_asref.rs | 1 - clippy_lints/src/methods/utils.rs | 14 +- clippy_lints/src/methods/vec_resize_to_zero.rs | 10 +- clippy_lints/src/methods/zst_offset.rs | 1 - clippy_lints/src/misc.rs | 16 +-- clippy_lints/src/mismatching_type_param_order.rs | 44 +++--- clippy_lints/src/missing_doc.rs | 1 - clippy_lints/src/missing_enforced_import_rename.rs | 4 +- clippy_lints/src/mixed_read_write_in_expression.rs | 7 +- clippy_lints/src/needless_arbitrary_self_type.rs | 5 +- clippy_lints/src/needless_for_each.rs | 4 +- clippy_lints/src/needless_late_init.rs | 13 +- .../src/needless_parens_on_range_literals.rs | 8 +- clippy_lints/src/needless_pass_by_value.rs | 56 ++++---- clippy_lints/src/needless_question_mark.rs | 1 - clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 - clippy_lints/src/neg_multiply.rs | 18 ++- clippy_lints/src/new_without_default.rs | 3 +- clippy_lints/src/no_effect.rs | 15 +- clippy_lints/src/non_copy_const.rs | 8 +- clippy_lints/src/non_octal_unix_permissions.rs | 9 +- clippy_lints/src/non_send_fields_in_send_ty.rs | 17 ++- clippy_lints/src/nonstandard_macro_braces.rs | 1 - clippy_lints/src/operators/assign_op_pattern.rs | 4 +- clippy_lints/src/operators/const_comparisons.rs | 17 ++- clippy_lints/src/operators/float_cmp.rs | 5 +- .../src/operators/float_equality_without_abs.rs | 18 +-- clippy_lints/src/operators/modulo_arithmetic.rs | 4 +- clippy_lints/src/operators/op_ref.rs | 9 +- clippy_lints/src/operators/ptr_eq.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 45 ++++-- clippy_lints/src/overflow_check_conditional.rs | 1 - clippy_lints/src/partialeq_ne_impl.rs | 7 +- clippy_lints/src/pass_by_ref_or_value.rs | 6 +- clippy_lints/src/precedence.rs | 1 - clippy_lints/src/question_mark.rs | 19 ++- clippy_lints/src/ranges.rs | 24 ++-- clippy_lints/src/rc_clone_in_vec_init.rs | 4 +- clippy_lints/src/redundant_clone.rs | 32 ++--- clippy_lints/src/redundant_closure_call.rs | 3 +- clippy_lints/src/redundant_pub_crate.rs | 3 +- clippy_lints/src/redundant_slicing.rs | 22 +-- clippy_lints/src/ref_option_ref.rs | 5 +- clippy_lints/src/reference.rs | 19 ++- clippy_lints/src/return_self_not_must_use.rs | 4 +- clippy_lints/src/returns.rs | 6 +- clippy_lints/src/same_name_method.rs | 11 +- clippy_lints/src/self_named_constructors.rs | 4 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 4 +- clippy_lints/src/size_of_in_element_count.rs | 15 +- clippy_lints/src/slow_vector_initialization.rs | 6 +- clippy_lints/src/strings.rs | 14 +- clippy_lints/src/strlen_on_c_strings.rs | 10 +- clippy_lints/src/suspicious_doc_comments.rs | 3 +- clippy_lints/src/suspicious_operation_groupings.rs | 41 ++---- clippy_lints/src/suspicious_trait_impl.rs | 7 +- clippy_lints/src/swap.rs | 2 - clippy_lints/src/to_digit_is_some.rs | 13 +- clippy_lints/src/trait_bounds.rs | 57 +++++--- clippy_lints/src/transmute/mod.rs | 7 +- .../src/transmute/transmute_float_to_int.rs | 3 +- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 50 +++---- clippy_lints/src/types/borrowed_box.rs | 1 - clippy_lints/src/types/box_collection.rs | 6 +- clippy_lints/src/types/option_option.rs | 1 - clippy_lints/src/types/rc_mutex.rs | 3 +- clippy_lints/src/types/utils.rs | 1 - clippy_lints/src/uninit_vec.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 3 +- clippy_lints/src/unit_types/unit_arg.rs | 9 +- clippy_lints/src/unnamed_address.rs | 4 +- .../src/unnecessary_owned_empty_strings.rs | 55 ++++--- clippy_lints/src/unnecessary_self_imports.rs | 8 +- clippy_lints/src/unnecessary_wraps.rs | 19 ++- clippy_lints/src/unused_self.rs | 1 - clippy_lints/src/unused_unit.rs | 8 +- clippy_lints/src/unwrap.rs | 68 +++++---- clippy_lints/src/unwrap_in_result.rs | 1 - clippy_lints/src/use_self.rs | 36 +++-- clippy_lints/src/useless_conversion.rs | 14 +- clippy_lints/src/utils/internal_lints.rs | 1 - .../src/utils/internal_lints/collapsible_calls.rs | 1 - .../internal_lints/compiler_lint_functions.rs | 1 - .../src/utils/internal_lints/if_chain_style.rs | 160 --------------------- .../internal_lints/interning_defined_symbol.rs | 7 +- .../src/utils/internal_lints/invalid_paths.rs | 1 - .../utils/internal_lints/lint_without_lint_pass.rs | 7 +- .../src/utils/internal_lints/metadata_collector.rs | 2 - .../src/utils/internal_lints/msrv_attr_impl.rs | 14 +- .../utils/internal_lints/outer_expn_data_pass.rs | 1 - .../utils/internal_lints/unnecessary_def_path.rs | 3 +- clippy_lints/src/vec.rs | 1 - clippy_lints/src/wildcard_imports.rs | 20 +-- clippy_lints/src/zero_div_zero.rs | 10 +- clippy_lints/src/zero_sized_map_values.rs | 10 +- clippy_utils/Cargo.toml | 1 - clippy_utils/src/consts.rs | 4 +- clippy_utils/src/higher.rs | 5 +- clippy_utils/src/lib.rs | 39 ++--- tests/ui-internal/if_chain_style.rs | 97 ------------- tests/ui-internal/if_chain_style.stderr | 86 ----------- 230 files changed, 1455 insertions(+), 1848 deletions(-) delete mode 100644 clippy_lints/src/utils/internal_lints/if_chain_style.rs delete mode 100644 tests/ui-internal/if_chain_style.rs delete mode 100644 tests/ui-internal/if_chain_style.stderr (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 4bc27fd48e2..a4116603688 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -14,7 +14,6 @@ cargo_metadata = "0.15.3" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } -if_chain = "1.0" itertools = "0.10.1" quine-mc_cluskey = "0.2" regex-syntax = "0.7" diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 112ded59e13..240ff859764 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -5,7 +5,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug use clippy_utils::is_from_proc_macro; use clippy_utils::macros::{is_panic, macro_backtrace}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; -use if_chain::if_chain; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; use rustc_ast::{ diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 9ad68f115ea..28bd3fc7011 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait; use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{get_parent_expr, higher}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 69550f6879a..66fd64c1cd0 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 33b7bde3a41..789cd3b6c21 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -54,25 +54,25 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { && !addrof_target.span.from_expansion() && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind && !deref_target.span.from_expansion() - && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ) + && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() && !is_from_proc_macro(cx, e) { - - if let Some(parent_expr) = get_parent_expr(cx, e){ - if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) && - !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) { + if let Some(parent_expr) = get_parent_expr(cx, e) { + if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) + && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) + { return; } // modification to `&mut &*x` is different from `&mut x` - if matches!(deref_target.kind, ExprKind::Path(..) - | ExprKind::Field(..) - | ExprKind::Index(..) - | ExprKind::Unary(UnOp::Deref, ..)) - && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) { - return; + if matches!( + deref_target.kind, + ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..) + ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) + { + return; } } @@ -86,12 +86,12 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { e.span, "if you would like to reborrow, try removing `&*`", snippet_opt(cx, deref_target.span).unwrap(), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); // has deref trait -> give 2 help // doesn't have deref trait -> give 1 help - if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){ + if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() { if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) { return; } @@ -100,16 +100,11 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to deref, try using `&**`", - format!( - "&**{}", - &snippet_opt(cx, deref_target.span).unwrap(), - ), - Applicability::MaybeIncorrect + format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()), + Applicability::MaybeIncorrect, ); - - } + }, ); - } } } diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 446b1f961b9..473646d00d5 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -2,7 +2,6 @@ use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId}; use clippy_utils::diagnostics::span_lint; -use if_chain::if_chain; use itertools::Itertools; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; @@ -16,9 +15,13 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { packages.sort_by(|a, b| a.name.cmp(&b.name)); if let Some(resolve) = &metadata.resolve - && let Some(local_id) = packages - .iter() - .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None }) + && let Some(local_id) = packages.iter().find_map(|p| { + if p.name == local_name.as_str() { + Some(&p.id) + } else { + None + } + }) { for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { let group: Vec<&Package> = group.collect(); diff --git a/clippy_lints/src/cargo/wildcard_dependencies.rs b/clippy_lints/src/cargo/wildcard_dependencies.rs index f255963e480..3b7546dfd31 100644 --- a/clippy_lints/src/cargo/wildcard_dependencies.rs +++ b/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -1,6 +1,5 @@ use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; -use if_chain::if_chain; use rustc_lint::LateContext; use rustc_span::source_map::DUMMY_SP; diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 71a2581613d..bd12ee40628 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,7 +1,6 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{method_chain_args, sext}; -use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 6eae45e6c7b..2a9f7fec172 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -1,7 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source; -use if_chain::if_chain; use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index bacbea39768..3db1e3e6d97 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,7 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; @@ -37,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, { let func = match rpk { RawPartsKind::Immutable => "from_raw_parts", - RawPartsKind::Mutable => "from_raw_parts_mut" + RawPartsKind::Mutable => "from_raw_parts_mut", }; let span = expr.span; let mut applicability = Applicability::MachineApplicable; @@ -50,7 +49,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, &format!("casting the result of `{func}` to {cast_to}"), "replace with", format!("core::ptr::slice_{func}({ptr}, {len})"), - applicability + applicability, ); } } diff --git a/clippy_lints/src/casts/char_lit_as_u8.rs b/clippy_lints/src/casts/char_lit_as_u8.rs index 802f2614796..a7d3868f76c 100644 --- a/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/clippy_lints/src/casts/char_lit_as_u8.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -34,6 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { applicability, ); } - }); + }, + ); } } diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 68a409824e7..ff069860a11 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,7 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; @@ -18,10 +17,18 @@ pub(super) fn check<'tcx>( msrv: &Msrv, ) { if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) - && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind() - && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind() - && matches!((from_mutbl, to_mutbl), - (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)) + && let ty::RawPtr(TypeAndMut { + mutbl: from_mutbl, + ty: from_ty, + }) = cast_from.kind() + && let ty::RawPtr(TypeAndMut { + mutbl: to_mutbl, + ty: to_ty, + }) = cast_to.kind() + && matches!( + (from_mutbl, to_mutbl), + (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not) + ) && from_ty == to_ty { let sugg = Sugg::hir(cx, cast_expr, "_"); diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index e060977d253..849920bb76d 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -3,7 +3,6 @@ use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; use clippy_utils::visitors::{for_each_expr, Visitable}; use clippy_utils::{get_parent_expr, get_parent_node, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; -use if_chain::if_chain; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -52,7 +51,9 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_CAST, expr.span, - &format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"), + &format!( + "casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)" + ), "try", cast_str.clone(), Applicability::MaybeIncorrect, @@ -87,8 +88,8 @@ pub(super) fn check<'tcx>( if let ExprKind::Cast(_, cast_to) = expr.kind && let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind && let Res::PrimTy(_) = path.res - {} - else { + { + } else { return false; } @@ -108,10 +109,13 @@ pub(super) fn check<'tcx>( && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) && let from_nbits = 128 - n.leading_zeros() && let to_nbits = fp_ty_mantissa_nbits(cast_to) - && from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal() + && from_nbits != 0 + && to_nbits != 0 + && from_nbits <= to_nbits + && num_lit.is_decimal() { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); - return true + return true; } match lit.node { diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 26ec1dd2d43..69fa0821e3f 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -4,7 +4,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -58,7 +57,6 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions { let result = if !in_constant(cx, item.hir_id) && !in_external_macro(cx.sess(), item.span) && let ExprKind::Binary(op, left, right) = &item.kind - { match op.node { BinOpKind::Ge | BinOpKind::Le => single_check(item), @@ -192,12 +190,11 @@ impl ConversionType { /// Check for `expr <= (to_type::MAX as from_type)` fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { if let ExprKind::Binary(ref op, left, right) = &expr.kind - && let Some((candidate, check)) = normalize_le_ge(op, left, right) - && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX") - - { - Conversion::try_new(candidate, from, to) - } else { + && let Some((candidate, check)) = normalize_le_ge(op, left, right) + && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX") + { + Conversion::try_new(candidate, from, to) + } else { None } } @@ -243,7 +240,6 @@ fn get_types_from_cast<'a>( // to_type::max_value(), from_type && let TyKind::Path(ref from_type_path) = &from_type.kind && let Some(from_sym) = int_ty_to_sym(from_type_path) - { Some((limit, from_sym)) } else { @@ -257,7 +253,6 @@ fn get_types_from_cast<'a>( // `from_type::from` && let ExprKind::Path(ref path) = &from_func.kind && let Some(from_sym) = get_implementing_type(path, INTS, "from") - { Some((limit, from_sym)) } else { diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 763a2d2ad89..e5aaf88ab6c 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -15,7 +15,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability}; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -131,7 +130,11 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: // Prevent "elseif" // Check that the "else" is followed by whitespace let up_to_else = then_span.between(block.span); - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false }; + let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { + !c.is_whitespace() + } else { + false + }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( @@ -160,21 +163,27 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: & && let ctxt = expr.span.ctxt() && inner.span.ctxt() == ctxt { - span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| { - let mut app = Applicability::MachineApplicable; - let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app); - let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app); - diag.span_suggestion( - expr.span, - "collapse nested if block", - format!( - "if {} {}", - lhs.and(&rhs), - snippet_block(cx, content.span, "..", Some(expr.span)), - ), - app, // snippet - ); - }); + span_lint_and_then( + cx, + COLLAPSIBLE_IF, + expr.span, + "this `if` statement can be collapsed", + |diag| { + let mut app = Applicability::MachineApplicable; + let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app); + let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app); + diag.span_suggestion( + expr.span, + "collapse nested if block", + format!( + "if {} {}", + lhs.and(&rhs), + snippet_block(cx, content.span, "..", Some(expr.span)), + ), + app, // snippet + ); + }, + ); } } diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 9d578054188..db850edd640 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -5,8 +5,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; -use if_chain::if_chain; - declare_clippy_lint! { /// ### What it does /// Checks for types that implement `Copy` as well as @@ -39,9 +37,9 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for CopyIterator { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(ref trait_ref), - .. - }) = item.kind + of_trait: Some(ref trait_ref), + .. + }) = item.kind && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && is_copy(cx, ty) && let Some(trait_id) = trait_ref.trait_def_id() diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 8d9b2ebff7f..637d5aae1be 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -104,9 +104,19 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { } fn is_crate_keyword(tt: &TokenTree) -> Option { - if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }, _) = tt + if let TokenTree::Token( + Token { + kind: TokenKind::Ident(symbol, _), + span, + }, + _, + ) = tt && symbol.as_str() == "crate" - { Some(*span) } else { None } + { + Some(*span) + } else { + None + } } fn is_token(tt: &TokenTree, kind: &TokenKind) -> bool { diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index cd92f38b0ca..97b736dfd8f 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -46,7 +45,7 @@ impl LateLintPass<'_> for CreateDir { "consider calling `std::fs::create_dir_all` instead", format!("create_dir_all({})", snippet(cx, arg.span, "..")), Applicability::MaybeIncorrect, - ) + ); } } } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 1a646ba38c3..04dcccede08 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -10,8 +10,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 1ad71631089..b325449c5a3 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index edd47be5840..b90d01b765a 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -79,7 +79,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { "remove this call to `default`", String::new(), Applicability::MachineApplicable, - ) + ); }; } } diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 62583b99eaa..fb29703957d 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::{get_parent_node, numeric_literal}; -use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; @@ -83,38 +82,40 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { /// Check whether a passed literal has potential to cause fallback or not. fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { if !in_external_macro(self.cx.sess(), lit.span) - && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))) - && matches!(lit.node, - LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)) - { - let (suffix, is_float) = match lit_ty.kind() { - ty::Int(IntTy::I32) => ("i32", false), - ty::Float(FloatTy::F64) => ("f64", true), - // Default numeric fallback never results in other types. + && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))) + && matches!( + lit.node, + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) + ) + { + let (suffix, is_float) = match lit_ty.kind() { + ty::Int(IntTy::I32) => ("i32", false), + ty::Float(FloatTy::F64) => ("f64", true), + // Default numeric fallback never results in other types. + _ => return, + }; + + let src = if let Some(src) = snippet_opt(self.cx, lit.span) { + src + } else { + match lit.node { + LitKind::Int(src, _) => format!("{src}"), + LitKind::Float(src, _) => format!("{src}"), _ => return, - }; - - let src = if let Some(src) = snippet_opt(self.cx, lit.span) { - src - } else { - match lit.node { - LitKind::Int(src, _) => format!("{src}"), - LitKind::Float(src, _) => format!("{src}"), - _ => return, - } - }; - let sugg = numeric_literal::format(&src, Some(suffix), is_float); - span_lint_hir_and_then( - self.cx, - DEFAULT_NUMERIC_FALLBACK, - emit_hir_id, - lit.span, - "default numeric fallback might occur", - |diag| { - diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect); - } - ); - } + } + }; + let sugg = numeric_literal::format(&src, Some(suffix), is_float); + span_lint_hir_and_then( + self.cx, + DEFAULT_NUMERIC_FALLBACK, + emit_hir_id, + lit.span, + "default numeric fallback might occur", + |diag| { + diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect); + }, + ); + } } } @@ -155,14 +156,13 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { // Push field type then visit each field expr. for field in *fields { - let bound = - fields_def - .iter() - .find_map(|f_def| { - if f_def.ident(self.cx.tcx) == field.ident - { Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) } - else { None } - }); + let bound = fields_def.iter().find_map(|f_def| { + if f_def.ident(self.cx.tcx) == field.ident { + Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) + } else { + None + } + }); self.ty_bounds.push(bound.into()); self.visit_expr(field.expr); self.ty_bounds.pop(); diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 233391ff3bb..9db56fa8ad0 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -154,55 +154,42 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id) && variant_def.fields.is_empty() && !variant_def.is_field_list_non_exhaustive() - { let enum_span = cx.tcx.def_span(adt_def.did()); let indent_enum = indent_of(cx, enum_span).unwrap_or(0); let variant_span = cx.tcx.def_span(variant_def.def_id); let indent_variant = indent_of(cx, variant_span).unwrap_or(0); - span_lint_and_then( - cx, - DERIVABLE_IMPLS, - item.span, - "this `impl` can be derived", - |diag| { - diag.span_suggestion_hidden( - item.span, - "remove the manual implementation...", - String::new(), - Applicability::MachineApplicable - ); - diag.span_suggestion( - enum_span.shrink_to_lo(), - "...and instead derive it...", - format!( - "#[derive(Default)]\n{indent}", - indent = " ".repeat(indent_enum), - ), - Applicability::MachineApplicable - ); - diag.span_suggestion( - variant_span.shrink_to_lo(), - "...and mark the default variant", - format!( - "#[default]\n{indent}", - indent = " ".repeat(indent_variant), - ), - Applicability::MachineApplicable - ); - } - ); + span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable, + ); + diag.span_suggestion( + enum_span.shrink_to_lo(), + "...and instead derive it...", + format!("#[derive(Default)]\n{indent}", indent = " ".repeat(indent_enum),), + Applicability::MachineApplicable, + ); + diag.span_suggestion( + variant_span.shrink_to_lo(), + "...and mark the default variant", + format!("#[default]\n{indent}", indent = " ".repeat(indent_variant),), + Applicability::MachineApplicable, + ); + }); } } impl<'tcx> LateLintPass<'tcx> for DerivableImpls { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(ref trait_ref), - items: [child], - self_ty, - .. - }) = item.kind + of_trait: Some(ref trait_ref), + items: [child], + self_ty, + .. + }) = item.kind && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) && !item.span.from_expansion() && let Some(def_id) = trait_ref.trait_def_id() @@ -215,7 +202,6 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { && let attrs = cx.tcx.hir().attrs(item.hir_id()) && !attrs.iter().any(|attr| attr.doc_str().is_some()) && cx.tcx.hir().attrs(impl_item_hir).is_empty() - { if adt_def.is_struct() { check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b)); diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 6913c87ae01..9807823ada3 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{is_lint_allowed, match_def_path, paths}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; @@ -258,12 +257,9 @@ fn check_hash_peq<'tcx>( |diag| { if let Some(local_def_id) = impl_id.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - diag.span_note( - cx.tcx.hir().span(hir_id), - "`PartialEq` implemented here" - ); + diag.span_note(cx.tcx.hir().span(hir_id), "`PartialEq` implemented here"); } - } + }, ); } }); @@ -302,21 +298,12 @@ fn check_ord_partial_ord<'tcx>( "you are deriving `Ord` but have implemented `PartialOrd` explicitly" }; - span_lint_and_then( - cx, - DERIVE_ORD_XOR_PARTIAL_ORD, - span, - mess, - |diag| { - if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); - diag.span_note( - cx.tcx.hir().span(hir_id), - "`PartialOrd` implemented here" - ); - } + span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| { + if let Some(local_def_id) = impl_id.as_local() { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); + diag.span_note(cx.tcx.hir().span(hir_id), "`PartialOrd` implemented here"); } - ); + }); } }); } @@ -397,7 +384,9 @@ fn check_unsafe_derive_deserialize<'tcx>( && let Some(local_def_id) = def.did().as_local() && let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id) && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id) - && cx.tcx.inherent_impls(def.did()) + && cx + .tcx + .inherent_impls(def.did()) .iter() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) @@ -408,7 +397,7 @@ fn check_unsafe_derive_deserialize<'tcx>( item.span, "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", None, - "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html" + "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html", ); } } @@ -477,7 +466,7 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r "consider deriving `Eq` as well", "PartialEq, Eq".to_string(), Applicability::MachineApplicable, - ) + ); } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index f6dde3232bf..587360545cb 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -4,7 +4,6 @@ use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty}; -use if_chain::if_chain; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; @@ -428,23 +427,21 @@ fn lint_for_missing_headers( span, "docs for function returning `Result` missing `# Errors` section", ); - } else { - if let Some(body_id) = body_id - && let Some(future) = cx.tcx.lang_items().future_trait() - && let typeck = cx.tcx.typeck_body(body_id) - && let body = cx.tcx.hir().body(body_id) - && let ret_ty = typeck.expr_ty(body.value) - && implements_trait(cx, ret_ty, future, &[]) - && let ty::Coroutine(_, subs, _) = ret_ty.kind() - && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) - { - span_lint( - cx, - MISSING_ERRORS_DOC, - span, - "docs for function returning `Result` missing `# Errors` section", - ); - } + } else if let Some(body_id) = body_id + && let Some(future) = cx.tcx.lang_items().future_trait() + && let typeck = cx.tcx.typeck_body(body_id) + && let body = cx.tcx.hir().body(body_id) + && let ret_ty = typeck.expr_ty(body.value) + && implements_trait(cx, ret_ty, future, &[]) + && let ty::Coroutine(_, subs, _) = ret_ty.kind() + && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) + { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); } } } diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index da1103f39e0..17be95780cc 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::peel_blocks; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; @@ -37,10 +36,10 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]); impl LateLintPass<'_> for EmptyDrop { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(ref trait_ref), - items: [child], - .. - }) = item.kind + of_trait: Some(ref trait_ref), + items: [child], + .. + }) = item.kind && trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait() && let impl_item_hir = child.id.hir_id() && let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir) @@ -48,7 +47,8 @@ impl LateLintPass<'_> for EmptyDrop { && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b) && let func_expr = peel_blocks(func_expr) && let ExprKind::Block(block, _) = func_expr.kind - && block.stmts.is_empty() && block.expr.is_none() + && block.stmts.is_empty() + && block.expr.is_none() { span_lint_and_sugg( cx, @@ -57,7 +57,7 @@ impl LateLintPass<'_> for EmptyDrop { "empty drop implementation", "try removing this impl", String::new(), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 201bf13a0df..b7e62e082e4 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -77,9 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems { && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) { let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { - if v.fields().iter().any(|f| { - !cx.tcx.visibility(f.def_id).is_public() - }) { + if v.fields().iter().any(|f| !cx.tcx.visibility(f.def_id).is_public()) { // skip structs with private fields return; } @@ -89,20 +86,15 @@ impl LateLintPass<'_> for ExhaustiveItems { }; let suggestion_span = item.span.shrink_to_lo(); let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); - span_lint_and_then( - cx, - lint, - item.span, - msg, - |diag| { - let sugg = format!("#[non_exhaustive]\n{indent}"); - diag.span_suggestion(suggestion_span, - "try adding #[non_exhaustive]", - sugg, - Applicability::MaybeIncorrect); - } - ); - + span_lint_and_then(cx, lint, item.span, msg, |diag| { + let sugg = format!("#[non_exhaustive]\n{indent}"); + diag.span_suggestion( + suggestion_span, + "try adding #[non_exhaustive]", + sugg, + Applicability::MaybeIncorrect, + ); + }); } } } diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index a366749560b..07d025f68c3 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_entrypoint_fn; -use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index c8d901d08bd..08cb2114a2b 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 5824f462f4b..753f75d83a8 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::method_chain_args; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -55,7 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom { // check for `impl From for ..` if let hir::ItemKind::Impl(impl_) = &item.kind && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) - && cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id) + && cx + .tcx + .is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id) { lint_impl_body(cx, item.span, impl_.items); } @@ -97,8 +98,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl for impl_item in impl_items { if impl_item.ident.name == sym::from - && let ImplItemKind::Fn(_, body_id) = - cx.tcx.hir().impl_item(impl_item.id).kind + && let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind { // check the body for `begin_panic` or `unwrap` let body = cx.tcx.hir().body(body_id); @@ -119,9 +119,11 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl move |diag| { diag.help( "`From` is intended for infallible conversions only. \ - Use `TryFrom` if there's a possibility for the conversion to fail"); + Use `TryFrom` if there's a possibility for the conversion to fail", + ); diag.span_note(fpu.result, "potential failure(s)"); - }); + }, + ); } } } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 07640a77584..663c33e8cee 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal; -use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { let type_suffix = match lit_float_ty { LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"), LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"), - LitFloatType::Unsuffixed => None + LitFloatType::Unsuffixed => None, }; let (is_whole, is_inf, mut float_str) = match fty { FloatTy::F32 => { @@ -90,7 +89,6 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { FloatTy::F64 => { let value = sym_str.parse::().unwrap(); - (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, }; diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 21cedf17385..d522873472b 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, numeric_literal, peel_blocks, sugg, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -143,17 +142,14 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su "{suggestion}{}{}", // Check for float literals without numbers following the decimal // separator such as `2.` and adds a trailing zero - if sym.as_str().ends_with('.') { - "0" - } else { - "" - }, + if sym.as_str().ends_with('.') { "0" } else { "" }, float_ty.name_str() - ).into(); + ) + .into(); suggestion = match suggestion { Sugg::MaybeParen(_) => Sugg::MaybeParen(op), - _ => Sugg::NonParen(op) + _ => Sugg::NonParen(op), }; } @@ -357,31 +353,59 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { ) = receiver.kind { // check if expression of the form x * x + y * y - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind - && let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + lmul_lhs, + lmul_rhs, + ) = add_lhs.kind + && let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + rmul_lhs, + rmul_rhs, + ) = add_rhs.kind && eq_expr_value(cx, lmul_lhs, lmul_rhs) && eq_expr_value(cx, rmul_lhs, rmul_rhs) { - return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, ".."))); + return Some(format!( + "{}.hypot({})", + Sugg::hir(cx, lmul_lhs, "..").maybe_par(), + Sugg::hir(cx, rmul_lhs, "..") + )); } // check if expression of the form x.powi(2) + y.powi(2) if let ExprKind::MethodCall( - PathSegment { ident: lmethod_name, .. }, - largs_0, [largs_1, ..], - _ - ) = &add_lhs.kind + PathSegment { + ident: lmethod_name, .. + }, + largs_0, + [largs_1, ..], + _, + ) = &add_lhs.kind && let ExprKind::MethodCall( - PathSegment { ident: rmethod_name, .. }, - rargs_0, [rargs_1, ..], - _ + PathSegment { + ident: rmethod_name, .. + }, + rargs_0, + [rargs_1, ..], + _, ) = &add_rhs.kind - && lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi" + && lmethod_name.as_str() == "powi" + && rmethod_name.as_str() == "powi" && let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1) && let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1) - && Int(2) == lvalue && Int(2) == rvalue + && Int(2) == lvalue + && Int(2) == rvalue { - return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); + return Some(format!( + "{}.hypot({})", + Sugg::hir(cx, largs_0, "..").maybe_par(), + Sugg::hir(cx, rargs_0, "..") + )); } } @@ -405,7 +429,13 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { // TODO: Lint expressions of the form `x.exp() - y` where y > 1 // and suggest usage of `x.exp_m1() - (y - 1)` instead fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, .. + }, + lhs, + rhs, + ) = expr.kind && cx.typeck_results().expr_ty(lhs).is_floating_point() && let Some(value) = constant(cx, cx.typeck_results(), rhs) && (F32(1.0) == value || F64(1.0) == value) @@ -419,17 +449,20 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", - format!( - "{}.exp_m1()", - Sugg::hir(cx, self_arg, "..").maybe_par() - ), + format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_par()), Applicability::MachineApplicable, ); } } fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { - if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + lhs, + rhs, + ) = &expr.kind && cx.typeck_results().expr_ty(lhs).is_floating_point() && cx.typeck_results().expr_ty(rhs).is_floating_point() { @@ -543,7 +576,11 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a } fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr) + if let Some(higher::If { + cond, + then, + r#else: Some(r#else), + }) = higher::If::hir(expr) && let if_body_expr = peel_blocks(then) && let else_body_expr = peel_blocks(r#else) && let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr) @@ -584,15 +621,27 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { } fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { - if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind - && let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind + if let ExprKind::MethodCall( + PathSegment { + ident: method_name_a, .. + }, + _, + args_a, + _, + ) = expr_a.kind + && let ExprKind::MethodCall( + PathSegment { + ident: method_name_b, .. + }, + _, + args_b, + _, + ) = expr_b.kind { - return method_name_a.as_str() == method_name_b.as_str() && - args_a.len() == args_b.len() && - ( - ["ln", "log2", "log10"].contains(&method_name_a.as_str()) || - method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]) - ); + return method_name_a.as_str() == method_name_b.as_str() + && args_a.len() == args_b.len() + && (["ln", "log2", "log10"].contains(&method_name_a.as_str()) + || method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])); } false @@ -601,12 +650,12 @@ fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_> fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { // check if expression of the form x.logN() / y.logN() if let ExprKind::Binary( - Spanned { - node: BinOpKind::Div, .. - }, - lhs, - rhs, - ) = &expr.kind + Spanned { + node: BinOpKind::Div, .. + }, + lhs, + rhs, + ) = &expr.kind && are_same_base_logs(cx, lhs, rhs) && let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind && let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind @@ -617,7 +666,11 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "log base can be expressed more clearly", "consider using", - format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),), + format!( + "{}.log({})", + Sugg::hir(cx, largs_self, "..").maybe_par(), + Sugg::hir(cx, rargs_self, ".."), + ), Applicability::MachineApplicable, ); } @@ -625,12 +678,12 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Binary( - Spanned { - node: BinOpKind::Div, .. - }, - div_lhs, - div_rhs, - ) = &expr.kind + Spanned { + node: BinOpKind::Div, .. + }, + div_lhs, + div_rhs, + ) = &expr.kind && let ExprKind::Binary( Spanned { node: BinOpKind::Mul, .. @@ -642,8 +695,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { && let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs) { // TODO: also check for constant values near PI/180 or 180/PI - if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && - (F32(180_f32) == lvalue || F64(180_f64) == lvalue) + if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) + && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) { let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if let ExprKind::Lit(literal) = mul_lhs.kind @@ -665,9 +718,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { proposal, Applicability::MachineApplicable, ); - } else if - (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && - (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) + } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) + && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) { let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if let ExprKind::Lit(literal) = mul_lhs.kind diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 737ea05d92d..c9868255dcf 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -8,7 +8,6 @@ use clippy_utils::macros::{ }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; -use if_chain::if_chain; use itertools::Itertools; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, @@ -422,9 +421,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex cx, TO_STRING_IN_FORMAT_ARGS, to_string_span.with_lo(receiver.span.hi()), - &format!( - "`to_string` applied to a type that implements `Display` in `{name}!` args" - ), + &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "remove this", String::new(), Applicability::MachineApplicable, @@ -434,9 +431,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex cx, TO_STRING_IN_FORMAT_ARGS, value.span, - &format!( - "`to_string` applied to a type that implements `Display` in `{name}!` args" - ), + &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "use this", format!( "{}{:*>n_needed_derefs$}{receiver_snippet}", diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 7eee3a97669..ec87629a344 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; -use if_chain::if_chain; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; @@ -243,20 +242,22 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { if impl_item.ident.name == sym::fmt && let ImplItemKind::Fn(_, body_id) = impl_item.kind - && let Some(Impl { of_trait: Some(trait_ref),..}) = get_parent_as_impl(cx.tcx, impl_item.hir_id()) + && let Some(Impl { + of_trait: Some(trait_ref), + .. + }) = get_parent_as_impl(cx.tcx, impl_item.hir_id()) && let Some(did) = trait_ref.trait_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(did) && matches!(name, sym::Debug | sym::Display) { let body = cx.tcx.hir().body(body_id); - let formatter_name = body.params.get(1) + let formatter_name = body + .params + .get(1) .and_then(|param| param.pat.simple_ident()) .map(|ident| ident.name); - Some(FormatTraitNames { - name, - formatter_name, - }) + Some(FormatTraitNames { name, formatter_name }) } else { None } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index be35b850c0a..a1db7b63b17 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; -use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -193,9 +192,7 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { `{binop_str}{unop_str}` is a single operator" ), None, - &format!( - "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`" - ), + &format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"), ); } } @@ -219,7 +216,6 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { && let Some(else_snippet) = snippet_opt(cx, else_span) && let Some((pre_else, post_else)) = else_snippet.split_once("else") && let Some((_, post_else_post_eol)) = post_else.split_once('\n') - { // Allow allman style braces `} \n else \n {` if is_block(else_) @@ -234,7 +230,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { // Don't warn if the only thing inside post_else_post_eol is a comment block. let trimmed_post_else_post_eol = post_else_post_eol.trim(); if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") { - return + return; } let else_desc = if is_if(else_) { "if" } else { "{..}" }; @@ -267,7 +263,8 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Array(ref array) = expr.kind { for element in array { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind - && has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span) + && has_unary_equivalent(op.node) + && lhs.span.eq_ctxt(op.span) && let space_span = lhs.span.between(op.span) && let Some(space_snippet) = snippet_opt(cx, space_span) && let lint_span = lhs.span.with_lo(lhs.span.hi()) @@ -313,9 +310,7 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { else_span, &format!("this looks like {looks_like} but the `else` is missing"), None, - &format!( - "to remove this lint, add the missing `else` or add a new line before {next_thing}", - ), + &format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",), ); } } diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 804b6d31e61..18d11ccc0b5 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_integer_literal; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -61,25 +60,16 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { // check if the second argument is a primitive `10` && is_integer_literal(radix, 10) - { let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { let ty = cx.typeck_results().expr_ty(expr); - if is_ty_stringish(cx, ty) { - expr - } else { - &src - } + if is_ty_stringish(cx, ty) { expr } else { &src } } else { &src }; - let sugg = Sugg::hir_with_applicability( - cx, - expr, - "", - &mut Applicability::MachineApplicable - ).maybe_par(); + let sugg = + Sugg::hir_with_applicability(cx, expr, "", &mut Applicability::MachineApplicable).maybe_par(); span_lint_and_sugg( cx, @@ -88,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { "this call to `from_str_radix` can be replaced with a call to `str::parse`", "try", format!("{sugg}.parse::<{}>()", prim_ty.name_str()), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index 77718893300..bf96c0d62b0 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -43,7 +43,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: // Body must be &(mut) .name // self_data is not necessarily self, to also lint sub-getters, etc… - let block_expr = if let ExprKind::Block(block,_) = body.value.kind + let block_expr = if let ExprKind::Block(block, _) = body.value.kind && block.stmts.is_empty() && let Some(block_expr) = block.expr { diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index aab9cce1e00..47db107d669 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -87,11 +87,12 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { if let Adt(adt, subst) = err_ty.kind() - && let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local() - && let Some(hir::Node::Item(item)) = cx - .tcx - .hir() - .find_by_def_id(local_def_id) + && let Some(local_def_id) = err_ty + .ty_adt_def() + .expect("already checked this is adt") + .did() + .as_local() + && let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(local_def_id) && let hir::ItemKind::Enum(ref def, _) = item.kind { let variants_size = AdtVariantInfo::new(cx, *adt, subst); @@ -114,17 +115,19 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty let variant_def = &def.variants[variant.ind]; diag.span_label( variant_def.span, - format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size), + format!( + "the variant `{}` contains at least {} bytes", + variant_def.ident, variant.size + ), ); } } diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); - } + }, ); } - } - else { + } else { let ty_size = approx_ty_size(cx, err_ty); if ty_size >= large_err_threshold { span_lint_and_then( diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 7f111925657..644b9cdaeb2 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, SpanlessEq}; -use if_chain::if_chain; use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 16af49a092a..4545f6e42e3 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -13,8 +13,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::sym; -use if_chain::if_chain; - use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -348,8 +346,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { if method.ident.name == sym::new { - self.suggestions - .insert(e.span, "HashMap::default()".to_string()); + self.suggestions.insert(e.span, "HashMap::default()".to_string()); } else if method.ident.name == sym!(with_capacity) { self.suggestions.insert( e.span, @@ -361,8 +358,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't } } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { if method.ident.name == sym::new { - self.suggestions - .insert(e.span, "HashSet::default()".to_string()); + self.suggestions.insert(e.span, "HashSet::default()".to_string()); } else if method.ident.name == sym!(with_capacity) { self.suggestions.insert( e.span, diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index af21d261644..f2fac9a29cb 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -2,7 +2,6 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; -use if_chain::if_chain; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; @@ -47,10 +46,20 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { && let ExprKind::Block(block, None) = then.kind && let Block { stmts: - [Stmt - { kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }], - expr: None, ..} | - Block { stmts: [], expr: Some(ex), ..} = block + [ + Stmt { + kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), + .. + }, + ], + expr: None, + .. + } + | Block { + stmts: [], + expr: Some(ex), + .. + } = block && let ExprKind::AssignOp(op1, target, value) = ex.kind && let ty = cx.typeck_results().expr_ty(target) && Some(c) == get_int_max(ty) @@ -73,7 +82,15 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { } else { format!("{code} = {code}.saturating_add(1);") }; - span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app); + span_lint_and_sugg( + cx, + IMPLICIT_SATURATING_ADD, + expr.span, + "manual saturating add detected", + "use instead", + sugg, + app, + ); } } } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 3a45c68c255..fc66f86ae86 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; @@ -59,7 +58,6 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Extracting out the variable name && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind - { // Handle symmetric conditions in the if statement let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { @@ -102,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() { - print_lint_and_sugg(cx, var_name, expr) + print_lint_and_sugg(cx, var_name, expr); } }, ExprKind::Call(func, []) => { @@ -113,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() { - print_lint_and_sugg(cx, var_name, expr) + print_lint_and_sugg(cx, var_name, expr); } }, _ => (), @@ -131,9 +129,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp ExprKind::Assign(target, value, _) => { if let ExprKind::Binary(ref op1, left1, right1) = value.kind && BinOpKind::Sub == op1.node - && SpanlessEq::new(cx).eq_expr(left1, target) - && is_integer_literal(right1, 1) { Some(target) diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 14842800b57..f6e1281a291 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -94,14 +93,15 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fields_snippet.push_str(&last_ident.to_string()); let base_snippet = if let Some(base) = base { - format!(", ..{}", snippet(cx, base.span, "..")) - } else { - String::new() - }; + format!(", ..{}", snippet(cx, base.span, "..")) + } else { + String::new() + }; - let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}", + let sugg = format!( + "{} {{ {fields_snippet}{base_snippet} }}", snippet(cx, qpath.span(), ".."), - ); + ); span_lint_and_sugg( cx, @@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { "try", sugg, Applicability::MachineApplicable, - ) + ); } } } diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 5b831af3045..fa6536db796 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; -use if_chain::if_chain; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -71,10 +70,9 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]); impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) - && let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr) + && let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) && self.msrv.meets(msrvs::SLICE_PATTERNS) - && let found_slices = find_slice_values(cx, let_pat) && !found_slices.is_empty() && let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index d8966dddeac..8e84c73666f 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -90,22 +90,16 @@ impl LateLintPass<'_> for InstantSubtraction { ) = expr.kind { if is_instant_now_call(cx, lhs) - && is_an_instant(cx, rhs) && let Some(sugg) = Sugg::hir_opt(cx, rhs) - { - print_manual_instant_elapsed_sugg(cx, expr, sugg) - } else { - if !expr.span.from_expansion() - && self.msrv.meets(msrvs::TRY_FROM) - - && is_an_instant(cx, lhs) - && is_a_duration(cx, rhs) - - { - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr) - } + print_manual_instant_elapsed_sugg(cx, expr, sugg); + } else if !expr.span.from_expansion() + && self.msrv.meets(msrvs::TRY_FROM) + && is_an_instant(cx, lhs) + && is_a_duration(cx, rhs) + { + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } } diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 385945045bc..7db088f986f 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -59,7 +58,6 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) - { let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); let sugg_span = Span::new( @@ -80,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { "static", Applicability::MachineApplicable, ); - } + }, ); } } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index f998a00edee..902b72ba5e4 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -53,7 +53,7 @@ impl LateLintPass<'_> for LargeIncludeFile { if let Some(macro_call) = root_macro_call_first_node(cx, expr) && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id) && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) - || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) + || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) && let ExprKind::Lit(lit) = &expr.kind { let len = match &lit.node { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 6d9cec5e957..305dd2c7f29 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -144,10 +143,8 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { && let Some(local_id) = ty_id.as_local() && let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id) && !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id) - && let Some(output) = parse_len_output( - cx, - cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder() - ) + && let Some(output) = + parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) { let (name, kind) = match cx.tcx.hir().find(ty_hir_id) { Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"), @@ -156,10 +153,10 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ItemKind::Enum(..) => (x.ident.name, "enum"), ItemKind::Union(..) => (x.ident.name, "union"), _ => (x.ident.name, "type"), - } + }, _ => return, }; - check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind) + check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind); } } diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 49c25e3dd9a..da269ec61ff 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local_id; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{BindingAnnotation, Mutability}; @@ -65,7 +64,14 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { && let hir::StmtKind::Local(local) = stmt.kind && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind && let hir::StmtKind::Expr(if_) = expr.kind - && let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind + && let hir::ExprKind::If( + hir::Expr { + kind: hir::ExprKind::DropTemps(cond), + .. + }, + then, + else_, + ) = if_.kind && !is_local_used(cx, *cond, canonical_id) && let hir::ExprKind::Block(then, _) = then.kind && let Some(value) = check_assign(cx, canonical_id, then) @@ -73,11 +79,13 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { { let span = stmt.span.to(if_.span); - let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze( - cx.tcx, - cx.param_env, - ); - if has_interior_mutability { return; } + let has_interior_mutability = !cx + .typeck_results() + .node_type(canonical_id) + .is_freeze(cx.tcx, cx.param_env); + if has_interior_mutability { + return; + } let (default_multi_stmts, default) = if let Some(else_) = else_ { if let hir::ExprKind::Block(else_, _) = else_.kind { @@ -114,21 +122,23 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { value=snippet(cx, value.span, ""), default=snippet(cx, default.span, ""), ); - span_lint_and_then(cx, - USELESS_LET_IF_SEQ, - span, - "`if _ { .. } else { .. }` is an expression", - |diag| { - diag.span_suggestion( - span, - "it is more idiomatic to write", - sug, - Applicability::HasPlaceholders, - ); - if !mutability.is_empty() { - diag.note("you might not need `mut` at all"); - } - }); + span_lint_and_then( + cx, + USELESS_LET_IF_SEQ, + span, + "`if _ { .. } else { .. }` is an expression", + |diag| { + diag.span_suggestion( + span, + "it is more idiomatic to write", + sug, + Applicability::HasPlaceholders, + ); + if !mutability.is_empty() { + diag.note("you might not need `mut` at all"); + } + }, + ); } } } @@ -145,7 +155,12 @@ fn check_assign<'tcx>( && let hir::ExprKind::Assign(var, value, _) = expr.kind && path_to_local_id(var, decl) { - if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| is_local_used(cx, stmt, decl)) { + if block + .stmts + .iter() + .take(block.stmts.len() - 1) + .any(|stmt| is_local_used(cx, stmt, decl)) + { None } else { Some(value) diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index e7b887d800b..d4f410de957 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -44,8 +44,8 @@ impl LateLintPass<'_> for UnderscoreTyped { local.span, "variable declared with type underscore", Some(ty.span.with_lo(local.pat.span.hi())), - "remove the explicit type `_` declaration" - ) + "remove the explicit type `_` declaration", + ); }; } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ab978a677c2..e5f8bd5c471 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -521,7 +521,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| { Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new()) }); - store.register_late_pass(|_| Box::new(utils::internal_lints::if_chain_style::IfChainStyle)); store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths)); store.register_late_pass(|_| { Box::::default() diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 05cc9ac035f..b190955d54c 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -313,7 +313,6 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: if let Some(ident) = ident && ident.name == kw::SelfLower && !func.implicit_self.has_implicit_self() - && let Some(self_ty) = func.inputs.first() { let mut visitor = RefVisitor::new(cx); diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 1e67183f13a..8f34a9b1fed 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::{NumericLiteral, Radix}; use clippy_utils::source::snippet_opt; -use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -268,18 +267,17 @@ impl LiteralDigitGrouping { } let result = (|| { - let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?; if let Some(fraction) = num_lit.fraction { - let fractional_group_size = Self::get_group_size( - fraction.rsplit('_'), - num_lit.radix, - self.lint_fraction_readability)?; - - let consistent = Self::parts_consistent(integral_group_size, - fractional_group_size, - num_lit.integer.len(), - fraction.len()); + let fractional_group_size = + Self::get_group_size(fraction.rsplit('_'), num_lit.radix, self.lint_fraction_readability)?; + + let consistent = Self::parts_consistent( + integral_group_size, + fractional_group_size, + num_lit.integer.len(), + fraction.len(), + ); if !consistent { return Err(WarningType::InconsistentDigitGrouping); }; @@ -288,18 +286,13 @@ impl LiteralDigitGrouping { Ok(()) })(); - if let Err(warning_type) = result { let should_warn = match warning_type { - | WarningType::UnreadableLiteral + WarningType::UnreadableLiteral | WarningType::InconsistentDigitGrouping | WarningType::UnusualByteGroupings - | WarningType::LargeDigitGroups => { - !span.from_expansion() - } - WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => { - true - } + | WarningType::LargeDigitGroups => !span.from_expansion(), + WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => true, }; if should_warn { warning_type.display(num_lit.format(), cx, span); diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index f49508cf97d..277062a8490 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -2,7 +2,6 @@ use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{get_enclosing_block, is_integer_const}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; use rustc_hir::{Expr, Pat}; @@ -53,7 +52,7 @@ pub(super) fn check<'tcx>( applicability, ); return; - } + }, Some(ty::Int(int_ty)) => int_ty.name_str(), Some(ty::Uint(uint_ty)) => uint_ty.name_str(), _ => return, diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index 2b49e188e3c..c6c16f4673f 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::lang_items::LangItem; @@ -23,7 +22,11 @@ pub(super) fn check<'tcx>( let inner_expr = peel_blocks_with_stmt(body); // Check for the specific case that the result is returned and optimize suggestion for that (more // cases can be added later) - if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr) + if let Some(higher::If { + cond, + then, + r#else: None, + }) = higher::If::hir(inner_expr) && let Some(binding_id) = get_binding(pat) && let ExprKind::Block(block, _) = then.kind && let [stmt] = block.stmts @@ -51,7 +54,12 @@ pub(super) fn check<'tcx>( ); } let ty = cx.typeck_results().expr_ty(inner_ret); - if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) { + if cx + .tcx + .lang_items() + .copy_trait() + .map_or(false, |id| implements_trait(cx, ty, id, &[])) + { snippet.push_str( &format!( ".find(|{}{}| {})", @@ -84,12 +92,7 @@ pub(super) fn check<'tcx>( if applicability == Applicability::MaybeIncorrect { diag.note("you may need to dereference some variables"); } - diag.span_suggestion( - lint_span, - "replace with an iterator", - snippet, - applicability, - ); + diag.span_suggestion(lint_span, "replace with an iterator", snippet, applicability); }, ); } diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 7659b506e97..de4e13bd84f 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -3,7 +3,6 @@ use super::MANUAL_FLATTEN; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; @@ -38,7 +37,8 @@ pub(super) fn check<'tcx>( { let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message - let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); + let msg = + format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message let mut applicability = Applicability::MaybeIncorrect; @@ -46,39 +46,25 @@ pub(super) fn check<'tcx>( let copied = match cx.typeck_results().expr_ty(let_expr).kind() { ty::Ref(_, inner, _) => match inner.kind() { ty::Ref(..) => ".copied()", - _ => "" - } - _ => "" + _ => "", + }, + _ => "", }; let sugg = format!("{arg_snippet}{copied}.flatten()"); - // If suggestion is not a one-liner, it won't be shown inline within the error message. In that case, - // it will be shown in the extra `help` message at the end, which is why the first `help_msg` needs - // to refer to the correct relative position of the suggestion. + // If suggestion is not a one-liner, it won't be shown inline within the error message. In that + // case, it will be shown in the extra `help` message at the end, which is why the first + // `help_msg` needs to refer to the correct relative position of the suggestion. let help_msg = if sugg.contains('\n') { "remove the `if let` statement in the for loop and then..." } else { "...and remove the `if let` statement in the for loop" }; - span_lint_and_then( - cx, - MANUAL_FLATTEN, - span, - &msg, - |diag| { - diag.span_suggestion( - arg.span, - "try", - sugg, - applicability, - ); - diag.span_help( - inner_expr.span, - help_msg, - ); - } - ); + span_lint_and_then(cx, MANUAL_FLATTEN, span, &msg, |diag| { + diag.span_suggestion(arg.span, "try", sugg, applicability); + diag.span_help(inner_expr.span, help_msg); + }); } } diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 9be888578b5..89f70519c20 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -4,7 +4,6 @@ use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_copy; use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir::intravisit::walk_block; @@ -69,8 +68,19 @@ pub(super) fn check<'tcx>( // Source and destination must be different && path_to_local(base_left) != path_to_local(base_right) { - Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, - IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) + Some(( + ty, + IndexExpr { + base: base_left, + idx: start_left, + idx_offset: offset_left, + }, + IndexExpr { + base: base_right, + idx: start_right, + idx_offset: offset_right, + }, + )) } else { None } @@ -127,9 +137,7 @@ fn build_manual_memcpy_suggestion<'tcx>( } } else { match limits { - ast::RangeLimits::Closed => { - sugg + &sugg::ONE.into() - }, + ast::RangeLimits::Closed => sugg + &sugg::ONE.into(), ast::RangeLimits::HalfOpen => sugg, } } @@ -329,7 +337,11 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if let ExprKind::MethodCall(method, arg, [], _) = expr.kind && method.ident.name == sym::clone - { arg } else { expr } + { + arg + } else { + expr + } } fn get_details_from_idx<'tcx>( diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs index f332cd87707..e405829b2f4 100644 --- a/clippy_lints/src/loops/missing_spin_loop.rs +++ b/clippy_lints/src/loops/missing_spin_loop.rs @@ -31,7 +31,12 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { - if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind + if let ExprKind::Block( + Block { + stmts: [], expr: None, .. + }, + _, + ) = body.kind && let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name) && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind() @@ -47,8 +52,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' "{ core::hint::spin_loop() }" } else { "{ std::hint::spin_loop() }" - }).into(), - Applicability::MachineApplicable + }) + .into(), + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index ad0b7e33354..6e3477a1c76 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -1,7 +1,6 @@ use super::MUT_RANGE_BOUND; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::{get_enclosing_block, higher, path_to_local}; -use if_chain::if_chain; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -13,10 +12,10 @@ use rustc_span::source_map::Span; pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) { if let Some(higher::Range { - start: Some(start), - end: Some(end), - .. - }) = higher::Range::hir(arg) + start: Some(start), + end: Some(end), + .. + }) = higher::Range::hir(arg) && let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end)) && (mut_id_start.is_some() || mut_id_end.is_some()) { diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 036247c2318..e2be861a708 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -4,7 +4,6 @@ use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 0c0a9138b27..15e11fd386c 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::path_to_local; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -76,7 +75,7 @@ pub(super) fn check<'tcx>( if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { emit_lint(cx, vec, pushed_item, ctxt); } - } + }, _ => {}, } } @@ -182,8 +181,8 @@ fn get_vec_push<'tcx>( // Check that the method being called is push() on a Vec && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec) && path.ident.name.as_str() == "push" - { - return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) - } + { + return Some((self_expr, pushed_item, semi_stmt.span.ctxt())); + } None } diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 0511ec011c4..d860b297a02 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -2,7 +2,6 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet_with_applicability}; use clippy_utils::visitors::contains_break_or_continue; -use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; use rustc_errors::Applicability; @@ -79,10 +78,12 @@ pub(super) fn check<'tcx>( let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)); // Reference iterator from `&(mut) []` or `[].iter(_mut)()`. - if !prefix.is_empty() && ( - // Precedence of internal expression is less than or equal to precedence of `&expr`. - arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression) - ) { + if !prefix.is_empty() + && ( + // Precedence of internal expression is less than or equal to precedence of `&expr`. + arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression) + ) + { arg_snip = format!("({arg_snip})").into(); } @@ -94,6 +95,6 @@ pub(super) fn check<'tcx>( "try", format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), applicability, - ) + ); } } diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index c4d89dc3f0e..38fdca573c6 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -1,6 +1,5 @@ use clippy_utils::ty::{has_iter_method, implements_trait}; use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; -use if_chain::if_chain; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor}; @@ -156,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { ty, name: ident.name, } - }) + }); } walk_local(self, l); diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index d5b50db4501..9fd9b7a1631 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -2,7 +2,6 @@ use super::WHILE_IMMUTABLE_CONDITION; use clippy_utils::consts::constant; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; -use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::intravisit::{walk_expr, Visitor}; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 144f4b0fb4c..21b9efba54c 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::visitors::is_res_used; use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -15,7 +14,7 @@ use rustc_span::symbol::sym; use rustc_span::Symbol; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr) + if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr) // check for `Some(..)` pattern && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome) @@ -27,45 +26,41 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // get the loop containing the match expression && !uses_iter(cx, &iter_expr_struct, if_then) { - (let_expr, iter_expr_struct, iter_expr, some_pat, expr) - } else { - return; - }; - - let mut applicability = Applicability::MachineApplicable; - let loop_var = if let Some(some_pat) = some_pat.first() { - if is_refutable(cx, some_pat) { - // Refutable patterns don't work with for loops. - return; - } - snippet_with_applicability(cx, some_pat.span, "..", &mut applicability) - } else { - "_".into() - }; + let mut applicability = Applicability::MachineApplicable; + let loop_var = if let Some(some_pat) = some_pat.first() { + if is_refutable(cx, some_pat) { + // Refutable patterns don't work with for loops. + return; + } + snippet_with_applicability(cx, some_pat.span, "..", &mut applicability) + } else { + "_".into() + }; - // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be - // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used - // afterwards a mutable borrow of a field isn't necessary. - let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut) - || !iter_expr_struct.can_move - || !iter_expr_struct.fields.is_empty() - || needs_mutable_borrow(cx, &iter_expr_struct, loop_expr) - { - ".by_ref()" - } else { - "" - }; + // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be + // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used + // afterwards a mutable borrow of a field isn't necessary. + let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut) + || !iter_expr_struct.can_move + || !iter_expr_struct.fields.is_empty() + || needs_mutable_borrow(cx, &iter_expr_struct, expr) + { + ".by_ref()" + } else { + "" + }; - let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); - span_lint_and_sugg( - cx, - WHILE_LET_ON_ITERATOR, - expr.span.with_hi(scrutinee_expr.span.hi()), - "this loop could be written as a `for` loop", - "try", - format!("for {loop_var} in {iterator}{by_ref}"), - applicability, - ); + let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + WHILE_LET_ON_ITERATOR, + expr.span.with_hi(let_expr.span.hi()), + "this loop could be written as a `for` loop", + "try", + format!("for {loop_var} in {iterator}{by_ref}"), + applicability, + ); + } } #[derive(Debug)] diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 42987e583af..6f1c5461dc0 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -108,10 +107,8 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { self.imports.push((def_path, span, hir_id)); } } - } else { - if item.span.from_expansion() { - self.push_unique_macro_pat_ty(cx, item.span); - } + } else if item.span.from_expansion() { + self.push_unique_macro_pat_ty(cx, item.span); } } fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 0be0b2850c4..ea1d25d80e1 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; -use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -54,8 +53,8 @@ impl LateLintPass<'_> for MainRecursion { func.span, &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), None, - "consider using another function for this recursion" - ) + "consider using another function for this recursion", + ); } } } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index efa40a9929c..a5d91c949bc 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -85,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { header_span, help, format!("{header_snip}{ret_snip}"), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)); @@ -93,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { block.span, "move the body of the async block to the enclosing function", body_snip, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } }, diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 3452177c525..69c65cf305c 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -98,16 +98,18 @@ fn get_one_size_of_ty<'tcx>( fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> { if let ExprKind::Call(count_func, _func_args) = expr.kind && let ExprKind::Path(ref count_func_qpath) = count_func.kind - && let QPath::Resolved(_, count_func_path) = count_func_qpath && let Some(segment_zero) = count_func_path.segments.first() && let Some(args) = segment_zero.args && let Some(GenericArg::Type(real_ty)) = args.args.first() - && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id) { - cx.typeck_results().node_args(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty)) + cx.typeck_results() + .node_args(count_func.hir_id) + .types() + .next() + .map(|resolved_ty| (*real_ty, resolved_ty)) } else { None } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 0559dc39363..b41bf2d767e 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -4,7 +4,6 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; use clippy_utils::{eq_expr_value, higher, match_def_path, paths}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -97,25 +96,35 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { let strippings = find_stripping(cx, strip_kind, target_res, pattern, then); if !strippings.is_empty() { - let kind_word = match strip_kind { StripKind::Prefix => "prefix", StripKind::Suffix => "suffix", }; let test_span = expr.span.until(then.span); - span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| { - diag.span_note(test_span, format!("the {kind_word} was tested here")); - multispan_sugg( - diag, - &format!("try using the `strip_{kind_word}` method"), - vec![(test_span, - format!("if let Some() = {}.strip_{kind_word}({}) ", - snippet(cx, target_arg.span, ".."), - snippet(cx, pattern.span, "..")))] - .into_iter().chain(strippings.into_iter().map(|span| (span, "".into()))), - ); - }); + span_lint_and_then( + cx, + MANUAL_STRIP, + strippings[0], + &format!("stripping a {kind_word} manually"), + |diag| { + diag.span_note(test_span, format!("the {kind_word} was tested here")); + multispan_sugg( + diag, + &format!("try using the `strip_{kind_word}` method"), + vec![( + test_span, + format!( + "if let Some() = {}.strip_{kind_word}({}) ", + snippet(cx, target_arg.span, ".."), + snippet(cx, pattern.span, "..") + ), + )] + .into_iter() + .chain(strippings.into_iter().map(|span| (span, "".into()))), + ); + }, + ); } } } @@ -210,7 +219,13 @@ fn find_stripping<'tcx>( } }, (StripKind::Suffix, None, Some(end)) => { - if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, .. + }, + left, + right, + ) = end.kind && let Some(left_arg) = len_arg(self.cx, left) && let ExprKind::Path(left_path) = &left_arg.kind && self.cx.qpath_res(left_path, left_arg.hir_id) == self.target @@ -220,7 +235,7 @@ fn find_stripping<'tcx>( return; } }, - _ => {} + _ => {}, } } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 03df8a67540..5cef4d91b5b 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{iter_input_pats, method_chain_args}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 750f8305730..bf035969477 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, is_res_lang_ctor}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index f9dc8440aca..48fc5746b3c 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -5,7 +5,6 @@ use clippy_utils::visitors::is_local_used; use clippy_utils::{ is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq, }; -use if_chain::if_chain; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Arm, Expr, Guard, HirId, Let, Pat, PatKind}; @@ -84,7 +83,11 @@ fn check_arm<'tcx>( { let msg = format!( "this `{}` can be collapsed into the outer `{}`", - if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" }, + if matches!(inner, IfLetOrMatch::Match(..)) { + "match" + } else { + "if let" + }, if outer_is_match { "match" } else { "if let" }, ); // collapsing patterns need an explicit field name in struct pattern matching @@ -94,18 +97,15 @@ fn check_arm<'tcx>( } else { String::new() }; - span_lint_and_then( - cx, - COLLAPSIBLE_MATCH, - inner_expr.span, - &msg, - |diag| { - let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); - help_span.push_span_label(binding_span, "replace this binding"); - help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); - diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern"); - }, - ); + span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, &msg, |diag| { + let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); + help_span.push_span_label(binding_span, "replace this binding"); + help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); + diag.span_help( + help_span, + "the outer pattern can be modified to include the inner pattern", + ); + }); } } diff --git a/clippy_lints/src/matches/infallible_destructuring_match.rs b/clippy_lints/src/matches/infallible_destructuring_match.rs index 313a9cba327..c8a48246e67 100644 --- a/clippy_lints/src/matches/infallible_destructuring_match.rs +++ b/clippy_lints/src/matches/infallible_destructuring_match.rs @@ -11,14 +11,13 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool { if !local.span.from_expansion() && let Some(expr) = local.init && let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind - && arms.len() == 1 && arms[0].guard.is_none() - && let PatKind::TupleStruct( - QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind + && arms.len() == 1 + && arms[0].guard.is_none() + && let PatKind::TupleStruct(QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind && args.len() == 1 && let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind && let body = peel_blocks(arms[0].body) && path_to_local_id(body, arg) - { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index bd8a9d10e8a..619ec83127a 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -23,16 +23,18 @@ fn get_cond_expr<'tcx>( ) -> Option> { if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr) && let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind - && let PatKind::Binding(_,target, ..) = pat.kind + && let PatKind::Binding(_, target, ..) = pat.kind && (is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr) - || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr)) // check that one expr resolves to `Some(x)`, the other to `None` + || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr)) + // check that one expr resolves to `Some(x)`, the other to `None` { return Some(SomeExpr { - expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()), - needs_unsafe_block: contains_unsafe_block(cx, expr), - needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond - }) - }; + expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()), + needs_unsafe_block: contains_unsafe_block(cx, expr), + needs_negated: is_none_expr(cx, then_expr), /* if the `then_expr` resolves to `None`, need to negate the + * cond */ + }); + }; None } diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 723528bbe2e..3e79cabd795 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -4,7 +4,6 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{OptionNone, ResultErr}; @@ -17,30 +16,27 @@ use super::MANUAL_UNWRAP_OR; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { let ty = cx.typeck_results().expr_ty(scrutinee); if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) { - Some("Option") - } else if is_type_diagnostic_item(cx, ty, sym::Result) { - Some("Result") - } else { - None - } - && let Some(or_arm) = applicable_or_arm(cx, arms) + Some("Option") + } else if is_type_diagnostic_item(cx, ty, sym::Result) { + Some("Result") + } else { + None + } && let Some(or_arm) = applicable_or_arm(cx, arms) && let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span) && let Some(indent) = indent_of(cx, expr.span) && constant_simple(cx, cx.typeck_results(), or_arm.body).is_some() { - let reindented_or_body = - reindent_multiline(or_body_snippet.into(), true, Some(indent)); + let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); let mut app = Applicability::MachineApplicable; let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); span_lint_and_sugg( cx, - MANUAL_UNWRAP_OR, expr.span, + MANUAL_UNWRAP_OR, + expr.span, &format!("this pattern reimplements `{ty_name}::unwrap_or`"), "replace with", - format!( - "{suggestion}.unwrap_or({reindented_or_body})", - ), + format!("{suggestion}.unwrap_or({reindented_or_body})",), app, ); } @@ -49,14 +45,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if arms.len() == 2 && arms.iter().all(|arm| arm.guard.is_none()) - && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| { - match arm.pat.kind { - PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), - PatKind::TupleStruct(ref qpath, [pat], _) => - matches!(pat.kind, PatKind::Wild) - && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr), - _ => false, - } + && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind { + PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone), + PatKind::TupleStruct(ref qpath, [pat], _) => { + matches!(pat.kind, PatKind::Wild) + && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr) + }, + _ => false, }) && let unwrap_arm = &arms[1 - idx] && let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 812a0aab94f..3f737da92c0 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -71,9 +71,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind - && path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name + && path2.segments.len() == 1 + && ident.name == path2.segments[0].ident.name { - return Some(mutabl) + return Some(mutabl); } None } diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index f100cb97a19..56123326fe4 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -87,10 +87,7 @@ where && b0 != b1 && (first_guard.is_none() || iter.len() == 0) && first_attrs.is_empty() - && iter - .all(|arm| { - find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty() - }) + && iter.all(|arm| find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()) { if let Some(last_pat) = last_pat_opt { if !is_wild(last_pat) { @@ -119,7 +116,10 @@ where .join(" | ") }; let pat_and_guard = if let Some(Guard::If(g)) = first_guard { - format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability)) + format!( + "{pat} if {}", + snippet_with_applicability(cx, g.span, "..", &mut applicability) + ) } else { pat }; @@ -135,7 +135,10 @@ where cx, MATCH_LIKE_MATCHES_MACRO, expr.span, - &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }), + &format!( + "{} expression looks like `matches!` macro", + if is_if_let { "if let .. else" } else { "match" } + ), "try", format!( "{}matches!({}, {pat_and_guard})", diff --git a/clippy_lints/src/matches/match_on_vec_items.rs b/clippy_lints/src/matches/match_on_vec_items.rs index d15ecce34f1..dd71560e169 100644 --- a/clippy_lints/src/matches/match_on_vec_items.rs +++ b/clippy_lints/src/matches/match_on_vec_items.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; @@ -12,7 +11,6 @@ use super::MATCH_ON_VEC_ITEMS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { if let Some(idx_expr) = is_vec_indexing(cx, scrutinee) && let ExprKind::Index(vec, idx, _) = idx_expr.kind - { // FIXME: could be improved to suggest surrounding every pattern with Some(_), // but only when `or_patterns` are stabilized. @@ -22,12 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { scrutinee.span, "indexing into a vector may panic", "try", - format!( - "{}.get({})", - snippet(cx, vec.span, ".."), - snippet(cx, idx.span, "..") - ), - Applicability::MaybeIncorrect + format!("{}.get({})", snippet(cx, vec.span, ".."), snippet(cx, idx.span, "..")), + Applicability::MaybeIncorrect, ); } } @@ -36,7 +30,6 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti if let ExprKind::Index(array, index, _) = expr.kind && is_vector(cx, array) && !is_full_range(cx, index) - { return Some(expr); } diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 3d920e9537f..bd38648bcf1 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -23,10 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind() && let ty::Str = ty.kind() { - let mut visitor = MatchExprVisitor { - cx, - case_method: None, - }; + let mut visitor = MatchExprVisitor { cx, case_method: None }; visitor.visit_expr(scrutinee); @@ -87,9 +84,9 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( for arm in arms { if let PatKind::Lit(Expr { - kind: ExprKind::Lit(lit), - .. - }) = arm.pat.kind + kind: ExprKind::Lit(lit), + .. + }) = arm.pat.kind && let LitKind::Str(symbol, _) = lit.node && let input = symbol.as_str() && !case_check(input) diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index f2fa404db5a..8a4c0ab9062 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -39,7 +39,8 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' && is_panic(cx, macro_call.def_id) { // `Err(_)` or `Err(_e)` arm with `panic!` found - span_lint_and_note(cx, + span_lint_and_note( + cx, MATCH_WILD_ERR_ARM, arm.pat.span, &format!("`Err({ident_bind_name})` matches all errors"), diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 9ce9c2e8381..2582f7edcf6 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -5,7 +5,6 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr}; use clippy_utils::{higher, is_expn_of, is_trait_method}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 2e19bbe42e4..316b2f63e4e 100644 --- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -14,7 +14,6 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { && (def.is_struct() || def.is_union()) && fields.len() == def.non_enum_variant().fields.len() && !def.non_enum_variant().is_field_list_non_exhaustive() - { span_lint_and_help( cx, diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index bbf59643aad..86c414dafcc 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -93,14 +93,18 @@ fn report_single_pattern( && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex)) && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait() && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait() - && (ty.is_integral() || ty.is_char() || ty.is_str() - || (implements_trait(cx, ty, spe_trait_id, &[]) - && implements_trait(cx, ty, pe_trait_id, &[ty.into()]))) + && (ty.is_integral() + || ty.is_char() + || ty.is_str() + || (implements_trait(cx, ty, spe_trait_id, &[]) && implements_trait(cx, ty, pe_trait_id, &[ty.into()]))) { // scrutinee derives PartialEq and the pattern is a constant. let pat_ref_count = match pat.kind { // string literals are already a reference. - PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1, + PatKind::Lit(Expr { + kind: ExprKind::Lit(lit), + .. + }) if lit.node.is_str() => pat_ref_count + 1, _ => pat_ref_count, }; // References are only implicitly added to the pattern, so no overflow here. diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 7e573aafef9..dd489fc250b 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; @@ -104,7 +103,6 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option< if let ty::Adt(def, subst) = ty.kind() && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()) && let ready_ty = subst.type_at(0) - && let ty::Adt(ready_def, ready_subst) = ready_ty.kind() && cx.tcx.is_diagnostic_item(sym::Result, ready_def.did()) { @@ -119,11 +117,9 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> if let ty::Adt(def, subst) = ty.kind() && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()) && let ready_ty = subst.type_at(0) - && let ty::Adt(ready_def, ready_subst) = ready_ty.kind() && cx.tcx.is_diagnostic_item(sym::Option, ready_def.did()) && let some_ty = ready_subst.type_at(0) - && let ty::Adt(some_def, some_subst) = some_ty.kind() && cx.tcx.is_diagnostic_item(sym::Result, some_def.did()) { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 0377af3f5db..13d6f511281 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -4,7 +4,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; @@ -163,8 +162,9 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' ), applicability, ); - } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) && - !cx.typeck_results().expr_ty(src).is_primitive() { + } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) + && !cx.typeck_results().expr_ty(src).is_primitive() + { span_lint_and_help( cx, MEM_REPLACE_WITH_UNINIT, diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 4e6a8c58bef..08bfa2e009b 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::visitors::find_all_ret_expressions; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -81,16 +80,11 @@ pub(crate) trait BindInsteadOfMap { let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); - let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME); - span_lint_and_sugg( - cx, - BIND_INSTEAD_OF_MAP, - expr.span, - &msg, - "try", - note, - app, + let note = format!( + "{option_snip}.{}({closure_args_snip} {some_inner_snip})", + Self::GOOD_METHOD_NAME ); + span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, "try", note, app); true } else { false @@ -115,7 +109,11 @@ pub(crate) trait BindInsteadOfMap { let (span, msg) = if can_sugg && let hir::ExprKind::MethodCall(segment, ..) = expr.kind && let Some(msg) = Self::lint_msg(cx) - { (segment.ident.span, msg) } else { return false; }; + { + (segment.ident.span, msg) + } else { + return false; + }; span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| { multispan_sugg_with_applicability( diag, @@ -136,7 +134,10 @@ pub(crate) trait BindInsteadOfMap { if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() && let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM) && adt.did() == cx.tcx.parent(vid) - {} else { return false; } + { + } else { + return false; + } match arg.kind { hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => { diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs index 039b92da1e1..4a2124c74a8 100644 --- a/clippy_lints/src/methods/bytecount.rs +++ b/clippy_lints/src/methods/bytecount.rs @@ -3,7 +3,6 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; @@ -24,9 +23,7 @@ pub(super) fn check<'tcx>( && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind && let ExprKind::Binary(ref op, l, r) = body.value.kind && op.node == BinOpKind::Eq - && is_type_diagnostic_item(cx, - cx.typeck_results().expr_ty(filter_recv).peel_refs(), - sym::SliceIter) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), sym::SliceIter) && let operand_is_arg = (|expr| { let expr = peel_ref_operators(cx, peel_blocks(expr)); path_to_local_id(expr, arg_id) @@ -41,8 +38,7 @@ pub(super) fn check<'tcx>( && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind() && !is_local_used(cx, needle, arg_id) { - let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = - filter_recv.kind { + let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = filter_recv.kind { let p = path.ident.name; if p == sym::iter || p == sym::iter_mut { receiver @@ -59,9 +55,11 @@ pub(super) fn check<'tcx>( expr.span, "you appear to be counting bytes the naive way", "consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet_with_applicability(cx, haystack.span, "..", &mut applicability), - snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + format!( + "bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability) + ), applicability, ); }; diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs index eebd8428cff..34159f2d150 100644 --- a/clippy_lints/src/methods/bytes_count_to_len.rs +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_lang_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -27,8 +26,11 @@ pub(super) fn check<'tcx>( expr.span, "using long and hard to read `.bytes().count()`", "consider calling `.len()` instead", - format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)), - applicability + format!( + "{}.len()", + snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability) + ), + applicability, ); }; } diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index b773e762d93..a37087d0abf 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_lang_item; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; @@ -30,7 +29,10 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && cx.tcx.type_of(impl_id).instantiate_identity().is_str() - && let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind + && let ExprKind::Lit(Spanned { + node: LitKind::Str(ext_literal, ..), + .. + }) = arg.kind && (2..=6).contains(&ext_literal.as_str().len()) && let ext_str = ext_literal.as_str() && ext_str.starts_with('.') @@ -47,7 +49,6 @@ pub(super) fn check<'tcx>( |diag| { diag.help("consider using a case-insensitive comparison instead"); if let Some(mut recv_source) = snippet_opt(cx, recv.span) { - if !cx.typeck_results().expr_ty(recv).is_ref() { recv_source = format!("&{recv_source}"); } @@ -57,9 +58,12 @@ pub(super) fn check<'tcx>( "std::path::Path::new({}) .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", - recv_source, ext_str.strip_prefix('.').unwrap()).into(), + recv_source, + ext_str.strip_prefix('.').unwrap() + ) + .into(), true, - Some(indent_of(cx, call_span).unwrap_or(0) + 4) + Some(indent_of(cx, call_span).unwrap_or(0) + 4), ); diag.span_suggestion( @@ -69,7 +73,7 @@ pub(super) fn check<'tcx>( Applicability::MaybeIncorrect, ); } - } + }, ); } } diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 06c0ee2e691..c99cec067bf 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{method_chain_args, path_def_id}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, Lint}; @@ -33,10 +32,12 @@ pub(super) fn check( info.expr.span, &format!("you should use the `{suggest}` method"), "like this", - format!("{}{}.{suggest}({})", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), + format!( + "{}{}.{suggest}({})", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), + snippet_with_applicability(cx, arg_char.span, "..", &mut applicability) + ), applicability, ); diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index a364bc9e525..d07e45434a7 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::method_chain_args; use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -26,10 +25,12 @@ pub(super) fn check( info.expr.span, &format!("you should use the `{suggest}` method"), "like this", - format!("{}{}.{suggest}('{}')", - if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), - c.escape_default()), + format!( + "{}{}.{suggest}('{}')", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), + c.escape_default() + ), applicability, ); diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index 89df0652855..dc978c8a584 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -27,7 +27,6 @@ pub(super) fn check( && let Some(data_type) = get_data_type(cx, result_type) // Tests if the T type in a `Result` implements debug && has_debug_impl(cx, data_type) - { span_lint_and_sugg( cx, @@ -36,8 +35,8 @@ pub(super) fn check( "called `.err().expect()` on a `Result` value", "try", "expect_err".to_string(), - Applicability::MachineApplicable - ); + Applicability::MachineApplicable, + ); }; } diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index 43a85f6e8a6..460ec7b3640 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 362f2589329..15f21fa6ac0 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::get_parent_expr; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index ee7a1538a5f..e52974103b2 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -4,7 +4,6 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; use hir::{Body, HirId, MatchSource, Pat}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; @@ -33,7 +32,7 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> && let hir::ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) { - return arg_id == *local + return arg_id == *local; } false }, @@ -324,7 +323,6 @@ pub(super) fn check( && let Some(check_result) = offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref) - { let span = filter_span.with_hi(expr.span.hi()); let (filter_name, lint) = if is_find { @@ -335,18 +333,23 @@ pub(super) fn check( let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); let (sugg, note_and_span, applicability) = match check_result { - CheckResult::Method { map_arg, method, side_effect_expr_span } => { + CheckResult::Method { + map_arg, + method, + side_effect_expr_span, + } => { let (to_opt, deref) = match method { CalledMethod::ResultIsOk => (".ok()", String::new()), CalledMethod::OptionIsSome => { - let derefs = cx.typeck_results() + let derefs = cx + .typeck_results() .expr_adjustments(map_arg) .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count(); ("", "*".repeat(derefs)) - } + }, }; let sugg = format!( @@ -363,15 +366,24 @@ pub(super) fn check( }; (sugg, note_and_span, applicability) - } - CheckResult::PatternMatching { variant_span, variant_ident } => { + }, + CheckResult::PatternMatching { + variant_span, + variant_ident, + } => { let pat = snippet(cx, variant_span, ""); - (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \ + ( + format!( + "{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \ {pat} => Some({variant_ident}), \ _ => None \ - }})"), None, Applicability::MachineApplicable) - } + }})" + ), + None, + Applicability::MachineApplicable, + ) + }, }; span_lint_and_then(cx, lint, span, &msg, |diag| { diag.span_suggestion(span, "try", sugg, applicability); diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index cee8d8eb029..917a8e33eb9 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_path_diagnostic_item, sugg}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -16,7 +15,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp && let ty = cx.typeck_results().expr_ty(expr) && let arg_ty = cx.typeck_results().expr_ty(&args[0]) && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) - && implements_trait(cx, arg_ty, iter_id, &[]) { // `expr` implements `FromIterator` trait @@ -44,7 +42,6 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> if let Some(snippet) = snippet_opt(cx, call_site) && let snippet_split = snippet.split("::").collect::>() && let Some((_, elements)) = snippet_split.split_last() - { if let [type_specifier, _] = snippet_split.as_slice() && let Some(type_specifier) = strip_angle_brackets(type_specifier) @@ -55,9 +52,16 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) { // remove the type specifier from the path elements - let without_ts = elements.iter().filter_map(|e| { - if e == type_specifier { None } else { Some((*e).to_string()) } - }).collect::>(); + let without_ts = elements + .iter() + .filter_map(|e| { + if e == type_specifier { + None + } else { + Some((*e).to_string()) + } + }) + .collect::>(); // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) format!("{}{type_specifier}", without_ts.join("::")) } else { diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index 9b6f76f0f42..e1f1e489355 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; @@ -20,7 +19,10 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && let identity = cx.tcx.type_of(impl_id).instantiate_identity() - && let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind + && let hir::ExprKind::Lit(Spanned { + node: LitKind::Int(0, _), + .. + }) = arg.kind { if identity.is_slice() { let mut app = Applicability::MachineApplicable; @@ -34,18 +36,18 @@ pub(super) fn check<'tcx>( format!("{slice_name}.first()"), app, ); - } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){ - let mut app = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), - "try", - format!("{slice_name}.front()"), - app, - ); + } else if is_type_diagnostic_item(cx, identity, sym::VecDeque) { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{slice_name}.get(0)`"), + "try", + format!("{slice_name}.front()"), + app, + ); } } } diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 73747340ef1..78a553eb8c0 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, peel_mid_ty_refs}; use clippy_utils::{is_diag_item_method, is_diag_trait_item}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index c0b7b3ae972..efc3ddd20b4 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -18,7 +17,8 @@ pub fn check( receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>], ) { - if args.is_empty() && method_name == sym::to_string + if args.is_empty() + && method_name == sym::to_string && let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did) && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id) diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 7bb32d6ea65..5ca841df5d9 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; use clippy_utils::ty::has_iter_method; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -28,9 +27,7 @@ pub(super) fn check( cx, INTO_ITER_ON_REF, method_span, - &format!( - "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`", - ), + &format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",), "call directly", method_name.to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index da841ca50f4..dd741cd43f9 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -1,7 +1,6 @@ use crate::methods::utils::derefs_to_slice; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -13,14 +12,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir: if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv)) && let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) - { span_lint_and_sugg( cx, ITER_CLONED_COLLECT, to_replace, - &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable"), + &format!( + "called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable" + ), "try", ".to_vec()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 687aee267fa..c5dbb6ad98b 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -24,27 +24,27 @@ pub(super) fn check<'tcx>( ) { if !expr.span.from_expansion() && let ExprKind::Closure(c) = m_arg.kind - && let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body) + && let Body { + params: [p], + value: body_expr, + coroutine_kind: _, + } = cx.tcx.hir().body(c.body) && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind - && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, } - && let ty = cx.typeck_results().expr_ty(recv) && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)) - { let mut applicability = rustc_errors::Applicability::MachineApplicable; let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); - let into_prefix = if map_type == "into_iter" {"into_"} else {""}; + let into_prefix = if map_type == "into_iter" { "into_" } else { "" }; if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind && let [local_ident] = path.segments && local_ident.ident.as_str() == bound_ident.as_str() - { span_lint_and_sugg( cx, @@ -56,24 +56,18 @@ pub(super) fn check<'tcx>( applicability, ); } else { - let ref_annotation = if annotation.0 == ByRef::Yes { - "ref " - } else { - "" - }; - let mut_annotation = if annotation.1 == Mutability::Mut { - "mut " - } else { - "" - }; + let ref_annotation = if annotation.0 == ByRef::Yes { "ref " } else { "" }; + let mut_annotation = if annotation.1 == Mutability::Mut { "mut " } else { "" }; span_lint_and_sugg( cx, ITER_KV_MAP, expr.span, &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", - snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), + format!( + "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", + snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability) + ), applicability, ); } diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index 9d97370116e..fd4650e1e45 100644 --- a/clippy_lints/src/methods/iter_next_slice.rs +++ b/clippy_lints/src/methods/iter_next_slice.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, higher}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -27,16 +26,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() { // caller is a Slice if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind - && let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) - = higher::Range::hir(index_expr) + && let Some(higher::Range { + start: Some(start_expr), + end: None, + limits: ast::RangeLimits::HalfOpen, + }) = higher::Range::hir(index_expr) && let hir::ExprKind::Lit(start_lit) = &start_expr.kind && let ast::LitKind::Int(start_idx, _) = start_lit.node { let mut applicability = Applicability::MachineApplicable; let suggest = if start_idx == 0 { - format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) + format!( + "{}.first()", + snippet_with_applicability(cx, caller_var.span, "..", &mut applicability) + ) } else { - format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)) + format!( + "{}.get({start_idx})", + snippet_with_applicability(cx, caller_var.span, "..", &mut applicability) + ) }; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index 872476a314c..fbe20dfe54e 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr |diag| { if let Some(id) = path_to_local(recv) && let Node::Pat(pat) = cx.tcx.hir().get(id) - && let PatKind::Binding(ann, _, _, _) = pat.kind + && let PatKind::Binding(ann, _, _, _) = pat.kind && ann != BindingAnnotation::MUT { application = Applicability::Unspecified; diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index 35d5e090cc8..b1af0083e65 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{ResultErr, ResultOk}; use rustc_hir::{Expr, ExprKind, PatKind}; @@ -35,9 +34,7 @@ pub(super) fn check<'tcx>( expr.span, "this pattern reimplements `Option::ok_or`", "replace with", - format!( - "{recv_snippet}.ok_or({reindented_err_arg_snippet})" - ), + format!("{recv_snippet}.ok_or({reindented_err_arg_snippet})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 464d4c37a87..04bdbc1ea25 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{match_def_path, path_def_id}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -76,7 +75,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { match segment.ident.as_str() { "max_value" => return Some(MinMax::Max), "min_value" => return Some(MinMax::Min), - _ => {} + _ => {}, } } diff --git a/clippy_lints/src/methods/manual_str_repeat.rs b/clippy_lints/src/methods/manual_str_repeat.rs index 5b4517f3d6c..61e74369cb0 100644 --- a/clippy_lints/src/methods/manual_str_repeat.rs +++ b/clippy_lints/src/methods/manual_str_repeat.rs @@ -3,7 +3,6 @@ use clippy_utils::is_path_diagnostic_item; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; @@ -73,13 +72,14 @@ pub(super) fn check( RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return, RepeatKind::Char('\'') => r#""'""#.into(), RepeatKind::Char('"') => r#""\"""#.into(), - RepeatKind::Char(_) => - match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) { - Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])), - s @ Cow::Borrowed(_) => s, - }, - RepeatKind::String => - Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(), + RepeatKind::Char(_) => match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) { + Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])), + s @ Cow::Borrowed(_) => s, + }, + RepeatKind::String => Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app) + .maybe_par() + .to_string() + .into(), }; span_lint_and_sugg( @@ -89,7 +89,7 @@ pub(super) fn check( "manual implementation of `str::repeat` using iterators", "try", format!("{val_str}.repeat({count_snip})"), - app - ) + app, + ); } } diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 417bcc41a28..cc6eeaa86e5 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use clippy_utils::{is_diag_trait_item, peel_blocks}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -17,19 +16,19 @@ use super::MAP_CLONE; pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) - && (cx.tcx.impl_of_method(method_id) - .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option)) - || is_diag_trait_item(cx, method_id, sym::Iterator)) - && let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind + && (cx.tcx.impl_of_method(method_id).map_or(false, |id| { + is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option) + }) || is_diag_trait_item(cx, method_id, sym::Iterator)) + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(closure_body.value); match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::NONE, .., name, None - ) = inner.kind { - if ident_eq(name, closure_expr) { - lint_explicit_closure(cx, e.span, recv.span, true, msrv); + hir::PatKind::Ref(inner, hir::Mutability::Not) => { + if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind { + if ident_eq(name, closure_expr) { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } } }, hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { @@ -41,22 +40,24 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ } } }, - hir::ExprKind::MethodCall(method, obj, [], _) => if ident_eq(name, obj) && method.ident.name == sym::clone + hir::ExprKind::MethodCall(method, obj, [], _) => { + if ident_eq(name, obj) && method.ident.name == sym::clone && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) - { - let obj_ty = cx.typeck_results().expr_ty(obj); - if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, *ty); - lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, *ty); + lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + } + } else { + lint_needless_cloning(cx, e.span, recv.span); } - } else { - lint_needless_cloning(cx, e.span, recv.span); } }, _ => {}, diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs index 0f8cacc3435..e944eac91e7 100644 --- a/clippy_lints/src/methods/map_collect_result_unit.rs +++ b/clippy_lints/src/methods/map_collect_result_unit.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -17,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr && let ty::Adt(_, args) = collect_ret_ty.kind() && let Some(result_t) = args.types().next() && result_t.is_unit() - // get parts for snippet + // get parts for snippet { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 88545b7286c..d1072475843 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -20,8 +20,8 @@ pub(super) fn check( let caller_ty = cx.typeck_results().expr_ty(caller); if (is_trait_method(cx, expr, sym::Iterator) - || is_type_diagnostic_item(cx, caller_ty, sym::Result) - || is_type_diagnostic_item(cx, caller_ty, sym::Option)) + || is_type_diagnostic_item(cx, caller_ty, sym::Result) + || is_type_diagnostic_item(cx, caller_ty, sym::Option)) && is_expr_untyped_identity_function(cx, map_arg) && let Some(sugg_span) = expr.span.trim_start(caller.span) { @@ -33,6 +33,6 @@ pub(super) fn check( &format!("remove the call to `{name}`"), String::new(), Applicability::MachineApplicable, - ) + ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1664a313fa9..ab376d66966 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -123,7 +123,6 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; 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, peel_blocks, return_ty}; -use if_chain::if_chain; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -3980,7 +3979,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(ref sig, _) = item.kind && sig.decl.implicit_self.has_implicit_self() && let Some(first_arg_hir_ty) = sig.decl.inputs.first() - && let Some(&first_arg_ty) = cx.tcx.fn_sig(item.owner_id) + && let Some(&first_arg_ty) = cx + .tcx + .fn_sig(item.owner_id) .instantiate_identity() .inputs() .skip_binder() @@ -4003,7 +4004,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { && let ret_ty = return_ty(cx, item.owner_id) && let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty() && !ret_ty.contains(self_ty) - { span_lint( cx, diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index 15ce7c2eee6..1a0fce2876d 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::expr_custom_deref_adjustment; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs index f6ba165a9a1..81df32bdee2 100644 --- a/clippy_lints/src/methods/no_effect_replace.rs +++ b/clippy_lints/src/methods/no_effect_replace.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_lang_item; use clippy_utils::SpanlessEq; -use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{ExprKind, LangItem}; use rustc_lint::LateContext; @@ -21,11 +20,9 @@ pub(super) fn check<'tcx>( if let ExprKind::Lit(spanned) = &arg1.kind && let Some(param1) = lit_string_value(&spanned.node) - && let ExprKind::Lit(spanned) = &arg2.kind && let LitKind::Str(param2, _) = &spanned.node && param1 == param2.as_str() - { span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself"); } diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs index 7c86c820a42..e10bc0216e5 100644 --- a/clippy_lints/src/methods/ok_expect.rs +++ b/clippy_lints/src/methods/ok_expect.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item}; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -15,7 +14,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr && let result_type = cx.typeck_results().expr_ty(recv) && let Some(error_type) = get_error_type(cx, result_type) && has_debug_impl(cx, error_type) - { span_lint_and_help( cx, diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 9463c39229d..15111006133 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6d970dbfab2..dd669e49956 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -3,7 +3,6 @@ use clippy_utils::eager_or_lazy::switch_to_lazy_eval; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; @@ -132,17 +131,12 @@ pub(super) fn check<'tcx>( ]; if KNOW_TYPES.iter().any(|k| k.2.contains(&name)) - && switch_to_lazy_eval(cx, arg) && !contains_return(arg) - && let self_ty = cx.typeck_results().expr_ty(self_expr) - && let Some(&(_, fn_has_arguments, poss, suffix)) = KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0)) - && poss.contains(&name) - { let ctxt = span.ctxt(); let mut app = Applicability::HasPlaceholders; diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs index c292b93843b..04a27cc98f3 100644 --- a/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index dabeba0b3c3..1148628b084 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq}; -use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -21,11 +20,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' && let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind && SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments) { - span_lint(cx, + span_lint( + cx, RANGE_ZIP_WITH_LEN, expr.span, - &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, recv.span, "_")) + &format!( + "it is more idiomatic to use `{}.iter().enumerate()`", + snippet(cx, recv.span, "_") + ), ); } } diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 01dc28a4076..9b90a3df72f 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -3,7 +3,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{is_trait_method, strip_pat_refs}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; @@ -108,9 +107,7 @@ pub(super) fn check<'tcx>( self_ty.is_str() } }; - if is_string_or_str_slice(search_recv) - && is_string_or_str_slice(search_arg) - { + if is_string_or_str_slice(search_recv) && is_string_or_str_slice(search_arg) { let msg = format!("called `{option_check_method}()` after calling `find()` on a string"); match option_check_method { "is_some" => { diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index d0b57bbf94e..3983f0c0cab 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -1,6 +1,5 @@ use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -47,7 +46,8 @@ pub(super) fn check( for &(method, pos) in &PATTERN_METHODS { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() && ty.is_str() - && method_name.as_str() == method && args.len() > pos + && method_name.as_str() == method + && args.len() > pos && let arg = &args[pos] && let mut applicability = Applicability::MachineApplicable && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index c6b79876115..0e7ad8fc996 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -6,7 +6,6 @@ use clippy_utils::usage::local_used_after_expr; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind, @@ -295,7 +294,7 @@ fn parse_iter_usage<'tcx>( Some(IterUsage { kind: IterUsageKind::NextTuple, span: e.span, - unwrap_kind: None + unwrap_kind: None, }) } else { None @@ -305,18 +304,16 @@ fn parse_iter_usage<'tcx>( if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) { let span = if name.ident.as_str() == "nth" { e.span + } else if let Some((_, Node::Expr(next_expr))) = iter.next() + && let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind + && next_name.ident.name == sym::next + && next_expr.span.ctxt() == ctxt + && let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id) + && cx.tcx.trait_of_item(next_id) == Some(iter_id) + { + next_expr.span } else { - if let Some((_, Node::Expr(next_expr))) = iter.next() - && let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind - && next_name.ident.name == sym::next - && next_expr.span.ctxt() == ctxt - && let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id) - && cx.tcx.trait_of_item(next_id) == Some(iter_id) - { - next_expr.span - } else { - return None; - } + return None; }; (IterUsageKind::Nth(idx), span) } else { diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 909f2fa6bfc..ed49233acb7 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::usage::mutated_variables; use clippy_utils::{expr_or_init, is_trait_method}; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 873968b6417..c45212581ee 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_note; -use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -23,24 +22,21 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se } let (msg, note_msg) = if count == 0 { - (format!("`{method_name}` called with `0` splits"), - "the resulting iterator will always return `None`") + ( + format!("`{method_name}` called with `0` splits"), + "the resulting iterator will always return `None`", + ) } else { - (format!("`{method_name}` called with `1` split"), - if self_ty.is_slice() { - "the resulting iterator will always return the entire slice followed by `None`" - } else { - "the resulting iterator will always return the entire string followed by `None`" - }) + ( + format!("`{method_name}` called with `1` split"), + if self_ty.is_slice() { + "the resulting iterator will always return the entire slice followed by `None`" + } else { + "the resulting iterator will always return the entire string followed by `None`" + }, + ) }; - span_lint_and_note( - cx, - SUSPICIOUS_SPLITN, - expr.span, - &msg, - None, - note_msg, - ); + span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, &msg, None, note_msg); } } diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index f1ffa8fd808..60864902a48 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_diag_trait_item; use clippy_utils::source::snippet_with_context; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -17,7 +16,6 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - && let input_type = cx.typeck_results().expr_ty(expr) && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind() && cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) - { let mut app = Applicability::MaybeIncorrect; let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; @@ -33,15 +31,15 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - expr.span, "depending on intent, either make the Cow an Owned variant", format!("{recv_snip}.into_owned()"), - app + app, ); diag.span_suggestion( expr.span, "or clone the Cow itself", format!("{recv_snip}.clone()"), - app + app, ); - } + }, ); return true; } diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index fef309db462..1ee655d61e1 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_path_diagnostic_item; use clippy_utils::ty::is_uninit_value_valid_for_ty; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; @@ -19,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, UNINIT_ASSUMED_INIT, expr.span, - "this call for this type may be undefined behavior" + "this call for this type may be undefined behavior", ); } } diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 7694cd42beb..7afd3802f7d 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -77,7 +76,6 @@ fn check_fold_with_op( && path_to_local_id(left_expr, first_arg_id) && (replacement.has_args || path_to_local_id(right_expr, second_arg_id)) - { let mut applicability = Applicability::MachineApplicable; @@ -94,10 +92,7 @@ fn check_fold_with_op( r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { - format!( - "{method}{turbofish}()", - method = replacement.method_name, - ) + format!("{method}{turbofish}()", method = replacement.method_name,) }; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index f55de39c10d..36497d59a5a 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -42,17 +42,14 @@ pub fn check_for_loop_iter( { let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind && maybe_iter_method_name.ident.name == sym::iter - && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator) && let receiver_ty = cx.typeck_results().expr_ty(receiver) && implements_trait(cx, receiver_ty, iterator_trait_id, &[]) && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty) - && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let collection_ty = cx.typeck_results().expr_ty(collection) && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") - && iter_item_ty == into_iter_item_ty && let Some(collection_snippet) = snippet_opt(cx, collection.span) { @@ -82,11 +79,11 @@ pub fn check_for_loop_iter( ExprKind::AddrOf(_, _, referent) => { let span = addr_of_expr.span.with_hi(referent.span.lo()); diag.span_suggestion(span, "remove this `&`", "", applicability); - } + }, _ => unreachable!(), } } - } + }, ); return true; } diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index b66e962017c..4949ccd770e 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::LateContext; @@ -122,30 +121,51 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp && let ExprKind::Closure(&Closure { body, .. }) = arg.kind && let closure_body = cx.tcx.hir().body(body) && let &[ - Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, - Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } + Param { + pat: + Pat { + kind: PatKind::Binding(_, _, left_ident, _), + .. + }, + .. + }, + Param { + pat: + Pat { + kind: PatKind::Binding(_, _, right_ident, _), + .. + }, + .. + }, ] = &closure_body.params && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind && method_path.ident.name == sym::cmp && is_trait_method(cx, closure_body.value, sym::Ord) { - let (closure_body, closure_arg, reverse) = if mirrored_exprs( - left_expr, - left_ident, - right_expr, - right_ident - ) { - (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false) + let (closure_body, closure_arg, reverse) = if mirrored_exprs(left_expr, left_ident, right_expr, right_ident) { + ( + Sugg::hir(cx, left_expr, "..").to_string(), + left_ident.name.to_string(), + false, + ) } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) { - (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true) + ( + Sugg::hir(cx, left_expr, "..").to_string(), + right_ident.name.to_string(), + true, + ) } else { return None; }; let vec_name = Sugg::hir(cx, recv, "..").to_string(); - if let ExprKind::Path(QPath::Resolved(_, Path { - segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind + if let ExprKind::Path(QPath::Resolved( + _, + Path { + segments: [PathSegment { ident: left_name, .. }], + .. + }, + )) = &left_expr.kind && left_name == left_ident && cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index c23966f95e9..84ee64e88a6 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::walk_ptrs_ty_depth; use clippy_utils::{get_parent_expr, is_trait_method}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index f776e055833..9ad4250a141 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,7 +1,6 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; @@ -70,11 +69,14 @@ pub(super) fn get_hint_if_single_char_arg( &snip[1..(snip.len() - 1)] }; - let hint = format!("'{}'", match ch { - "'" => "\\'" , - r"\" => "\\\\", - _ => ch, - }); + let hint = format!( + "'{}'", + match ch { + "'" => "\\'", + r"\" => "\\\\", + _ => ch, + } + ); Some(hint) } else { diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs index 9f0507916e1..9e87fb45aa6 100644 --- a/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -20,8 +19,13 @@ pub(super) fn check<'tcx>( if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec) - && let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind - && let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind + && let ExprKind::Lit(Spanned { + node: LitKind::Int(0, _), + .. + }) = count_arg.kind + && let ExprKind::Lit(Spanned { + node: LitKind::Int(..), .. + }) = default_arg.kind { let method_call_span = expr.span.with_lo(name_span.lo()); span_lint_and_then( diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs index 4f5cf734fa4..0b829d99aef 100644 --- a/clippy_lints/src/methods/zst_offset.rs +++ b/clippy_lints/src/methods/zst_offset.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index ee58a47743d..a3d5a8a9d83 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -5,7 +5,6 @@ use clippy_utils::{ any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats, last_path_segment, SpanlessEq, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::FnKind; @@ -174,13 +173,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { diag.span_suggestion( stmt.span, "try", - format!( - "let {name}{tyopt} = {initref};", - name=snippet(cx, name.span, ".."), - ), + format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),), app, ); - } + }, ); }; if let StmtKind::Semi(expr) = stmt.kind @@ -199,13 +195,11 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { diag.span_suggestion( stmt.span, "replace it with", - format!( - "if {sugg} {{ {}; }}", - &snippet(cx, b.span, ".."), - ), + format!("if {sugg} {{ {}; }}", &snippet(cx, b.span, ".."),), Applicability::MachineApplicable, // snippet ); - }); + }, + ); }; } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 724f2c8e597..c74d0d623df 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -60,8 +60,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { let mut impl_params = Vec::new(); for p in generic_args.args { match p { - GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) => - impl_params.push((path.segments[0].ident.to_string(), path.span)), + GenericArg::Type(Ty { + kind: TyKind::Path(QPath::Resolved(_, path)), + .. + }) => impl_params.push((path.segments[0].ident.to_string(), path.span)), GenericArg::Type(_) => return, _ => (), }; @@ -70,36 +72,36 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { // find the type that the Impl is for // only lint on struct/enum/union for now let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else { - return + return; }; // get the names of the generic parameters in the type let type_params = &cx.tcx.generics_of(defid).params; - let type_param_names: Vec<_> = type_params.iter() - .filter_map(|p| - match p.kind { - GenericParamDefKind::Type {..} => Some(p.name.to_string()), + let type_param_names: Vec<_> = type_params + .iter() + .filter_map(|p| match p.kind { + GenericParamDefKind::Type { .. } => Some(p.name.to_string()), _ => None, - } - ).collect(); + }) + .collect(); // hashmap of name -> index for mismatch_param_name - let type_param_names_hashmap: FxHashMap<&String, usize> = - type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect(); + let type_param_names_hashmap: FxHashMap<&String, usize> = type_param_names + .iter() + .enumerate() + .map(|(i, param)| (param, i)) + .collect(); let type_name = segment.ident; for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() { if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) { - let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order"); - let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params", - type_param_names[i]); - span_lint_and_help( - cx, - MISMATCHING_TYPE_PARAM_ORDER, - *impl_param_span, - &msg, - None, - &help + let msg = format!( + "`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order" + ); + let help = format!( + "try `{}`, or a name that does not conflict with `{type_name}`'s generic params", + type_param_names[i] ); + span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, &msg, None, &help); } } } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index cfc4af35f33..1dcaa60ac7b 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -8,7 +8,6 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; -use if_chain::if_chain; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 1d07727f1c0..f7e42815104 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -94,9 +94,7 @@ impl LateLintPass<'_> for ImportRename { span_without_semi, "this import should be renamed", "try", - format!( - "{import} as {name}", - ), + format!("{import} as {name}",), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 9634b4357c2..b46c006cd57 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; -use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -83,7 +82,11 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { let var = if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind && let Some(var) = path_to_local(lhs) && expr.span.desugaring_kind().is_none() - { var } else { return; }; + { + var + } else { + return; + }; let mut visitor = ReadVisitor { cx, var, diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index b6aafd35b58..1712262ff3e 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use if_chain::if_chain; use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -105,7 +104,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod "consider to change this parameter to", self_param, applicability, - ) + ); } } @@ -124,7 +123,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { }, TyKind::Ref(lifetime, mut_ty) => { if let TyKind::Path(None, path) = &mut_ty.ty.kind - && let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind + && let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 42bce1ee276..0203e2ccd63 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -6,8 +6,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; -use if_chain::if_chain; - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; @@ -108,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { if let Some(ret_suggs) = ret_suggs { diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability); } - }) + }); } } } diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 886c0f3a430..0a95678d31a 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -136,7 +136,6 @@ impl LocalAssign { // avoid visiting if not needed && assign.lhs_id == binding_id && other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt)) - { Some(assign) } else { @@ -367,17 +366,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { let mut parents = cx.tcx.hir().parent_iter(local.hir_id); if let Local { - init: None, - pat: &Pat { + init: None, + pat: + &Pat { kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None), .. }, - source: LocalSource::Normal, - .. - } = local + source: LocalSource::Normal, + .. + } = local && let Some((_, Node::Stmt(local_stmt))) = parents.next() && let Some((_, Node::Block(block))) = parents.next() - { check(cx, local, local_stmt, block, binding_id); } diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index 6d4a4ee603e..490c3f9c1ab 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -60,12 +60,16 @@ fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { && snippet_enclosed_in_parenthesis(&snippet(cx, e.span, "")) { let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERALS, e.span, + span_lint_and_then( + cx, + NEEDLESS_PARENS_ON_RANGE_LITERALS, + e.span, "needless parenthesis on range literals can be removed", |diag| { let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability); diag.span_suggestion(e.span, "try", suggestion, applicability); - }); + }, + ); } } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 24b9eaac088..7c48b84e430 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -5,7 +5,6 @@ use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; -use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; @@ -181,16 +180,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !ty.is_mutable_ptr() && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.param_env) - && !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter( - cx.tcx, - cx.param_env, - ty, - t, - [Option::>::None], - )) + && !allowed_traits.iter().any(|&t| { + implements_trait_with_env_from_iter( + cx.tcx, + cx.param_env, + ty, + t, + [Option::>::None], + ) + }) && !implements_borrow_trait && !all_borrowable_trait - && let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind && !moved_vars.contains(&canonical_id) { @@ -203,23 +203,32 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { cx.param_env, ty, traits::ObligationCause::dummy_with_span(span), - ).is_ok() { + ) + .is_ok() + { diag.span_help(span, "consider marking this type as `Copy`"); } } } if is_type_diagnostic_item(cx, ty, sym::Vec) - && let Some(clone_spans) = - get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]) + && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]) && let TyKind::Path(QPath::Resolved(_, path)) = input.kind - && let Some(elem_ty) = path.segments.iter() + && let Some(elem_ty) = path + .segments + .iter() .find(|seg| seg.ident.name == sym::Vec) .and_then(|ps| ps.args.as_ref()) - .map(|params| params.args.iter().find_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }).unwrap()) + .map(|params| { + params + .args + .iter() + .find_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }) + .unwrap() + }) { let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_")); diag.span_suggestion( @@ -233,10 +242,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { diag.span_suggestion( span, snippet_opt(cx, span) - .map_or( - "change the call to".into(), - |x| format!("change `{x}` to"), - ), + .map_or("change the call to".into(), |x| format!("change `{x}` to")), suggestion, Applicability::Unspecified, ); @@ -248,7 +254,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if is_type_lang_item(cx, ty, LangItem::String) { if let Some(clone_spans) = - get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { + get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) + { diag.span_suggestion( input.span, "consider changing the type to", @@ -260,10 +267,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { diag.span_suggestion( span, snippet_opt(cx, span) - .map_or( - "change the call to".into(), - |x| format!("change `{x}` to") - ), + .map_or("change the call to".into(), |x| format!("change `{x}` to")), suggestion, Applicability::Unspecified, ); diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 66ad45e1cb8..7ec0879ba38 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_res; use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 5e692d7d205..30aed8cc04a 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::implements_trait; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -50,7 +49,6 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { && let ExprKind::Unary(UnOp::Not, inner) = expr.kind && let ExprKind::Binary(ref op, left, _) = inner.kind && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node - { let ty = cx.typeck_results().expr_ty(left); diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 62a8f04bf17..a6786e913e9 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -2,7 +2,6 @@ use clippy_utils::consts::{self, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::has_enclosing_paren; -use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -56,7 +55,6 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { if let ExprKind::Lit(l) = lit.kind && consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1) && cx.typeck_results().expr_ty(exp).is_integral() - { let mut applicability = Applicability::MachineApplicable; let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); @@ -66,13 +64,13 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { format!("-{snip}") }; span_lint_and_sugg( - cx, - NEG_MULTIPLY, - span, - "this multiplication by -1 can be written more succinctly", - "consider using", - suggestion, - applicability, - ); + cx, + NEG_MULTIPLY, + span, + "this multiplication by -1 can be written more succinctly", + "consider using", + suggestion, + applicability, + ); } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index bd75a8c2a98..abba622a285 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::return_ty; use clippy_utils::source::snippet; use clippy_utils::sugg::DiagnosticExt; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::HirIdSet; @@ -150,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { &create_new_without_default_suggest_msg( &self_type_snip, &generics_sugg, - &where_clause_sugg + &where_clause_sugg, ), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index c5d6ff9b2f5..de8bb123e9b 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -145,7 +145,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { NO_EFFECT_UNDERSCORE_BINDING, init.hir_id, stmt.span, - "binding to `_` prefixed variable with no side-effect" + "binding to `_` prefixed variable with no side-effect", ); return true; } @@ -205,13 +205,12 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { - let snippet = if let (Some(arr), Some(func)) = - (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) - { - format!("assert!({}.len() > {});", &arr, &func) - } else { - return; - }; + let snippet = + if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { + format!("assert!({}.len() > {});", &arr, &func) + } else { + return; + }; span_lint_hir_and_then( cx, UNNECESSARY_OPERATION, diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 5a91468a214..3059eb25d29 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -7,7 +7,6 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::macro_backtrace; use clippy_utils::{def_path_def_ids, in_constant}; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -414,12 +413,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { && !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized) && self.is_value_unfrozen_poly(cx, *body_id, normalized) { - lint( - cx, - Source::Assoc { - item: impl_item.span, - }, - ); + lint(cx, Source::Assoc { item: impl_item.span }); } }, ItemKind::Impl(Impl { of_trait: None, .. }) => { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index ab52ed5a7ca..6cfcc81025d 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -46,15 +45,17 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { ExprKind::MethodCall(path, func, [param], _) => { if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() && ((path.ident.name == sym!(mode) - && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder))) + && matches!( + cx.tcx.get_diagnostic_name(adt.did()), + Some(sym::FsOpenOptions | sym::DirBuilder) + )) || (path.ident.name == sym!(set_mode) && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - { let Some(snip) = snippet_opt(cx, param.span) else { - return + return; }; if !snip.starts_with("0o") { diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 23e756c850f..df1476e6809 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -98,9 +98,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { for variant in adt_def.variants() { for field in &variant.fields { if let Some(field_hir_id) = field - .did - .as_local() - .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)) + .did + .as_local() + .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)) && !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id) && let field_ty = field.ty(cx.tcx, impl_trait_args) && !ty_allowed_in_send(cx, field_ty, send_trait) @@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { def: field_def, ty: field_ty, generic_params: collect_generic_params(field_ty), - }) + }); } } } @@ -128,12 +128,17 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { for field in non_send_fields { diag.span_note( field.def.span, - format!("it is not safe to send field `{}` to another thread", field.def.ident.name), + format!( + "it is not safe to send field `{}` to another thread", + field.def.ident.name + ), ); match field.generic_params.len() { 0 => diag.help("use a thread-safe type that implements `Send`"), - 1 if is_ty_param(field.ty) => diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)), + 1 if is_ty_param(field.ty) => { + diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)) + }, _ => diag.help(format!( "add bounds on type parameter{} `{}` that satisfy `{}: Send`", if field.generic_params.len() > 1 { "s" } else { "" }, diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 87359086512..8604fe08e50 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,6 @@ use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index bc7ad151aee..2f85130fba1 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; @@ -28,8 +27,7 @@ pub(super) fn check<'tcx>( if let Some((_, lang_item)) = binop_traits(op.node) && let Some(trait_id) = cx.tcx.lang_items().get(lang_item) && let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id - && trait_ref_of_method(cx, parent_fn) - .map_or(true, |t| t.path.res.def_id() != trait_id) + && trait_ref_of_method(cx, parent_fn).map_or(true, |t| t.path.res.def_id() != trait_id) && implements_trait(cx, ty, trait_id, &[rty.into()]) { // Primitive types execute assign-ops right-to-left. Every other type is left-to-right. diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index 408c9a2cf29..52ef9546110 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -3,7 +3,6 @@ use std::cmp::Ordering; use clippy_utils::consts::{constant, Constant}; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; @@ -76,7 +75,6 @@ pub(super) fn check<'tcx>( (&left_cmp_op, &right_cmp_op, ordering), (CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal) ) - { if left_cmp_op.direction() == right_cmp_op.direction() { let lhs_str = snippet(cx, left_cond.span, ""); @@ -104,15 +102,20 @@ pub(super) fn check<'tcx>( } // We could autofix this error but choose not to, // because code triggering this lint probably not behaving correctly in the first place - } - else if !comparison_is_possible(left_cmp_op.direction(), ordering) { + } else if !comparison_is_possible(left_cmp_op.direction(), ordering) { let expr_str = snippet(cx, left_expr.span, ".."); let lhs_str = snippet(cx, left_const_expr.span, ""); let rhs_str = snippet(cx, right_const_expr.span, ""); let note = match ordering { - Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"), - Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"), - Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"), + Ordering::Less => format!( + "since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`" + ), + Ordering::Equal => { + format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`") + }, + Ordering::Greater => format!( + "since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`" + ), }; span_lint_and_note( cx, diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index fecaf14bf5e..0561739d160 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -2,7 +2,6 @@ use clippy_utils::consts::{constant_with_source, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -107,8 +106,8 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind && sym!(signum) == method_name.ident.name - // Check that the receiver of the signum() is a float (expressions[0] is the receiver of - // the method call) + // Check that the receiver of the signum() is a float (expressions[0] is the receiver of + // the method call) { return is_float(cx, self_arg); } diff --git a/clippy_lints/src/operators/float_equality_without_abs.rs b/clippy_lints/src/operators/float_equality_without_abs.rs index 91eaa296f14..cace85a2451 100644 --- a/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/clippy_lints/src/operators/float_equality_without_abs.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths, sugg}; -use if_chain::if_chain; use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -44,26 +43,23 @@ pub(crate) fn check<'tcx>( && let t_val_r = cx.typeck_results().expr_ty(val_r) && let ty::Float(_) = t_val_l.kind() && let ty::Float(_) = t_val_r.kind() - { let sug_l = sugg::Sugg::hir(cx, val_l, ".."); let sug_r = sugg::Sugg::hir(cx, val_r, ".."); // format the suggestion - let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); + let suggestion = format!( + "{}.abs()", + sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par() + ); // spans the lint span_lint_and_then( cx, FLOAT_EQUALITY_WITHOUT_ABS, expr.span, "float equality check without `.abs()`", - | diag | { - diag.span_suggestion( - lhs.span, - "add `.abs()`", - suggestion, - Applicability::MaybeIncorrect, - ); - } + |diag| { + diag.span_suggestion(lhs.span, "add `.abs()`", suggestion, Applicability::MaybeIncorrect); + }, ); } } diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index 2c7eebc5ae9..cb3916484c1 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -1,7 +1,6 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sext; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -23,8 +22,7 @@ pub(super) fn check<'tcx>( && let Some(rhs_operand) = rhs_operand { check_const_operands(cx, e, &lhs_operand, &rhs_operand); - } - else { + } else { check_non_const_operands(cx, e, lhs); } }; diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs index 77ef4a43497..7d8aa3f56fe 100644 --- a/clippy_lints/src/operators/op_ref.rs +++ b/clippy_lints/src/operators/op_ref.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::get_enclosing_block; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; @@ -190,11 +189,9 @@ fn in_impl<'tcx>( && trait_id == bin_op && let Some(generic_args) = seg.args && let Some(GenericArg::Type(other_ty)) = generic_args.args.last() - { Some((item.self_ty, other_ty)) - } - else { + } else { None } } @@ -206,11 +203,9 @@ fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_> && let middle_ty_id = item.owner_id.to_def_id() && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind && let Res::Def(_, hir_ty_id) = path.res - { hir_ty_id == middle_ty_id - } - else { + } else { false } } diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 7ae269655c6..9db2e24630a 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -35,7 +34,7 @@ pub(super) fn check<'tcx>( "try", format!("std::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, - ); + ); } } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index b69d374fbfd..6e4e0c98d29 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -4,7 +4,6 @@ use clippy_utils::{ can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks, peel_hir_expr_while, CaptureKind, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; @@ -130,18 +129,29 @@ fn try_get_option_occurrence<'tcx>( .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()) { - let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" }; + let capture_mut = if bind_annotation == BindingAnnotation::MUT { + "mut " + } else { + "" + }; let some_body = peel_blocks(if_then); let none_body = peel_blocks(if_else); - let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; + let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { + "map_or" + } else { + "map_or_else" + }; let capture_name = id.name.to_ident_string(); let (as_ref, as_mut) = match &expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => { (mutb == Mutability::Not, mutb == Mutability::Mut) - } - _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT), + }, + _ => ( + bind_annotation == BindingAnnotation::REF, + bind_annotation == BindingAnnotation::REF_MUT, + ), }; // Check if captures the closure will need conflict with borrows made in the scrutinee. @@ -152,10 +162,19 @@ fn try_get_option_occurrence<'tcx>( ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e), _ => None, }); - if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind { - match some_captures.get(local_id) - .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id))) - { + if let ExprKind::Path(QPath::Resolved( + None, + Path { + res: Res::Local(local_id), + .. + }, + )) = e.kind + { + match some_captures.get(local_id).or_else(|| { + (method_sugg == "map_or_else") + .then_some(()) + .and_then(|()| none_captures.get(local_id)) + }) { Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, Some(CaptureKind::Ref(Mutability::Not)) | None => (), @@ -183,7 +202,13 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "}, + if method_sugg == "map_or" || is_argless_call { + "" + } else if is_result { + "|_| " + } else { + "|| " + }, Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), ), }); diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 36ad6cf5f9b..e661bfbb96c 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::SpanlessEq; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 105af98f1aa..1b06762415d 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_hir; -use if_chain::if_chain; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -34,7 +33,11 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]); impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind + if let ItemKind::Impl(Impl { + of_trait: Some(ref trait_ref), + items: impl_items, + .. + }) = item.kind && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) && let Some(eq_trait) = cx.tcx.lang_items().eq_trait() && trait_ref.path.res.def_id() == eq_trait diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 3a6f37f01a8..0f025c16ab5 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -5,7 +5,6 @@ use clippy_utils::source::snippet; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{is_self, is_self_ty}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -238,7 +237,10 @@ impl<'tcx> PassByRefOrValue { cx, LARGE_TYPES_PASSED_BY_VALUE, input.span, - &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size), + &format!( + "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", + self.value_max_size + ), "consider passing by reference instead", format!("&{}", snippet(cx, input.span, "_")), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 0aebd9a6df3..b638e83997a 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp}; use rustc_ast::token; use rustc_errors::Applicability; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 0c01934433a..5c395143b9a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -10,7 +10,6 @@ use clippy_utils::{ is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; @@ -226,8 +225,8 @@ impl QuestionMark { { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) && - !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { if eq_expr_value(cx, caller, peel_blocks(else_inner)) { format!("Some({receiver_str}?)") @@ -252,7 +251,12 @@ impl QuestionMark { fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if !self.inside_try_block() - && let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr) + && let Some(higher::IfLet { + let_pat, + let_expr, + if_then, + if_else, + }) = higher::IfLet::hir(cx, expr) && !is_else_clause(cx.tcx, expr) && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind && ddpos.as_opt_usize().is_none() @@ -264,11 +268,14 @@ impl QuestionMark { ident.name, let_expr, if_then, - if_else + if_else, ) && ((is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) || is_early_return(sym::Result, cx, &if_block)) - && if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none() + && if_else + .map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))) + .filter(|e| *e) + .is_none() { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index f62acc79b03..9bdba994020 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -4,7 +4,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; -use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; @@ -350,7 +349,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { && let Some(higher::Range { start, end: Some(end), - limits: RangeLimits::HalfOpen + limits: RangeLimits::HalfOpen, }) = higher::Range::hir(expr) && let Some(y) = y_plus_one(cx, end) { @@ -365,12 +364,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { let end = Sugg::hir(cx, y, "y").maybe_par(); if let Some(is_wrapped) = &snippet_opt(cx, span) { if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { - diag.span_suggestion( - span, - "use", - format!("({start}..={end})"), - Applicability::MaybeIncorrect, - ); + diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect); } else { diag.span_suggestion( span, @@ -388,7 +382,11 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { // inclusive range minus one: `x..=(y-1)` fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { if expr.span.can_be_used_for_suggestions() - && let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr) + && let Some(higher::Range { + start, + end: Some(end), + limits: RangeLimits::Closed, + }) = higher::Range::hir(expr) && let Some(y) = y_minus_one(cx, end) { span_lint_and_then( @@ -440,7 +438,11 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { } } - if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr) + if let Some(higher::Range { + start: Some(start), + end: Some(end), + limits, + }) = higher::Range::hir(expr) && let ty = cx.typeck_results().expr_ty(start) && let ty::Int(_) | ty::Uint(_) = ty.kind() && let Some(start_idx) = constant(cx, cx.typeck_results(), start) @@ -471,7 +473,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { let end_snippet = snippet(cx, end.span, "_"); let dots = match limits { RangeLimits::HalfOpen => "..", - RangeLimits::Closed => "..=" + RangeLimits::Closed => "..=", }; diag.span_suggestion( diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 7d86252e6c5..b99af44655d 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -122,13 +122,13 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { && let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind && let TyKind::Path(ref ty_path) = ty.kind && let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id() - { if last_path_segment(func_path).ident.name == sym::new && let Some(symbol) = cx .tcx .get_diagnostic_name(def_id) - .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) { + .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) + { return Some((symbol, func.span)); } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index ecc5a28519b..88dbf9ef549 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -3,7 +3,6 @@ use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{def_id, Body, FnDecl, LangItem}; @@ -147,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // receiver of the `deref()` call let (pred_arg, deref_clone_ret) = if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) = - is_call_with_ref_arg(cx, mir, &pred_terminator.kind) + is_call_with_ref_arg(cx, mir, &pred_terminator.kind) && res == cloned && cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id) && (is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf) @@ -213,31 +212,25 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { if let Some(snip) = snippet_opt(cx, span) && let Some(dot) = snip.rfind('.') { - let sugg_span = span.with_lo( - span.lo() + BytePos(u32::try_from(dot).unwrap()) - ); + let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap())); let mut app = Applicability::MaybeIncorrect; let call_snip = &snip[dot + 1..]; // Machine applicable when `call_snip` looks like `foobar()` if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) { - if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') { + if call_snip + .as_bytes() + .iter() + .all(|b| b.is_ascii_alphabetic() || *b == b'_') + { app = Applicability::MachineApplicable; } } span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| { - diag.span_suggestion( - sugg_span, - "remove this", - "", - app, - ); + diag.span_suggestion(sugg_span, "remove this", "", app); if clone_usage.cloned_used { - diag.span_note( - span, - "cloned value is neither consumed nor mutated", - ); + diag.span_note(span, "cloned value is neither consumed nor mutated"); } else { diag.span_note( span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())), @@ -258,7 +251,12 @@ fn is_call_with_ref_arg<'tcx>( mir: &'tcx mir::Body<'tcx>, kind: &'tcx mir::TerminatorKind<'tcx>, ) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, mir::Local)> { - if let mir::TerminatorKind::Call { func, args, destination, .. } = kind + if let mir::TerminatorKind::Call { + func, + args, + destination, + .. + } = kind && args.len() == 1 && let mir::Operand::Move(mir::Place { local, .. }) = &args[0] && let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind() diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index e8906d51e88..f2a006ebdfc 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -2,7 +2,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit as hir_visit; @@ -141,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { } if let hir::ExprKind::Call(recv, _) = expr.kind - // don't lint if the receiver is a call, too. + // don't lint if the receiver is a call, too. // we do this in order to prevent linting multiple times; consider: // `(|| || 1)()()` // ^^ we only want to lint for this call (but we walk up the calls to consider both calls). diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index d25e8c2de03..32e0c3749ab 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -46,7 +46,8 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]); impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) - && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) + && !cx.effective_visibilities.is_exported(item.owner_id.def_id) + && self.is_exported.last() == Some(&false) && is_not_macro_export(item) { let span = item.span.with_hi(item.ident.span.hi()); diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 48bcd676ab9..c9fc65653c2 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs}; -use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; @@ -86,9 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); - let needs_parens_for_prefix = parent_expr.map_or(false, |parent| { - parent.precedence().order() > PREC_PREFIX - }); + let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX); let mut app = Applicability::MachineApplicable; let ((lint, msg), help, sugg) = if expr_ty == indexed_ty { @@ -112,7 +109,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { .. }) ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| { - matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))) + matches!( + a.kind, + Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })) + ) }) { // The slice was used to make a temporary reference. (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead") @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), + Ty::new_projection(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), ) { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; @@ -153,15 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { return; }; - span_lint_and_sugg( - cx, - lint, - expr.span, - msg, - help, - sugg, - app, - ); + span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg, app); } } } diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 472cde7cd15..0ba898e75a1 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::last_path_segment; use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -43,9 +42,8 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { && let TyKind::Path(ref qpath) = &mut_ty.ty.kind && let last = last_path_segment(qpath) && let Some(def_id) = last.res.opt_def_id() - && cx.tcx.is_diagnostic_item(sym::Option, def_id) - && let Some(params) = last_path_segment(qpath).args + && let Some(params) = last_path_segment(qpath).args && params.parenthesized == GenericArgsParentheses::No && let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(inner_ty) => Some(inner_ty), @@ -53,7 +51,6 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { }) && let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind && inner_mut_ty.mutbl == Mutability::Not - { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 74d2814f91e..69818db7c82 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use if_chain::if_chain; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -58,12 +57,13 @@ impl EarlyLintPass for DerefAddrOf { // Remove leading whitespace from the given span // e.g: ` $visitor` turns into `$visitor` let trim_leading_whitespaces = |span| { - snippet_opt(cx, span).and_then(|snip| { - #[expect(clippy::cast_possible_truncation)] - snip.find(|c: char| !c.is_whitespace()).map(|pos| { - span.lo() + BytePos(pos as u32) + snippet_opt(cx, span) + .and_then(|snip| { + #[expect(clippy::cast_possible_truncation)] + snip.find(|c: char| !c.is_whitespace()) + .map(|pos| span.lo() + BytePos(pos as u32)) }) - }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) + .map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) }; let mut generate_snippet = |pattern: &str| { @@ -85,7 +85,12 @@ impl EarlyLintPass for DerefAddrOf { Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) } } else { - Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)) + Some(snippet_with_applicability( + cx, + addrof_target.span, + "_", + &mut applicability, + )) }; if let Some(sugg) = sugg { span_lint_and_sugg( diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 8913f4a2e7e..ad22b751bef 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -86,7 +86,6 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa && self_arg.peel_refs() == ret_ty // If `Self` is already marked as `#[must_use]`, no need for the attribute here. && !is_must_use_ty(cx, ret_ty) - { span_lint_and_help( cx, @@ -94,7 +93,7 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa span, "missing `#[must_use]` attribute on a method returning `Self`", None, - "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type" + "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type", ); } } @@ -115,7 +114,6 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse { // We don't want this method to be te implementation of a trait because the // `#[must_use]` should be put on the trait definition directly. && cx.tcx.trait_id_of_impl(impl_def).is_none() - { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def); check_method(cx, decl, fn_def, span, hir_id.expect_owner()); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index bab20d0e1f6..7468bda02e8 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -4,7 +4,6 @@ use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -220,10 +219,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } err.multipart_suggestion( "return the expression directly", - vec![ - (local.span, String::new()), - (retexpr.span, snippet), - ], + vec![(local.span, String::new()), (retexpr.span, snippet)], Applicability::MachineApplicable, ); } else { diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index a6ad0b5cc1e..52475ff9ef7 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -75,8 +75,9 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { match of_trait { Some(trait_ref) => { - let mut methods_in_trait: BTreeSet = if let Some(Node::TraitRef(TraitRef { path, .. })) = - cx.tcx.hir().find(trait_ref.hir_ref_id) + let mut methods_in_trait: BTreeSet = if let Some(Node::TraitRef(TraitRef { + path, .. + })) = cx.tcx.hir().find(trait_ref.hir_ref_id) && let Res::Def(DefKind::Trait, did) = path.res { // FIXME: if @@ -86,12 +87,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { cx.tcx .associated_items(did) .in_definition_order() - .filter(|assoc_item| { - matches!(assoc_item.kind, AssocKind::Fn) - }) + .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) .map(|assoc_item| assoc_item.name) .collect() - }else{ + } else { BTreeSet::new() }; diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 578188a66af..c1edcf509ef 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -75,8 +75,8 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { && let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did) && let Some(Node::Item(x)) = cx.tcx.hir().find(self_id) && let type_name = x.ident.name.as_str().to_lowercase() - && (impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name) - + && (impl_item.ident.name.as_str() == type_name + || impl_item.ident.name.as_str().replace('_', "") == type_name) { span_lint( cx, diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index dc606e90707..3aabcadaa1f 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -44,7 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { && t_expr.is_unit() && let mut app = Applicability::MachineApplicable && let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0 - && !snippet.ends_with('}') && !snippet.ends_with(';') + && !snippet.ends_with('}') + && !snippet.ends_with(';') && cx.sess().source_map().is_multiline(block.span) { // filter out the desugared `for` loop diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 2ea9122cfc4..0385f1a98e5 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -2,7 +2,6 @@ //! expecting a count of T use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TypeAndMut}; @@ -42,7 +41,10 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: if !inverted && let ExprKind::Path(ref count_func_qpath) = count_func.kind && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id() - && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::mem_size_of | sym::mem_size_of_val)) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::mem_size_of | sym::mem_size_of_val) + ) { cx.typeck_results().node_args(count_func.hir_id).types().next() } else { @@ -130,14 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { && let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false) && pointee_ty == ty_used_for_size_of { - span_lint_and_help( - cx, - SIZE_OF_IN_ELEMENT_COUNT, - count_expr.span, - LINT_MSG, - None, - HELP_MSG - ); + span_lint_and_help(cx, SIZE_OF_IN_ELEMENT_COUNT, count_expr.span, LINT_MSG, None, HELP_MSG); }; } } diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 7de0beb1292..733da790441 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -5,7 +5,6 @@ use clippy_utils::{ get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, paths, SpanlessEq, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; @@ -106,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { if let ExprKind::Assign(left, right, _) = expr.kind && let Some(local_id) = path_to_local(left) && let Some(size_expr) = Self::as_vec_initializer(cx, right) - { let vi = VecAllocation { local_id, @@ -125,7 +123,6 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { && let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind && let Some(init) = local.init && let Some(size_expr) = Self::as_vec_initializer(cx, init) - { let vi = VecAllocation { local_id, @@ -243,7 +240,6 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { && path_to_local_id(self_arg, self.vec_alloc.local_id) && path.ident.name == sym!(extend) && self.is_repeat_take(extend_arg) - { self.slow_expression = Some(InitializationType::Extend(expr)); } @@ -283,7 +279,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr { // Check that len expression is equals to `with_capacity` expression return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr) - || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity") + || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity"); } self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index f4f0d0ac551..baa9750cc01 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -5,7 +5,6 @@ use clippy_utils::{ get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls, peel_blocks, SpanlessEq, }; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath}; @@ -251,7 +250,6 @@ const MAX_LENGTH_BYTE_STRING_LIT: usize = 32; declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]); impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { - #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use rustc_ast::LitKind; @@ -270,16 +268,11 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { // Check for slicer && let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind - { let mut applicability = Applicability::MachineApplicable; let string_expression = &expressions[0].0; - let snippet_app = snippet_with_applicability( - cx, - string_expression.span, "..", - &mut applicability, - ); + let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability); span_lint_and_sugg( cx, @@ -288,8 +281,8 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", "try", format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), - applicability - ) + applicability, + ); } if !in_external_macro(cx.sess(), e.span) @@ -348,7 +341,6 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { && matches!(path.ident.name.as_str(), "to_owned" | "to_string") && let ExprKind::Lit(lit) = &recv.kind && let LitKind::Str(lit_content, _) = &lit.node - && lit_content.as_str().is_ascii() && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT && !recv.span.from_expansion() diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 23aa1f76d2d..644664b104d 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -3,7 +3,6 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::is_expr_unsafe; use clippy_utils::{get_parent_node, match_libc_symbol}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; @@ -53,11 +52,10 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { let ctxt = expr.span.ctxt(); let span = match get_parent_node(cx.tcx, expr.hir_id) { Some(Node::Block(&Block { - rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), span, .. - })) - if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => { - span - } + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + span, + .. + })) if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => span, _ => expr.span, }; diff --git a/clippy_lints/src/suspicious_doc_comments.rs b/clippy_lints/src/suspicious_doc_comments.rs index dd799d24ca3..cbd6e745841 100644 --- a/clippy_lints/src/suspicious_doc_comments.rs +++ b/clippy_lints/src/suspicious_doc_comments.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}; -use if_chain::if_chain; use rustc_ast::token::CommentKind; use rustc_ast::{AttrKind, AttrStyle, Attribute, Item}; use rustc_errors::Applicability; @@ -82,7 +81,7 @@ fn collect_doc_comment_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { let sugg = match com_kind { CommentKind::Line => format!("//!{com}"), - CommentKind::Block => format!("/*!{com}*/") + CommentKind::Block => format!("/*!{com}*/"), }; Some((attr.span, sugg)) } else { diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index eff0c8cd561..92de7917871 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -2,7 +2,6 @@ use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; -use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -168,19 +167,9 @@ fn check_binops(cx: &EarlyContext<'_>, binops: &[&BinaryOp<'_>]) { return; }; - if let Some(sugg) = ident_swap_sugg( - cx, - &paired_identifiers, - binop, - changed_loc, - &mut applicability, - ) { - emit_suggestion( - cx, - binop.span, - sugg, - applicability, - ); + if let Some(sugg) = ident_swap_sugg(cx, &paired_identifiers, binop, changed_loc, &mut applicability) + { + emit_suggestion(cx, binop.span, sugg, applicability); } } }, @@ -210,16 +199,10 @@ fn attempt_to_emit_no_difference_lint( let old_right_ident = get_ident(binop.right, expected_loc); for b in skip_index(binops.iter(), i) { - if let (Some(old_ident), Some(new_ident)) = - (old_left_ident, get_ident(b.left, expected_loc)) + if let (Some(old_ident), Some(new_ident)) = (old_left_ident, get_ident(b.left, expected_loc)) && old_ident != new_ident - && let Some(sugg) = suggestion_with_swapped_ident( - cx, - binop.left, - expected_loc, - new_ident, - &mut applicability, - ) + && let Some(sugg) = + suggestion_with_swapped_ident(cx, binop.left, expected_loc, new_ident, &mut applicability) { emit_suggestion( cx, @@ -230,16 +213,10 @@ fn attempt_to_emit_no_difference_lint( return; } - if let (Some(old_ident), Some(new_ident)) = - (old_right_ident, get_ident(b.right, expected_loc)) + if let (Some(old_ident), Some(new_ident)) = (old_right_ident, get_ident(b.right, expected_loc)) && old_ident != new_ident - && let Some(sugg) = suggestion_with_swapped_ident( - cx, - binop.right, - expected_loc, - new_ident, - &mut applicability, - ) + && let Some(sugg) = + suggestion_with_swapped_ident(cx, binop.right, expected_loc, new_ident, &mut applicability) { emit_suggestion( cx, diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index b2badd7b2ac..3244933a124 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::visitors::for_each_expr; use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -84,7 +83,11 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { cx, lint, binop.span, - &format!("suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id)), + &format!( + "suspicious use of `{}` in `{}` impl", + binop.node.as_str(), + cx.tcx.item_name(trait_id) + ), ); } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 29f85907f9e..285f2f4f6f9 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -3,7 +3,6 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -173,7 +172,6 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { && s3.span.ctxt() == ctxt && first.span.ctxt() == ctxt && second.span.ctxt() == ctxt - { let span = s1.span.to(s3.span); generate_swap_warning(cx, lhs1, lhs2, span, false); diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 6990e7468f8..1dca523a966 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::match_def_path; use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -51,20 +50,24 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { } else { None } - } + }, hir::ExprKind::Call(to_digits_call, to_digit_args) => { if let [char_arg, radix_arg] = *to_digit_args && let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id) && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id() - && match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "", "to_digit"]) + && match_def_path( + cx, + to_digits_def_id, + &["core", "char", "methods", "", "to_digit"], + ) { Some((false, char_arg, radix_arg)) } else { None } - } - _ => None + }, + _ => None, }; if let Some((is_method_call, char_arg, radix_arg)) = match_result { diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 0bcb1afeea2..e624bbe5ff1 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; -use if_chain::if_chain; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unhash::UnhashMap; @@ -129,19 +128,19 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { && !bound_predicate.span.from_expansion() && let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind && let Some(PathSegment { - res: Res::SelfTyParam { trait_: def_id }, .. + res: Res::SelfTyParam { trait_: def_id }, + .. }) = segments.first() - && let Some( - Node::Item( - Item { - kind: ItemKind::Trait(_, _, _, self_bounds, _), - .. } - ) - ) = cx.tcx.hir().get_if_local(*def_id) + && let Some(Node::Item(Item { + kind: ItemKind::Trait(_, _, _, self_bounds, _), + .. + })) = cx.tcx.hir().get_if_local(*def_id) { if self_bounds_map.is_empty() { for bound in *self_bounds { - let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue }; + let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { + continue; + }; self_bounds_map.insert(self_res, self_segments); } } @@ -173,7 +172,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { && let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind && bounds.len() > 2 { - // Build up a hash of every trait we've seen // When we see a trait for the first time, add it to unique_traits // so we can later use it to build a string of all traits exactly once, without duplicates @@ -184,7 +182,9 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // Iterate the bounds and add them to our seen hash // If we haven't yet seen it, add it to the fixed traits for bound in bounds { - let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; + let Some(def_id) = bound.trait_ref.trait_def_id() else { + continue; + }; let new_trait = seen_def_ids.insert(def_id); @@ -267,7 +267,11 @@ impl TraitBounds { && p.origin != PredicateOrigin::ImplTrait && p.bounds.len() as u64 <= self.max_trait_bounds && !p.span.from_expansion() - && let bounds = p.bounds.iter().filter(|b| !self.cannot_combine_maybe_bound(cx, b)).collect::>() + && let bounds = p + .bounds + .iter() + .filter(|b| !self.cannot_combine_maybe_bound(cx, b)) + .collect::>() && !bounds.is_empty() && let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds) && !is_from_proc_macro(cx, p.bounded_ty) @@ -314,11 +318,17 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { .filter_map(|pred| { if pred.in_where_clause() && let WherePredicate::BoundPredicate(bound_predicate) = pred - && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind + && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind { return Some( - rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements") - .into_iter().map(|(trait_ref, _)| (path.res, trait_ref))) + rollup_traits( + cx, + bound_predicate.bounds, + "these where clauses contain repeated elements", + ) + .into_iter() + .map(|(trait_ref, _)| (path.res, trait_ref)), + ); } None }) @@ -335,7 +345,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if let WherePredicate::BoundPredicate(bound_predicate) = predicate && bound_predicate.origin != PredicateOrigin::ImplTrait && !bound_predicate.span.from_expansion() - && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind + && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind { let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements"); for (trait_ref, span) in traits { @@ -393,7 +403,9 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { Some(segment.args?.args.iter().filter_map(|arg| { if let GenericArg::Type(ty) = arg && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - { return Some(path.res) } + { + return Some(path.res); + } None })) }) @@ -432,12 +444,11 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) - comparable_bounds[i] = (k, v); } - if repeated_res - && let [first_trait, .., last_trait] = bounds - { + if repeated_res && let [first_trait, .., last_trait] = bounds { let all_trait_span = first_trait.span().to(last_trait.span()); - let traits = comparable_bounds.iter() + let traits = comparable_bounds + .iter() .filter_map(|&(_, span)| snippet_opt(cx, span)) .collect::>(); let traits = traits.join(" + "); @@ -449,7 +460,7 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) - msg, "try", traits, - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 89580005c52..a3a50acb609 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -19,7 +19,6 @@ mod wrong_transmute; use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; -use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -530,10 +529,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) - | ( - unsound_collection_transmute::check(cx, e, from_ty, to_ty) - || transmute_undefined_repr::check(cx, e, from_ty, to_ty) - ); + | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) + || transmute_undefined_repr::check(cx, e, from_ty, to_ty)); if !linted { transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg); diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index fe30a585da0..aef520923e4 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -1,7 +1,6 @@ use super::TRANSMUTE_FLOAT_TO_INT; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg; -use if_chain::if_chain; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; @@ -40,7 +39,7 @@ pub(super) fn check<'tcx>( let op = format!("{sugg}{}", float_ty.name_str()).into(); match sugg { sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op), - _ => sugg = sugg::Sugg::NonParen(op) + _ => sugg = sugg::Sugg::NonParen(op), } } diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 52bb68845db..98e9ea2d775 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -2,7 +2,6 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::sugg; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; @@ -26,11 +25,7 @@ pub(super) fn check<'tcx>( && let ty::Uint(ty::UintTy::U8) = slice_ty.kind() && from_mutbl == to_mutbl { - let postfix = if *from_mutbl == Mutability::Mut { - "_mut" - } else { - "" - }; + let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" }; let snippet = snippet(cx, arg.span, ".."); @@ -48,39 +43,36 @@ pub(super) fn check<'tcx>( Applicability::MaybeIncorrect, ); triggered = true; - } else { - if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) - && !const_context { - span_lint_and_then( - cx, - TRANSMUTE_PTR_TO_PTR, - e.span, - "transmute from a reference to a reference", - |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { + } else if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) && !const_context { + span_lint_and_then( + cx, + TRANSMUTE_PTR_TO_PTR, + e.span, + "transmute from a reference to a reference", + |diag| { + if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { let ty_from_and_mut = ty::TypeAndMut { ty: *ty_from, - mutbl: *from_mutbl + mutbl: *from_mutbl, + }; + let ty_to_and_mut = ty::TypeAndMut { + ty: *ty_to, + mutbl: *to_mutbl, }; - let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl }; let sugg_paren = arg - .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut)) - .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut)); + .as_ty(Ty::new_ptr(cx.tcx, ty_from_and_mut)) + .as_ty(Ty::new_ptr(cx.tcx, ty_to_and_mut)); let sugg = if *to_mutbl == Mutability::Mut { sugg_paren.mut_addr_deref() } else { sugg_paren.addr_deref() }; - diag.span_suggestion( - e.span, - "try", - sugg, - Applicability::Unspecified, - ); - }, - ); + diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); + } + }, + ); - triggered = true; - } + triggered = true; } } diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index a67431123ad..801e8862619 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind, diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index badd8acbc90..fc3420af020 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -21,11 +21,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, BOX_COLLECTION, hir_ty.span, - &format!( - "you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), + &format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), None, - &format!( - "`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation") + &format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), ); true } else { diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index 98284031344..d12d14f2b14 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::{path_def_id, qpath_generic_tys}; -use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/types/rc_mutex.rs b/clippy_lints/src/types/rc_mutex.rs index 1ab4d233ff7..afc31921704 100644 --- a/clippy_lints/src/types/rc_mutex.rs +++ b/clippy_lints/src/types/rc_mutex.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{path_def_id, qpath_generic_tys}; -use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; @@ -9,7 +8,7 @@ use rustc_span::symbol::sym; use super::RC_MUTEX; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if cx.tcx.is_diagnostic_item(sym::Rc, def_id) + if cx.tcx.is_diagnostic_item(sym::Rc, def_id) && let Some(arg) = qpath_generic_tys(qpath).next() && let Some(id) = path_def_id(cx, arg) && cx.tcx.is_diagnostic_item(sym::Mutex, id) diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index 7278447a70e..b1aa1ab4566 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -1,5 +1,4 @@ use clippy_utils::last_path_segment; -use if_chain::if_chain; use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index ff616805d08..a7119434517 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -161,7 +161,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt return Some(TargetVec { location: VecLocation::Local(hir_id), init_kind: Some(init_kind), - }) + }); } }, StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind { diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 8145c4e5108..385f8255a39 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use if_chain::if_chain; use rustc_hir::def_id::DefId; use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -128,7 +127,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa { let data = stmt.span.data(); // Make a span out of the semicolon for the help message - Some((fn_decl_span, Some(data.with_lo(data.hi-BytePos(1))))) + Some((fn_decl_span, Some(data.with_lo(data.hi - BytePos(1))))) } else { Some((fn_decl_span, None)) } diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 76d07f77f46..44cff78a793 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; @@ -84,12 +83,8 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp && let StmtKind::Semi(last_expr) = last_stmt.kind && let Some(snip) = snippet_opt(cx, last_expr.span) { - Some(( - last_stmt.span, - snip, - )) - } - else { + Some((last_stmt.span, snip)) + } else { None } }) diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index bc217ac2906..2223cbcb060 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -78,7 +77,8 @@ impl LateLintPass<'_> for UnnamedAddress { if let ExprKind::Binary(binop, left, right) = expr.kind && is_comparison(binop.node) - && is_trait_ptr(cx, left) && is_trait_ptr(cx, right) + && is_trait_ptr(cx, left) + && is_trait_ptr(cx, right) { span_lint_and_help( cx, diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 70c276fe1ce..14694bb3a28 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; @@ -44,34 +43,32 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { && inner_str.is_str() { if match_def_path(cx, fun_def_id, &paths::STRING_NEW) { - span_lint_and_sugg( - cx, - UNNECESSARY_OWNED_EMPTY_STRINGS, - expr.span, - "usage of `&String::new()` for a function expecting a `&str` argument", - "try", - "\"\"".to_owned(), - Applicability::MachineApplicable, - ); - } else { - if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id) - && let [.., last_arg] = args - && let ExprKind::Lit(spanned) = &last_arg.kind - && let LitKind::Str(symbol, _) = spanned.node - && symbol.is_empty() - && let inner_expr_type = cx.typeck_results().expr_ty(inner_expr) - && is_type_lang_item(cx, inner_expr_type, LangItem::String) - { - span_lint_and_sugg( - cx, - UNNECESSARY_OWNED_EMPTY_STRINGS, - expr.span, - "usage of `&String::from(\"\")` for a function expecting a `&str` argument", - "try", - "\"\"".to_owned(), - Applicability::MachineApplicable, - ); - } + span_lint_and_sugg( + cx, + UNNECESSARY_OWNED_EMPTY_STRINGS, + expr.span, + "usage of `&String::new()` for a function expecting a `&str` argument", + "try", + "\"\"".to_owned(), + Applicability::MachineApplicable, + ); + } else if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id) + && let [.., last_arg] = args + && let ExprKind::Lit(spanned) = &last_arg.kind + && let LitKind::Str(symbol, _) = spanned.node + && symbol.is_empty() + && let inner_expr_type = cx.typeck_results().expr_ty(inner_expr) + && is_type_lang_item(cx, inner_expr_type, LangItem::String) + { + span_lint_and_sugg( + cx, + UNNECESSARY_OWNED_EMPTY_STRINGS, + expr.span, + "usage of `&String::from(\"\")` for a function expecting a `&str` argument", + "try", + "\"\"".to_owned(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 338a4daf6c1..1e2b20469ef 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use if_chain::if_chain; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -42,7 +41,6 @@ impl EarlyLintPass for UnnecessarySelfImports { && let [self_seg] = &*self_tree.prefix.segments && self_seg.ident.name == kw::SelfLower && let Some(last_segment) = use_tree.prefix.segments.last() - { span_lint_and_then( cx, @@ -56,7 +54,11 @@ impl EarlyLintPass for UnnecessarySelfImports { format!( "{}{};", last_segment.ident, - if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() }, + if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { + format!(" as {alias}") + } else { + String::new() + }, ), Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 8b1d9d4a739..5599a9dc4e8 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::{OptionSome, ResultOk}; @@ -126,16 +125,14 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Make sure the function argument does not contain a return expression. && !contains_return(arg) { - suggs.push( - ( - ret_expr.span, - if inner_type.is_unit() { - String::new() - } else { - snippet(cx, arg.span.source_callsite(), "..").to_string() - } - ) - ); + suggs.push(( + ret_expr.span, + if inner_type.is_unit() { + String::new() + } else { + snippet(cx, arg.span.source_callsite(), "..").to_string() + }, + )); true } else { false diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 1ecce18c9ae..532207310bc 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::visitors::is_local_used; -use if_chain::if_chain; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 7ceb6df9c44..633040f2633 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{position_before_rarrow, snippet_opt}; -use if_chain::if_chain; use rustc_ast::visit::FnKind; use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; @@ -40,7 +39,9 @@ impl EarlyLintPass for UnusedUnit { fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { if let ast::FnRetTy::Ty(ref ty) = kind.decl().output && let ast::TyKind::Tup(ref vals) = ty.kind - && vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span) + && vals.is_empty() + && !ty.span.from_expansion() + && get_def(span) == get_def(ty.span) { // implicit types in closure signatures are forbidden when `for<...>` is present if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind { @@ -56,7 +57,8 @@ impl EarlyLintPass for UnusedUnit { && let ast::StmtKind::Expr(ref expr) = stmt.kind && is_unit_expr(expr) && let ctxt = block.span.ctxt() - && stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt + && stmt.span.ctxt() == ctxt + && expr.span.ctxt() == ctxt { let sp = expr.span; span_lint_and_sugg( diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 8b7429d8e38..5e5b1ab38e0 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{higher, path_to_local}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; @@ -156,39 +155,35 @@ fn collect_unwrap_info<'tcx>( } } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind { return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); - } else { - if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind - && let Some(local_id) = path_to_local(receiver) - && let ty = cx.typeck_results().expr_ty(receiver) - && let name = method_name.ident.as_str() - && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) - { - assert!(args.is_empty()); - let unwrappable = match name { - "is_some" | "is_ok" => true, - "is_err" | "is_none" => false, - _ => unreachable!(), - }; - let safe_to_unwrap = unwrappable != invert; - let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { - UnwrappableKind::Option - } else { - UnwrappableKind::Result - }; + } else if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind + && let Some(local_id) = path_to_local(receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && let name = method_name.ident.as_str() + && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) + { + assert!(args.is_empty()); + let unwrappable = match name { + "is_some" | "is_ok" => true, + "is_err" | "is_none" => false, + _ => unreachable!(), + }; + let safe_to_unwrap = unwrappable != invert; + let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { + UnwrappableKind::Option + } else { + UnwrappableKind::Result + }; - return vec![ - UnwrapInfo { - local_id, - if_expr, - check: expr, - check_name: method_name, - branch, - safe_to_unwrap, - kind, - is_entire_condition, - } - ] - } + return vec![UnwrapInfo { + local_id, + if_expr, + check: expr, + check_name: method_name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + }]; } Vec::new() } @@ -379,9 +374,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { PANICKING_UNWRAP, expr.hir_id, expr.span, - &format!("this call to `{}()` will always panic", - method_name.ident.name), - |diag| { diag.span_label(unwrappable.check.span, "because of this check"); }, + &format!("this call to `{}()` will always panic", method_name.ident.name), + |diag| { + diag.span_label(unwrappable.check.span, "because of this check"); + }, ); } } diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index a3977f1b6c8..df4b42133f8 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -3,7 +3,6 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; use clippy_utils::{method_chain_args, return_ty}; use core::ops::ControlFlow; -use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 4bfd4d22c70..f058fe5f831 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -2,7 +2,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::ty::same_type_and_consts; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -93,23 +92,33 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { // relevant for linting, since this is the self type of the `impl` we're currently in. To // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that // we're in an `impl` or nested item, that we don't want to lint - let stack_item = if let ItemKind::Impl(Impl { self_ty, generics,.. }) = item.kind + let stack_item = if let ItemKind::Impl(Impl { self_ty, generics, .. }) = item.kind && let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args && parameters.as_ref().map_or(true, |params| { - params.parenthesized == GenericArgsParentheses::No + params.parenthesized == GenericArgsParentheses::No && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) }) && !item.span.from_expansion() - && !is_from_proc_macro(cx, item) // expensive, should be last check + && !is_from_proc_macro(cx, item) + // expensive, should be last check { // Self cannot be used inside const generic parameters - let types_to_skip = generics.params.iter().filter_map(|param| { - match param { - GenericParam { kind: GenericParamKind::Const { ty: Ty { hir_id, ..}, ..}, ..} => Some(*hir_id), + let types_to_skip = generics + .params + .iter() + .filter_map(|param| match param { + GenericParam { + kind: + GenericParamKind::Const { + ty: Ty { hir_id, .. }, .. + }, + .. + } => Some(*hir_id), _ => None, - } - }).chain(std::iter::once(self_ty.hir_id)).collect(); + }) + .chain(std::iter::once(self_ty.hir_id)) + .collect(); StackItem::Check { impl_id: item.owner_id.def_id, in_body: 0, @@ -209,9 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind && !matches!( path.res, - Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } - | Res::Def(DefKind::TyParam, _) + Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _) ) && !types_to_skip.contains(&hir_ty.hir_id) && let ty = if in_body > 0 { @@ -230,7 +237,10 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last() && cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity() - {} else { return; } + { + } else { + return; + } match expr.kind { ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path), ExprKind::Call(fun, _) => { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index bc83fddcc53..52327b82e84 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -3,7 +3,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_con use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -311,14 +310,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into + if is_trait_method(cx, e, sym::TryInto) + && name.ident.name == sym::try_into && let a = cx.typeck_results().expr_ty(e) && let b = cx.typeck_results().expr_ty(recv) && is_type_diagnostic_item(cx, a, sym::Result) && let ty::Adt(_, args) = a.kind() && let Some(a_type) = args.types().next() && same_type_and_consts(a_type, b) - { span_lint_and_help( cx, @@ -343,7 +342,6 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { && let ty::Adt(_, args) = a.kind() && let Some(a_type) = args.types().next() && same_type_and_consts(a_type, b) - { let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); span_lint_and_help( @@ -356,14 +354,10 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } - if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) - && same_type_and_consts(a, b) - - { + if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) && same_type_and_consts(a, b) { let mut app = Applicability::MachineApplicable; let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); - let sugg_msg = - format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); + let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( cx, USELESS_CONVERSION, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index ddcb9f27c6c..877a77fd6d2 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,7 +1,6 @@ pub mod almost_standard_lint_formulation; pub mod collapsible_calls; pub mod compiler_lint_functions; -pub mod if_chain_style; pub mod interning_defined_symbol; pub mod invalid_paths; pub mod lint_without_lint_pass; diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index 1ed74982486..f514f166cff 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, Expr, ExprKind}; diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index 6781c1aef3e..5aa1417cfb4 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::match_type; use clippy_utils::{is_lint_allowed, paths}; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/clippy_lints/src/utils/internal_lints/if_chain_style.rs deleted file mode 100644 index 873e136136f..00000000000 --- a/clippy_lints/src/utils/internal_lints/if_chain_style.rs +++ /dev/null @@ -1,160 +0,0 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::{higher, is_else_clause, is_expn_of}; -use if_chain::if_chain; -use rustc_hir as hir; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{BytePos, Span}; - -declare_clippy_lint! { - /// Finds unidiomatic usage of `if_chain!` - pub IF_CHAIN_STYLE, - internal, - "non-idiomatic `if_chain!` usage" -} - -declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]); - -impl<'tcx> LateLintPass<'tcx> for IfChainStyle { - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - let (local, after, if_chain_span) = if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts - && let Some(if_chain_span) = is_expn_of(block.span, "if_chain") - { (local, after, if_chain_span) } else { return }; - if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) { - span_lint( - cx, - IF_CHAIN_STYLE, - if_chain_local_span(cx, local, if_chain_span), - "`let` expression should be above the `if_chain!`", - ); - } else if local.span.eq_ctxt(block.span) && is_if_chain_then(after, block.expr, if_chain_span) { - span_lint( - cx, - IF_CHAIN_STYLE, - if_chain_local_span(cx, local, if_chain_span), - "`let` expression should be inside `then { .. }`", - ); - } - } - - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) { - (cond, then, r#else.is_some()) - } else { - return; - }; - let ExprKind::Block(then_block, _) = then.kind else { - return; - }; - let if_chain_span = is_expn_of(expr.span, "if_chain"); - if !els { - check_nested_if_chains(cx, expr, then_block, if_chain_span); - } - let Some(if_chain_span) = if_chain_span else { return }; - // check for `if a && b;` - if let ExprKind::Binary(op, _, _) = cond.kind - && op.node == BinOpKind::And - && cx.sess().source_map().is_multiline(cond.span) - { - span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`"); - } - if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span) - && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span) - { - span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`"); - } - } -} - -fn check_nested_if_chains( - cx: &LateContext<'_>, - if_expr: &Expr<'_>, - then_block: &Block<'_>, - if_chain_span: Option, -) { - #[rustfmt::skip] - let (head, tail) = match *then_block { - Block { stmts, expr: Some(tail), .. } => (stmts, tail), - Block { - stmts: &[ - ref head @ .., - Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. } - ], - .. - } => (head, tail), - _ => return, - }; - if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail) - && let sm = cx.sess().source_map() - && head - .iter() - .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span)) - && (if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr)) - { - } else { - return; - } - let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) { - (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"), - (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"), - (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"), - _ => return, - }; - span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| { - let (span, msg) = match head { - [] => return, - [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"), - [a, .., b] => ( - a.span.to(b.span), - "these `let` statements can also be in the `if_chain!`", - ), - }; - diag.span_help(span, msg); - }); -} - -fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool { - cx.tcx - .hir() - .parent_iter(hir_id) - .find(|(_, node)| { - #[rustfmt::skip] - !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_)) - }) - .map_or(false, |(id, _)| { - is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span) - }) -} - -/// Checks a trailing slice of statements and expression of a `Block` to see if they are part -/// of the `then {..}` portion of an `if_chain!` -fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool { - let span = if let [stmt, ..] = stmts { - stmt.span - } else if let Some(expr) = expr { - expr.span - } else { - // empty `then {}` - return true; - }; - is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span) -} - -/// Creates a `Span` for `let x = ..;` in an `if_chain!` call. -fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span { - let mut span = local.pat.span; - if let Some(init) = local.init { - span = span.to(init.span); - } - span.adjust(if_chain_span.ctxt().outer_expn()); - let sm = cx.sess().source_map(); - let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span); - let span = sm.span_extend_to_next_char(span, ';', false); - Span::new( - span.lo() - BytePos(3), - span.hi() + BytePos(1), - span.ctxt(), - span.parent(), - ) -} diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index c2b36fc28f7..16d0636b834 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths}; -use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -161,7 +160,11 @@ impl InterningDefinedSymbol { static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING]; let call = if let ExprKind::AddrOf(_, _, e) = expr.kind && let ExprKind::Unary(UnOp::Deref, e) = e.kind - { e } else { expr }; + { + e + } else { + expr + }; if let ExprKind::MethodCall(_, item, [], _) = call.kind // is a method call && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id) diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index b5a4787175a..66d32087fcd 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -1,7 +1,6 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::def_path_res; use clippy_utils::diagnostics::span_lint; -use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::Item; diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 871c8f99ebf..486e8220484 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -2,7 +2,6 @@ use crate::utils::internal_lints::metadata_collector::is_deprecated_lint; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{is_lint_allowed, match_def_path, paths}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; @@ -315,7 +314,11 @@ pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item< && tool_name.ident.name == sym::clippy && attr_name.ident.name == sym::version && let Some(version) = attr.value_str() - { Some(version) } else { None } + { + Some(version) + } else { + None + } }) } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index e4e72bbc388..8ecdba47f89 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -14,7 +14,6 @@ use clippy_config::{get_configuration_metadata, ClippyConfiguration}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths}; -use if_chain::if_chain; use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; @@ -923,7 +922,6 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { if let ExprKind::Path(qpath) = &expr.kind && let QPath::Resolved(_, path) = qpath - && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)) && match_type(self.cx, expr_ty, &paths::LINT) { diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 1c09695c9dd..86b1a0ae624 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -23,11 +22,14 @@ declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]); impl LateLintPass<'_> for MsrvAttrImpl { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { if let hir::ItemKind::Impl(hir::Impl { - of_trait: Some(_), - items, - .. - }) = &item.kind - && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity) + of_trait: Some(_), + items, + .. + }) = &item.kind + && let Some(trait_ref) = cx + .tcx + .impl_trait_ref(item.owner_id) + .map(EarlyBinder::instantiate_identity) && let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS) && (is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS)) && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind() diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs index 78eeb04d58d..77b95e51f62 100644 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::match_type; use clippy_utils::{is_lint_allowed, method_calls, paths}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 3ad02afd88a..9aa23b6efe3 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs}; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::Applicability; @@ -109,7 +108,7 @@ impl UnnecessaryDefPath { && let item_arg = if which_path == 4 { &args[1] } else { &args[0] } // Extract the path to the matched type && let Some(segments) = path_to_matched_type(cx, item_arg) - && let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect() + && let segments = segments.iter().map(|sym| &**sym).collect::>() && let Some(def_id) = def_path_def_ids(cx, &segments[..]).next() { // Check if the target item is a diagnostic item or LangItem. diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index d215e6b5768..9ad2ad2d195 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -7,7 +7,6 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, higher, is_trait_method}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index c94ed82646e..5c1bea74486 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_test_module_or_function; use clippy_utils::source::{snippet, snippet_with_applicability}; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; @@ -139,10 +138,7 @@ impl LateLintPass<'_> for WildcardImports { // This is a `_::{_, *}` import // In this case `use_path.span` is empty and ends directly in front of the `*`, // so we need to extend it by one byte. - ( - use_path.span.with_hi(use_path.span.hi() + BytePos(1)), - true, - ) + (use_path.span.with_hi(use_path.span.hi() + BytePos(1)), true) } else { // In this case, the `use_path.span` ends right before the `::*`, so we need to // extend it up to the `*`. Since it is hard to find the `*` in weird @@ -153,9 +149,7 @@ impl LateLintPass<'_> for WildcardImports { if snippet(cx, span, "").ends_with(';') { span = use_path.span.with_hi(item.span.hi() - BytePos(1)); } - ( - span, false, - ) + (span, false) }; let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(); @@ -180,15 +174,7 @@ impl LateLintPass<'_> for WildcardImports { (WILDCARD_IMPORTS, "usage of wildcard import") }; - span_lint_and_sugg( - cx, - lint, - span, - message, - "try", - sugg, - applicability, - ); + span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability); } } diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 7f7d30d03ab..1d6217d186c 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,6 +1,5 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,9 +44,8 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { // since we're about to suggest a use of f32::NAN or f64::NAN, // match the precision of the literals that are given. let float_type = match (lhs_value, rhs_value) { - (Constant::F64(_), _) - | (_, Constant::F64(_)) => "f64", - _ => "f32" + (Constant::F64(_), _) | (_, Constant::F64(_)) => "f64", + _ => "f32", }; span_lint_and_help( cx, @@ -55,9 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { expr.span, "constant division of `0.0` with `0.0` will always result in NaN", None, - &format!( - "consider using `{float_type}::NAN` if you would like a constant representing NaN", - ), + &format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), ); } } diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 6504b0fa5f9..41c1757fde8 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item}; -use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -60,7 +59,14 @@ impl LateLintPass<'_> for ZeroSizedMapValues { && let Ok(layout) = cx.layout_of(ty) && layout.is_zst() { - span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, hir_ty.span, "map with zero-sized value type", None, "consider using a set instead"); + span_lint_and_help( + cx, + ZERO_SIZED_MAP_VALUES, + hir_ty.span, + "map with zero-sized value type", + None, + "consider using a set instead", + ); } } } diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index c9b01a68f42..1f9802dc5ee 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -7,7 +7,6 @@ publish = false [dependencies] clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } -if_chain = "1.0" itertools = "0.10.1" rustc-semver = "1.1" diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 791f815c850..3748e2a26d1 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -2,7 +2,7 @@ use crate::source::{get_source_text, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; -use if_chain::if_chain; + use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; @@ -377,7 +377,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && let res = self.typeck_results.qpath_res(qpath, callee.hir_id) && let Some(def_id) = res.opt_def_id() && let def_path = self.lcx.get_def_path(def_id) - && let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect() + && let def_path = def_path.iter().take(4).map(Symbol::as_str).collect::>() && let ["core", "num", int_impl, "max_value"] = *def_path { let value = match int_impl { diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 93cd5b3fe1e..3135a033648 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -5,7 +5,7 @@ use crate::consts::{constant_simple, Constant}; use crate::ty::is_type_diagnostic_item; use crate::{is_expn_of, match_def_path, paths}; -use if_chain::if_chain; + use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath}; @@ -286,7 +286,8 @@ impl<'a> VecArgs<'a> { } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { // `vec![a, b, c]` case if let hir::ExprKind::Call(_, [arg]) = &args[0].kind - && let hir::ExprKind::Array(args) = arg.kind { + && let hir::ExprKind::Array(args) = arg.kind + { Some(VecArgs::Vec(args)) } else { None diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e3c26525a6a..21225dc7098 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -76,7 +76,6 @@ use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use std::sync::{Mutex, MutexGuard, OnceLock}; -use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; @@ -823,7 +822,11 @@ pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() && (is_diag_trait_item(cx, repl_def_id, sym::Default) || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath)) - { true } else { false } + { + true + } else { + false + } } /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. @@ -837,14 +840,16 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { _ => false, }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), - ExprKind::Repeat(x, ArrayLen::Body(len)) => if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind - && let LitKind::Int(v, _) = const_lit.node - && v <= 32 && is_default_equivalent(cx, x) - { - true - } - else { - false + ExprKind::Repeat(x, ArrayLen::Body(len)) => { + if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind + && let LitKind::Int(v, _) = const_lit.node + && v <= 32 + && is_default_equivalent(cx, x) + { + true + } else { + false + } }, ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func), ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg), @@ -1992,12 +1997,14 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t // check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { - ExprKind::Call(path, _) => if let ExprKind::Path(ref qpath) = path.kind - && let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) - { - Some(did) - } else { - None + ExprKind::Call(path, _) => { + if let ExprKind::Path(ref qpath) = path.kind + && let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) + { + Some(did) + } else { + None + } }, ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), _ => None, diff --git a/tests/ui-internal/if_chain_style.rs b/tests/ui-internal/if_chain_style.rs deleted file mode 100644 index b462b20e04c..00000000000 --- a/tests/ui-internal/if_chain_style.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![warn(clippy::if_chain_style)] -#![allow( - clippy::needless_if, - clippy::no_effect, - clippy::nonminimal_bool, - clippy::missing_clippy_version_attribute -)] - -extern crate if_chain; - -use if_chain::if_chain; - -fn main() { - if true { - let x = ""; - // `if_chain!` inside `if` - if_chain! { - if true; - if true; - then {} - } - } - if_chain! { - if true - // multi-line AND'ed conditions - && false; - if let Some(1) = Some(1); - // `let` before `then` - let x = ""; - then { - (); - } - } - if_chain! { - // single `if` condition - if true; - then { - let x = ""; - // nested if - if true {} - } - } - if_chain! { - // starts with `let ..` - let x = ""; - if let Some(1) = Some(1); - then { - let x = ""; - let x = ""; - // nested if_chain! - if_chain! { - if true; - if true; - then {} - } - } - } -} - -fn negative() { - if true { - (); - if_chain! { - if true; - if true; - then { (); } - } - } - if_chain! { - if true; - let x = ""; - if true; - then { (); } - } - if_chain! { - if true; - if true; - then { - if true { 1 } else { 2 } - } else { - 3 - } - }; - if true { - if_chain! { - if true; - if true; - then {} - } - } else if false { - if_chain! { - if true; - if false; - then {} - } - } -} diff --git a/tests/ui-internal/if_chain_style.stderr b/tests/ui-internal/if_chain_style.stderr deleted file mode 100644 index ea04955323d..00000000000 --- a/tests/ui-internal/if_chain_style.stderr +++ /dev/null @@ -1,86 +0,0 @@ -error: this `if` can be part of the inner `if_chain!` - --> $DIR/if_chain_style.rs:14:5 - | -LL | / if true { -LL | | let x = ""; -LL | | // `if_chain!` inside `if` -LL | | if_chain! { -... | -LL | | } -LL | | } - | |_____^ - | -help: this `let` statement can also be in the `if_chain!` - --> $DIR/if_chain_style.rs:15:9 - | -LL | let x = ""; - | ^^^^^^^^^^^ - = note: `-D clippy::if-chain-style` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::if_chain_style)]` - -error: `if a && b;` should be `if a; if b;` - --> $DIR/if_chain_style.rs:24:12 - | -LL | if true - | ____________^ -LL | | // multi-line AND'ed conditions -LL | | && false; - | |____________________^ - -error: `let` expression should be inside `then { .. }` - --> $DIR/if_chain_style.rs:29:9 - | -LL | let x = ""; - | ^^^^^^^^^^^ - -error: this `if` can be part of the outer `if_chain!` - --> $DIR/if_chain_style.rs:40:13 - | -LL | if true {} - | ^^^^^^^^^^ - | -help: this `let` statement can also be in the `if_chain!` - --> $DIR/if_chain_style.rs:38:13 - | -LL | let x = ""; - | ^^^^^^^^^^^ - -error: `if_chain!` only has one `if` - --> $DIR/if_chain_style.rs:34:5 - | -LL | / if_chain! { -LL | | // single `if` condition -LL | | if true; -LL | | then { -... | -LL | | } -LL | | } - | |_____^ - | - = note: this error originates in the macro `__if_chain` which comes from the expansion of the macro `if_chain` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `let` expression should be above the `if_chain!` - --> $DIR/if_chain_style.rs:45:9 - | -LL | let x = ""; - | ^^^^^^^^^^^ - -error: this `if_chain!` can be merged with the outer `if_chain!` - --> $DIR/if_chain_style.rs:51:13 - | -LL | / if_chain! { -LL | | if true; -LL | | if true; -LL | | then {} -LL | | } - | |_____________^ - | -help: these `let` statements can also be in the `if_chain!` - --> $DIR/if_chain_style.rs:48:13 - | -LL | / let x = ""; -LL | | let x = ""; - | |_______________________^ - -error: aborting due to 7 previous errors - -- cgit 1.4.1-3-g733a5 From f1979d48d7b8b90bc45b2c4fa1afe62c3c1066e8 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 10 Nov 2023 23:41:57 +0000 Subject: Destructure `Conf` in `register_lints` --- CONTRIBUTING.md | 8 +- book/src/development/adding_lints.md | 2 +- book/src/development/defining_lints.md | 2 +- clippy_config/src/types.rs | 24 +--- clippy_lints/src/disallowed_names.rs | 4 +- clippy_lints/src/doc.rs | 4 +- clippy_lints/src/lib.rs | 185 ++++++++++++++------------- clippy_lints/src/methods/mod.rs | 4 +- clippy_lints/src/nonstandard_macro_braces.rs | 88 ++++--------- clippy_lints/src/pass_by_ref_or_value.rs | 5 +- clippy_lints/src/raw_strings.rs | 2 +- src/driver.rs | 2 +- 12 files changed, 138 insertions(+), 192 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04af1b98b55..b1a59238c82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -146,16 +146,10 @@ For example, the [`else_if_without_else`][else_if_without_else] lint is register pub mod else_if_without_else; // ... -pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { +pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { // ... store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); // ... - - store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ - // ... - LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), - // ... - ]); } ``` diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 3b26565369c..1803fc2d2f3 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -270,7 +270,7 @@ When using `cargo dev new_lint`, the lint is automatically registered and nothing more has to be done. When declaring a new lint by hand and `cargo dev update_lints` is used, the lint -pass may have to be registered manually in the `register_plugins` function in +pass may have to be registered manually in the `register_lints` function in `clippy_lints/src/lib.rs`: ```rust,ignore diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md index 7c4aa5d4523..54f77b00190 100644 --- a/book/src/development/defining_lints.md +++ b/book/src/development/defining_lints.md @@ -186,7 +186,7 @@ However, sometimes we might want to declare a new lint by hand. In this case, we'd use `cargo dev update_lints` command afterwards. When a lint is manually declared, we might need to register the lint pass -manually in the `register_plugins` function in `clippy_lints/src/lib.rs`: +manually in the `register_lints` function in `clippy_lints/src/lib.rs`: ```rust store.register_late_pass(|_| Box::new(foo_functions::FooFunctions)); diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index e898221ffa7..df48cc3f5e3 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -1,7 +1,6 @@ use serde::de::{self, Deserializer, Visitor}; use serde::{ser, Deserialize, Serialize}; use std::fmt; -use std::hash::{Hash, Hasher}; #[derive(Clone, Debug, Deserialize)] pub struct Rename { @@ -33,32 +32,19 @@ impl DisallowedPath { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum MatchLintBehaviour { AllTypes, WellKnownTypes, Never, } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct MacroMatcher { pub name: String, - pub braces: (String, String), + pub braces: (char, char), } -impl Hash for MacroMatcher { - fn hash(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl PartialEq for MacroMatcher { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} -impl Eq for MacroMatcher {} - impl<'de> Deserialize<'de> for MacroMatcher { fn deserialize(deser: D) -> Result where @@ -83,7 +69,7 @@ impl<'de> Deserialize<'de> for MacroMatcher { V: de::MapAccess<'de>, { let mut name = None; - let mut brace: Option = None; + let mut brace: Option = None; while let Some(key) = map.next_key()? { match key { Field::Name => { @@ -104,7 +90,7 @@ impl<'de> Deserialize<'de> for MacroMatcher { let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?; Ok(MacroMatcher { name, - braces: [("(", ")"), ("{", "}"), ("[", "]")] + braces: [('(', ')'), ('{', '}'), ('[', ']')] .into_iter() .find(|b| b.0 == brace) .map(|(o, c)| (o.to_owned(), c.to_owned())) diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 5e46b29b639..a1dd4805b9c 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -31,9 +31,9 @@ pub struct DisallowedNames { } impl DisallowedNames { - pub fn new(disallow: FxHashSet) -> Self { + pub fn new(disallowed_names: &[String]) -> Self { Self { - disallow, + disallow: disallowed_names.iter().cloned().collect(), test_modules_deep: 0, } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 587360545cb..6a12baa4201 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -268,9 +268,9 @@ pub struct DocMarkdown { } impl DocMarkdown { - pub fn new(valid_idents: FxHashSet) -> Self { + pub fn new(valid_idents: &[String]) -> Self { Self { - valid_idents, + valid_idents: valid_idents.iter().cloned().collect(), in_trait_impl: false, } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e5f8bd5c471..609ff3d051a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -52,7 +52,6 @@ extern crate declare_clippy_lint; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; -use rustc_session::Session; #[cfg(feature = "internal")] pub mod deprecated_lints; @@ -492,11 +491,83 @@ fn register_categories(store: &mut rustc_lint::LintStore) { groups.register(store); } -/// Register all lints and lint groups with the rustc plugin registry +/// Register all lints and lint groups with the rustc lint store /// /// Used in `./src/driver.rs`. #[expect(clippy::too_many_lines)] -pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) { +pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { + let Conf { + ref absolute_paths_allowed_crates, + absolute_paths_max_segments, + accept_comment_above_attributes, + accept_comment_above_statement, + allow_dbg_in_tests, + allow_expect_in_tests, + allow_mixed_uninlined_format_args, + allow_one_hash_in_raw_strings, + allow_print_in_tests, + allow_private_module_inception, + allow_unwrap_in_tests, + ref allowed_dotfiles, + ref allowed_idents_below_min_chars, + ref allowed_scripts, + ref arithmetic_side_effects_allowed_binary, + ref arithmetic_side_effects_allowed_unary, + ref arithmetic_side_effects_allowed, + array_size_threshold, + avoid_breaking_exported_api, + ref await_holding_invalid_types, + cargo_ignore_publish, + cognitive_complexity_threshold, + ref disallowed_macros, + ref disallowed_methods, + ref disallowed_names, + ref disallowed_types, + ref doc_valid_idents, + enable_raw_pointer_heuristic_for_send, + enforce_iter_loop_reborrow, + ref enforced_import_renames, + enum_variant_name_threshold, + enum_variant_size_threshold, + excessive_nesting_threshold, + future_size_threshold, + ref ignore_interior_mutability, + large_error_threshold, + literal_representation_threshold, + matches_for_let_else, + max_fn_params_bools, + max_include_file_size, + max_struct_bools, + max_suggested_slice_pattern_length, + max_trait_bounds, + min_ident_chars_threshold, + missing_docs_in_crate_items, + ref msrv, + pass_by_value_size_limit, + semicolon_inside_block_ignore_singleline, + semicolon_outside_block_ignore_multiline, + single_char_binding_names_threshold, + stack_size_threshold, + ref standard_macro_braces, + struct_field_name_threshold, + suppress_restriction_lint_in_const, + too_large_for_stack, + too_many_arguments_threshold, + too_many_lines_threshold, + trivial_copy_size_limit, + type_complexity_threshold, + unnecessary_box_size, + unreadable_literal_lint_fractions, + upper_case_acronyms_aggressive, + vec_box_size_threshold, + verbose_bit_mask_threshold, + warn_on_all_wildcard_imports, + + blacklisted_names: _, + cyclomatic_complexity_threshold: _, + } = *conf; + let msrv = || msrv.clone(); + register_removed_non_tool_lints(store); register_categories(store); @@ -536,9 +607,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); } - let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone(); - let arithmetic_side_effects_allowed_binary = conf.arithmetic_side_effects_allowed_binary.clone(); - let arithmetic_side_effects_allowed_unary = conf.arithmetic_side_effects_allowed_unary.clone(); store.register_late_pass(move |_| { Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new( arithmetic_side_effects_allowed @@ -556,16 +624,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::::default()); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); - let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); store.register_late_pass(move |_| { Box::new(await_holding_invalid::AwaitHolding::new( await_holding_invalid_types.clone(), )) }); store.register_late_pass(|_| Box::new(serde_api::SerdeApi)); - let vec_box_size_threshold = conf.vec_box_size_threshold; - let type_complexity_threshold = conf.type_complexity_threshold; - let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; store.register_late_pass(move |_| { Box::new(types::Types::new( vec_box_size_threshold, @@ -598,19 +662,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); - - let msrv = || conf.msrv.clone(); - let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; - let allow_expect_in_tests = conf.allow_expect_in_tests; - let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; - let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const; store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv()))); - let allowed_dotfiles = conf - .allowed_dotfiles - .iter() - .cloned() - .chain(methods::DEFAULT_ALLOWED_DOTFILES.iter().copied().map(ToOwned::to_owned)) - .collect::>(); store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, @@ -621,7 +673,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv()))); - let matches_for_let_else = conf.matches_for_let_else; store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv()))); store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv()))); store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv()))); @@ -638,7 +689,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv()))); store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod)); - let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; store.register_late_pass(move |_| { Box::new(index_refutable_slice::IndexRefutableSlice::new( max_suggested_slice_pattern_length, @@ -647,7 +697,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(unit_types::UnitTypes)); - let enforce_iter_loop_reborrow = conf.enforce_iter_loop_reborrow; store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv(), enforce_iter_loop_reborrow))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(lifetimes::Lifetimes)); @@ -661,13 +710,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(no_effect::NoEffect)); store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv()))); - let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; store.register_late_pass(move |_| { Box::new(cognitive_complexity::CognitiveComplexity::new( cognitive_complexity_threshold, )) }); - let too_large_for_stack = conf.too_large_for_stack; store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack })); store.register_late_pass(move |_| { Box::new(vec::UselessVec { @@ -683,18 +730,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); store.register_late_pass(|_| Box::::default()); - let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); store.register_late_pass(|_| Box::new(format::UselessFormat)); store.register_late_pass(|_| Box::new(swap::Swap)); store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|_| Box::::default()); - let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); - store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); - let too_many_arguments_threshold = conf.too_many_arguments_threshold; - let too_many_lines_threshold = conf.too_many_lines_threshold; - let large_error_threshold = conf.large_error_threshold; + store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names))); store.register_late_pass(move |_| { Box::new(functions::Functions::new( too_many_arguments_threshold, @@ -703,9 +745,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: avoid_breaking_exported_api, )) }); - let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); - let missing_docs_in_crate_items = conf.missing_docs_in_crate_items; - store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); + store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); @@ -715,17 +755,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk)); store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)); store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount)); - let enum_variant_size_threshold = conf.enum_variant_size_threshold; store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite)); store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue)); - let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new( - conf.trivial_copy_size_limit, - conf.pass_by_value_size_limit, - conf.avoid_breaking_exported_api, - &sess.target, - ); - store.register_late_pass(move |_| Box::new(pass_by_ref_or_value)); + store.register_late_pass(move |tcx| { + Box::new(pass_by_ref_or_value::PassByRefOrValue::new( + trivial_copy_size_limit, + pass_by_value_size_limit, + avoid_breaking_exported_api, + tcx.sess.target.pointer_width, + )) + }); store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef)); store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter)); store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody)); @@ -745,7 +785,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: suppress_restriction_lint_in_const, )) }); - let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone)); @@ -754,10 +793,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates)); store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString)); - let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv()))); store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain)); - let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone()))); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); @@ -778,21 +815,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(redundant_else::RedundantElse)); store.register_late_pass(|_| Box::new(create_dir::CreateDir)); store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType)); - let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; store.register_early_pass(move || { Box::new(literal_representation::LiteralDigitGrouping::new( - literal_representation_lint_fraction_readability, + unreadable_literal_lint_fractions, )) }); - let literal_representation_threshold = conf.literal_representation_threshold; store.register_early_pass(move || { Box::new(literal_representation::DecimalLiteralRepresentation::new( literal_representation_threshold, )) }); - let enum_variant_name_threshold = conf.enum_variant_name_threshold; - let struct_field_name_threshold = conf.struct_field_name_threshold; - let allow_private_module_inception = conf.allow_private_module_inception; store.register_late_pass(move |_| { Box::new(item_name_repetitions::ItemNameRepetitions::new( enum_variant_name_threshold, @@ -802,7 +834,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); - let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive; store.register_late_pass(move |_| { Box::new(upper_case_acronyms::UpperCaseAcronyms::new( avoid_breaking_exported_api, @@ -814,15 +845,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(exit::Exit)); store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); - let array_size_threshold = u128::from(conf.array_size_threshold); - store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); - store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); + store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold.into()))); + store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold.into()))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); store.register_late_pass(|_| Box::new(as_conversions::AsConversions)); store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore)); store.register_early_pass(|| Box::::default()); - let max_fn_params_bools = conf.max_fn_params_bools; - let max_struct_bools = conf.max_struct_bools; store.register_late_pass(move |_| { Box::new(excessive_bools::ExcessiveBools::new( max_struct_bools, @@ -830,36 +858,30 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); - let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(|_| Box::>::default()); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); - let future_size_threshold = conf.future_size_threshold; store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold))); store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|_| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn)); store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn)); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || { Box::new(non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, }) }); - let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::>(); - store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); + store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(standard_macro_braces))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch)); store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync)); - let disallowed_macros = conf.disallowed_macros.clone(); store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone()))); - let disallowed_methods = conf.disallowed_methods.clone(); store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone()))); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax)); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax)); @@ -874,36 +896,30 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_early_pass(move || Box::new(module_style::ModStyle)); store.register_late_pass(|_| Box::::default()); - let disallowed_types = conf.disallowed_types.clone(); store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone()))); - let import_renames = conf.enforced_import_renames.clone(); store.register_late_pass(move |_| { Box::new(missing_enforced_import_rename::ImportRename::new( - import_renames.clone(), + enforced_import_renames.clone(), )) }); - let scripts = conf.allowed_scripts.clone(); - store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts))); + store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(allowed_scripts))); store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings)); store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors)); store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator)); store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert)); - let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; store.register_late_pass(move |_| { Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new( enable_raw_pointer_heuristic_for_send, )) }); - let accept_comment_above_statement = conf.accept_comment_above_statement; - let accept_comment_above_attributes = conf.accept_comment_above_attributes; store.register_late_pass(move |_| { Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new( accept_comment_above_statement, accept_comment_above_attributes, )) }); - let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args; - store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined))); + store + .register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined_format_args))); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); @@ -913,11 +929,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv()))); store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_late_pass(|_| Box::::default()); - let allow_dbg_in_tests = conf.allow_dbg_in_tests; store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); - let allow_print_in_tests = conf.allow_print_in_tests; store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests))); - let cargo_ignore_publish = conf.cargo_ignore_publish; store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, @@ -928,7 +941,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); - let max_include_file_size = conf.max_include_file_size; store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); @@ -941,7 +953,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv()))); store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv()))); - let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv()))); @@ -958,8 +969,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); - let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline; - let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline; store.register_late_pass(move |_| { Box::new(semicolon_block::SemicolonBlock::new( semicolon_inside_block_ignore_singleline, @@ -982,7 +991,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); - let unnecessary_box_size = conf.unnecessary_box_size; store.register_late_pass(move |_| { Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new( avoid_breaking_exported_api, @@ -993,7 +1001,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); - let excessive_nesting_threshold = conf.excessive_nesting_threshold; store.register_early_pass(move || { Box::new(excessive_nesting::ExcessiveNesting { excessive_nesting_threshold, @@ -1009,15 +1016,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations)); store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync)); store.register_late_pass(|_| Box::new(needless_if::NeedlessIf)); - let allowed_idents_below_min_chars = conf.allowed_idents_below_min_chars.clone(); - let min_ident_chars_threshold = conf.min_ident_chars_threshold; store.register_late_pass(move |_| { Box::new(min_ident_chars::MinIdentChars { allowed_idents_below_min_chars: allowed_idents_below_min_chars.clone(), min_ident_chars_threshold, }) }); - let stack_size_threshold = conf.stack_size_threshold; store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold))); store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit)); store.register_late_pass(move |_| { @@ -1032,10 +1036,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(), }) }); - let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_strings; store.register_early_pass(move || { Box::new(raw_strings::RawStrings { - needless_raw_string_hashes_allow_one, + allow_one_hash_in_raw_strings, }) }); store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); @@ -1044,8 +1047,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods)); store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes)); store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError)); - let absolute_paths_max_segments = conf.absolute_paths_max_segments; - let absolute_paths_allowed_crates = conf.absolute_paths_allowed_crates.clone(); store.register_late_pass(move |_| { Box::new(absolute_paths::AbsolutePaths { absolute_paths_max_segments, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ab376d66966..57c3913944f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3697,8 +3697,10 @@ impl Methods { msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, - allowed_dotfiles: FxHashSet, + mut allowed_dotfiles: FxHashSet, ) -> Self { + allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string)); + Self { avoid_breaking_exported_api, msrv, diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 8604fe08e50..1c6a8e16ae2 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -33,17 +33,17 @@ declare_clippy_lint! { } /// The (callsite span, (open brace, close brace), source snippet) -type MacroInfo<'a> = (Span, &'a (String, String), String); +type MacroInfo = (Span, (char, char), String); -#[derive(Clone, Debug, Default)] +#[derive(Debug)] pub struct MacroBraces { - macro_braces: FxHashMap, + macro_braces: FxHashMap, done: FxHashSet, } impl MacroBraces { - pub fn new(conf: &FxHashSet) -> Self { - let macro_braces = macro_braces(conf.clone()); + pub fn new(conf: &[MacroMatcher]) -> Self { + let macro_braces = macro_braces(conf); Self { macro_braces, done: FxHashSet::default(), @@ -83,7 +83,7 @@ impl EarlyLintPass for MacroBraces { } } -fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a MacroBraces) -> Option> { +fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBraces) -> Option { let unnested_or_local = || { !span.ctxt().outer_expn_data().call_site.from_expansion() || span @@ -94,7 +94,7 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac let span_call_site = span.ctxt().outer_expn_data().call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind && let name = mac_name.as_str() - && let Some(braces) = mac_braces.macro_braces.get(name) + && let Some(&braces) = mac_braces.macro_braces.get(name) && let Some(snip) = snippet_opt(cx, span_call_site) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 @@ -111,7 +111,7 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac } } -fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: Span) { +fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), span: Span) { if let Some((macro_name, macro_args_str)) = snip.split_once('!') { let mut macro_args = macro_args_str.trim().to_string(); // now remove the wrong braces @@ -123,67 +123,31 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: span, &format!("use of irregular braces for `{macro_name}!` macro"), "consider writing", - format!("{macro_name}!{}{macro_args}{}", braces.0, braces.1), + format!("{macro_name}!{open}{macro_args}{close}"), Applicability::MachineApplicable, ); } } -fn macro_braces(conf: FxHashSet) -> FxHashMap { - let mut braces = vec![ - macro_matcher!( - name: "print", - braces: ("(", ")"), - ), - macro_matcher!( - name: "println", - braces: ("(", ")"), - ), - macro_matcher!( - name: "eprint", - braces: ("(", ")"), - ), - macro_matcher!( - name: "eprintln", - braces: ("(", ")"), - ), - macro_matcher!( - name: "write", - braces: ("(", ")"), - ), - macro_matcher!( - name: "writeln", - braces: ("(", ")"), - ), - macro_matcher!( - name: "format", - braces: ("(", ")"), - ), - macro_matcher!( - name: "format_args", - braces: ("(", ")"), - ), - macro_matcher!( - name: "vec", - braces: ("[", "]"), - ), - macro_matcher!( - name: "matches", - braces: ("(", ")"), - ), - ] - .into_iter() - .collect::>(); +fn macro_braces(conf: &[MacroMatcher]) -> FxHashMap { + let mut braces = FxHashMap::from_iter( + [ + ("print", ('(', ')')), + ("println", ('(', ')')), + ("eprint", ('(', ')')), + ("eprintln", ('(', ')')), + ("write", ('(', ')')), + ("writeln", ('(', ')')), + ("format", ('(', ')')), + ("format_args", ('(', ')')), + ("vec", ('[', ']')), + ("matches", ('(', ')')), + ] + .map(|(k, v)| (k.to_string(), v)), + ); // We want users items to override any existing items for it in conf { - braces.insert(it.name, it.braces); + braces.insert(it.name.clone(), it.braces); } braces } - -macro_rules! macro_matcher { - (name: $name:expr, braces: ($open:expr, $close:expr) $(,)?) => { - ($name.to_owned(), ($open.to_owned(), $close.to_owned())) - }; -} -pub(crate) use macro_matcher; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0f025c16ab5..85cea8db490 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -19,7 +19,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; -use rustc_target::spec::Target; declare_clippy_lint! { /// ### What it does @@ -116,10 +115,10 @@ impl<'tcx> PassByRefOrValue { ref_min_size: Option, value_max_size: u64, avoid_breaking_exported_api: bool, - target: &Target, + pointer_width: u32, ) -> Self { let ref_min_size = ref_min_size.unwrap_or_else(|| { - let bit_width = u64::from(target.pointer_width); + let bit_width = u64::from(pointer_width); // Cap the calculated bit width at 32-bits to reduce // portability problems between 32 and 64-bit targets let bit_width = cmp::min(bit_width, 32); diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 391c77dbf90..98f5a07da0d 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -56,7 +56,7 @@ declare_clippy_lint! { impl_lint_pass!(RawStrings => [NEEDLESS_RAW_STRINGS, NEEDLESS_RAW_STRING_HASHES]); pub struct RawStrings { - pub needless_raw_string_hashes_allow_one: bool, + pub allow_one_hash_in_raw_strings: bool, } impl EarlyLintPass for RawStrings { diff --git a/src/driver.rs b/src/driver.rs index 7bb49d08da6..1ae8ac81695 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -148,7 +148,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } let conf = clippy_config::Conf::read(sess, &conf_path); - clippy_lints::register_plugins(lint_store, sess, conf); + clippy_lints::register_lints(lint_store, conf); clippy_lints::register_pre_expansion_lints(lint_store, conf); clippy_lints::register_renamed(lint_store); })); -- cgit 1.4.1-3-g733a5 From 4dead776e196832320f0c49a6e6d779934b97193 Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Tue, 7 Nov 2023 16:01:52 +0100 Subject: add type details to unnecessary_fallible_conversions note --- .../methods/unnecessary_fallible_conversions.rs | 38 ++++++++++++++++------ tests/ui/unnecessary_fallible_conversions.stderr | 3 ++ ...necessary_fallible_conversions_unfixable.stderr | 11 +++++++ 3 files changed, 42 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index bb32b1bb7fc..89cf20c14fc 100644 --- a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -1,10 +1,11 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_expr; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_span::{sym, Span}; use super::UNNECESSARY_FALLIBLE_CONVERSIONS; @@ -42,6 +43,7 @@ fn check<'tcx>( // (else there would be conflicting impls, even with #![feature(spec)]), so we don't even need to check // what `>::Error` is: it's always `Infallible` && implements_trait(cx, self_ty, from_into_trait, &[other_ty]) + && let Some(other_ty) = other_ty.as_type() { let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| { if let ExprKind::MethodCall(path, .., span) = parent.kind @@ -52,8 +54,7 @@ fn check<'tcx>( None } }); - - let (sugg, span, applicability) = match kind { + let (source_ty, target_ty, sugg, span, applicability) = match kind { FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => { // Extend the span to include the unwrap/expect call: // `foo.try_into().expect("..")` @@ -63,24 +64,41 @@ fn check<'tcx>( // so that can be machine-applicable ( + self_ty, + other_ty, "into()", primary_span.with_hi(unwrap_span.hi()), Applicability::MachineApplicable, ) }, - FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified), - FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified), - FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified), + FunctionKind::TryFromFunction => ( + other_ty, + self_ty, + "From::from", + primary_span, + Applicability::Unspecified, + ), + FunctionKind::TryIntoFunction => ( + self_ty, + other_ty, + "Into::into", + primary_span, + Applicability::Unspecified, + ), + FunctionKind::TryIntoMethod => (self_ty, other_ty, "into", primary_span, Applicability::Unspecified), }; - span_lint_and_sugg( + span_lint_and_then( cx, UNNECESSARY_FALLIBLE_CONVERSIONS, span, "use of a fallible conversion when an infallible one could be used", - "use", - sugg.into(), - applicability, + |diag| { + with_forced_trimmed_paths!({ + diag.note(format!("converting `{source_ty}` to `{target_ty}` cannot fail")); + }); + diag.span_suggestion(span, "use", sugg, applicability); + }, ); } } diff --git a/tests/ui/unnecessary_fallible_conversions.stderr b/tests/ui/unnecessary_fallible_conversions.stderr index b918fdf774b..26b152515ac 100644 --- a/tests/ui/unnecessary_fallible_conversions.stderr +++ b/tests/ui/unnecessary_fallible_conversions.stderr @@ -4,6 +4,7 @@ error: use of a fallible conversion when an infallible one could be used LL | let _: i64 = 0i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: use: `into()` | + = note: converting `i32` to `i64` cannot fail = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]` @@ -12,6 +13,8 @@ error: use of a fallible conversion when an infallible one could be used | LL | let _: i64 = 0i32.try_into().expect("can't happen"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `into()` + | + = note: converting `i32` to `i64` cannot fail error: aborting due to 2 previous errors diff --git a/tests/ui/unnecessary_fallible_conversions_unfixable.stderr b/tests/ui/unnecessary_fallible_conversions_unfixable.stderr index 286decf8f35..033de0e9250 100644 --- a/tests/ui/unnecessary_fallible_conversions_unfixable.stderr +++ b/tests/ui/unnecessary_fallible_conversions_unfixable.stderr @@ -4,6 +4,7 @@ error: use of a fallible conversion when an infallible one could be used LL | let _: Result = 0i64.try_into(); | ^^^^^^^^ help: use: `into` | + = note: converting `i64` to `Foo` cannot fail = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]` @@ -12,30 +13,40 @@ error: use of a fallible conversion when an infallible one could be used | LL | let _: Result = i64::try_into(0i64); | ^^^^^^^^^^^^^ help: use: `Into::into` + | + = note: converting `i64` to `Foo` cannot fail error: use of a fallible conversion when an infallible one could be used --> $DIR/unnecessary_fallible_conversions_unfixable.rs:31:29 | LL | let _: Result = Foo::try_from(0i64); | ^^^^^^^^^^^^^ help: use: `From::from` + | + = note: converting `i64` to `Foo` cannot fail error: use of a fallible conversion when an infallible one could be used --> $DIR/unnecessary_fallible_conversions_unfixable.rs:34:34 | LL | let _: Result = 0i32.try_into(); | ^^^^^^^^ help: use: `into` + | + = note: converting `i32` to `i64` cannot fail error: use of a fallible conversion when an infallible one could be used --> $DIR/unnecessary_fallible_conversions_unfixable.rs:36:29 | LL | let _: Result = i32::try_into(0i32); | ^^^^^^^^^^^^^ help: use: `Into::into` + | + = note: converting `i32` to `i64` cannot fail error: use of a fallible conversion when an infallible one could be used --> $DIR/unnecessary_fallible_conversions_unfixable.rs:38:29 | LL | let _: Result = <_>::try_from(0i32); | ^^^^^^^^^^^^^ help: use: `From::from` + | + = note: converting `i32` to `i64` cannot fail error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From 5f651da2de3e4141df42a47ef47762b642c447bc Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Fri, 3 Nov 2023 23:23:59 +0100 Subject: fix iter_kv_map dont suggest into_keys and into_values if msrv is to low --- clippy_config/src/msrvs.rs | 1 + clippy_lints/src/methods/iter_kv_map.rs | 5 +++ clippy_lints/src/methods/mod.rs | 2 +- tests/ui/iter_kv_map.fixed | 43 +++++++++++++++++++++++ tests/ui/iter_kv_map.rs | 43 +++++++++++++++++++++++ tests/ui/iter_kv_map.stderr | 62 ++++++++++++++++++++++++++++++++- 6 files changed, 154 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 011d54629d4..b3ef666e306 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -23,6 +23,7 @@ msrv_aliases! { 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } 1,55,0 { SEEK_REWIND } + 1,54,0 { INTO_KEYS } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index c5dbb6ad98b..e1b934d36ea 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] use super::ITER_KV_MAP; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; @@ -21,7 +22,11 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v + msrv: &Msrv, ) { + if map_type == "into_iter" && !msrv.meets(msrvs::INTO_KEYS) { + return; + } if !expr.span.from_expansion() && let ExprKind::Closure(c) = m_arg.kind && let Body { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 57c3913944f..d9ab0f3b8ca 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4255,7 +4255,7 @@ impl Methods { map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { - iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv); }, Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index 566a5b690d8..2cbf972fca5 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -89,3 +89,46 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_values().count(); } + +#[clippy::msrv = "1.53"] +fn msrv_1_53() { + let map: HashMap = HashMap::new(); + + // Don't lint because into_iter is not supported + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + // Lint + let _ = map.keys().collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.values().collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.values().map(|v| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} + +#[clippy::msrv = "1.54"] +fn msrv_1_54() { + // Lint all + let map: HashMap = HashMap::new(); + + let _ = map.clone().into_keys().collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + //~^ ERROR: iterating on a map's keys + + let _ = map.clone().into_values().collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + //~^ ERROR: iterating on a map's values + + let _ = map.keys().collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.values().collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.values().map(|v| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index d85e501da48..6a9a4267a76 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -93,3 +93,46 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); } + +#[clippy::msrv = "1.53"] +fn msrv_1_53() { + let map: HashMap = HashMap::new(); + + // Don't lint because into_iter is not supported + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + // Lint + let _ = map.iter().map(|(key, _)| key).collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.iter().map(|(_, value)| value).collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} + +#[clippy::msrv = "1.54"] +fn msrv_1_54() { + // Lint all + let map: HashMap = HashMap::new(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + //~^ ERROR: iterating on a map's keys + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + //~^ ERROR: iterating on a map's values + + let _ = map.iter().map(|(key, _)| key).collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.iter().map(|(_, value)| value).collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 62155b7f838..471615978e1 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -201,5 +201,65 @@ error: iterating on a map's values LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` -error: aborting due to 28 previous errors +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:109:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:111:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:113:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:122:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:124:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:127:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:129:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:132:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:134:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:136:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: aborting due to 38 previous errors -- cgit 1.4.1-3-g733a5 From bffb664fbf094f53d51bec66d1b042265db1cbad Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 16 Nov 2023 10:11:13 -0800 Subject: Fix markup in recent lint documentation. Also make the examples more realistic by hiding the `;`s so as not to visibly be discarding the computed value. --- clippy_lints/src/methods/mod.rs | 8 +++++--- clippy_lints/src/unnecessary_map_on_constructor.rs | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 57c3913944f..3166a33fc2f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3609,7 +3609,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself. + /// Checks for usage of `as_str()` on a `String` chained with a method available on the `String` itself. /// /// ### Why is this bad? /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. @@ -3618,14 +3618,16 @@ declare_clippy_lint! { /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_str().as_bytes(); + /// owned_string.as_str().as_bytes() + /// # ; /// ``` /// /// Use instead: /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_bytes(); + /// owned_string.as_bytes() + /// # ; /// ``` #[clippy::version = "1.74.0"] pub REDUNDANT_AS_STR, diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 3a6d0895c72..39a83bfa005 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -9,19 +9,22 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Suggest removing the use of a map (or map_err) method when an Option or Result is being constructed. + /// Suggests removing the use of a `map()` (or `map_err()`) method when an `Option` or `Result` + /// is being constructed. /// /// ### Why is this bad? /// It introduces unnecessary complexity. In this case the function can be used directly and - /// construct the Option or Result from the output. + /// construct the `Option` or `Result` from the output. /// /// ### Example /// ```no_run - /// Some(4).map(i32::swap_bytes); + /// Some(4).map(i32::swap_bytes) + /// # ; /// ``` /// Use instead: /// ```no_run - /// Some(i32::swap_bytes(4)); + /// Some(i32::swap_bytes(4)) + /// # ; /// ``` #[clippy::version = "1.74.0"] pub UNNECESSARY_MAP_ON_CONSTRUCTOR, -- cgit 1.4.1-3-g733a5 From 34d9e88a4739a33d0d570947691c78d6980c48a9 Mon Sep 17 00:00:00 2001 From: ofeeg Date: Sat, 2 Sep 2023 23:42:11 +0200 Subject: New lint `clippy::join_absolute_paths` * `join_absolute_paths` Address PR review * Move `clippy::join_absolute_paths` to `clippy::suspicious` * `join_absolute_paths`: Address PR review Co-Authored-By: ofeeg --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/join_absolute_paths.rs | 52 +++++++++++++++++++ clippy_lints/src/methods/mod.rs | 44 ++++++++++++++++ tests/ui/join_absolute_paths.rs | 30 +++++++++++ tests/ui/join_absolute_paths.stderr | 68 +++++++++++++++++++++++++ 6 files changed, 196 insertions(+) create mode 100644 clippy_lints/src/methods/join_absolute_paths.rs create mode 100644 tests/ui/join_absolute_paths.rs create mode 100644 tests/ui/join_absolute_paths.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 1760d19b385..46f5ff168f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5190,6 +5190,7 @@ Released 2018-09-13 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain [`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero +[`join_absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#join_absolute_paths [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 55dedc0a658..7d4ab9fde1f 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -377,6 +377,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_SKIP_NEXT_INFO, crate::methods::ITER_SKIP_ZERO_INFO, crate::methods::ITER_WITH_DRAIN_INFO, + crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs new file mode 100644 index 00000000000..02f28779cf6 --- /dev/null +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::expr_or_init; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use rustc_span::Span; + +use super::JOIN_ABSOLUTE_PATHS; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if (is_type_diagnostic_item(cx, ty, sym::Path) || is_type_diagnostic_item(cx, ty, sym::PathBuf)) + && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind + && let LitKind::Str(symbol, _) = spanned.node + && let sym_str = symbol.as_str() + && sym_str.starts_with(['/', '\\']) + { + span_lint_and_then( + cx, + JOIN_ABSOLUTE_PATHS, + join_arg.span, + "argument to `Path::join` starts with a path separator", + |diag| { + let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string()); + + let no_separator = if sym_str.starts_with('/') { + arg_str.replacen('/', "", 1) + } else { + arg_str.replacen('\\', "", 1) + }; + + diag.note("joining a path starting with separator will replace the path instead") + .span_suggestion( + spanned.span, + "if this is unintentional, try removing the starting separator", + no_separator, + Applicability::Unspecified, + ) + .span_suggestion( + expr_span, + "if this is intentional, try using `Path::new` instead", + format!("PathBuf::from({arg_str})"), + Applicability::Unspecified, + ); + }, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3166a33fc2f..9ea2f6448b6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -49,6 +49,7 @@ mod iter_skip_next; mod iter_skip_zero; mod iter_with_drain; mod iterator_step_by_zero; +mod join_absolute_paths; mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; @@ -3684,6 +3685,46 @@ declare_clippy_lint! { "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `Path::join` that start with a path separator (`\\` or `/`). + /// + /// ### Why is this bad? + /// If the argument to `Path::join` starts with a separator, it will overwrite + /// the original path. If this is intentional, prefer using `Path::new` instead. + /// + /// Note the behavior is platform dependent. A leading `\\` will be accepted + /// on unix systems as part of the file name + /// + /// See [`Path::join`](https://doc.rust-lang.org/std/path/struct.Path.html#method.join) + /// + /// ### Example + /// ```rust + /// # use std::path::{Path, PathBuf}; + /// let path = Path::new("/bin"); + /// let joined_path = path.join("/sh"); + /// assert_eq!(joined_path, PathBuf::from("/sh")); + /// ``` + /// + /// Use instead; + /// ```rust + /// # use std::path::{Path, PathBuf}; + /// let path = Path::new("/bin"); + /// + /// // If this was unintentional, remove the leading separator + /// let joined_path = path.join("sh"); + /// assert_eq!(joined_path, PathBuf::from("/bin/sh")); + /// + /// // If this was intentional, create a new path instead + /// let new = Path::new("/sh"); + /// assert_eq!(new, PathBuf::from("/sh")); + /// ``` + #[clippy::version = "1.76.0"] + pub JOIN_ABSOLUTE_PATHS, + suspicious, + "calls to `Path::join` which will overwrite the original path" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3833,6 +3874,7 @@ impl_lint_pass!(Methods => [ REDUNDANT_AS_STR, WAKER_CLONE_WAKE, UNNECESSARY_FALLIBLE_CONVERSIONS, + JOIN_ABSOLUTE_PATHS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4235,6 +4277,8 @@ impl Methods { ("join", [join_arg]) => { if let Some(("collect", _, _, span, _)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); + } else { + join_absolute_paths::check(cx, recv, join_arg, expr.span); } }, ("last", []) => { diff --git a/tests/ui/join_absolute_paths.rs b/tests/ui/join_absolute_paths.rs new file mode 100644 index 00000000000..efa77a0492e --- /dev/null +++ b/tests/ui/join_absolute_paths.rs @@ -0,0 +1,30 @@ +//@no-rustfix + +#![allow(clippy::needless_raw_string_hashes)] +#![warn(clippy::join_absolute_paths)] + +use std::path::{Path, PathBuf}; + +fn main() { + let path = Path::new("/bin"); + path.join("/sh"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = Path::new("C:\\Users"); + path.join("\\user"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = PathBuf::from("/bin"); + path.join("/sh"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = PathBuf::from("/bin"); + path.join(r#"/sh"#); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path: &[&str] = &["/bin"]; + path.join("/sh"); + + let path = Path::new("/bin"); + path.join("sh"); +} diff --git a/tests/ui/join_absolute_paths.stderr b/tests/ui/join_absolute_paths.stderr new file mode 100644 index 00000000000..0c2f89d9978 --- /dev/null +++ b/tests/ui/join_absolute_paths.stderr @@ -0,0 +1,68 @@ +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:10:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead + = note: `-D clippy::join-absolute-paths` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::join_absolute_paths)]` +help: if this is unintentional, try removing the starting separator + | +LL | path.join("sh"); + | ~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("/sh"); + | ~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:14:15 + | +LL | path.join("\\user"); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join("\user"); + | ~~~~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("\\user"); + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:18:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join("sh"); + | ~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("/sh"); + | ~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:22:15 + | +LL | path.join(r#"/sh"#); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join(r#"sh"#); + | ~~~~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from(r#"/sh"#); + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 2817c5fc14cbf44b07fae0d7fe9cec4c321b4705 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Nov 2023 14:54:20 +0100 Subject: Extend `result_map_or_into_option` lint to handle `Result::map_or_else(|_| None, Some)` --- clippy_lints/src/methods/mod.rs | 4 ++ .../src/methods/result_map_or_else_none.rs | 46 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 clippy_lints/src/methods/result_map_or_else_none.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 82cd3ac0486..71de77acfc1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -81,6 +81,7 @@ mod read_line_without_trim; mod readonly_write_lock; mod redundant_as_str; mod repeat_once; +mod result_map_or_else_none; mod search_is_some; mod seek_from_current; mod seek_to_start_instead_of_rewind; @@ -4335,6 +4336,9 @@ impl Methods { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); }, + ("map_or_else", [def, map]) => { + result_map_or_else_none::check(cx, expr, recv, def, map); + }, ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { match (name2, args2) { diff --git a/clippy_lints/src/methods/result_map_or_else_none.rs b/clippy_lints/src/methods/result_map_or_else_none.rs new file mode 100644 index 00000000000..b0e3ca367b4 --- /dev/null +++ b/clippy_lints/src/methods/result_map_or_else_none.rs @@ -0,0 +1,46 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::RESULT_MAP_OR_INTO_OPTION; + +/// lint use of `_.map_or_else(|_| None, Some)` for `Result`s +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + def_arg: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, +) { + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); + + if !is_result { + return; + } + + let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome); + + if f_arg_is_some + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind + && let body = cx.tcx.hir().body(body) + && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone) + { + let msg = "called `map_or_else(|_| None, Some)` on a `Result` value"; + let self_snippet = snippet(cx, recv.span, ".."); + span_lint_and_sugg( + cx, + RESULT_MAP_OR_INTO_OPTION, + expr.span, + msg, + "try using `ok` instead", + format!("{self_snippet}.ok()"), + Applicability::MachineApplicable, + ); + } +} -- cgit 1.4.1-3-g733a5 From 6c84b968862ef605eca33ec9770009be5e1f0adf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Nov 2023 13:30:36 +0100 Subject: Improve error messages format --- clippy_lints/src/methods/map_unwrap_or.rs | 6 ++-- clippy_lints/src/methods/option_as_ref_deref.rs | 5 +--- clippy_lints/src/methods/option_map_or_none.rs | 9 ++---- clippy_lints/src/methods/option_map_unwrap_or.rs | 5 +--- tests/ui/map_unwrap_or.stderr | 30 ++++++++++---------- tests/ui/map_unwrap_or_fixable.stderr | 4 +-- tests/ui/option_as_ref_deref.stderr | 36 ++++++++++++------------ tests/ui/option_map_or_none.stderr | 10 +++---- tests/ui/result_map_or_into_option.fixed | 2 +- tests/ui/result_map_or_into_option.rs | 2 +- tests/ui/result_map_or_into_option.stderr | 2 +- 11 files changed, 50 insertions(+), 61 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index cb81b3919bf..52ea584a2c8 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -44,11 +44,9 @@ pub(super) fn check<'tcx>( // lint message let msg = if is_option { - "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling \ - `map_or_else(, )` instead" + "called `map().unwrap_or_else()` on an `Option` value" } else { - "called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling \ - `.map_or_else(, )` instead" + "called `map().unwrap_or_else()` on a `Result` value" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_arg.span, ".."); diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 15111006133..756dbe62d84 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -99,10 +99,7 @@ pub(super) fn check( let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); let suggestion = format!("try using {method_hint} instead"); - let msg = format!( - "called `{current_method}` on an Option value. This can be done more directly \ - by calling `{hint}` instead" - ); + let msg = format!("called `{current_method}` on an `Option` value"); span_lint_and_sugg( cx, OPTION_AS_REF_DEREF, diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 418e6a7d6a0..ff4d8cc9e3e 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -66,8 +66,7 @@ pub(super) fn check<'tcx>( && Some(id) == cx.tcx.lang_items().option_some_variant() { let func_snippet = snippet(cx, arg_char.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `map(..)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value"; return span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, @@ -80,8 +79,7 @@ pub(super) fn check<'tcx>( } let func_snippet = snippet(cx, map_arg.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `and_then(..)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value"; span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, @@ -92,8 +90,7 @@ pub(super) fn check<'tcx>( Applicability::MachineApplicable, ); } else if f_arg_is_some { - let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ - `ok()` instead"; + let msg = "called `map_or(None, Some)` on a `Result` value"; let self_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index c78f8b71c78..575c2d8f157 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -97,10 +97,7 @@ pub(super) fn check<'tcx>( } else { "map_or(, )" }; - let msg = &format!( - "called `map().unwrap_or({arg})` on an `Option` value. \ - This can be done more directly by calling `{suggest}` instead" - ); + let msg = &format!("called `map().unwrap_or({arg})` on an `Option` value"); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_arg.span; diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 7b7eeb322a5..54ddd1402e3 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -1,4 +1,4 @@ -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:17:13 | LL | let _ = opt.map(|x| x + 1) @@ -15,7 +15,7 @@ LL - let _ = opt.map(|x| x + 1) LL + let _ = opt.map_or(0, |x| x + 1); | -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:21:13 | LL | let _ = opt.map(|x| { @@ -33,7 +33,7 @@ LL | } LL ~ ); | -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:25:13 | LL | let _ = opt.map(|x| x + 1) @@ -50,7 +50,7 @@ LL + 0 LL ~ }, |x| x + 1); | -error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead +error: called `map().unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:30:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); @@ -62,7 +62,7 @@ LL - let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); LL + let _ = opt.and_then(|x| Some(x + 1)); | -error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead +error: called `map().unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:32:13 | LL | let _ = opt.map(|x| { @@ -80,7 +80,7 @@ LL | } LL ~ ); | -error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead +error: called `map().unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:36:13 | LL | let _ = opt @@ -95,7 +95,7 @@ LL - .map(|x| Some(x + 1)) LL + .and_then(|x| Some(x + 1)); | -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:47:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); @@ -107,7 +107,7 @@ LL - let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); LL + let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | -error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead +error: called `map().unwrap_or_else()` on an `Option` value --> $DIR/map_unwrap_or.rs:51:13 | LL | let _ = opt.map(|x| { @@ -117,7 +117,7 @@ LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ -error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead +error: called `map().unwrap_or_else()` on an `Option` value --> $DIR/map_unwrap_or.rs:55:13 | LL | let _ = opt.map(|x| x + 1) @@ -127,7 +127,7 @@ LL | | 0 LL | | ); | |_________^ -error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead +error: called `map().unwrap_or(false)` on an `Option` value --> $DIR/map_unwrap_or.rs:61:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); @@ -139,7 +139,7 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.is_some_and(|x| x > 5); | -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or.rs:71:13 | LL | let _ = res.map(|x| { @@ -149,7 +149,7 @@ LL | | } LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or.rs:75:13 | LL | let _ = res.map(|x| x + 1) @@ -159,13 +159,13 @@ LL | | 0 LL | | }); | |__________^ -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or.rs:99:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:106:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); @@ -177,7 +177,7 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.map_or(false, |x| x > 5); | -error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead +error: called `map().unwrap_or(false)` on an `Option` value --> $DIR/map_unwrap_or.rs:113:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index ca611ac9d7f..d1a9fdd6ecf 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead +error: called `map().unwrap_or_else()` on an `Option` value --> $DIR/map_unwrap_or_fixable.rs:16:13 | LL | let _ = opt.map(|x| x + 1) @@ -10,7 +10,7 @@ LL | | .unwrap_or_else(|| 0); = note: `-D clippy::map-unwrap-or` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or_fixable.rs:46:13 | LL | let _ = res.map(|x| x + 1) diff --git a/tests/ui/option_as_ref_deref.stderr b/tests/ui/option_as_ref_deref.stderr index eb0661c523a..9d173e409ab 100644 --- a/tests/ui/option_as_ref_deref.stderr +++ b/tests/ui/option_as_ref_deref.stderr @@ -1,4 +1,4 @@ -error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead +error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:11:13 | LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); @@ -7,7 +7,7 @@ LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); = note: `-D clippy::option-as-ref-deref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_deref)]` -error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead +error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:14:13 | LL | let _ = opt.clone() @@ -17,97 +17,97 @@ LL | | Deref::deref LL | | ) | |_________^ help: try using as_deref instead: `opt.clone().as_deref()` -error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(DerefMut::deref_mut)` on an `Option` value --> $DIR/option_as_ref_deref.rs:20:13 | LL | let _ = opt.as_mut().map(DerefMut::deref_mut); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:22:13 | LL | let _ = opt.as_ref().map(String::as_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| x.as_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:23:13 | LL | let _ = opt.as_ref().map(|x| x.as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(String::as_mut_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:24:13 | LL | let _ = opt.as_mut().map(String::as_mut_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(|x| x.as_mut_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:25:13 | LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead +error: called `.as_ref().map(CString::as_c_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:26:13 | LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()` -error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead +error: called `.as_ref().map(OsString::as_os_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:27:13 | LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()` -error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead +error: called `.as_ref().map(PathBuf::as_path)` on an `Option` value --> $DIR/option_as_ref_deref.rs:28:13 | LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()` -error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead +error: called `.as_ref().map(Vec::as_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:29:13 | LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()` -error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead +error: called `.as_mut().map(Vec::as_mut_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:30:13 | LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()` -error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| x.deref())` on an `Option` value --> $DIR/option_as_ref_deref.rs:32:13 | LL | let _ = opt.as_ref().map(|x| x.deref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead +error: called `.as_mut().map(|x| x.deref_mut())` on an `Option` value --> $DIR/option_as_ref_deref.rs:33:13 | LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()` -error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| &**x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:40:13 | LL | let _ = opt.as_ref().map(|x| &**x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(|x| &mut **x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:41:13 | LL | let _ = opt.as_mut().map(|x| &mut **x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(std::ops::Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:44:13 | LL | let _ = opt.as_ref().map(std::ops::Deref::deref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:56:13 | LL | let _ = opt.as_ref().map(String::as_str); diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index fa150718f89..f2cfc3f9a28 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:10:26 | LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); @@ -7,7 +7,7 @@ LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); = note: `-D clippy::option-map-or-none` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_map_or_none)]` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:13:26 | LL | let _: Option = opt.map_or(None, |x| { @@ -16,13 +16,13 @@ LL | | Some(x + 1) LL | | }); | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:17:26 | LL | let _: Option = opt.map_or(None, bar); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:18:26 | LL | let _: Option = opt.map_or(None, |x| { @@ -42,7 +42,7 @@ LL + Some(offset + height) LL ~ }); | -error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead +error: called `map_or(None, Some)` on a `Result` value --> $DIR/option_map_or_none.rs:25:26 | LL | let _: Option = r.map_or(None, Some); diff --git a/tests/ui/result_map_or_into_option.fixed b/tests/ui/result_map_or_into_option.fixed index 8c1b2041ff8..cf42b24b2dd 100644 --- a/tests/ui/result_map_or_into_option.fixed +++ b/tests/ui/result_map_or_into_option.fixed @@ -3,7 +3,7 @@ fn main() { let opt: Result = Ok(1); let _ = opt.ok(); - //~^ ERROR: called `map_or(None, Some)` on a `Result` value. + //~^ ERROR: called `map_or(None, Some)` on a `Result` value let _ = opt.ok(); //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value #[rustfmt::skip] diff --git a/tests/ui/result_map_or_into_option.rs b/tests/ui/result_map_or_into_option.rs index 17bbed02fa4..cdb45d6b82a 100644 --- a/tests/ui/result_map_or_into_option.rs +++ b/tests/ui/result_map_or_into_option.rs @@ -3,7 +3,7 @@ fn main() { let opt: Result = Ok(1); let _ = opt.map_or(None, Some); - //~^ ERROR: called `map_or(None, Some)` on a `Result` value. + //~^ ERROR: called `map_or(None, Some)` on a `Result` value let _ = opt.map_or_else(|_| None, Some); //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value #[rustfmt::skip] diff --git a/tests/ui/result_map_or_into_option.stderr b/tests/ui/result_map_or_into_option.stderr index b0fc4a1fbca..3d6bfef48ec 100644 --- a/tests/ui/result_map_or_into_option.stderr +++ b/tests/ui/result_map_or_into_option.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead +error: called `map_or(None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:5:13 | LL | let _ = opt.map_or(None, Some); -- cgit 1.4.1-3-g733a5 From ea733172e69844d772b4c9e80daf2745ac3355b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Nov 2023 17:56:47 +0100 Subject: Create new lint `option_map_or_err_ok` --- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 28 ++++++++++++++++ clippy_lints/src/methods/option_map_or_err_ok.rs | 41 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 clippy_lints/src/methods/option_map_or_err_ok.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7d4ab9fde1f..5a109fcc2cc 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -405,6 +405,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OK_EXPECT_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, + crate::methods::OPTION_MAP_OR_ERR_OK_INFO, crate::methods::OPTION_MAP_OR_NONE_INFO, crate::methods::OR_FUN_CALL_INFO, crate::methods::OR_THEN_UNWRAP_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 71de77acfc1..7ce14242cae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -70,6 +70,7 @@ mod obfuscated_if_else; mod ok_expect; mod open_options; mod option_as_ref_deref; +mod option_map_or_err_ok; mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; @@ -3726,6 +3727,31 @@ declare_clippy_lint! { "calls to `Path::join` which will overwrite the original path" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `_.map_or(Err(_), Ok)`. + /// + /// ### Why is this bad? + /// Readability, this can be written more concisely as + /// `_.ok_or(_)`. + /// + /// ### Example + /// ```no_run + /// # let opt = Some(1); + /// opt.map_or(Err("error"), Ok); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let opt = Some(1); + /// opt.ok_or("error"); + /// ``` + #[clippy::version = "1.76.0"] + pub OPTION_MAP_OR_ERR_OK, + style, + "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3876,6 +3902,7 @@ impl_lint_pass!(Methods => [ WAKER_CLONE_WAKE, UNNECESSARY_FALLIBLE_CONVERSIONS, JOIN_ABSOLUTE_PATHS, + OPTION_MAP_OR_ERR_OK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4335,6 +4362,7 @@ impl Methods { ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); + option_map_or_err_ok::check(cx, expr, recv, def, map); }, ("map_or_else", [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); diff --git a/clippy_lints/src/methods/option_map_or_err_ok.rs b/clippy_lints/src/methods/option_map_or_err_ok.rs new file mode 100644 index 00000000000..91e39d5a1cd --- /dev/null +++ b/clippy_lints/src/methods/option_map_or_err_ok.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res}; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::OPTION_MAP_OR_ERR_OK; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'_>, + or_expr: &'tcx Expr<'_>, + map_expr: &'tcx Expr<'_>, +) { + // We check that it's called on an `Option` type. + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) + // We check that first we pass an `Err`. + && let ExprKind::Call(call, &[arg]) = or_expr.kind + && is_res_lang_ctor(cx, path_res(cx, call), ResultErr) + // And finally we check that it is mapped as `Ok`. + && is_res_lang_ctor(cx, path_res(cx, map_expr), ResultOk) + { + let msg = "called `map_or(Err(_), Ok)` on an `Option` value"; + let self_snippet = snippet(cx, recv.span, ".."); + let err_snippet = snippet(cx, arg.span, ".."); + span_lint_and_sugg( + cx, + OPTION_MAP_OR_ERR_OK, + expr.span, + msg, + "try using `ok_or` instead", + format!("{self_snippet}.ok_or({err_snippet})"), + Applicability::MachineApplicable, + ); + } +} -- cgit 1.4.1-3-g733a5 From 148cd041406e8c950a5bb9cc655113fbcff53f98 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Nov 2023 11:07:59 +0100 Subject: Simplify code for `result_map_or_else_none` --- clippy_lints/src/methods/result_map_or_else_none.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/result_map_or_else_none.rs b/clippy_lints/src/methods/result_map_or_else_none.rs index b0e3ca367b4..bc16a112816 100644 --- a/clippy_lints/src/methods/result_map_or_else_none.rs +++ b/clippy_lints/src/methods/result_map_or_else_none.rs @@ -18,17 +18,13 @@ pub(super) fn check<'tcx>( def_arg: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>, ) { - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - - if !is_result { - return; - } - - let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome); - - if f_arg_is_some + // lint if the caller of `map_or_else()` is a `Result` + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) + // We check that it is mapped as `Some`. + && is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome) && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind && let body = cx.tcx.hir().body(body) + // And finally we check that we return a `None` in the "else case". && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone) { let msg = "called `map_or_else(|_| None, Some)` on a `Result` value"; -- cgit 1.4.1-3-g733a5 From 7093444bfac3b24e380d645b0da4f16ef5c25970 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 25 Nov 2023 17:45:27 +0000 Subject: Use absolute path for `declare_tool_lint` in `declare_clippy_lint` --- book/src/development/adding_lints.md | 2 +- clippy_dev/src/new_lint.rs | 4 ++-- clippy_lints/src/absolute_paths.rs | 2 +- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/almost_complete_range.rs | 2 +- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/arc_with_non_send_sync.rs | 2 +- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/asm_syntax.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/assertions_on_result_states.rs | 2 +- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/blocks_in_if_conditions.rs | 2 +- clippy_lints/src/bool_assert_comparison.rs | 2 +- clippy_lints/src/bool_to_int_with_if.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/cargo/mod.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/collection_is_never_read.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 2 +- clippy_lints/src/copy_iterator.rs | 2 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/create_dir.rs | 2 +- clippy_lints/src/dbg_macro.rs | 2 +- clippy_lints/src/default.rs | 2 +- clippy_lints/src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/default_instead_of_iter_empty.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/default_union_representation.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/disallowed_macros.rs | 2 +- clippy_lints/src/disallowed_methods.rs | 2 +- clippy_lints/src/disallowed_names.rs | 2 +- clippy_lints/src/disallowed_script_idents.rs | 2 +- clippy_lints/src/disallowed_types.rs | 2 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/duplicate_mod.rs | 2 +- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_drop.rs | 2 +- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/empty_structs_with_brackets.rs | 2 +- clippy_lints/src/endian_bytes.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/equatable_if_let.rs | 2 +- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/excessive_bools.rs | 2 +- clippy_lints/src/excessive_nesting.rs | 2 +- clippy_lints/src/exhaustive_items.rs | 2 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/extra_unused_type_parameters.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/from_raw_with_void_ptr.rs | 2 +- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/if_not_else.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/ignored_unit_patterns.rs | 2 +- clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/implicit_return.rs | 2 +- clippy_lints/src/implicit_saturating_add.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/implied_bounds_in_impls.rs | 2 +- clippy_lints/src/inconsistent_struct_constructor.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/inherent_to_string.rs | 2 +- clippy_lints/src/init_numbered_fields.rs | 2 +- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/int_plus_one.rs | 2 +- clippy_lints/src/invalid_upcast_comparisons.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 2 +- clippy_lints/src/items_after_statements.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- clippy_lints/src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/iter_over_hash_type.rs | 2 +- clippy_lints/src/iter_without_into_iter.rs | 2 +- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/large_include_file.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/lines_filter_map_ok.rs | 2 +- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/main_recursion.rs | 2 +- clippy_lints/src/manual_assert.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/manual_let_else.rs | 2 +- clippy_lints/src/manual_main_separator_str.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_range_patterns.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/manual_slice_size_calculation.rs | 2 +- clippy_lints/src/manual_string_new.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/match_result_ok.rs | 2 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/min_ident_chars.rs | 2 +- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 2 +- clippy_lints/src/mismatching_type_param_order.rs | 2 +- clippy_lints/src/missing_assert_message.rs | 2 +- clippy_lints/src/missing_asserts_for_indexing.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/missing_fields_in_debug.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/missing_trait_methods.rs | 2 +- clippy_lints/src/mixed_read_write_in_expression.rs | 2 +- clippy_lints/src/module_style.rs | 2 +- clippy_lints/src/multi_assignments.rs | 2 +- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 2 +- clippy_lints/src/needless_borrowed_ref.rs | 2 +- clippy_lints/src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/needless_continue.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/needless_if.rs | 2 +- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_parens_on_range_literals.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 2 +- clippy_lints/src/non_canonical_impls.rs | 2 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 2 +- clippy_lints/src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/non_send_fields_in_send_ty.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- clippy_lints/src/operators/mod.rs | 2 +- clippy_lints/src/option_env_unwrap.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/overflow_check_conditional.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/partial_pub_fields.rs | 2 +- clippy_lints/src/partialeq_ne_impl.rs | 2 +- clippy_lints/src/partialeq_to_none.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 2 +- clippy_lints/src/permissions_set_readonly_false.rs | 2 +- clippy_lints/src/precedence.rs | 2 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/pub_use.rs | 2 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/question_mark_used.rs | 2 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/raw_strings.rs | 2 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/read_zero_byte_vec.rs | 2 +- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_else.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_locals.rs | 2 +- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/redundant_type_annotations.rs | 2 +- clippy_lints/src/ref_option_ref.rs | 2 +- clippy_lints/src/ref_patterns.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/reserve_after_initialization.rs | 2 +- clippy_lints/src/return_self_not_must_use.rs | 2 +- clippy_lints/src/returns.rs | 2 +- clippy_lints/src/same_name_method.rs | 2 +- clippy_lints/src/self_named_constructors.rs | 2 +- clippy_lints/src/semicolon_block.rs | 2 +- clippy_lints/src/semicolon_if_nothing_returned.rs | 2 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/significant_drop_tightening.rs | 2 +- clippy_lints/src/single_call_fn.rs | 2 +- clippy_lints/src/single_char_lifetime_names.rs | 2 +- clippy_lints/src/single_component_path_imports.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- clippy_lints/src/size_of_ref.rs | 2 +- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/std_instead_of_core.rs | 2 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/strlen_on_c_strings.rs | 2 +- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 2 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/tabs_in_doc_comments.rs | 2 +- clippy_lints/src/temporary_assignment.rs | 2 +- clippy_lints/src/tests_outside_test_module.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 2 +- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/uninit_vec.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/mod.rs | 2 +- clippy_lints/src/unnamed_address.rs | 2 +- clippy_lints/src/unnecessary_box_returns.rs | 2 +- clippy_lints/src/unnecessary_map_on_constructor.rs | 2 +- clippy_lints/src/unnecessary_owned_empty_strings.rs | 2 +- clippy_lints/src/unnecessary_self_imports.rs | 2 +- clippy_lints/src/unnecessary_struct_initialization.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 2 +- clippy_lints/src/unsafe_removed_from_name.rs | 2 +- clippy_lints/src/unused_async.rs | 2 +- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_lints/src/unused_peekable.rs | 2 +- clippy_lints/src/unused_rounding.rs | 2 +- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/unused_unit.rs | 2 +- clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/useless_conversion.rs | 2 +- .../src/utils/internal_lints/almost_standard_lint_formulation.rs | 2 +- clippy_lints/src/utils/internal_lints/collapsible_calls.rs | 2 +- clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs | 2 +- clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs | 2 +- clippy_lints/src/utils/internal_lints/invalid_paths.rs | 2 +- clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs | 2 +- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs | 2 +- clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs | 2 +- clippy_lints/src/utils/internal_lints/produce_ice.rs | 2 +- clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs | 2 +- clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs | 2 +- clippy_lints/src/vec.rs | 2 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/write.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- declare_clippy_lint/src/lib.rs | 2 +- 308 files changed, 309 insertions(+), 309 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index e79e5e75cd1..e30a5f9fe10 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -202,7 +202,7 @@ is. This file has already imported some initial things we will need: ```rust use rustc_lint::{EarlyLintPass, EarlyContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_ast::ast::*; ``` diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index ddc20f7f37f..31a42734c13 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -283,7 +283,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { use clippy_utils::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; - use rustc_session::{{declare_tool_lint, impl_lint_pass}}; + use rustc_session::impl_lint_pass; "# ) @@ -292,7 +292,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { r#" {pass_import} use rustc_lint::{{{context_import}, {pass_type}}}; - use rustc_session::{{declare_lint_pass, declare_tool_lint}}; + use rustc_session::declare_lint_pass; "# ) diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 582423603eb..83d15c0c425 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -5,7 +5,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 98299e1e4bd..39fc49dee37 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_errors::Applicability; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index e85878eb570..57a5cd8fba8 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -5,7 +5,7 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimit use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index b4f778f12b9..409ae0c85ac 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 9799e703afe..657d52d0e9e 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index b9dda49ca41..e052d36f115 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 9717aa9e981..feb6437ee26 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -3,7 +3,7 @@ use std::fmt; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; #[derive(Clone, Copy, PartialEq, Eq)] enum AsmStyle { diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index b90914e936a..a15ec199a28 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 71ec87a8874..aec22965b1b 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index ec2447dae96..3e5a01c45df 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 694bc8755a6..da38422874b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, impl_lint_pass}; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span, DUMMY_SP}; use semver::Version; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 06b74b972b7..9894a163961 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Body, CoroutineKind, CoroutineSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 28bd3fc7011..692309629b7 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 665dbd6f708..74201e9cc30 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; declare_clippy_lint! { diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 156cb34df9c..cfb76cab6dc 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -2,7 +2,7 @@ use clippy_utils::higher::If; use rustc_ast::LitKind; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index d4f2e316890..e68ea2571b6 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 789cd3b6c21..d3d4f3c41c8 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -8,7 +8,7 @@ use rustc_hir::{ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 9c78c6e532d..b69dc5c1291 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::IsSuggestable; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 3a872e54c9a..fea6924d89e 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -8,7 +8,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; declare_clippy_lint! { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 49a90a2f3c2..e05b8f66d86 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -27,7 +27,7 @@ use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 69fa0821e3f..92810ea2aa0 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 74ecaa60c7c..60f436dc5d2 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -10,7 +10,7 @@ use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, BytePos, Span}; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index e5aaf88ab6c..07b02c98df1 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -18,7 +18,7 @@ use clippy_utils::sugg::Sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 1dfc2e251d9..d0c989cfff3 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -5,7 +5,7 @@ use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Symbol; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 0fe973b49a3..2c23c0b4f15 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait; use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 3b6d4886ba3..d91af76f5e0 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::DefIdSet; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index db850edd640..50fd76a3a47 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 637d5aae1be..d4828778be2 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -4,7 +4,7 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 97b736dfd8f..7a3d5a07091 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 4774917c7b5..9424a9103db 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index b325449c5a3..d8a070b785d 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -9,7 +9,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index b90d01b765a..9ce5acfbcc2 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 553b670fdb7..2472e2ee76f 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index fb29703957d..64a924a776a 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -8,7 +8,7 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index 8c6749a95fa..db01ff2cd22 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -3,7 +3,7 @@ use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, FieldDef, GenericArg, List}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index afca8850ac5..09cb8feac6a 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 9db56fa8ad0..53ef6d7e387 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::{self, Adt, AdtDef, GenericArgsRef, Ty, TypeckResults}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 169c2a15db7..77f15aa776b 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 324b5e0798e..656b3d9bfaf 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index d23aeebb5a8..1868d3cd391 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -4,7 +4,7 @@ use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index a1dd4805b9c..09dad5554ad 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -3,7 +3,7 @@ use clippy_utils::is_test_module_or_function; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Item, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 96a7f0e4fde..d5205e65cef 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use unicode_script::{Script, UnicodeScript}; declare_clippy_lint! { diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 3578fb640fc..130f56b698f 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -5,7 +5,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 607af6ba905..18874b1cb8e 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::ty; use rustc_resolve::rustdoc::{ add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment, }; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::{sym, Span}; use std::ops::Range; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 63f32173b05..b51bb7951b7 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 177e04dfa6b..124d78fc4ff 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; use clippy_utils::{get_parent_node, is_must_use_func_call}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::borrow::Cow; diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs index 7ff7068f0b0..471335c098f 100644 --- a/clippy_lints/src/duplicate_mod.rs +++ b/clippy_lints/src/duplicate_mod.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind}; use rustc_errors::MultiSpan; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{FileName, Span}; use std::collections::BTreeMap; use std::path::PathBuf; diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 61db1c1abd1..47780cab9ed 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 17be95780cc..e97030cc8b6 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -3,7 +3,7 @@ use clippy_utils::peel_blocks; use rustc_errors::Applicability; use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index a5699727b5b..420888b6ccb 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index 4e2a8b73c0a..3cf67b3ecbf 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, ItemKind, VariantData}; use rustc_errors::Applicability; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index 6f5a0cb8801..b8a817e21b1 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Symbol; use std::borrow::Cow; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 3e3c62e85d0..ce0a1dfdc61 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -10,7 +10,7 @@ use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 003b5fc7261..30eb643c42e 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -7,7 +7,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, IntTy, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 575fead5bf3..9ea52750c84 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index bc878555c66..c077bdd788c 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Visibility; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 2f22f344a21..546b228b1b0 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 241b51eeca0..450cee4007c 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 1d18e194d15..815352010f7 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -3,7 +3,7 @@ use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool}; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index 83480fc5eeb..4b0d11c5d1b 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_block, walk_item, Visitor}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index b7e62e082e4..3a621d967f4 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -3,7 +3,7 @@ use clippy_utils::source::indent_of; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 07d025f68c3..a974c10bc7d 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_entrypoint_fn; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 08cb2114a2b..4e2e1d1724a 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, ExpnId}; declare_clippy_lint! { diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index d6c746901fc..538d29eb43d 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 753f75d83a8..0446943321a 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 663c33e8cee..38a16c5c8b0 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::fmt; declare_clippy_lint! { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index d522873472b..aaf1fee3f00 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_ast::ast; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 18ed05c1ca6..8a0cd155d21 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index c9868255dcf..8af321e4d55 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -19,7 +19,7 @@ use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; use rustc_span::{sym, Span, Symbol}; diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index ec87629a344..9360eb1fa91 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -5,7 +5,7 @@ use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span, Symbol}; diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index ac45f5aedfa..3901dd984f9 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_lang_item; use clippy_utils::{higher, match_def_path, paths}; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 70892ce608f..cdb593d9b0c 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 69bc0b726fc..0599e08e6c0 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::Item; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 5477532bb95..fa1f98ba013 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -12,7 +12,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, sym}; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index d9138d48b2c..c8d10dc4b92 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{RawPtr, TypeAndMut}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 18d11ccc0b5..633ed96d6a6 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 3f5cceec70e..9cc958db645 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -9,7 +9,7 @@ mod too_many_lines; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index eee5b7540ba..2c162baad1e 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -5,7 +5,7 @@ use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 644b9cdaeb2..5e354209cbf 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -5,7 +5,7 @@ use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index cae561f7802..4dc1ff83771 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 66c10ab228f..cd6c46a71a8 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index 76bdfb94eb8..0a2fd0c663e 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -3,7 +3,7 @@ use hir::{Node, PatKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs index 9374582b54b..940adbae428 100644 --- a/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs +++ b/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, Path, TraitRef}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 6594636d884..43eb6a9b838 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -9,7 +9,7 @@ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index c6bcf3ba40c..d68c5c4bac6 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, SyntaxContext}; diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index f2fac9a29cb..cc74844f294 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index fc66f86ae86..81df1a889c7 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 232d8eeb11b..589fcfbf1ea 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index f6e1281a291..1075975f0a2 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use std::fmt::{self, Write as _}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index fa6536db796..b6f9d8b81f8 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 1ce7d85d382..0ae03d101ab 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index e9c53671a93..9ad02735878 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -3,7 +3,7 @@ use clippy_utils::higher; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::{sym, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index a61a6416193..35b45a5b505 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index fe5eb5ccac5..ca2ac60306b 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index 269311a67d6..e486563808a 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::borrow::Cow; use std::cmp::Reverse; use std::collections::BinaryHeap; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 899126565f7..bc236c5c71f 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 8e84c73666f..655f4b82aa4 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -6,7 +6,7 @@ use clippy_utils::ty; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 9ffcee07d28..b8e0eef7c7e 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index de82935e66b..8bcd9b532bd 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -2,7 +2,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, IntTy, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::comparisons; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 2b131d27b7b..b6aacba2517 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -6,7 +6,7 @@ use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 9605d76fbf0..39223c20470 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Block, ItemKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 35e01862cee..3614fb8cc96 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -4,7 +4,7 @@ use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::hygiene::AstPass; use rustc_span::{sym, ExpnKind}; diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 505aadd1a11..00ddadbaa4f 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index 7755adc4c1d..8110c1970d9 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -7,7 +7,7 @@ use clippy_utils::paths::{ }; use clippy_utils::ty::is_type_diagnostic_item; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 3c291f25590..3a5756482a1 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; use std::iter; diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 7db088f986f..b561054b582 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -4,7 +4,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 0bf9b8718cd..6feb1885576 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -8,7 +8,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Adt, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 26a7278524e..eb7570e9b44 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_target::abi::Size; declare_clippy_lint! { diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 902b72ba5e4..1b5981ecc28 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -4,7 +4,7 @@ use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 5e312ab7240..fd33ba91bfd 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -4,7 +4,7 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 33636eb687f..b397180a69c 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 6fc14dd8941..08819b9f541 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index da269ec61ff..270162ae771 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{BindingAnnotation, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 04f23a213f2..606c2ed72be 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{GenericArgKind, IsSuggestable}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index d4f410de957..5f3f9b43f45 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index bb0edec3373..17ca48683b3 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 00ca553445f..8a0955147bb 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 8f34a9b1fed..f33151cf4c5 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -9,7 +9,7 @@ use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use std::iter; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 67c80fb8387..892336878c7 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -24,7 +24,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 2744b0ca416..aea973bd249 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::{sym, Span}; use std::collections::BTreeMap; diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index ea1d25d80e1..a381b35cf2e 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 9a3da975f83..4f6a2cf017c 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index a5d91c949bc..41599f39d3a 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -7,7 +7,7 @@ use rustc_hir::{ ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 69c65cf305c..96c652283da 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 09c90e38e11..385fe387a31 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -14,7 +14,7 @@ use rustc_hir::def::Res; use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; use std::ops::Deref; diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 0c4101ceb6b..31cfb41640d 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 472b4eb9006..252b3a83a18 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -6,7 +6,7 @@ use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 468f4170732..e433c5a3b32 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -8,7 +8,7 @@ use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 01eccb56a0a..92dc4d57ab1 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::declare_tool_lint; + use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::slice; diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 23f47c86fcc..5732bdda7f2 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index fb30e371f59..7e60764115e 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index d24bfe18224..d585290f777 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{Span, DUMMY_SP}; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index bc8372fbd41..e006df7d666 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 2f8682d0418..1fe247dacb9 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; const ACCEPTABLE_METHODS: [&[&str]; 5] = [ diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 3b97d165998..1de686dbcb5 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index f8afae0e1f5..737c70496c2 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability::MachineApplicable; use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, symbol, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index b41bf2d767e..7b04fd28b89 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -10,7 +10,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 147e72ea894..3b82c50a84e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index bf035969477..62cedc8847b 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -5,7 +5,7 @@ use clippy_utils::{higher, is_res_lang_ctor}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index dea46d4d360..4c7568f39b4 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -31,7 +31,7 @@ use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, SpanData, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 1517223ab9a..c22f76484d0 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7ce14242cae..1f48b13987d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -133,7 +133,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index 4ad12e899fe..f5b749c7f80 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_item, Visitor}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use std::borrow::Cow; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index e0904f17b8d..fca626fa5c3 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_trait_method; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::cmp::Ordering; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 814fc3303b0..b9784a58596 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index df0dd9e4e39..abe5b00e888 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -16,7 +16,7 @@ use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index c74d0d623df..0739b49fe19 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{GenericArg, Item, ItemKind, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::GenericParamDefKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 4e00215c5cb..04df7b7a7e5 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -3,7 +3,7 @@ use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_cal use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 5d6dc8d5582..8f2a5390781 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -11,7 +11,7 @@ use rustc_data_structures::unhash::UnhashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 97522cbe6ce..c8d8920635c 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index b5a884f7c8b..bf4af7946f4 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index f7e42815104..c1f6c71a63e 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Item, ItemKind, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 95f9df4e42a..8be45b8c2f3 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -12,7 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index b815da79b69..07bcbfc4ff4 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index ad5f45a3280..6bbf18d52d1 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefIdMap; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocItem; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index b46c006cd57..9cea0ebff03 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index cd45467407e..0226b31dd19 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{FileName, SourceFile, Span, SyntaxContext}; use std::ffi::OsStr; diff --git a/clippy_lints/src/multi_assignments.rs b/clippy_lints/src/multi_assignments.rs index b42dce7a13a..9a6b1dfc52b 100644 --- a/clippy_lints/src/multi_assignments.rs +++ b/clippy_lints/src/multi_assignments.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index d4f8008aece..049f44f3246 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 823715f8840..a8ec1d8cf1b 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; use rustc_middle::ty::{Adt, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 6989504a4a9..72a2cca1e40 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -5,7 +5,7 @@ use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 4f8e244222d..f905a4e5b64 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 9256119e6a4..2d7ce7b52ae 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -5,7 +5,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 9d8c06cd077..a23e12f7a18 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -7,7 +7,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 1712262ff3e..2ab83f733cb 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 02c177c9227..218ca5e80f3 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -13,7 +13,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index fdb91f0dc0d..4710a69443b 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index f25475aaa8e..85166b0dd95 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::{ self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamTy, ProjectionPredicate, Ty, }; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 6803034f475..4b9ab50e4fd 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -37,7 +37,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index d881c13f84a..b6aad69d166 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, trim_span}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 70571d18e78..84a07df1bb0 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -2,7 +2,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; use clippy_utils::diagnostics::span_lint_and_then; diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 1ed7ea6b325..41d05d72284 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 0a95678d31a..3e63c0a1d36 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -10,7 +10,7 @@ use rustc_hir::{ StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index 490c3f9c1ab..8a62106377c 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index d610ba520a4..c55031f4722 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -17,7 +17,7 @@ use rustc_middle::hir::map::associated_body; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 7c48b84e430..0fc2f03c6e2 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -17,7 +17,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 7ec0879ba38..a4d3aaf0de9 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index f8888d36878..6a2893cefbd 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 30aed8cc04a..f7621822b66 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index a6adb7c8a5f..f84d9fadb85 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -6,7 +6,7 @@ use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index abba622a285..5af0e8b10d7 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index de8bb123e9b..6e65dd628a4 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::ops::Deref; declare_clippy_lint! { diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index 04d75014892..8d5a523fd8f 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 9689f63a013..63050080ac6 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use rustc_span::symbol::kw; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 3059eb25d29..4f8922aea17 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::query::Key; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::VariantIdx; diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 649a23565a9..70b7ef1a5ea 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -5,7 +5,7 @@ use rustc_ast::ast::{ use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, Span}; use std::cmp::Ordering; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 6cfcc81025d..49e9e2c00cc 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -4,7 +4,7 @@ use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index df1476e6809..433664cda64 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -8,7 +8,7 @@ use rustc_hir::{FieldDef, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 1c6a8e16ae2..1c6069e9c65 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 0faf4ce3d3e..8822dfeeddd 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -4,7 +4,7 @@ use rustc_ast::token::{Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use std::fmt::Write; diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index ef7b367649f..d621051ef16 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -8,7 +8,7 @@ use rustc_hir::hir_id::HirIdMap; use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use std::iter; diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index ee79ea27689..4c09c4eea58 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -25,7 +25,7 @@ pub(crate) mod arithmetic_side_effects; use rustc_hir::{Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 7792efe6acd..4bfb26209d2 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_direct_expn_of; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 6e4e0c98d29..cca90d813e0 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::SyntaxContext; declare_clippy_lint! { diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index e661bfbb96c..de789879331 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::SpanlessEq; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 6a760f9fe64..1d6a3f37eed 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -7,7 +7,7 @@ use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index f4f1f6ddb3f..ef51a9a9a1c 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/partial_pub_fields.rs b/clippy_lints/src/partial_pub_fields.rs index 99ba55b6b31..ffa403e27ca 100644 --- a/clippy_lints/src/partial_pub_fields.rs +++ b/clippy_lints/src/partial_pub_fields.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Item, ItemKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 1b06762415d..18e6aad9c9a 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 11e9a2bc394..6d4216970cc 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_oper use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0f6ddb35da3..2cb36af7b44 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index dcd1e7af0c2..60ced9c1208 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -3,7 +3,7 @@ use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Muta use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index b98005d5922..704acdc103e 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index b638e83997a..3cb9e05e912 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 410f4ec651b..16581a934f2 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -20,7 +20,7 @@ use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 66d869bc45a..ff8ec2ad57c 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::fmt; diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs index 316a72988aa..c0e999e76ef 100644 --- a/clippy_lints/src/pub_use.rs +++ b/clippy_lints/src/pub_use.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Item, ItemKind, VisibilityKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 5c395143b9a..fc5835408a9 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -18,7 +18,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index d0de33e3c4f..ddfc53083c4 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::span_is_local; use rustc_hir::{Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index fd9de76bacf..6b54258dd61 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; use std::cmp::Ordering; diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 98f5a07da0d..ac29d27303c 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -8,7 +8,7 @@ use rustc_ast::token::LitKind; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index b99af44655d..d0b45b59526 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index b27d4cc6e4f..62f3c09aa7e 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -7,7 +7,7 @@ use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 90297ca8bb6..19d9d64b31e 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -9,7 +9,7 @@ use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSo use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 698af9fb192..c62c351e716 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -9,7 +9,7 @@ use rustc_hir::{def_id, Body, FnDecl, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, BytePos, Span}; diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f2a006ebdfc..7971a5d86e3 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 221aa317e5d..1168e79bb0d 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -3,7 +3,7 @@ use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{walk_expr, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index b8e606df737..fb000cd7184 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 15b784039b6..8c374d7d6db 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -6,7 +6,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 32e0c3749ab..0e43e4a7ee5 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::hygiene::MacroKind; diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index c9fc65653c2..c99b657c23a 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -8,7 +8,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{GenericArg, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index a70b831a80c..07b604f2326 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index f6af9cac3de..07fcb69afbc 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 0ba898e75a1..19ce08bde10 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index 8b3dabde9be..a4be78b310b 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 69818db7c82..16086ba6637 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::BytePos; declare_clippy_lint! { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index ae8be006781..687bad35a36 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -8,7 +8,7 @@ use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index b4842e7d48a..ca7a0c7c87b 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index ad22b751bef..b84a8500c81 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index d64e931a2f3..c32cc8b73d2 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 52475ff9ef7..cddbbb317ef 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; use std::collections::{BTreeMap, BTreeSet}; diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index c1edcf509ef..015f37abcbc 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -3,7 +3,7 @@ use clippy_utils::return_ty; use clippy_utils::ty::contains_adt_constructor; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index b0601bba4af..0b3adfb7a4b 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 3aabcadaa1f..2cd3e57f885 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index fc1c2af9257..90834d784a5 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::{get_trait_def_id, paths}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 41c10b34a42..c74364d89d6 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 57bcee1a871..6c99ccda7ea 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{self as hir}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, DUMMY_SP}; use std::borrow::Cow; diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index ae81e1198af..396d2717a13 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -7,7 +7,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 74ee8ce2de7..42f1564db35 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{GenericParam, GenericParamKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 9c21d70c82c..18fbbdb4079 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_expr, Visitor}; use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::symbol::kw; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 099743d229d..95b4a11a783 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -8,7 +8,7 @@ use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::fmt::{self, Display, Formatter}; declare_clippy_lint! { diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 0385f1a98e5..756e47cbdf0 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TypeAndMut}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 7de029b7b94..14ca7a3f004 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::path_def_id; use clippy_utils::ty::peel_mid_ty_refs; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 733da790441..c4a5e48e855 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index d07a44770cc..38fd54a0f1e 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index baa9750cc01..13ae1ff52dd 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -11,7 +11,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 644664b104d..8cf4715eeb8 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_parent_node, match_libc_symbol}; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 92de7917871..4cfccc3d869 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 3244933a124..268c0c1b2df 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -4,7 +4,7 @@ use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TR use core::ops::ControlFlow; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 4340c23f830..1cc27670fa8 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 285f2f4f6f9..daa6fe8715c 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, SyntaxContext}; diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 6a6c94425d1..20e9608a15d 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index dcf1fac023a..af9e13dba36 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index c717ccc35a6..8151dd8f2cf 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_adjusted; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index 9481c78a505..da557582647 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 1dca523a966..dafe9e38818 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 7eef02b3c65..cbdf31c9336 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -3,7 +3,7 @@ use clippy_utils::has_repr_attr; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Const; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index e624bbe5ff1..e4054393d0a 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -13,7 +13,7 @@ use rustc_hir::{ TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index a3a50acb609..95a92afea66 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -21,7 +21,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 642e39e8270..e1cd82e18d5 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use std::iter::once; use std::ops::ControlFlow; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index f333b2cdcb4..4b6810b684b 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -16,7 +16,7 @@ use rustc_hir::{ TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 32aebdd8c0f..2e68bfe391e 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index b824deac2c8..3d319b9fe76 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use unicode_normalization::UnicodeNormalization; diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index a7119434517..fc8519d5628 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -6,7 +6,7 @@ use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKi use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 385f8255a39..ad76e4c1f53 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -4,7 +4,7 @@ use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 884c6ca4d31..0abd48e6423 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -5,7 +5,7 @@ mod utils; use rustc_hir::{Expr, Local}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 2223cbcb060..41e13e13e56 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index ca159eb4d5f..a05fa149c4d 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 5c880288430..148ad87beb2 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 14694bb3a28..6b5e6c6ab20 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 1e2b20469ef..ddee06b59ca 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index c35a2afab48..ed4d87ef8f8 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 5599a9dc4e8..a5f087aaf5b 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 8ff088a208f..14d5bac7177 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -11,7 +11,7 @@ use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; use std::cell::Cell; use std::mem; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index a7b2d2148e9..3f2f765f751 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index aea72c798be..d72adf678a6 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -5,7 +5,7 @@ use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; use rustc_span::Span; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 0fcb62017c6..1de9adfcb96 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 0473ecaabeb..ba72b3450b9 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index fbb36bea068..d5ca844b9e2 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 532207310bc..a67f53f00ae 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -3,7 +3,7 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::visitors::is_local_used; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use std::ops::ControlFlow; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 9627f4c7454..0a73da202ec 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -4,7 +4,7 @@ use rustc_ast::visit::FnKind; use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 6e1d0e09fe2..ae2ac38cffe 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -12,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index df4b42133f8..a615ef11691 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -6,7 +6,7 @@ use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index de6a75b79fc..0d559821386 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; declare_clippy_lint! { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f058fe5f831..4fa92a45b96 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 52327b82e84..ab6bd10aaba 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,7 +12,7 @@ use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index d78f67c05f0..5ddedb24b15 100644 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -4,7 +4,7 @@ use regex::Regex; use rustc_ast as ast; use rustc_hir::{Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index f514f166cff..7c70d3f45db 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::borrow::{Borrow, Cow}; diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index 5aa1417cfb4..5059712d69c 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_lint_allowed, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 16d0636b834..07879e81fc2 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -11,7 +11,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::ConstValue; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 66d32087fcd..4fb615e1d57 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -7,7 +7,7 @@ use rustc_hir::Item; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::FloatTy; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 486e8220484..370ed430bcf 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -11,7 +11,7 @@ use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 8ecdba47f89..f60ff1a93c7 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -22,7 +22,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath}; use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; use rustc_middle::hir::nested_filter; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Loc, Span, Symbol}; use serde::ser::SerializeStruct; diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 86b1a0ae624..6d5240db832 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs index 77b95e51f62..326e1721461 100644 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_lint_allowed, method_calls, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/produce_ice.rs b/clippy_lints/src/utils/internal_lints/produce_ice.rs index 5899b94e16b..9169e2968eb 100644 --- a/clippy_lints/src/utils/internal_lints/produce_ice.rs +++ b/clippy_lints/src/utils/internal_lints/produce_ice.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::NodeId; use rustc_ast::visit::FnKind; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 9aa23b6efe3..70ca1b206b4 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs index fd51bca9e5b..a5c4bf474f7 100644 --- a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs +++ b/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index f58641289f8..d49d3cc4cc9 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -12,7 +12,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; #[expect(clippy::module_name_repetitions)] diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index c8b9402f1ae..ac3b2bdaf65 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -11,7 +11,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 8abcc964b89..83369c66367 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5c1bea74486..9b0dac6af25 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, BytePos}; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index b6f942a90d3..be16d2e5cc3 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -10,7 +10,7 @@ use rustc_ast::{ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 1d6217d186c..d3623d6fda4 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 41c1757fde8..fba3808261a 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -5,7 +5,7 @@ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{Adt, Ty, TypeVisitableExt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index dc3037f6669..25b2fc9395c 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -148,7 +148,7 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let category_variant = format_ident!("{category}"); let output = quote! { - declare_tool_lint! { + rustc_session::declare_tool_lint! { #(#attrs)* pub clippy::#name, #level, -- cgit 1.4.1-3-g733a5 From 0d09cb0a6b22066ccf1470b35f50886d675108d1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 26 Nov 2023 22:46:13 +0100 Subject: `manual_try_fold`: check that `fold` is really `Iterator::fold` --- clippy_lints/src/methods/manual_try_fold.rs | 5 +++-- tests/ui/manual_try_fold.rs | 30 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 51145afda7f..f93edded729 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,14 +1,14 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_from_proc_macro, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::MANUAL_TRY_FOLD; @@ -22,6 +22,7 @@ pub(super) fn check<'tcx>( ) { if !in_external_macro(cx.sess(), fold_span) && msrv.meets(msrvs::ITERATOR_TRY_FOLD) + && is_trait_method(cx, expr, sym::Iterator) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() && implements_trait(cx, init_ty, try_trait, &[]) diff --git a/tests/ui/manual_try_fold.rs b/tests/ui/manual_try_fold.rs index bddf03ac3f1..7299d7cf986 100644 --- a/tests/ui/manual_try_fold.rs +++ b/tests/ui/manual_try_fold.rs @@ -96,3 +96,33 @@ fn msrv_juust_right() { .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) .unwrap(); } + +mod issue11876 { + struct Foo; + + impl Bar for Foo { + type Output = u32; + } + + trait Bar: Sized { + type Output; + fn fold(self, init: A, func: F) -> Fold + where + A: Clone, + F: Fn(A, Self::Output) -> A, + { + Fold { this: self, init, func } + } + } + + #[allow(dead_code)] + struct Fold { + this: S, + init: A, + func: F, + } + + fn main() { + Foo.fold(Some(0), |acc, entry| Some(acc? + entry)); + } +} -- cgit 1.4.1-3-g733a5 From f3f2f17478e958885330e0716a63e7e60596515a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 19 Sep 2023 16:32:05 -0400 Subject: Delay several `is_from_proc_macro` checks --- clippy_lints/src/as_conversions.rs | 9 ++++---- clippy_lints/src/borrow_deref_ref.rs | 4 +++- clippy_lints/src/manual_float_methods.rs | 4 +++- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 6 +----- clippy_lints/src/needless_if.rs | 2 +- .../src/operators/arithmetic_side_effects.rs | 25 ++++++++++++---------- clippy_lints/src/single_call_fn.rs | 2 +- 7 files changed, 27 insertions(+), 25 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index e052d36f115..e3daf75c3eb 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -48,11 +48,10 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for AsConversions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) { - return; - } - - if let ExprKind::Cast(_, _) = expr.kind { + if let ExprKind::Cast(_, _) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + { span_lint_and_help( cx, AS_CONVERSIONS, diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index d3d4f3c41c8..0ca4a0e067d 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -57,7 +57,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() - && !is_from_proc_macro(cx, e) { if let Some(parent_expr) = get_parent_expr(cx, e) { if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) @@ -75,6 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { return; } } + if is_from_proc_macro(cx, e) { + return; + } span_lint_and_then( cx, diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 31cfb41640d..72cf1d7a354 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -105,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (is_infinity(const_1) && is_neg_infinity(const_2) || is_neg_infinity(const_1) && is_infinity(const_2)) - && !is_from_proc_macro(cx, expr) && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { @@ -113,6 +112,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite, _ => return, }; + if is_from_proc_macro(cx, expr) { + return; + } span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| { match variant { diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 4a651396f14..4429f032605 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -19,10 +19,6 @@ pub(super) fn check<'tcx>( arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { - if is_from_proc_macro(cx, expr) { - return; - } - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); @@ -32,7 +28,7 @@ pub(super) fn check<'tcx>( let body = cx.tcx.hir().body(body); let body_expr = &body.value; - if usage::BindingUsageFinder::are_params_used(cx, body) { + if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) { return; } diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 41d05d72284..51bee4b51f6 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -44,7 +44,6 @@ impl LateLintPass<'_> for NeedlessIf { && block.stmts.is_empty() && block.expr.is_none() && !in_external_macro(cx.sess(), expr.span) - && !is_from_proc_macro(cx, expr) && let Some(then_snippet) = snippet_opt(cx, then.span) // Ignore // - empty macro expansions @@ -53,6 +52,7 @@ impl LateLintPass<'_> for NeedlessIf { // - #[cfg]'d out code && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) && let Some(cond_snippet) = snippet_opt(cx, cond.span) + && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 1a2b20bf438..c081dec9b6b 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -132,7 +132,11 @@ impl ArithmeticSideEffects { } // Common entry-point to avoid code duplication. - fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + fn issue_lint<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if is_from_proc_macro(cx, expr) { + return; + } + let msg = "arithmetic operation that can potentially result in unexpected side-effects"; span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg); self.expr_span = Some(expr.span); @@ -160,10 +164,10 @@ impl ArithmeticSideEffects { fn manage_bin_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, - expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'_>, op: &Spanned, - lhs: &hir::Expr<'tcx>, - rhs: &hir::Expr<'tcx>, + lhs: &'tcx hir::Expr<'_>, + rhs: &'tcx hir::Expr<'_>, ) { if constant_simple(cx, cx.typeck_results(), expr).is_some() { return; @@ -236,10 +240,10 @@ impl ArithmeticSideEffects { /// provided input. fn manage_method_call<'tcx>( &mut self, - args: &[hir::Expr<'tcx>], + args: &'tcx [hir::Expr<'_>], cx: &LateContext<'tcx>, - ps: &hir::PathSegment<'tcx>, - receiver: &hir::Expr<'tcx>, + ps: &'tcx hir::PathSegment<'_>, + receiver: &'tcx hir::Expr<'_>, ) { let Some(arg) = args.first() else { return; @@ -264,8 +268,8 @@ impl ArithmeticSideEffects { fn manage_unary_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, - expr: &hir::Expr<'tcx>, - un_expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'_>, + un_expr: &'tcx hir::Expr<'_>, un_op: hir::UnOp, ) { let hir::UnOp::Neg = un_op else { @@ -287,14 +291,13 @@ impl ArithmeticSideEffects { fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) - || is_from_proc_macro(cx, expr) || self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) } } impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if self.should_skip_expr(cx, expr) { return; } diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index 396d2717a13..8e181c3ccc7 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn { ) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) || in_external_macro(cx.sess(), span) - || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) || is_in_test_function(cx.tcx, body.value.hir_id) + || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) { return; } -- cgit 1.4.1-3-g733a5 From 27c5b21fb653d8fab29f920cdc0a922ce34534a4 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 11 Dec 2023 10:46:14 -0500 Subject: Fix binder handling in `unnecessary_to_owned` --- clippy_lints/src/methods/unnecessary_to_owned.rs | 31 ++-- tests/ui/unnecessary_to_owned.fixed | 23 ++- tests/ui/unnecessary_to_owned.rs | 23 ++- tests/ui/unnecessary_to_owned.stderr | 176 ++++++++++++----------- 4 files changed, 150 insertions(+), 103 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 395b22ebc5d..c4775b6bd04 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -15,8 +15,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ - self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, - TraitPredicate, Ty, + self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -359,6 +358,7 @@ fn get_input_traits_and_projections<'tcx>( (trait_predicates, projection_predicates) } +#[expect(clippy::too_many_lines)] fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { match node { @@ -387,22 +387,21 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< if let Some((callee_def_id, call_generic_args, recv, call_args)) = get_callee_generic_args_and_args(cx, parent_expr) { - // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually - // call `tcx.try_instantiate_and_normalize_erasing_regions` further down - // (i.e., we are explicitly not in the identity context). - let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder(); + let bound_fn_sig = cx.tcx.fn_sig(callee_def_id); + let fn_sig = bound_fn_sig.skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) - && let Some(param_ty) = fn_sig.inputs().get(arg_index) - && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + && let param_ty = fn_sig.input(arg_index).skip_binder() + && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind() // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021 - && (*param_index as usize) < call_generic_args.len() + && (param_index as usize) < call_generic_args.len() { if fn_sig + .skip_binder() .inputs() .iter() .enumerate() .filter(|(i, _)| *i != arg_index) - .any(|(_, ty)| ty.contains(*param_ty)) + .any(|(_, ty)| ty.contains(param_ty)) { return false; } @@ -414,7 +413,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< .iter() .filter(|predicate| { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && trait_predicate.trait_ref.self_ty() == *param_ty + && trait_predicate.trait_ref.self_ty() == param_ty { true } else { @@ -425,7 +424,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let new_subst = cx .tcx .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| { - if i == (*param_index as usize) { + if i == param_index as usize { GenericArg::from(ty) } else { t @@ -433,7 +432,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst); + let predicate = bound_fn_sig.rebind(predicate).instantiate(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx .infer_ctxt() @@ -443,12 +442,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< return false; } - let output_ty = fn_sig.output(); - if output_ty.contains(*param_ty) { + let output_ty = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output()); + if output_ty.contains(param_ty) { if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( new_subst, cx.param_env, - EarlyBinder::bind(output_ty), + bound_fn_sig.rebind(output_ty), ) { expr = parent_expr; ty = new_ty; diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 67faabc53cb..2dd1d746626 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,4 +1,10 @@ -#![allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::ptr_arg)] +#![allow( + clippy::needless_borrow, + clippy::needless_borrows_for_generic_args, + clippy::ptr_arg, + clippy::manual_async_fn, + clippy::needless_lifetimes +)] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; @@ -506,3 +512,18 @@ mod issue_10033 { } } } + +mod issue_11952 { + use core::future::{Future, IntoFuture}; + + fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future> { + async move { + let _y = y; + Ok(()) + } + } + + fn bar() { + IntoFuture::into_future(foo([], &0)); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 99f9136427d..17fad33402b 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,4 +1,10 @@ -#![allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::ptr_arg)] +#![allow( + clippy::needless_borrow, + clippy::needless_borrows_for_generic_args, + clippy::ptr_arg, + clippy::manual_async_fn, + clippy::needless_lifetimes +)] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; @@ -506,3 +512,18 @@ mod issue_10033 { } } } + +mod issue_11952 { + use core::future::{Future, IntoFuture}; + + fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future> { + async move { + let _y = y; + Ok(()) + } + } + + fn bar() { + IntoFuture::into_future(foo([].to_vec(), &0)); + } +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index d8971b51dca..ad6fa422b8c 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:148:64 + --> $DIR/unnecessary_to_owned.rs:154:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:148:20 + --> $DIR/unnecessary_to_owned.rs:154:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()) = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> $DIR/unnecessary_to_owned.rs:149:40 + --> $DIR/unnecessary_to_owned.rs:155:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:149:21 + --> $DIR/unnecessary_to_owned.rs:155:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:150:48 + --> $DIR/unnecessary_to_owned.rs:156:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:150:19 + --> $DIR/unnecessary_to_owned.rs:156:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:151:35 + --> $DIR/unnecessary_to_owned.rs:157:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:151:18 + --> $DIR/unnecessary_to_owned.rs:157:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:152:39 + --> $DIR/unnecessary_to_owned.rs:158:39 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:152:20 + --> $DIR/unnecessary_to_owned.rs:158:20 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:57:36 + --> $DIR/unnecessary_to_owned.rs:63:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -70,415 +70,415 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:58:19 + --> $DIR/unnecessary_to_owned.rs:64:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> $DIR/unnecessary_to_owned.rs:60:20 + --> $DIR/unnecessary_to_owned.rs:66:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:61:38 + --> $DIR/unnecessary_to_owned.rs:67:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:62:20 + --> $DIR/unnecessary_to_owned.rs:68:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> $DIR/unnecessary_to_owned.rs:64:18 + --> $DIR/unnecessary_to_owned.rs:70:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:65:34 + --> $DIR/unnecessary_to_owned.rs:71:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:66:18 + --> $DIR/unnecessary_to_owned.rs:72:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:68:17 + --> $DIR/unnecessary_to_owned.rs:74:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:69:30 + --> $DIR/unnecessary_to_owned.rs:75:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:70:17 + --> $DIR/unnecessary_to_owned.rs:76:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:71:17 + --> $DIR/unnecessary_to_owned.rs:77:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:73:19 + --> $DIR/unnecessary_to_owned.rs:79:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:74:36 + --> $DIR/unnecessary_to_owned.rs:80:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:75:19 + --> $DIR/unnecessary_to_owned.rs:81:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:76:19 + --> $DIR/unnecessary_to_owned.rs:82:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:77:19 + --> $DIR/unnecessary_to_owned.rs:83:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:80:42 + --> $DIR/unnecessary_to_owned.rs:86:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:83:25 + --> $DIR/unnecessary_to_owned.rs:89:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:84:26 + --> $DIR/unnecessary_to_owned.rs:90:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:85:24 + --> $DIR/unnecessary_to_owned.rs:91:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:86:23 + --> $DIR/unnecessary_to_owned.rs:92:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:87:25 + --> $DIR/unnecessary_to_owned.rs:93:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:89:30 + --> $DIR/unnecessary_to_owned.rs:95:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:90:31 + --> $DIR/unnecessary_to_owned.rs:96:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:91:29 + --> $DIR/unnecessary_to_owned.rs:97:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:92:28 + --> $DIR/unnecessary_to_owned.rs:98:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:93:30 + --> $DIR/unnecessary_to_owned.rs:99:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:95:29 + --> $DIR/unnecessary_to_owned.rs:101:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:95:43 + --> $DIR/unnecessary_to_owned.rs:101:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:96:29 + --> $DIR/unnecessary_to_owned.rs:102:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:96:47 + --> $DIR/unnecessary_to_owned.rs:102:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:98:26 + --> $DIR/unnecessary_to_owned.rs:104:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:99:27 + --> $DIR/unnecessary_to_owned.rs:105:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:100:25 + --> $DIR/unnecessary_to_owned.rs:106:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:101:24 + --> $DIR/unnecessary_to_owned.rs:107:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:102:24 + --> $DIR/unnecessary_to_owned.rs:108:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:103:26 + --> $DIR/unnecessary_to_owned.rs:109:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:104:26 + --> $DIR/unnecessary_to_owned.rs:110:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:105:26 + --> $DIR/unnecessary_to_owned.rs:111:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:107:31 + --> $DIR/unnecessary_to_owned.rs:113:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:108:32 + --> $DIR/unnecessary_to_owned.rs:114:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:109:30 + --> $DIR/unnecessary_to_owned.rs:115:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:110:29 + --> $DIR/unnecessary_to_owned.rs:116:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:111:29 + --> $DIR/unnecessary_to_owned.rs:117:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:112:31 + --> $DIR/unnecessary_to_owned.rs:118:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:113:31 + --> $DIR/unnecessary_to_owned.rs:119:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:114:31 + --> $DIR/unnecessary_to_owned.rs:120:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:30 + --> $DIR/unnecessary_to_owned.rs:122:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:44 + --> $DIR/unnecessary_to_owned.rs:122:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:117:30 + --> $DIR/unnecessary_to_owned.rs:123:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:117:44 + --> $DIR/unnecessary_to_owned.rs:123:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:30 + --> $DIR/unnecessary_to_owned.rs:124:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:44 + --> $DIR/unnecessary_to_owned.rs:124:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:30 + --> $DIR/unnecessary_to_owned.rs:125:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:48 + --> $DIR/unnecessary_to_owned.rs:125:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:120:30 + --> $DIR/unnecessary_to_owned.rs:126:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:120:52 + --> $DIR/unnecessary_to_owned.rs:126:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:121:30 + --> $DIR/unnecessary_to_owned.rs:127:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:121:48 + --> $DIR/unnecessary_to_owned.rs:127:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:123:20 + --> $DIR/unnecessary_to_owned.rs:129:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:125:13 + --> $DIR/unnecessary_to_owned.rs:131:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:126:13 + --> $DIR/unnecessary_to_owned.rs:132:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:127:13 + --> $DIR/unnecessary_to_owned.rs:133:13 | LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:128:13 + --> $DIR/unnecessary_to_owned.rs:134:13 | LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:130:13 + --> $DIR/unnecessary_to_owned.rs:136:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:131:13 + --> $DIR/unnecessary_to_owned.rs:137:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:132:13 + --> $DIR/unnecessary_to_owned.rs:138:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:133:13 + --> $DIR/unnecessary_to_owned.rs:139:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:195:14 + --> $DIR/unnecessary_to_owned.rs:201:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -494,28 +494,34 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:218:14 + --> $DIR/unnecessary_to_owned.rs:224:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:223:14 + --> $DIR/unnecessary_to_owned.rs:229:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:270:24 + --> $DIR/unnecessary_to_owned.rs:276:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:378:12 + --> $DIR/unnecessary_to_owned.rs:384:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` -error: aborting due to 79 previous errors +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:527:37 + | +LL | IntoFuture::into_future(foo([].to_vec(), &0)); + | ^^^^^^^^^^^ help: use: `[]` + +error: aborting due to 80 previous errors -- cgit 1.4.1-3-g733a5 From 19f5b853308d7504a95a5ee27d6c3adfe14d4554 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 Dec 2023 16:57:18 +0100 Subject: Add `write_and_append` lint --- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/ineffective_open_options.rs | 95 ++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/mod.rs | 2 +- 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/ineffective_open_options.rs (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a9ae22e8d43..d3105ed9d18 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -215,6 +215,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO, crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, + crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO, crate::infinite_iter::INFINITE_ITER_INFO, crate::infinite_iter::MAYBE_INFINITE_ITER_INFO, crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO, diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs new file mode 100644 index 00000000000..955f90d4262 --- /dev/null +++ b/clippy_lints/src/ineffective_open_options.rs @@ -0,0 +1,95 @@ +use crate::methods::method_call; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::peel_blocks; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, BytePos, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks if both `.write(true)` and `.append(true)` methods are called + /// on a same `OpenOptions`. + /// + /// ### Why is this bad? + /// `.append(true)` already enables `write(true)`, making this one + /// superflous. + /// + /// ### Example + /// ```no_run + /// # use std::fs::OpenOptions; + /// let _ = OpenOptions::new() + /// .write(true) + /// .append(true) + /// .create(true) + /// .open("file.json"); + /// ``` + /// Use instead: + /// ```no_run + /// # use std::fs::OpenOptions; + /// let _ = OpenOptions::new() + /// .append(true) + /// .create(true) + /// .open("file.json"); + /// ``` + #[clippy::version = "1.76.0"] + pub INEFFECTIVE_OPEN_OPTIONS, + suspicious, + "usage of both `write(true)` and `append(true)` on same `OpenOptions`" +} + +declare_lint_pass!(IneffectiveOpenOptions => [INEFFECTIVE_OPEN_OPTIONS]); + +fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option { + if let [arg] = args + && let ExprKind::Lit(lit) = peel_blocks(arg).kind + && lit.node == LitKind::Bool(true) + { + // The `.` is not included in the span so we cheat a little bit to include it as well. + Some(call_span.with_lo(call_span.lo() - BytePos(1))) + } else { + None + } +} + +impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else { + return; + }; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + match receiver_ty.peel_refs().kind() { + ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::FsOpenOptions, adt.did()) => {}, + _ => return, + } + + let mut append = None; + let mut write = None; + + while let Some((name, recv, args, _, span)) = method_call(receiver) { + if name == "append" { + append = index_if_arg_is_boolean(args, span); + } else if name == "write" { + write = index_if_arg_is_boolean(args, span); + } + receiver = recv; + } + + if let Some(write_span) = write + && append.is_some() + { + span_lint_and_sugg( + cx, + INEFFECTIVE_OPEN_OPTIONS, + write_span, + "unnecessary use of `.write(true)` because there is `.append(true)`", + "remove `.write(true)`", + String::new(), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 660d3c0bdd2..e4ff7ebb0f7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -153,6 +153,7 @@ mod implied_bounds_in_impls; mod inconsistent_struct_constructor; mod index_refutable_slice; mod indexing_slicing; +mod ineffective_open_options; mod infinite_iter; mod inherent_impl; mod inherent_to_string; @@ -1073,6 +1074,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)); store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity)); store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences)); + store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 25c681bb9d9..b4f60ffadd7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3906,7 +3906,7 @@ impl_lint_pass!(Methods => [ ]); /// Extracts a method call name, args, and `Span` of the method name. -fn method_call<'tcx>( +pub fn method_call<'tcx>( recv: &'tcx hir::Expr<'tcx>, ) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind { -- cgit 1.4.1-3-g733a5 From 8892420aa742e1f8e2ae80edd694aba59ac60e87 Mon Sep 17 00:00:00 2001 From: Quinn Sinclair Date: Mon, 4 Dec 2023 02:20:47 +0100 Subject: New Lint: `Result_filter_map` Added the `Result` mirror of `option_filter_map` to catch ``` .into_iter().filter(Result::is_ok).map(Result::unwrap) ``` changelog: New Lint: [`result_filter_map`] Co-authored-by: Alex Macleod --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/filter_map.rs | 86 +++++++++++++++++++++++++--------- clippy_lints/src/methods/mod.rs | 27 ++++++++++- tests/ui/option_filter_map.fixed | 6 +++ tests/ui/option_filter_map.rs | 8 ++++ tests/ui/option_filter_map.stderr | 16 ++++--- tests/ui/result_filter_map.fixed | 27 +++++++++++ tests/ui/result_filter_map.rs | 35 ++++++++++++++ tests/ui/result_filter_map.stderr | 41 ++++++++++++++++ 10 files changed, 217 insertions(+), 31 deletions(-) create mode 100644 tests/ui/result_filter_map.fixed create mode 100644 tests/ui/result_filter_map.rs create mode 100644 tests/ui/result_filter_map.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 70aff7f60e0..da6bb32cd45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5470,6 +5470,7 @@ Released 2018-09-13 [`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used +[`result_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_filter_map [`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2ce938fbe92..8ae68da3e9f 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -419,6 +419,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::READ_LINE_WITHOUT_TRIM_INFO, crate::methods::REDUNDANT_AS_STR_INFO, crate::methods::REPEAT_ONCE_INFO, + crate::methods::RESULT_FILTER_MAP_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, crate::methods::SEARCH_IS_SOME_INFO, crate::methods::SEEK_FROM_CURRENT_INFO, diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 844ab40cab1..fad45041aca 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::borrow::Cow; -use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP}; +use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { match &expr.kind { @@ -46,6 +46,9 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } +fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { + is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok)) +} #[derive(Debug, Copy, Clone)] enum OffendingFilterExpr<'tcx> { @@ -273,6 +276,18 @@ fn is_filter_some_map_unwrap( (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg) } +/// is `filter(|x| x.is_ok()).map(|x| x.unwrap())` +fn is_filter_ok_map_unwrap( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + filter_arg: &hir::Expr<'_>, + map_arg: &hir::Expr<'_>, +) -> bool { + // result has no filter, so we only check for iterators + let iterator = is_trait_method(cx, expr, sym::Iterator); + iterator && is_ok_filter_map(cx, filter_arg, map_arg) +} + /// lint use of `filter().map()` or `find().map()` for `Iterators` #[allow(clippy::too_many_arguments)] pub(super) fn check( @@ -300,30 +315,21 @@ pub(super) fn check( return; } - if is_trait_method(cx, map_recv, sym::Iterator) - - // filter(|x| ...is_some())... - && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind - && let filter_body = cx.tcx.hir().body(filter_body_id) - && let [filter_param] = filter_body.params - // optional ref pattern: `filter(|&x| ..)` - && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { - (ref_pat, true) - } else { - (filter_param.pat, false) - } - - && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind - && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) + if is_filter_ok_map_unwrap(cx, expr, filter_arg, map_arg) { + span_lint_and_sugg( + cx, + RESULT_FILTER_MAP, + filter_span.with_hi(expr.span.hi()), + "`filter` for `Ok` followed by `unwrap`", + "consider using `flatten` instead", + reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(), + Applicability::MachineApplicable, + ); - && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind - && let map_body = cx.tcx.hir().body(map_body_id) - && let [map_param] = map_body.params - && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind + return; + } - && let Some(check_result) = - offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref) - { + if let Some((map_param_ident, check_result)) = is_find_or_filter(cx, map_recv, filter_arg, map_arg) { let span = filter_span.with_hi(expr.span.hi()); let (filter_name, lint) = if is_find { ("find", MANUAL_FIND_MAP) @@ -395,6 +401,40 @@ pub(super) fn check( } } +fn is_find_or_filter<'a>( + cx: &LateContext<'a>, + map_recv: &hir::Expr<'_>, + filter_arg: &hir::Expr<'_>, + map_arg: &hir::Expr<'_>, +) -> Option<(Ident, CheckResult<'a>)> { + if is_trait_method(cx, map_recv, sym::Iterator) + // filter(|x| ...is_some())... + && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind + && let filter_body = cx.tcx.hir().body(filter_body_id) + && let [filter_param] = filter_body.params + // optional ref pattern: `filter(|&x| ..)` + && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + } + + && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind + && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) + + && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind + && let map_body = cx.tcx.hir().body(map_body_id) + && let [map_param] = map_body.params + && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind + + && let Some(check_result) = + offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref) + { + return Some((map_param_ident, check_result)); + } + None +} + fn acceptable_methods(method: &PathSegment<'_>) -> bool { let methods: [Symbol; 8] = [ sym::clone, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b4f60ffadd7..a94524b3ba6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1175,7 +1175,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for indirect collection of populated `Option` + /// Checks for iterators of `Option`s using ``.filter(Option::is_some).map(Option::unwrap)` that may + /// be replaced with a `.flatten()` call. /// /// ### Why is this bad? /// `Option` is like a collection of 0-1 things, so `flatten` @@ -3752,6 +3753,29 @@ declare_clippy_lint! { "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for iterators of `Result`s using ``.filter(Result::is_ok).map(Result::unwrap)` that may + /// be replaced with a `.flatten()` call. + /// + /// ### Why is this bad? + /// `Result` implements `IntoIterator`. This means that `Result` can be flattened + /// automatically without suspicious-looking `unwrap` calls. + /// + /// ### Example + /// ```no_run + /// let _ = std::iter::empty::>().filter(Result::is_ok).map(Result::unwrap); + /// ``` + /// Use instead: + /// ```no_run + /// let _ = std::iter::empty::>().flatten(); + /// ``` + #[clippy::version = "1.76.0"] + pub RESULT_FILTER_MAP, + complexity, + "filtering `Result` for `Ok` then force-unwrapping, which can be one type-safe operation" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3903,6 +3927,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_FALLIBLE_CONVERSIONS, JOIN_ABSOLUTE_PATHS, OPTION_MAP_OR_ERR_OK, + RESULT_FILTER_MAP, ]); /// Extracts a method call name, args, and `Span` of the method name. diff --git a/tests/ui/option_filter_map.fixed b/tests/ui/option_filter_map.fixed index ee004c0e194..b1c3cfa48a4 100644 --- a/tests/ui/option_filter_map.fixed +++ b/tests/ui/option_filter_map.fixed @@ -3,12 +3,18 @@ fn main() { let _ = Some(Some(1)).flatten(); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = Some(Some(1)).flatten(); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = Some(1).map(odds_out).flatten(); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = Some(1).map(odds_out).flatten(); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = vec![Some(1)].into_iter().flatten(); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = vec![Some(1)].into_iter().flatten(); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = vec![1] .into_iter() .map(odds_out) diff --git a/tests/ui/option_filter_map.rs b/tests/ui/option_filter_map.rs index eae2fa176a8..2550b9cd2b3 100644 --- a/tests/ui/option_filter_map.rs +++ b/tests/ui/option_filter_map.rs @@ -3,21 +3,29 @@ fn main() { let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); + //~^ ERROR: `filter` for `Some` followed by `unwrap` let _ = vec![1] .into_iter() .map(odds_out) .filter(Option::is_some) + //~^ ERROR: `filter` for `Some` followed by `unwrap` .map(Option::unwrap); let _ = vec![1] .into_iter() .map(odds_out) .filter(|o| o.is_some()) + //~^ ERROR: `filter` for `Some` followed by `unwrap` .map(|o| o.unwrap()); } diff --git a/tests/ui/option_filter_map.stderr b/tests/ui/option_filter_map.stderr index 148f9d02f5e..6a0fc10822b 100644 --- a/tests/ui/option_filter_map.stderr +++ b/tests/ui/option_filter_map.stderr @@ -8,48 +8,50 @@ LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); = help: to override `-D warnings` add `#[allow(clippy::option_filter_map)]` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:6:27 + --> $DIR/option_filter_map.rs:7:27 | LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:7:35 + --> $DIR/option_filter_map.rs:9:35 | LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:8:35 + --> $DIR/option_filter_map.rs:11:35 | LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:10:39 + --> $DIR/option_filter_map.rs:14:39 | LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:11:39 + --> $DIR/option_filter_map.rs:16:39 | LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:15:10 + --> $DIR/option_filter_map.rs:21:10 | LL | .filter(Option::is_some) | __________^ +LL | | LL | | .map(Option::unwrap); | |____________________________^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> $DIR/option_filter_map.rs:20:10 + --> $DIR/option_filter_map.rs:27:10 | LL | .filter(|o| o.is_some()) | __________^ +LL | | LL | | .map(|o| o.unwrap()); | |____________________________^ help: consider using `flatten` instead: `flatten()` diff --git a/tests/ui/result_filter_map.fixed b/tests/ui/result_filter_map.fixed new file mode 100644 index 00000000000..e8943dbc72d --- /dev/null +++ b/tests/ui/result_filter_map.fixed @@ -0,0 +1,27 @@ +#![warn(clippy::result_filter_map)] +#![allow(clippy::map_flatten, clippy::unnecessary_map_on_constructor)] + +fn odds_out(x: i32) -> Result { + if x % 2 == 0 { Ok(x) } else { Err(()) } +} + +fn main() { + // Unlike the Option version, Result does not have a filter operation => we will check for iterators + // only + let _ = vec![Ok(1) as Result] + .into_iter() + .flatten(); + + let _ = vec![Ok(1) as Result] + .into_iter() + .flatten(); + + let _ = vec![1] + .into_iter() + .map(odds_out) + .flatten(); + let _ = vec![1] + .into_iter() + .map(odds_out) + .flatten(); +} diff --git a/tests/ui/result_filter_map.rs b/tests/ui/result_filter_map.rs new file mode 100644 index 00000000000..bfe47ffcf38 --- /dev/null +++ b/tests/ui/result_filter_map.rs @@ -0,0 +1,35 @@ +#![warn(clippy::result_filter_map)] +#![allow(clippy::map_flatten, clippy::unnecessary_map_on_constructor)] + +fn odds_out(x: i32) -> Result { + if x % 2 == 0 { Ok(x) } else { Err(()) } +} + +fn main() { + // Unlike the Option version, Result does not have a filter operation => we will check for iterators + // only + let _ = vec![Ok(1) as Result] + .into_iter() + .filter(Result::is_ok) + //~^ ERROR: `filter` for `Ok` followed by `unwrap` + .map(Result::unwrap); + + let _ = vec![Ok(1) as Result] + .into_iter() + .filter(|o| o.is_ok()) + //~^ ERROR: `filter` for `Ok` followed by `unwrap` + .map(|o| o.unwrap()); + + let _ = vec![1] + .into_iter() + .map(odds_out) + .filter(Result::is_ok) + //~^ ERROR: `filter` for `Ok` followed by `unwrap` + .map(Result::unwrap); + let _ = vec![1] + .into_iter() + .map(odds_out) + .filter(|o| o.is_ok()) + //~^ ERROR: `filter` for `Ok` followed by `unwrap` + .map(|o| o.unwrap()); +} diff --git a/tests/ui/result_filter_map.stderr b/tests/ui/result_filter_map.stderr new file mode 100644 index 00000000000..4687794949d --- /dev/null +++ b/tests/ui/result_filter_map.stderr @@ -0,0 +1,41 @@ +error: `filter` for `Ok` followed by `unwrap` + --> $DIR/result_filter_map.rs:13:10 + | +LL | .filter(Result::is_ok) + | __________^ +LL | | +LL | | .map(Result::unwrap); + | |____________________________^ help: consider using `flatten` instead: `flatten()` + | + = note: `-D clippy::result-filter-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_filter_map)]` + +error: `filter` for `Ok` followed by `unwrap` + --> $DIR/result_filter_map.rs:19:10 + | +LL | .filter(|o| o.is_ok()) + | __________^ +LL | | +LL | | .map(|o| o.unwrap()); + | |____________________________^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Ok` followed by `unwrap` + --> $DIR/result_filter_map.rs:26:10 + | +LL | .filter(Result::is_ok) + | __________^ +LL | | +LL | | .map(Result::unwrap); + | |____________________________^ help: consider using `flatten` instead: `flatten()` + +error: `filter` for `Ok` followed by `unwrap` + --> $DIR/result_filter_map.rs:32:10 + | +LL | .filter(|o| o.is_ok()) + | __________^ +LL | | +LL | | .map(|o| o.unwrap()); + | |____________________________^ help: consider using `flatten` instead: `flatten()` + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 850d77ed5575d06d274cf6ce0aa6c2c7f4af120b Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 16 Dec 2023 16:37:58 +0100 Subject: [`redundant_pattern_matching`]: catch `if let true` --- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/loops/manual_flatten.rs | 2 +- clippy_lints/src/manual_let_else.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 4 +-- clippy_lints/src/matches/mod.rs | 1 + .../src/matches/redundant_pattern_match.rs | 34 +++++++++++++++++++--- clippy_lints/src/methods/filter_map.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 1 + clippy_lints/src/question_mark.rs | 1 + clippy_utils/src/higher.rs | 13 +++++++-- 10 files changed, 50 insertions(+), 12 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 3901dd984f9..2b08437d827 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -57,7 +57,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => { arms.iter().any(|arm| is_format(cx, arm.body)) }, - Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => { + Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => { is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) }, _ => false, diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index a726b116956..36de9021f49 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -20,7 +20,7 @@ pub(super) fn check<'tcx>( span: Span, ) { let inner_expr = peel_blocks_with_stmt(body); - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None }) + if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. }) = higher::IfLet::hir(cx, inner_expr) // Ensure match_expr in `if let` statement is the same as the pat from the for-loop && let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 92dc4d57ab1..fdf8fa4e277 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -61,7 +61,7 @@ impl<'tcx> QuestionMark { && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { - IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => { + IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => { if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) && let Some(if_else) = if_else && is_never_expr(cx, if_else).is_some() diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 48fc5746b3c..91e6ca7fa8b 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -41,7 +41,7 @@ fn check_arm<'tcx>( let inner_expr = peel_blocks_with_stmt(outer_then_body); if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr) && let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner { - IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)), + IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)), IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none()) // if there are more than two arms, collapsing would be non-trivial // one of the arms must be "wild-like" @@ -75,7 +75,7 @@ fn check_arm<'tcx>( ) // ...or anywhere in the inner expression && match inner { - IfLetOrMatch::IfLet(_, _, body, els) => { + IfLetOrMatch::IfLet(_, _, body, els, _) => { !is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id)) }, IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)), diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 4c7568f39b4..af6894545b8 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1104,6 +1104,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_let.let_pat, if_let.let_expr, if_let.if_else.is_some(), + if_let.let_span, ); needless_match::check_if_let(cx, expr, &if_let); } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 2582f7edcf6..81c084b979a 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -12,13 +12,13 @@ use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, Span, Symbol}; use std::fmt::Write; use std::ops::ControlFlow; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { - find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); + find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); } } @@ -28,8 +28,34 @@ pub(super) fn check_if_let<'tcx>( pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, has_else: bool, + let_span: Span, ) { - find_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else); + find_if_let_true(cx, pat, scrutinee, let_span); + find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else); +} + +fn find_if_let_true<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, let_span: Span) { + if let PatKind::Lit(lit) = pat.kind + && let ExprKind::Lit(lit) = lit.kind + && let LitKind::Bool(is_true) = lit.node + { + let mut snip = snippet(cx, scrutinee.span, "..").into_owned(); + + if !is_true { + // Invert condition for `if let false = ...` + snip.insert(0, '!'); + } + + span_lint_and_sugg( + cx, + REDUNDANT_PATTERN_MATCHING, + let_span, + "using `if let` to pattern match a boolean", + "consider using a regular `if` expression", + snip, + Applicability::MachineApplicable, + ); + } } // Extract the generic arguments out of a type @@ -100,7 +126,7 @@ fn find_method_and_type<'tcx>( } } -fn find_sugg_for_if_let<'tcx>( +fn find_method_sugg_for_if_let<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, let_pat: &Pat<'_>, diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 844ab40cab1..db15bf2ad6c 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -186,7 +186,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { match higher::IfLetOrMatch::parse(cx, map_body.value) { // For `if let` we want to check that the variant matching arm references the local created by // its pattern - Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_))) + Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_), ..)) if let Some((ident, span)) = expr_uses_local(pat, then) => { (sc, else_, ident, span) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 89e4e3c740d..556c493d36c 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -238,6 +238,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> let_expr, if_then, if_else: Some(if_else), + .. }) = higher::IfLet::hir(cx, expr) && !cx.typeck_results().expr_ty(expr).is_unit() && !is_else_clause(cx.tcx, expr) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index fc5835408a9..6add1a81a0a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -256,6 +256,7 @@ impl QuestionMark { let_expr, if_then, if_else, + .. }) = higher::IfLet::hir(cx, expr) && !is_else_clause(cx.tcx, expr) && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 3135a033648..b2054bf7d41 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -91,6 +91,9 @@ pub struct IfLet<'hir> { pub if_then: &'hir Expr<'hir>, /// `if let` else expression pub if_else: Option<&'hir Expr<'hir>>, + /// `if let PAT = EXPR` + /// ^^^^^^^^^^^^^^ + pub let_span: Span, } impl<'hir> IfLet<'hir> { @@ -99,9 +102,10 @@ impl<'hir> IfLet<'hir> { if let ExprKind::If( Expr { kind: - ExprKind::Let(hir::Let { + ExprKind::Let(&hir::Let { pat: let_pat, init: let_expr, + span: let_span, .. }), .. @@ -129,6 +133,7 @@ impl<'hir> IfLet<'hir> { let_expr, if_then, if_else, + let_span, }); } None @@ -146,6 +151,9 @@ pub enum IfLetOrMatch<'hir> { &'hir Pat<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>, + /// `if let PAT = EXPR` + /// ^^^^^^^^^^^^^^ + Span, ), } @@ -160,7 +168,8 @@ impl<'hir> IfLetOrMatch<'hir> { let_pat, if_then, if_else, - }| { Self::IfLet(let_expr, let_pat, if_then, if_else) }, + let_span, + }| { Self::IfLet(let_expr, let_pat, if_then, if_else, let_span) }, ), } } -- cgit 1.4.1-3-g733a5 From 71ea36b5391be5e19ae31e8d576fe7b31f6c8760 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Nov 2023 22:35:39 +0100 Subject: Extend `UNNECESSARY_TO_OWNED` to handle `split` --- clippy_lints/src/methods/unnecessary_to_owned.rs | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index c4775b6bd04..637368e9361 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -7,6 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node}; use rustc_hir_typeck::{FnCtxt, Inherited}; @@ -37,6 +38,9 @@ pub fn check<'tcx>( if is_cloned_or_copied(cx, method_name, method_def_id) { unnecessary_iter_cloned::check(cx, expr, method_name, receiver); } else if is_to_owned_like(cx, expr, method_name, method_def_id) { + if check_split_call_arg(cx, expr, method_name, receiver) { + return; + } // At this point, we know the call is of a `to_owned`-like function. The functions // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary // based on its context, that is, whether it is a referent in an `AddrOf` expression, an @@ -233,6 +237,58 @@ fn check_into_iter_call_arg( false } +/// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its +/// call of a `to_owned`-like function is unnecessary. +fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { + if let Some(parent) = get_parent_expr(cx, expr) + && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent) + && fn_name.as_str() == "split" + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(arg_snippet) = snippet_opt(cx, argument_expr.span) + { + // The next suggestion may be incorrect because the removal of the `to_owned`-like + // function could cause the iterator to hold a reference to a resource that is used + // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. + span_lint_and_sugg( + cx, + UNNECESSARY_TO_OWNED, + parent.span, + &format!("unnecessary use of `{method_name}`"), + "use", + format!("{receiver_snippet}.split({arg_snippet})"), + Applicability::MaybeIncorrect, + ); + return true; + } + false +} + +fn get_fn_name_and_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(Symbol, Expr<'tcx>)> { + match &expr.kind { + ExprKind::MethodCall(path, _, [arg_expr], ..) => Some((path.ident.name, *arg_expr)), + ExprKind::Call( + Expr { + kind: ExprKind::Path(qpath), + hir_id: path_hir_id, + .. + }, + [arg_expr], + ) => { + // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or + // deref to fn pointers, dyn Fn, impl Fn - #8850 + if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, def_id) = + cx.typeck_results().qpath_res(qpath, *path_hir_id) + && let Some(fn_name) = cx.tcx.opt_item_name(def_id) + { + Some((fn_name, *arg_expr)) + } else { + None + } + }, + _ => None, + } +} + /// Checks whether `expr` is an argument in a function call and, if so, determines whether its call /// of a `to_owned`-like function is unnecessary. fn check_other_call_arg<'tcx>( -- cgit 1.4.1-3-g733a5 From 25b9ca3f64bd3f7fda96e50f340c9c3459fe2e0a Mon Sep 17 00:00:00 2001 From: Quinn Sinclair Date: Wed, 20 Dec 2023 22:49:33 +0200 Subject: New lints `iter_filter_is_some` and `iter_filter_is_ok` Adds a pair of lints that check for cases of an iterator over `Result` and `Option` followed by `filter` without being followed by `map` as that is covered already by a different, specialized lint. changelog: New Lint: [`iter_filter_is_some`] changelog: New Lint: [`iter_filter_is_ok`] --- CHANGELOG.md | 2 + clippy_lints/src/declared_lints.rs | 2 + clippy_lints/src/methods/filter_map.rs | 1 + clippy_lints/src/methods/iter_filter.rs | 79 +++++++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 76 +++++++++++++++++++++++++++++-- tests/ui/iter_filter_is_ok.fixed | 8 ++++ tests/ui/iter_filter_is_ok.rs | 8 ++++ tests/ui/iter_filter_is_ok.stderr | 17 +++++++ tests/ui/iter_filter_is_some.fixed | 12 +++++ tests/ui/iter_filter_is_some.rs | 12 +++++ tests/ui/iter_filter_is_some.stderr | 17 +++++++ 11 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/methods/iter_filter.rs create mode 100644 tests/ui/iter_filter_is_ok.fixed create mode 100644 tests/ui/iter_filter_is_ok.rs create mode 100644 tests/ui/iter_filter_is_ok.stderr create mode 100644 tests/ui/iter_filter_is_some.fixed create mode 100644 tests/ui/iter_filter_is_some.rs create mode 100644 tests/ui/iter_filter_is_some.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7beb4eb17d4..9318c85ced9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5177,6 +5177,8 @@ Released 2018-09-13 [`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count +[`iter_filter_is_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_filter_is_ok +[`iter_filter_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_filter_is_some [`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 38fda36c58a..a00e2d3e044 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -369,6 +369,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITERATOR_STEP_BY_ZERO_INFO, crate::methods::ITER_CLONED_COLLECT_INFO, crate::methods::ITER_COUNT_INFO, + crate::methods::ITER_FILTER_IS_OK_INFO, + crate::methods::ITER_FILTER_IS_SOME_INFO, crate::methods::ITER_KV_MAP_INFO, crate::methods::ITER_NEXT_SLICE_INFO, crate::methods::ITER_NTH_INFO, diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index a8ca82d20e7..7cfd3d346b6 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -22,6 +22,7 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> hir::ExprKind::Path(QPath::Resolved(_, segments)) => { segments.segments.last().unwrap().ident.name == method_name }, + hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs new file mode 100644 index 00000000000..04dc4820f6a --- /dev/null +++ b/clippy_lints/src/methods/iter_filter.rs @@ -0,0 +1,79 @@ +use rustc_lint::LateContext; + +use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; + +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline}; +use clippy_utils::{is_trait_method, peel_blocks}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::QPath; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; +use std::borrow::Cow; + +fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { + match &expr.kind { + hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, + hir::ExprKind::Path(QPath::Resolved(_, segments)) => { + segments.segments.last().unwrap().ident.name == method_name + }, + hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + let body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(body.value); + let arg_id = body.params[0].pat.hir_id; + match closure_expr.kind { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { + if ident.name == method_name + && let hir::ExprKind::Path(path) = &receiver.kind + && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) + { + return arg_id == *local; + } + false + }, + _ => false, + } + }, + _ => false, + } +} + +fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) { + is_method(cx, parent_expr, rustc_span::sym::map) + } else { + false + } +} + +#[allow(clippy::too_many_arguments)] +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) { + let is_iterator = is_trait_method(cx, expr, sym::Iterator); + let parent_is_not_map = !parent_is_map(cx, expr); + + if is_iterator && parent_is_not_map && is_method(cx, filter_arg, sym!(is_some)) { + span_lint_and_sugg( + cx, + ITER_FILTER_IS_SOME, + filter_span.with_hi(expr.span.hi()), + "`filter` for `is_some` on iterator over `Option`", + "consider using `flatten` instead", + reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(), + Applicability::MaybeIncorrect, + ); + } + if is_iterator && parent_is_not_map && is_method(cx, filter_arg, sym!(is_ok)) { + span_lint_and_sugg( + cx, + ITER_FILTER_IS_OK, + filter_span.with_hi(expr.span.hi()), + "`filter` for `is_ok` on iterator over `Result`s", + "consider using `flatten` instead", + reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(), + Applicability::MaybeIncorrect, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a94524b3ba6..d67fa28b30b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -38,6 +38,7 @@ mod into_iter_on_ref; mod is_digit_ascii_radix; mod iter_cloned_collect; mod iter_count; +mod iter_filter; mod iter_kv_map; mod iter_next_slice; mod iter_nth; @@ -1175,7 +1176,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for iterators of `Option`s using ``.filter(Option::is_some).map(Option::unwrap)` that may + /// Checks for iterators of `Option`s using `.filter(Option::is_some).map(Option::unwrap)` that may /// be replaced with a `.flatten()` call. /// /// ### Why is this bad? @@ -3755,7 +3756,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for iterators of `Result`s using ``.filter(Result::is_ok).map(Result::unwrap)` that may + /// Checks for iterators of `Result`s using `.filter(Result::is_ok).map(Result::unwrap)` that may /// be replaced with a `.flatten()` call. /// /// ### Why is this bad? @@ -3776,6 +3777,58 @@ declare_clippy_lint! { "filtering `Result` for `Ok` then force-unwrapping, which can be one type-safe operation" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.filter(Optional::is_some)` that may be replaced with a `.flatten()` call. + /// This lint is potentially incorrect as it affects the type of follow-up calls. + /// + /// ### Why is this bad? + /// This pattern is often followed by manual unwrapping of the `Option`. The simplification + /// results in more readable and succint code without the need for manual unwrapping. + /// + /// ### Example + /// ```no_run + /// // example code where clippy issues a warning + /// vec![Some(1)].into_iter().filter(Option::is_some); + /// + /// ``` + /// Use instead: + /// ```no_run + /// // example code which does not raise clippy warning + /// vec![Some(1)].into_iter().flatten(); + /// ``` + #[clippy::version = "1.76.0"] + pub ITER_FILTER_IS_SOME, + complexity, + "filtering an iterator over `Option`s for `Some` can be achieved with `flatten`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call. + /// This lint is potentially incorrect as it affects the type of follow-up calls. + /// + /// ### Why is this bad? + /// This pattern is often followed by manual unwrapping of `Result`. The simplification + /// results in more readable and succint code without the need for manual unwrapping. + /// + /// ### Example + /// ```no_run + /// // example code where clippy issues a warning + /// vec![Ok::(1)].into_iter().filter(Result::is_ok); + /// + /// ``` + /// Use instead: + /// ```no_run + /// // example code which does not raise clippy warning + /// vec![Ok::(1)].into_iter().flatten(); + /// ``` + #[clippy::version = "1.76.0"] + pub ITER_FILTER_IS_OK, + complexity, + "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3928,6 +3981,8 @@ impl_lint_pass!(Methods => [ JOIN_ABSOLUTE_PATHS, OPTION_MAP_OR_ERR_OK, RESULT_FILTER_MAP, + ITER_FILTER_IS_SOME, + ITER_FILTER_IS_OK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4257,7 +4312,22 @@ impl Methods { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); }, - (name @ ("filter" | "find"), [arg]) => { + ("filter", [arg]) => { + if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { + // if `arg` has side-effect, the semantic will change + iter_overeager_cloned::check( + cx, + expr, + recv, + recv2, + iter_overeager_cloned::Op::FixClosure(name, arg), + false, + ); + } + + iter_filter::check(cx, expr, arg, span); + }, + ("find", [arg]) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { // if `arg` has side-effect, the semantic will change iter_overeager_cloned::check( diff --git a/tests/ui/iter_filter_is_ok.fixed b/tests/ui/iter_filter_is_ok.fixed new file mode 100644 index 00000000000..9985877a02a --- /dev/null +++ b/tests/ui/iter_filter_is_ok.fixed @@ -0,0 +1,8 @@ +#![warn(clippy::iter_filter_is_ok)] + +fn main() { + let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); + //~^ HELP: consider using `flatten` instead + let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); + //~^ HELP: consider using `flatten` instead +} diff --git a/tests/ui/iter_filter_is_ok.rs b/tests/ui/iter_filter_is_ok.rs new file mode 100644 index 00000000000..176ce902637 --- /dev/null +++ b/tests/ui/iter_filter_is_ok.rs @@ -0,0 +1,8 @@ +#![warn(clippy::iter_filter_is_ok)] + +fn main() { + let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok); + //~^ HELP: consider using `flatten` instead + let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok()); + //~^ HELP: consider using `flatten` instead +} diff --git a/tests/ui/iter_filter_is_ok.stderr b/tests/ui/iter_filter_is_ok.stderr new file mode 100644 index 00000000000..a5d7da977ff --- /dev/null +++ b/tests/ui/iter_filter_is_ok.stderr @@ -0,0 +1,17 @@ +error: `filter` for `is_ok` on iterator over `Result`s + --> $DIR/iter_filter_is_ok.rs:4:52 + | +LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + | + = note: `-D clippy::iter-filter-is-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_ok)]` + +error: `filter` for `is_ok` on iterator over `Result`s + --> $DIR/iter_filter_is_ok.rs:6:52 + | +LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok()); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/iter_filter_is_some.fixed b/tests/ui/iter_filter_is_some.fixed new file mode 100644 index 00000000000..3732a8e72d1 --- /dev/null +++ b/tests/ui/iter_filter_is_some.fixed @@ -0,0 +1,12 @@ +#![warn(clippy::iter_filter_is_some)] + +fn odds_out(x: i32) -> Option { + if x % 2 == 0 { Some(x) } else { None } +} + +fn main() { + let _ = vec![Some(1)].into_iter().flatten(); + //~^ HELP: consider using `flatten` instead + let _ = vec![Some(1)].into_iter().flatten(); + //~^ HELP: consider using `flatten` instead +} diff --git a/tests/ui/iter_filter_is_some.rs b/tests/ui/iter_filter_is_some.rs new file mode 100644 index 00000000000..5cc457efed5 --- /dev/null +++ b/tests/ui/iter_filter_is_some.rs @@ -0,0 +1,12 @@ +#![warn(clippy::iter_filter_is_some)] + +fn odds_out(x: i32) -> Option { + if x % 2 == 0 { Some(x) } else { None } +} + +fn main() { + let _ = vec![Some(1)].into_iter().filter(Option::is_some); + //~^ HELP: consider using `flatten` instead + let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()); + //~^ HELP: consider using `flatten` instead +} diff --git a/tests/ui/iter_filter_is_some.stderr b/tests/ui/iter_filter_is_some.stderr new file mode 100644 index 00000000000..2b1c1cdf7ef --- /dev/null +++ b/tests/ui/iter_filter_is_some.stderr @@ -0,0 +1,17 @@ +error: `filter` for `is_some` on iterator over `Option` + --> $DIR/iter_filter_is_some.rs:8:39 + | +LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + | + = note: `-D clippy::iter-filter-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]` + +error: `filter` for `is_some` on iterator over `Option` + --> $DIR/iter_filter_is_some.rs:10:39 + | +LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 4b1ac31c18be2e7c8175c9a66bf45a038e76ee6e Mon Sep 17 00:00:00 2001 From: Quinn Sinclair Date: Sun, 24 Dec 2023 14:40:14 +0200 Subject: Added MSRV and more tests, improved wording --- clippy_config/src/msrvs.rs | 1 + clippy_lints/src/methods/iter_filter.rs | 26 ++++++++++++++++++++------ clippy_lints/src/methods/mod.rs | 15 +++++++++------ tests/ui/iter_filter_is_ok.fixed | 14 ++++++++++++++ tests/ui/iter_filter_is_ok.rs | 14 ++++++++++++++ tests/ui/iter_filter_is_some.fixed | 18 ++++++++++++++---- tests/ui/iter_filter_is_some.rs | 18 ++++++++++++++---- tests/ui/iter_filter_is_some.stderr | 4 ++-- 8 files changed, 88 insertions(+), 22 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index b3ef666e306..8dec477cfdd 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -41,6 +41,7 @@ msrv_aliases! { 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } + 1,29,0 { ITER_FLATTEN } 1,28,0 { FROM_BOOL } 1,27,0 { ITERATOR_TRY_FOLD } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index 04dc4820f6a..f80bd2e2707 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -1,10 +1,10 @@ -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::{is_trait_method, peel_blocks}; +use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; @@ -54,7 +54,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir let is_iterator = is_trait_method(cx, expr, sym::Iterator); let parent_is_not_map = !parent_is_map(cx, expr); - if is_iterator && parent_is_not_map && is_method(cx, filter_arg, sym!(is_some)) { + if is_iterator + && parent_is_not_map + && is_method(cx, filter_arg, sym!(is_some)) + && !span_contains_comment( + cx.sess().source_map(), + filter_span.with_hi(expr.span.hi()) + ) + { span_lint_and_sugg( cx, ITER_FILTER_IS_SOME, @@ -62,10 +69,17 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir "`filter` for `is_some` on iterator over `Option`", "consider using `flatten` instead", reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(), - Applicability::MaybeIncorrect, + Applicability::HasPlaceholders, ); } - if is_iterator && parent_is_not_map && is_method(cx, filter_arg, sym!(is_ok)) { + if is_iterator + && parent_is_not_map + && is_method(cx, filter_arg, sym!(is_ok)) + && !span_contains_comment( + cx.sess().source_map(), + filter_span.with_hi(expr.span.hi()) + ) + { span_lint_and_sugg( cx, ITER_FILTER_IS_OK, @@ -73,7 +87,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir "`filter` for `is_ok` on iterator over `Result`s", "consider using `flatten` instead", reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(), - Applicability::MaybeIncorrect, + Applicability::HasPlaceholders, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d67fa28b30b..7a28f10ea87 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3779,8 +3779,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `.filter(Optional::is_some)` that may be replaced with a `.flatten()` call. - /// This lint is potentially incorrect as it affects the type of follow-up calls. + /// Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call. + /// This lint will require additional changes to the follow-up calls as it appects the type. /// /// ### Why is this bad? /// This pattern is often followed by manual unwrapping of the `Option`. The simplification @@ -3799,14 +3799,14 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.76.0"] pub ITER_FILTER_IS_SOME, - complexity, + pedantic, "filtering an iterator over `Option`s for `Some` can be achieved with `flatten`" } declare_clippy_lint! { /// ### What it does /// Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call. - /// This lint is potentially incorrect as it affects the type of follow-up calls. + /// This lint will require additional changes to the follow-up calls as it appects the type. /// /// ### Why is this bad? /// This pattern is often followed by manual unwrapping of `Result`. The simplification @@ -3825,7 +3825,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.76.0"] pub ITER_FILTER_IS_OK, - complexity, + pedantic, "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`" } @@ -4324,8 +4324,11 @@ impl Methods { false, ); } + if self.msrv.meets(msrvs::ITER_FLATTEN) { - iter_filter::check(cx, expr, arg, span); + // use the sourcemap to get the span of the closure + iter_filter::check(cx, expr, arg, span); + } }, ("find", [arg]) => { if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { diff --git a/tests/ui/iter_filter_is_ok.fixed b/tests/ui/iter_filter_is_ok.fixed index 9985877a02a..acfd097675c 100644 --- a/tests/ui/iter_filter_is_ok.fixed +++ b/tests/ui/iter_filter_is_ok.fixed @@ -5,4 +5,18 @@ fn main() { //~^ HELP: consider using `flatten` instead let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); //~^ HELP: consider using `flatten` instead + + // Don't lint below + let mut counter = 0; + let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { + counter += 1; + o.is_ok() + }); + let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { + // Roses are red, + // Violets are blue, + // `Err` is not an `Option`, + // and this doesn't ryme + o.is_ok() + }); } diff --git a/tests/ui/iter_filter_is_ok.rs b/tests/ui/iter_filter_is_ok.rs index 176ce902637..f13a28ad0e3 100644 --- a/tests/ui/iter_filter_is_ok.rs +++ b/tests/ui/iter_filter_is_ok.rs @@ -5,4 +5,18 @@ fn main() { //~^ HELP: consider using `flatten` instead let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok()); //~^ HELP: consider using `flatten` instead + + // Don't lint below + let mut counter = 0; + let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { + counter += 1; + o.is_ok() + }); + let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { + // Roses are red, + // Violets are blue, + // `Err` is not an `Option`, + // and this doesn't ryme + o.is_ok() + }); } diff --git a/tests/ui/iter_filter_is_some.fixed b/tests/ui/iter_filter_is_some.fixed index 3732a8e72d1..f70f54b622e 100644 --- a/tests/ui/iter_filter_is_some.fixed +++ b/tests/ui/iter_filter_is_some.fixed @@ -1,12 +1,22 @@ #![warn(clippy::iter_filter_is_some)] -fn odds_out(x: i32) -> Option { - if x % 2 == 0 { Some(x) } else { None } -} - fn main() { let _ = vec![Some(1)].into_iter().flatten(); //~^ HELP: consider using `flatten` instead let _ = vec![Some(1)].into_iter().flatten(); //~^ HELP: consider using `flatten` instead + + // Don't lint below + let mut counter = 0; + let _ = vec![Some(1)].into_iter().filter(|o| { + counter += 1; + o.is_some() + }); + let _ = vec![Some(1)].into_iter().filter(|o| { + // Roses are red, + // Violets are blue, + // `Err` is not an `Option`, + // and this doesn't ryme + o.is_some() + }); } diff --git a/tests/ui/iter_filter_is_some.rs b/tests/ui/iter_filter_is_some.rs index 5cc457efed5..18d450e8a98 100644 --- a/tests/ui/iter_filter_is_some.rs +++ b/tests/ui/iter_filter_is_some.rs @@ -1,12 +1,22 @@ #![warn(clippy::iter_filter_is_some)] -fn odds_out(x: i32) -> Option { - if x % 2 == 0 { Some(x) } else { None } -} - fn main() { let _ = vec![Some(1)].into_iter().filter(Option::is_some); //~^ HELP: consider using `flatten` instead let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()); //~^ HELP: consider using `flatten` instead + + // Don't lint below + let mut counter = 0; + let _ = vec![Some(1)].into_iter().filter(|o| { + counter += 1; + o.is_some() + }); + let _ = vec![Some(1)].into_iter().filter(|o| { + // Roses are red, + // Violets are blue, + // `Err` is not an `Option`, + // and this doesn't ryme + o.is_some() + }); } diff --git a/tests/ui/iter_filter_is_some.stderr b/tests/ui/iter_filter_is_some.stderr index 2b1c1cdf7ef..a9ef1d547a9 100644 --- a/tests/ui/iter_filter_is_some.stderr +++ b/tests/ui/iter_filter_is_some.stderr @@ -1,5 +1,5 @@ error: `filter` for `is_some` on iterator over `Option` - --> $DIR/iter_filter_is_some.rs:8:39 + --> $DIR/iter_filter_is_some.rs:4:39 | LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` @@ -8,7 +8,7 @@ LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some); = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]` error: `filter` for `is_some` on iterator over `Option` - --> $DIR/iter_filter_is_some.rs:10:39 + --> $DIR/iter_filter_is_some.rs:6:39 | LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` -- cgit 1.4.1-3-g733a5 From 2177f2cb9699a410302d474d7baf3e6d546530e9 Mon Sep 17 00:00:00 2001 From: Quinn Sinclair Date: Sun, 24 Dec 2023 14:42:18 +0200 Subject: formatting --- clippy_lints/src/methods/iter_filter.rs | 10 ++-------- clippy_lints/src/methods/mod.rs | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index f80bd2e2707..ade8e3155fa 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -57,10 +57,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir if is_iterator && parent_is_not_map && is_method(cx, filter_arg, sym!(is_some)) - && !span_contains_comment( - cx.sess().source_map(), - filter_span.with_hi(expr.span.hi()) - ) + && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi())) { span_lint_and_sugg( cx, @@ -75,10 +72,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir if is_iterator && parent_is_not_map && is_method(cx, filter_arg, sym!(is_ok)) - && !span_contains_comment( - cx.sess().source_map(), - filter_span.with_hi(expr.span.hi()) - ) + && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi())) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7a28f10ea87..25b1ea526e2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4325,7 +4325,6 @@ impl Methods { ); } if self.msrv.meets(msrvs::ITER_FLATTEN) { - // use the sourcemap to get the span of the closure iter_filter::check(cx, expr, arg, span); } -- cgit 1.4.1-3-g733a5 From c4a80f2e3e8375ff54826840e2e2a5c53a20e2ce Mon Sep 17 00:00:00 2001 From: Yuxiang Qiu Date: Fri, 24 Nov 2023 20:56:57 -0500 Subject: feat: add `manual_is_variant_and` lint --- CHANGELOG.md | 1 + clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lines_filter_map_ok.rs | 3 +- clippy_lints/src/methods/manual_is_variant_and.rs | 59 ++++++++++++++++ clippy_lints/src/methods/mod.rs | 36 +++++++++- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/path_ends_with_ext.rs | 2 +- tests/ui/manual_is_variant_and.fixed | 51 ++++++++++++++ tests/ui/manual_is_variant_and.rs | 57 ++++++++++++++++ tests/ui/manual_is_variant_and.stderr | 82 +++++++++++++++++++++++ 11 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 clippy_lints/src/methods/manual_is_variant_and.rs create mode 100644 tests/ui/manual_is_variant_and.fixed create mode 100644 tests/ui/manual_is_variant_and.rs create mode 100644 tests/ui/manual_is_variant_and.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index e01c09b295c..054d9390dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5293,6 +5293,7 @@ Released 2018-09-13 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite +[`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 8dec477cfdd..773cce36df4 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -17,7 +17,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } - 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } + 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a00e2d3e044..1db94ad3045 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -385,6 +385,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 8a0955147bb..29957e423b0 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -96,8 +96,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo ExprKind::Path(qpath) => cx .qpath_res(qpath, fm_arg.hir_id) .opt_def_id() - .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)) - .unwrap_or_default(), + .is_some_and(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)), // Detect `|x| x.ok()` ExprKind::Closure(Closure { body, .. }) => { if let Body { diff --git a/clippy_lints/src/methods/manual_is_variant_and.rs b/clippy_lints/src/methods/manual_is_variant_and.rs new file mode 100644 index 00000000000..d29acd4622a --- /dev/null +++ b/clippy_lints/src/methods/manual_is_variant_and.rs @@ -0,0 +1,59 @@ +use clippy_config::msrvs::{Msrv, OPTION_RESULT_IS_VARIANT_AND}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_span::{sym, Span}; + +use super::MANUAL_IS_VARIANT_AND; + +pub(super) fn check<'tcx>( + cx: &LateContext<'_>, + expr: &'tcx rustc_hir::Expr<'_>, + map_recv: &'tcx rustc_hir::Expr<'_>, + map_arg: &'tcx rustc_hir::Expr<'_>, + map_span: Span, + msrv: &Msrv, +) { + // Don't lint if: + + // 1. the `expr` is generated by a macro + if expr.span.from_expansion() { + return; + } + + // 2. the caller of `map()` is neither `Option` nor `Result` + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(map_recv), sym::Option); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(map_recv), sym::Result); + if !is_option && !is_result { + return; + } + + // 3. the caller of `unwrap_or_default` is neither `Option` nor `Result` + if !cx.typeck_results().expr_ty(expr).is_bool() { + return; + } + + // 4. msrv doesn't meet `OPTION_RESULT_IS_VARIANT_AND` + if !msrv.meets(OPTION_RESULT_IS_VARIANT_AND) { + return; + } + + let lint_msg = if is_option { + "called `map().unwrap_or_default()` on an `Option` value" + } else { + "called `map().unwrap_or_default()` on a `Result` value" + }; + let suggestion = if is_option { "is_some_and" } else { "is_ok_and" }; + + span_lint_and_sugg( + cx, + MANUAL_IS_VARIANT_AND, + expr.span.with_lo(map_span.lo()), + lint_msg, + "use", + format!("{}({})", suggestion, snippet(cx, map_arg.span, "..")), + Applicability::MachineApplicable, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 25b1ea526e2..0cde17ef5ad 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -51,6 +51,7 @@ mod iter_skip_zero; mod iter_with_drain; mod iterator_step_by_zero; mod join_absolute_paths; +mod manual_is_variant_and; mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; @@ -3829,6 +3830,32 @@ declare_clippy_lint! { "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`" } +declare_clippy_lint! { + /// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type. + /// + /// ### Why is this bad? + /// Readability. These can be written more concisely as `option.is_some_and(f)` and `result.is_ok_and(f)`. + /// + /// ### Example + /// ```no_run + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.map(|a| a > 10).unwrap_or_default(); + /// result.map(|a| a > 10).unwrap_or_default(); + /// ``` + /// Use instead: + /// ```no_run + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option.is_some_and(|a| a > 10); + /// result.is_ok_and(|a| a > 10); + /// ``` + #[clippy::version = "1.76.0"] + pub MANUAL_IS_VARIANT_AND, + pedantic, + "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3983,6 +4010,7 @@ impl_lint_pass!(Methods => [ RESULT_FILTER_MAP, ITER_FILTER_IS_SOME, ITER_FILTER_IS_OK, + MANUAL_IS_VARIANT_AND, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4664,7 +4692,13 @@ impl Methods { } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, - ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => { + ("unwrap_or_default", []) => { + if let Some(("map", m_recv, [arg], span, _)) = method_call(recv) { + manual_is_variant_and::check(cx, expr, m_recv, arg, span, &self.msrv); + } + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + }, + ("unwrap_unchecked" | "unwrap_err_unchecked", []) => { unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("unwrap_or_else", [u_arg]) => { diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 63e64a5b35d..35deabe49b6 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -72,7 +72,7 @@ pub(super) fn check<'tcx>( } // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead - let suggest_is_some_and = msrv.meets(msrvs::OPTION_IS_SOME_AND) + let suggest_is_some_and = msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) && matches!(&unwrap_arg.kind, ExprKind::Lit(lit) if matches!(lit.node, rustc_ast::LitKind::Bool(false))); diff --git a/clippy_lints/src/methods/path_ends_with_ext.rs b/clippy_lints/src/methods/path_ends_with_ext.rs index 094ead9f4ad..29f44ec2a4d 100644 --- a/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/clippy_lints/src/methods/path_ends_with_ext.rs @@ -33,7 +33,7 @@ pub(super) fn check( && path.chars().all(char::is_alphanumeric) { let mut sugg = snippet(cx, recv.span, "..").into_owned(); - if msrv.meets(msrvs::OPTION_IS_SOME_AND) { + if msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) { let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#); } else { let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#); diff --git a/tests/ui/manual_is_variant_and.fixed b/tests/ui/manual_is_variant_and.fixed new file mode 100644 index 00000000000..8c34b51103c --- /dev/null +++ b/tests/ui/manual_is_variant_and.fixed @@ -0,0 +1,51 @@ +//@aux-build:option_helpers.rs +#![warn(clippy::manual_is_variant_and)] + +#[macro_use] +extern crate option_helpers; + +#[rustfmt::skip] +fn option_methods() { + let opt = Some(1); + + // Check for `option.map(_).unwrap_or_default()` use. + // Single line case. + let _ = opt.is_some_and(|x| x > 1); + // Multi-line cases. + let _ = opt.is_some_and(|x| { + x > 1 + }); + let _ = opt.is_some_and(|x| x > 1); + let _ = opt + .is_some_and(|x| x > 1); + + // won't fix because the return type of the closure is not `bool` + let _ = opt.map(|x| x + 1).unwrap_or_default(); + + let opt2 = Some('a'); + let _ = opt2.is_some_and(char::is_alphanumeric); // should lint + let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint +} + +#[rustfmt::skip] +fn result_methods() { + let res: Result = Ok(1); + + // multi line cases + let _ = res.is_ok_and(|x| { + x > 1 + }); + let _ = res.is_ok_and(|x| x > 1); + + // won't fix because the return type of the closure is not `bool` + let _ = res.map(|x| x + 1).unwrap_or_default(); + + let res2: Result = Ok('a'); + let _ = res2.is_ok_and(char::is_alphanumeric); // should lint + let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint +} + +fn main() { + option_methods(); + result_methods(); +} diff --git a/tests/ui/manual_is_variant_and.rs b/tests/ui/manual_is_variant_and.rs new file mode 100644 index 00000000000..25b2489d942 --- /dev/null +++ b/tests/ui/manual_is_variant_and.rs @@ -0,0 +1,57 @@ +//@aux-build:option_helpers.rs +#![warn(clippy::manual_is_variant_and)] + +#[macro_use] +extern crate option_helpers; + +#[rustfmt::skip] +fn option_methods() { + let opt = Some(1); + + // Check for `option.map(_).unwrap_or_default()` use. + // Single line case. + let _ = opt.map(|x| x > 1) + // Should lint even though this call is on a separate line. + .unwrap_or_default(); + // Multi-line cases. + let _ = opt.map(|x| { + x > 1 + } + ).unwrap_or_default(); + let _ = opt.map(|x| x > 1).unwrap_or_default(); + let _ = opt + .map(|x| x > 1) + .unwrap_or_default(); + + // won't fix because the return type of the closure is not `bool` + let _ = opt.map(|x| x + 1).unwrap_or_default(); + + let opt2 = Some('a'); + let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint + let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint +} + +#[rustfmt::skip] +fn result_methods() { + let res: Result = Ok(1); + + // multi line cases + let _ = res.map(|x| { + x > 1 + } + ).unwrap_or_default(); + let _ = res.map(|x| x > 1) + .unwrap_or_default(); + + // won't fix because the return type of the closure is not `bool` + let _ = res.map(|x| x + 1).unwrap_or_default(); + + let res2: Result = Ok('a'); + let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint + let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint +} + +fn main() { + option_methods(); + result_methods(); +} diff --git a/tests/ui/manual_is_variant_and.stderr b/tests/ui/manual_is_variant_and.stderr new file mode 100644 index 00000000000..c243de098dc --- /dev/null +++ b/tests/ui/manual_is_variant_and.stderr @@ -0,0 +1,82 @@ +error: called `map().unwrap_or_default()` on an `Option` value + --> $DIR/manual_is_variant_and.rs:13:17 + | +LL | let _ = opt.map(|x| x > 1) + | _________________^ +LL | | // Should lint even though this call is on a separate line. +LL | | .unwrap_or_default(); + | |____________________________^ help: use: `is_some_and(|x| x > 1)` + | + = note: `-D clippy::manual-is-variant-and` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]` + +error: called `map().unwrap_or_default()` on an `Option` value + --> $DIR/manual_is_variant_and.rs:17:17 + | +LL | let _ = opt.map(|x| { + | _________________^ +LL | | x > 1 +LL | | } +LL | | ).unwrap_or_default(); + | |_________________________^ + | +help: use + | +LL ~ let _ = opt.is_some_and(|x| { +LL + x > 1 +LL ~ }); + | + +error: called `map().unwrap_or_default()` on an `Option` value + --> $DIR/manual_is_variant_and.rs:21:17 + | +LL | let _ = opt.map(|x| x > 1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)` + +error: called `map().unwrap_or_default()` on an `Option` value + --> $DIR/manual_is_variant_and.rs:23:10 + | +LL | .map(|x| x > 1) + | __________^ +LL | | .unwrap_or_default(); + | |____________________________^ help: use: `is_some_and(|x| x > 1)` + +error: called `map().unwrap_or_default()` on an `Option` value + --> $DIR/manual_is_variant_and.rs:30:18 + | +LL | let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)` + +error: called `map().unwrap_or_default()` on a `Result` value + --> $DIR/manual_is_variant_and.rs:39:17 + | +LL | let _ = res.map(|x| { + | _________________^ +LL | | x > 1 +LL | | } +LL | | ).unwrap_or_default(); + | |_________________________^ + | +help: use + | +LL ~ let _ = res.is_ok_and(|x| { +LL + x > 1 +LL ~ }); + | + +error: called `map().unwrap_or_default()` on a `Result` value + --> $DIR/manual_is_variant_and.rs:43:17 + | +LL | let _ = res.map(|x| x > 1) + | _________________^ +LL | | .unwrap_or_default(); + | |____________________________^ help: use: `is_ok_and(|x| x > 1)` + +error: called `map().unwrap_or_default()` on a `Result` value + --> $DIR/manual_is_variant_and.rs:50:18 + | +LL | let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)` + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From e5c9fb68279322000536166a4a82a754904e52f7 Mon Sep 17 00:00:00 2001 From: Florian Brucker Date: Wed, 27 Dec 2023 22:15:17 +0100 Subject: 11973: Don't escape `"` in `'"'` --- clippy_lints/src/methods/utils.rs | 1 + tests/ui/single_char_pattern.fixed | 2 ++ tests/ui/single_char_pattern.rs | 2 ++ tests/ui/single_char_pattern.stderr | 26 ++++++++++++++++---------- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 9ad4250a141..3a0305b4d55 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -74,6 +74,7 @@ pub(super) fn get_hint_if_single_char_arg( match ch { "'" => "\\'", r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` _ => ch, } ); diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 79e7eda4070..9573fdbcfde 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -42,6 +42,8 @@ fn main() { x.split('\n'); x.split('\''); x.split('\''); + // Issue #11973: Don't escape `"` in `'"'` + x.split('"'); let h = HashSet::::new(); h.contains("X"); // should not warn diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 81962c0a6e9..8a04480dbc6 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -42,6 +42,8 @@ fn main() { x.split("\n"); x.split("'"); x.split("\'"); + // Issue #11973: Don't escape `"` in `'"'` + x.split("\""); let h = HashSet::::new(); h.contains("X"); // should not warn diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 6e57ab3489f..781ab316d9d 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -182,58 +182,64 @@ LL | x.split("\'"); | ^^^^ help: try using a `char` instead: `'\''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:49:31 + --> $DIR/single_char_pattern.rs:46:13 + | +LL | x.split("\""); + | ^^^^ help: try using a `char` instead: `'"'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:51:31 | LL | x.replace(';', ",").split(","); // issue #2978 | ^^^ help: try using a `char` instead: `','` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:50:19 + --> $DIR/single_char_pattern.rs:52:19 | LL | x.starts_with("\x03"); // issue #2996 | ^^^^^^ help: try using a `char` instead: `'\x03'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:57:13 + --> $DIR/single_char_pattern.rs:59:13 | LL | x.split(r"a"); | ^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:58:13 + --> $DIR/single_char_pattern.rs:60:13 | LL | x.split(r#"a"#); | ^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:59:13 + --> $DIR/single_char_pattern.rs:61:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: try using a `char` instead: `'a'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:60:13 + --> $DIR/single_char_pattern.rs:62:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: try using a `char` instead: `'\''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:61:13 + --> $DIR/single_char_pattern.rs:63:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:63:13 + --> $DIR/single_char_pattern.rs:65:13 | LL | x.split(r#"\"#); | ^^^^^^ help: try using a `char` instead: `'\\'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:64:13 + --> $DIR/single_char_pattern.rs:66:13 | LL | x.split(r"\"); | ^^^^ help: try using a `char` instead: `'\\'` -error: aborting due to 39 previous errors +error: aborting due to 40 previous errors -- cgit 1.4.1-3-g733a5 From 3fceca23bb64e304df56b3bd86d26790b5301bdf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 29 Dec 2023 05:16:53 +0000 Subject: Remove mitigations for incorrect node args --- clippy_lints/src/methods/unnecessary_to_owned.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 637368e9361..5f69cf6cd7a 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -445,11 +445,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< { let bound_fn_sig = cx.tcx.fn_sig(callee_def_id); let fn_sig = bound_fn_sig.skip_binder(); - if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) + if let Some(arg_index) = recv + .into_iter() + .chain(call_args) + .position(|arg| arg.hir_id == expr.hir_id) && let param_ty = fn_sig.input(arg_index).skip_binder() - && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind() - // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021 - && (param_index as usize) < call_generic_args.len() + && let ty::Param(ParamTy { index: param_index, .. }) = *param_ty.kind() { if fn_sig .skip_binder() -- cgit 1.4.1-3-g733a5 From fe35e08e9f96f9c829add20351b2fbf28faac324 Mon Sep 17 00:00:00 2001 From: Florian Brucker Date: Sun, 17 Dec 2023 18:46:49 +0100 Subject: 8733: Suggest `str.lines` when splitting at hard-coded newlines Adds a new `splitting_strings_at_newlines` lint that suggests to use `str.lines` instead of splitting a trimmed string at hard-coded newlines. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 35 ++++++++ clippy_lints/src/methods/str_split.rs | 38 +++++++++ tests/ui/str_split.fixed | 145 ++++++++++++++++++++++++++++++++++ tests/ui/str_split.rs | 145 ++++++++++++++++++++++++++++++++++ tests/ui/str_split.stderr | 65 +++++++++++++++ 7 files changed, 430 insertions(+) create mode 100644 clippy_lints/src/methods/str_split.rs create mode 100644 tests/ui/str_split.fixed create mode 100644 tests/ui/str_split.rs create mode 100644 tests/ui/str_split.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index e4e068f19d4..b9e441029b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5583,6 +5583,7 @@ Released 2018-09-13 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc [`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core +[`str_split_at_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_split_at_newline [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 9ab38dab1e5..02543ae912a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -435,6 +435,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, crate::methods::STRING_LIT_CHARS_ANY_INFO, + crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0cde17ef5ad..711cad1dcf6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -94,6 +94,7 @@ mod single_char_pattern; mod single_char_push_string; mod skip_while_next; mod stable_sort_primitive; +mod str_split; mod str_splitn; mod string_extend_chars; mod string_lit_chars_any; @@ -3856,6 +3857,36 @@ declare_clippy_lint! { "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usages of `str.trim().split("\n")` and `str.trim().split("\r\n")`. + /// + /// ### Why is this bad? + /// + /// Hard-coding the line endings makes the code less compatible. `str.lines` should be used instead. + /// + /// ### Example + /// ```no_run + /// "some\ntext\nwith\nnewlines\n".trim().split('\n'); + /// ``` + /// Use instead: + /// ```no_run + /// "some\ntext\nwith\nnewlines\n".lines(); + /// ``` + /// + /// ### Known Problems + /// + /// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or + /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is + /// valid. + /// ``` + #[clippy::version = "1.76.0"] + pub STR_SPLIT_AT_NEWLINE, + pedantic, + "splitting a trimmed string at hard-coded newlines" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4011,6 +4042,7 @@ impl_lint_pass!(Methods => [ ITER_FILTER_IS_SOME, ITER_FILTER_IS_OK, MANUAL_IS_VARIANT_AND, + STR_SPLIT_AT_NEWLINE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4597,6 +4629,9 @@ impl Methods { ("sort_unstable_by", [arg]) => { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, + ("split", [arg]) => { + str_split::check(cx, expr, recv, arg); + }, ("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); diff --git a/clippy_lints/src/methods/str_split.rs b/clippy_lints/src/methods/str_split.rs new file mode 100644 index 00000000000..3586e11f56a --- /dev/null +++ b/clippy_lints/src/methods/str_split.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::visitors::is_const_evaluatable; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::STR_SPLIT_AT_NEWLINE; + +pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'a Expr<'_>, split_arg: &'_ Expr<'_>) { + // We're looking for `A.trim().split(B)`, where the adjusted type of `A` is `&str` (e.g. an + // expression returning `String`), and `B` is a `Pattern` that hard-codes a newline (either `"\n"` + // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most + // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. + if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind + && trim_method_name.ident.as_str() == "trim" + && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str() + && !is_const_evaluatable(cx, trim_recv) + && let ExprKind::Lit(split_lit) = split_arg.kind + && (matches!(split_lit.node, LitKind::Char('\n')) + || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n"))) + { + let mut app = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + STR_SPLIT_AT_NEWLINE, + expr.span, + "using `str.trim().split()` with hard-coded newlines", + "use `str.lines()` instead", + format!( + "{}.lines()", + snippet_with_context(cx, trim_recv.span, expr.span.ctxt(), "..", &mut app).0 + ), + app, + ); + } +} diff --git a/tests/ui/str_split.fixed b/tests/ui/str_split.fixed new file mode 100644 index 00000000000..4f33241da7a --- /dev/null +++ b/tests/ui/str_split.fixed @@ -0,0 +1,145 @@ +#![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.lines(); + #[allow(clippy::single_char_pattern)] + let _ = s1.lines(); + let _ = s1.lines(); + + // Splitting a `String` variable at "\n" or "\r\n" after trimming should warn + let _ = s2.lines(); + #[allow(clippy::single_char_pattern)] + let _ = s2.lines(); + let _ = s2.lines(); + + // Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn. + let s3 = DerefsIntoStr { s: s1 }; + let _ = s3.lines(); + #[allow(clippy::single_char_pattern)] + let _ = s3.lines(); + let _ = s3.lines(); + + // If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix. + let _ = make_str!(s1).lines(); + + // 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"); +} diff --git a/tests/ui/str_split.rs b/tests/ui/str_split.rs new file mode 100644 index 00000000000..f24caa61c30 --- /dev/null +++ b/tests/ui/str_split.rs @@ -0,0 +1,145 @@ +#![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"); +} diff --git a/tests/ui/str_split.stderr b/tests/ui/str_split.stderr new file mode 100644 index 00000000000..ee0a9653711 --- /dev/null +++ b/tests/ui/str_split.stderr @@ -0,0 +1,65 @@ +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:59:13 + | +LL | let _ = s1.trim().split('\n'); + | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` + | + = note: `-D clippy::str-split-at-newline` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:61:13 + | +LL | let _ = s1.trim().split("\n"); + | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:62:13 + | +LL | let _ = s1.trim().split("\r\n"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:65:13 + | +LL | let _ = s2.trim().split('\n'); + | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:67:13 + | +LL | let _ = s2.trim().split("\n"); + | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:68:13 + | +LL | let _ = s2.trim().split("\r\n"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:72:13 + | +LL | let _ = s3.trim().split('\n'); + | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:74:13 + | +LL | let _ = s3.trim().split("\n"); + | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:75:13 + | +LL | let _ = s3.trim().split("\r\n"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` + +error: using `str.trim().split()` with hard-coded newlines + --> $DIR/str_split.rs:78:13 + | +LL | let _ = make_str!(s1).trim().split('\n'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()` + +error: aborting due to 10 previous errors + -- cgit 1.4.1-3-g733a5 From 457ab585fc5a5174021bed21c4c0a55deef9676c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 31 Dec 2023 14:44:11 +0100 Subject: Add `.front()` to `get_first` lint description --- clippy_lints/src/methods/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0cde17ef5ad..7f5c82a3e7a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2590,11 +2590,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for usage of `x.get(0)` instead of - /// `x.first()`. + /// `x.first()` or `x.front()`. /// /// ### Why is this bad? - /// Using `x.first()` is easier to read and has the same - /// result. + /// Using `x.first()` for `Vec`s and slices or `x.front()` + /// for `VecDeque`s is easier to read and has the same result. /// /// ### Example /// ```no_run @@ -2610,7 +2610,7 @@ declare_clippy_lint! { #[clippy::version = "1.63.0"] pub GET_FIRST, style, - "Using `x.get(0)` when `x.first()` is simpler" + "Using `x.get(0)` when `x.first()` or `x.front()` is simpler" } declare_clippy_lint! { -- cgit 1.4.1-3-g733a5 From 84e797499b803aed222b027e466113d2947c38ad Mon Sep 17 00:00:00 2001 From: roife Date: Mon, 1 Jan 2024 16:17:22 +0800 Subject: Add autofix for functions in unnecessary_fallible_conversions --- .../methods/unnecessary_fallible_conversions.rs | 101 ++++++++++++++------- 1 file changed, 68 insertions(+), 33 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index 89cf20c14fc..b646c5953e4 100644 --- a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_expr; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -29,6 +29,7 @@ fn check<'tcx>( node_args: ty::GenericArgsRef<'tcx>, kind: FunctionKind, primary_span: Span, + qpath: Option<&QPath<'_>>, ) { if let &[self_ty, other_ty] = node_args.as_slice() // useless_conversion already warns `T::try_from(T)`, so ignore it here @@ -45,47 +46,79 @@ fn check<'tcx>( && implements_trait(cx, self_ty, from_into_trait, &[other_ty]) && let Some(other_ty) = other_ty.as_type() { + // Extend the span to include the unwrap/expect call: + // `foo.try_into().expect("..")` + // ^^^^^^^^^^^^^^^^^^^^^^^ + // + // `try_into().unwrap()` specifically can be trivially replaced with just `into()`, + // so that can be machine-applicable let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| { if let ExprKind::MethodCall(path, .., span) = parent.kind && let sym::unwrap | sym::expect = path.ident.name { - Some(span) + // include `.` before `unwrap`/`expect` + Some(span.with_lo(expr.span.hi())) } else { None } }); - let (source_ty, target_ty, sugg, span, applicability) = match kind { - FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => { - // Extend the span to include the unwrap/expect call: - // `foo.try_into().expect("..")` - // ^^^^^^^^^^^^^^^^^^^^^^^ - // - // `try_into().unwrap()` specifically can be trivially replaced with just `into()`, - // so that can be machine-applicable - ( - self_ty, - other_ty, - "into()", - primary_span.with_hi(unwrap_span.hi()), - Applicability::MachineApplicable, - ) + let span = if let Some(unwrap_call) = parent_unwrap_call { + primary_span.with_hi(unwrap_call.hi()) + } else { + primary_span + }; + + let qpath_spans = qpath.and_then(|qpath| match qpath { + QPath::Resolved(_, path) => { + let segments = path.segments.iter().map(|seg| seg.ident).collect::>(); + (segments.len() == 2).then(|| vec![segments[0].span, segments[1].span]) + }, + QPath::TypeRelative(_, seg) => Some(vec![seg.ident.span]), + QPath::LangItem(_, _) => unreachable!("`TryFrom` and `TryInto` are not lang items"), + }); + + let (source_ty, target_ty, sugg, applicability) = match (kind, &qpath_spans, parent_unwrap_call) { + (FunctionKind::TryIntoMethod, _, Some(unwrap_span)) => { + let sugg = vec![(primary_span, String::from("into")), (unwrap_span, String::new())]; + (self_ty, other_ty, sugg, Applicability::MachineApplicable) + }, + (FunctionKind::TryFromFunction, Some(spans), Some(unwrap_span)) => { + let sugg = match spans.len() { + 1 => vec![(spans[0], String::from("from")), (unwrap_span, String::new())], + 2 => vec![ + (spans[0], String::from("From")), + (spans[1], String::from("from")), + (unwrap_span, String::new()), + ], + _ => unreachable!(), + }; + (other_ty, self_ty, sugg, Applicability::MachineApplicable) + }, + (FunctionKind::TryIntoFunction, Some(spans), Some(unwrap_span)) => { + let sugg = match spans.len() { + 1 => vec![(spans[0], String::from("into")), (unwrap_span, String::new())], + 2 => vec![ + (spans[0], String::from("Into")), + (spans[1], String::from("into")), + (unwrap_span, String::new()), + ], + _ => unreachable!(), + }; + (self_ty, other_ty, sugg, Applicability::MachineApplicable) + }, + (FunctionKind::TryFromFunction, _, _) => { + let sugg = vec![(primary_span, String::from("From::from"))]; + (other_ty, self_ty, sugg, Applicability::Unspecified) + }, + (FunctionKind::TryIntoFunction, _, _) => { + let sugg = vec![(primary_span, String::from("Into::into"))]; + (self_ty, other_ty, sugg, Applicability::Unspecified) + }, + (FunctionKind::TryIntoMethod, _, _) => { + let sugg = vec![(primary_span, String::from("into"))]; + (self_ty, other_ty, sugg, Applicability::Unspecified) }, - FunctionKind::TryFromFunction => ( - other_ty, - self_ty, - "From::from", - primary_span, - Applicability::Unspecified, - ), - FunctionKind::TryIntoFunction => ( - self_ty, - other_ty, - "Into::into", - primary_span, - Applicability::Unspecified, - ), - FunctionKind::TryIntoMethod => (self_ty, other_ty, "into", primary_span, Applicability::Unspecified), }; span_lint_and_then( @@ -97,7 +130,7 @@ fn check<'tcx>( with_forced_trimmed_paths!({ diag.note(format!("converting `{source_ty}` to `{target_ty}` cannot fail")); }); - diag.span_suggestion(span, "use", sugg, applicability); + diag.multipart_suggestion("use", sugg, applicability); }, ); } @@ -113,6 +146,7 @@ pub(super) fn check_method(cx: &LateContext<'_>, expr: &Expr<'_>) { cx.typeck_results().node_args(expr.hir_id), FunctionKind::TryIntoMethod, path.ident.span, + None, ); } } @@ -135,6 +169,7 @@ pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Exp _ => return, }, callee.span, + Some(qpath), ); } } -- cgit 1.4.1-3-g733a5 From 094ce3de3ee98842c9a2ffc74934959973da5d1b Mon Sep 17 00:00:00 2001 From: roife Date: Mon, 1 Jan 2024 16:28:34 +0800 Subject: Add comments for unnecessary_fallible_conversions --- .../methods/unnecessary_fallible_conversions.rs | 1 + tests/ui/unnecessary_fallible_conversions.rs | 6 ++---- tests/ui/unnecessary_fallible_conversions.stderr | 22 +++++++++------------- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index b646c5953e4..53069391633 100644 --- a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -63,6 +63,7 @@ fn check<'tcx>( } }); + // If there is an unwrap/expect call, extend the span to include the call let span = if let Some(unwrap_call) = parent_unwrap_call { primary_span.with_hi(unwrap_call.hi()) } else { diff --git a/tests/ui/unnecessary_fallible_conversions.rs b/tests/ui/unnecessary_fallible_conversions.rs index f9df782c4e2..9e4fd3b3f90 100644 --- a/tests/ui/unnecessary_fallible_conversions.rs +++ b/tests/ui/unnecessary_fallible_conversions.rs @@ -10,10 +10,8 @@ fn main() { let _: i64 = i32::try_into(0).unwrap(); let _: i64 = i32::try_into(0i32).expect("can't happen"); - let _ = >::try_from(0) - .unwrap(); - let _ = >::try_from(0). - expect("can't happen"); + let _ = >::try_from(0).unwrap(); + let _ = >::try_from(0).expect("can't happen"); let _: i64 = >::try_into(0).unwrap(); let _: i64 = >::try_into(0).expect("can't happen"); diff --git a/tests/ui/unnecessary_fallible_conversions.stderr b/tests/ui/unnecessary_fallible_conversions.stderr index 603c079bc0e..c16dd239a8b 100644 --- a/tests/ui/unnecessary_fallible_conversions.stderr +++ b/tests/ui/unnecessary_fallible_conversions.stderr @@ -81,35 +81,31 @@ LL + let _: i64 = i32::into(0i32); error: use of a fallible conversion when an infallible one could be used --> $DIR/unnecessary_fallible_conversions.rs:13:13 | -LL | let _ = >::try_from(0) - | _____________^ -LL | | .unwrap(); - | |_________________^ +LL | let _ = >::try_from(0).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: converting `i32` to `i64` cannot fail help: use | -LL - let _ = >::try_from(0) +LL - let _ = >::try_from(0).unwrap(); LL + let _ = >::from(0); | error: use of a fallible conversion when an infallible one could be used - --> $DIR/unnecessary_fallible_conversions.rs:15:13 + --> $DIR/unnecessary_fallible_conversions.rs:14:13 | -LL | let _ = >::try_from(0). - | _____________^ -LL | | expect("can't happen"); - | |______________________________^ +LL | let _ = >::try_from(0).expect("can't happen"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: converting `i32` to `i64` cannot fail help: use | -LL - let _ = >::try_from(0). +LL - let _ = >::try_from(0).expect("can't happen"); LL + let _ = >::from(0); | error: use of a fallible conversion when an infallible one could be used - --> $DIR/unnecessary_fallible_conversions.rs:18:18 + --> $DIR/unnecessary_fallible_conversions.rs:16:18 | LL | let _: i64 = >::try_into(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +118,7 @@ LL + let _: i64 = >::into(0); | error: use of a fallible conversion when an infallible one could be used - --> $DIR/unnecessary_fallible_conversions.rs:19:18 + --> $DIR/unnecessary_fallible_conversions.rs:17:18 | LL | let _: i64 = >::try_into(0).expect("can't happen"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 88541d66370aba7ec48661617afd4d712f4e6711 Mon Sep 17 00:00:00 2001 From: Yuxiang Qiu Date: Tue, 2 Jan 2024 19:21:51 -0500 Subject: fix some typos --- book/src/development/macro_expansions.md | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/missing_asserts_for_indexing.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_utils/src/ty/type_certainty/mod.rs | 6 +++--- tests/ui/as_conversions.rs | 2 +- tests/ui/default_numeric_fallback_i32.fixed | 2 +- tests/ui/default_numeric_fallback_i32.rs | 2 +- tests/ui/redundant_as_str.fixed | 2 +- tests/ui/redundant_as_str.rs | 2 +- tests/ui/regex.rs | 2 +- tests/ui/struct_fields.rs | 2 +- tests/ui/useless_conversion.fixed | 4 ++-- tests/ui/useless_conversion.rs | 4 ++-- 16 files changed, 21 insertions(+), 21 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/development/macro_expansions.md b/book/src/development/macro_expansions.md index c5eb000272d..aecca9ef72e 100644 --- a/book/src/development/macro_expansions.md +++ b/book/src/development/macro_expansions.md @@ -102,7 +102,7 @@ let x: Option = Some(42); m!(x, x.unwrap()); ``` -If the `m!(x, x.unwrapp());` line is expanded, we would get two expanded +If the `m!(x, x.unwrap());` line is expanded, we would get two expanded expressions: - `x.is_some()` (from the `$a.is_some()` line in the `m` macro) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4c21f49638b..fbca641cfa3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3786,7 +3786,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// This pattern is often followed by manual unwrapping of the `Option`. The simplification - /// results in more readable and succint code without the need for manual unwrapping. + /// results in more readable and succinct code without the need for manual unwrapping. /// /// ### Example /// ```no_run @@ -3812,7 +3812,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// This pattern is often followed by manual unwrapping of `Result`. The simplification - /// results in more readable and succint code without the need for manual unwrapping. + /// results in more readable and succinct code without the need for manual unwrapping. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 0f18e943451..bbc4d0a0f9a 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -331,7 +331,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap> slice, } if indexes.len() > 1 => { // if we have found an `assert!`, let's also check that it's actually right - // and if it convers the highest index and if not, suggest the correct length + // and if it covers the highest index and if not, suggest the correct length let sugg = match comparison { // `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks. // The user probably meant `v.len() > 5` diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 5978da83199..6bbe427ea29 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -165,7 +165,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { } fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - // It's very hard or impossable to check whether overridden operator have side-effect this lint. + // It's very hard or impossible to check whether overridden operator have side-effect this lint. // So, this function assume user-defined operator is overridden with an side-effect. // The definition of user-defined structure here is ADT-type, // Althrough this will weaken the ability of this lint, less error lint-fix happen. diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 90834d784a5..b4278d879e5 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for mis-uses of the serde API. + /// Checks for misuses of the serde API. /// /// ### Why is this bad? /// Serde is very finnicky about how its API should be diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 9b0dac6af25..b82bd1d7e7c 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -142,7 +142,7 @@ impl LateLintPass<'_> for WildcardImports { } else { // In this case, the `use_path.span` ends right before the `::*`, so we need to // extend it up to the `*`. Since it is hard to find the `*` in weird - // formattings like `use _ :: *;`, we extend it up to, but not including the + // formatting like `use _ :: *;`, we extend it up to, but not including the // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we // can just use the end of the item span let mut span = use_path.span.with_hi(item.span.hi()); diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index da71fc3aaa8..adca2ca1c3e 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -38,7 +38,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { ExprKind::Call(callee, args) => { let lhs = expr_type_certainty(cx, callee); - let rhs = if type_is_inferrable_from_arguments(cx, expr) { + let rhs = if type_is_inferable_from_arguments(cx, expr) { meet(args.iter().map(|arg| expr_type_certainty(cx, arg))) } else { Certainty::Uncertain @@ -57,7 +57,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id); }; let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false); - let rhs = if type_is_inferrable_from_arguments(cx, expr) { + let rhs = if type_is_inferable_from_arguments(cx, expr) { meet( std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))), ) @@ -279,7 +279,7 @@ fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: & } #[allow(clippy::cast_possible_truncation)] -fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { +fn type_is_inferable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let Some(callee_def_id) = (match expr.kind { ExprKind::Call(callee, _) => { let callee_ty = cx.typeck_results().expr_ty(callee); diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index 192eb51ea99..8499c0ac5a0 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -17,7 +17,7 @@ fn main() { with_span!( span - fn coverting() { + fn converting() { let x = 0u32 as u64; } ); diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index 9ef92d8f279..c364c683057 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -184,7 +184,7 @@ fn check_expect_suppression() { let x = 21; } -mod type_already_infered { +mod type_already_inferred { // Should NOT lint if bound to return type fn ret_i32() -> i32 { 1 diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 4b54b8d8458..ffa7b961d1c 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -184,7 +184,7 @@ fn check_expect_suppression() { let x = 21; } -mod type_already_infered { +mod type_already_inferred { // Should NOT lint if bound to return type fn ret_i32() -> i32 { 1 diff --git a/tests/ui/redundant_as_str.fixed b/tests/ui/redundant_as_str.fixed index a38523a7c79..4185b402226 100644 --- a/tests/ui/redundant_as_str.fixed +++ b/tests/ui/redundant_as_str.fixed @@ -11,7 +11,7 @@ fn main() { let _no_as_str = string.as_bytes(); let _no_as_str = string.is_empty(); - // These methods are not redundant, and are equivelant to + // These methods are not redundant, and are equivalent to // doing dereferencing the string and applying the method let _not_redundant = string.as_str().escape_unicode(); let _not_redundant = string.as_str().trim(); diff --git a/tests/ui/redundant_as_str.rs b/tests/ui/redundant_as_str.rs index 33adb609996..7a74d8a55de 100644 --- a/tests/ui/redundant_as_str.rs +++ b/tests/ui/redundant_as_str.rs @@ -11,7 +11,7 @@ fn main() { let _no_as_str = string.as_bytes(); let _no_as_str = string.is_empty(); - // These methods are not redundant, and are equivelant to + // These methods are not redundant, and are equivalent to // doing dereferencing the string and applying the method let _not_redundant = string.as_str().escape_unicode(); let _not_redundant = string.as_str().trim(); diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 1ea0d65bf1e..4fb6c08bb44 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -113,7 +113,7 @@ fn trivial_regex() { // #6005: unicode classes in bytes::Regex let a_byte_of_unicode = BRegex::new(r"\p{C}"); - // start and end word boundry, introduced in regex 0.10 + // start and end word boundary, introduced in regex 0.10 let _ = BRegex::new(r"\"); let _ = BRegex::new(r"\b{start}word\b{end}"); } diff --git a/tests/ui/struct_fields.rs b/tests/ui/struct_fields.rs index 8b1a1446e3c..a8b12c6dfe3 100644 --- a/tests/ui/struct_fields.rs +++ b/tests/ui/struct_fields.rs @@ -65,7 +65,7 @@ struct NotSnakeCase2 { someData_a_b: bool, } -// no error, threshold is 3 fiels by default +// no error, threshold is 3 fields by default struct Fooo { foo: u8, bar: u8, diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index ed8387b7eb2..ce00fde2f99 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -241,7 +241,7 @@ mod issue11300 { foo2::<(), _>([1, 2, 3].into_iter()); // This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`, - // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary. + // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary. foo3([1, 2, 3]); } @@ -253,7 +253,7 @@ mod issue11300 { S1.foo([1, 2]); - // ICE that occured in itertools + // ICE that occurred in itertools trait Itertools { fn interleave_shortest(self, other: J) where diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 991a7762fc6..39979619586 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -241,7 +241,7 @@ mod issue11300 { foo2::<(), _>([1, 2, 3].into_iter()); // This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`, - // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary. + // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary. foo3([1, 2, 3].into_iter()); } @@ -253,7 +253,7 @@ mod issue11300 { S1.foo([1, 2].into_iter()); - // ICE that occured in itertools + // ICE that occurred in itertools trait Itertools { fn interleave_shortest(self, other: J) where -- cgit 1.4.1-3-g733a5 From 5960107415caf34a84fc8bb2f2fd303b7e358041 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 30 Dec 2023 03:15:38 +0100 Subject: new lint: `option_as_ref_cloned` --- CHANGELOG.md | 1 + README.md | 2 +- book/src/README.md | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 32 +++++++++++++++++++- clippy_lints/src/methods/option_as_ref_cloned.rs | 24 +++++++++++++++ tests/ui/option_as_ref_cloned.fixed | 21 ++++++++++++++ tests/ui/option_as_ref_cloned.rs | 21 ++++++++++++++ tests/ui/option_as_ref_cloned.stderr | 37 ++++++++++++++++++++++++ 9 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/methods/option_as_ref_cloned.rs create mode 100644 tests/ui/option_as_ref_cloned.fixed create mode 100644 tests/ui/option_as_ref_cloned.rs create mode 100644 tests/ui/option_as_ref_cloned.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index e6c081ca94f..4d32bbec914 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5442,6 +5442,7 @@ Released 2018-09-13 [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some +[`option_as_ref_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_cloned [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used diff --git a/README.md b/README.md index 5d490645d89..0450b54121d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 486ea3df704..e7972b0db19 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f6c9ffea9fc..20230106d53 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -410,6 +410,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::NO_EFFECT_REPLACE_INFO, crate::methods::OBFUSCATED_IF_ELSE_INFO, crate::methods::OK_EXPECT_INFO, + crate::methods::OPTION_AS_REF_CLONED_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, crate::methods::OPTION_MAP_OR_ERR_OK_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fbca641cfa3..cf6f6ad1a0f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -71,6 +71,7 @@ mod no_effect_replace; mod obfuscated_if_else; mod ok_expect; mod open_options; +mod option_as_ref_cloned; mod option_as_ref_deref; mod option_map_or_err_ok; mod option_map_or_none; @@ -3887,6 +3888,31 @@ declare_clippy_lint! { "splitting a trimmed string at hard-coded newlines" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.as_ref().cloned()` and `.as_mut().cloned()` on `Option`s + /// + /// ### Why is this bad? + /// This can be written more concisely by cloning the `Option` directly. + /// + /// ### Example + /// ```no_run + /// fn foo(bar: &Option>) -> Option> { + /// bar.as_ref().cloned() + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn foo(bar: &Option>) -> Option> { + /// bar.clone() + /// } + /// ``` + #[clippy::version = "1.77.0"] + pub OPTION_AS_REF_CLONED, + pedantic, + "cloning an `Option` via `as_ref().cloned()`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4043,6 +4069,7 @@ impl_lint_pass!(Methods => [ ITER_FILTER_IS_OK, MANUAL_IS_VARIANT_AND, STR_SPLIT_AT_NEWLINE, + OPTION_AS_REF_CLONED, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4290,7 +4317,10 @@ 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), + ("cloned", []) => { + cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv); + option_as_ref_cloned::check(cx, recv, span); + }, ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => { needless_collect::check(cx, span, expr, recv, call_span); match method_call(recv) { diff --git a/clippy_lints/src/methods/option_as_ref_cloned.rs b/clippy_lints/src/methods/option_as_ref_cloned.rs new file mode 100644 index 00000000000..d7fec360fa2 --- /dev/null +++ b/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -0,0 +1,24 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::{sym, Span}; + +use super::{method_call, OPTION_AS_REF_CLONED}; + +pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { + if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option) + { + span_lint_and_sugg( + cx, + OPTION_AS_REF_CLONED, + as_ref_ident_span.to(cloned_ident_span), + &format!("cloning an `Option<_>` using `.{method}().cloned()`"), + "this can be written more concisely by cloning the `Option<_>` directly", + "clone".into(), + Applicability::MachineApplicable, + ); + } +} diff --git a/tests/ui/option_as_ref_cloned.fixed b/tests/ui/option_as_ref_cloned.fixed new file mode 100644 index 00000000000..394dad219f7 --- /dev/null +++ b/tests/ui/option_as_ref_cloned.fixed @@ -0,0 +1,21 @@ +#![warn(clippy::option_as_ref_cloned)] +#![allow(clippy::clone_on_copy)] + +fn main() { + let mut x = Some(String::new()); + + let _: Option = x.clone(); + let _: Option = x.clone(); + + let y = x.as_ref(); + let _: Option<&String> = y.clone(); + + macro_rules! cloned_recv { + () => { + x.as_ref() + }; + } + + // Don't lint when part of the expression is from a macro + let _: Option = cloned_recv!().cloned(); +} diff --git a/tests/ui/option_as_ref_cloned.rs b/tests/ui/option_as_ref_cloned.rs new file mode 100644 index 00000000000..7243957927b --- /dev/null +++ b/tests/ui/option_as_ref_cloned.rs @@ -0,0 +1,21 @@ +#![warn(clippy::option_as_ref_cloned)] +#![allow(clippy::clone_on_copy)] + +fn main() { + let mut x = Some(String::new()); + + let _: Option = x.as_ref().cloned(); + let _: Option = x.as_mut().cloned(); + + let y = x.as_ref(); + let _: Option<&String> = y.as_ref().cloned(); + + macro_rules! cloned_recv { + () => { + x.as_ref() + }; + } + + // Don't lint when part of the expression is from a macro + let _: Option = cloned_recv!().cloned(); +} diff --git a/tests/ui/option_as_ref_cloned.stderr b/tests/ui/option_as_ref_cloned.stderr new file mode 100644 index 00000000000..ea03da3b69f --- /dev/null +++ b/tests/ui/option_as_ref_cloned.stderr @@ -0,0 +1,37 @@ +error: cloning an `Option<_>` using `.as_ref().cloned()` + --> $DIR/option_as_ref_cloned.rs:7:31 + | +LL | let _: Option = x.as_ref().cloned(); + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::option-as-ref-cloned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_cloned)]` +help: this can be written more concisely by cloning the `Option<_>` directly + | +LL | let _: Option = x.clone(); + | ~~~~~ + +error: cloning an `Option<_>` using `.as_mut().cloned()` + --> $DIR/option_as_ref_cloned.rs:8:31 + | +LL | let _: Option = x.as_mut().cloned(); + | ^^^^^^^^^^^^^^^ + | +help: this can be written more concisely by cloning the `Option<_>` directly + | +LL | let _: Option = x.clone(); + | ~~~~~ + +error: cloning an `Option<_>` using `.as_ref().cloned()` + --> $DIR/option_as_ref_cloned.rs:11:32 + | +LL | let _: Option<&String> = y.as_ref().cloned(); + | ^^^^^^^^^^^^^^^ + | +help: this can be written more concisely by cloning the `Option<_>` directly + | +LL | let _: Option<&String> = y.clone(); + | ~~~~~ + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From e75841397365ff207553551f14ab35122774f23c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 4 Jan 2024 17:13:18 +0100 Subject: Add .as_ref() to suggestion to remove .to_string() --- clippy_lints/src/methods/unnecessary_to_owned.rs | 19 ++++++++++++++++--- tests/ui/unnecessary_to_owned_on_split.fixed | 18 +++++++++++++++++- tests/ui/unnecessary_to_owned_on_split.rs | 18 +++++++++++++++++- tests/ui/unnecessary_to_owned_on_split.stderr | 24 +++++++++++++++--------- 4 files changed, 65 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 5f69cf6cd7a..12106d44e36 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,13 +3,13 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_lang_item, peel_mid_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; use rustc_hir_typeck::{FnCtxt, Inherited}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; @@ -246,6 +246,19 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) && let Some(arg_snippet) = snippet_opt(cx, argument_expr.span) { + // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x` + // implements `AsRef` but does not implement `Deref`. In this case, we have to + // add `.as_ref()` to the suggestion. + let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) + && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) + && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target") + != Some(cx.tcx.types.str_) + { + ".as_ref()" + } else { + "" + }; + // The next suggestion may be incorrect because the removal of the `to_owned`-like // function could cause the iterator to hold a reference to a resource that is used // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. @@ -255,7 +268,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb parent.span, &format!("unnecessary use of `{method_name}`"), "use", - format!("{receiver_snippet}.split({arg_snippet})"), + format!("{receiver_snippet}{as_ref}.split({arg_snippet})"), Applicability::MaybeIncorrect, ); return true; diff --git a/tests/ui/unnecessary_to_owned_on_split.fixed b/tests/ui/unnecessary_to_owned_on_split.fixed index 53dc3c43e2f..f87c898f9b7 100644 --- a/tests/ui/unnecessary_to_owned_on_split.fixed +++ b/tests/ui/unnecessary_to_owned_on_split.fixed @@ -1,4 +1,18 @@ -#[allow(clippy::single_char_pattern)] +#![allow(clippy::single_char_pattern)] + +struct Issue12068; + +impl AsRef for Issue12068 { + fn as_ref(&self) -> &str { + "" + } +} + +impl ToString for Issue12068 { + fn to_string(&self) -> String { + String::new() + } +} fn main() { let _ = "a".split('a').next().unwrap(); @@ -9,6 +23,8 @@ fn main() { //~^ ERROR: unnecessary use of `to_owned` let _ = "a".split("a").next().unwrap(); //~^ ERROR: unnecessary use of `to_owned` + let _ = Issue12068.as_ref().split('a').next().unwrap(); + //~^ ERROR: unnecessary use of `to_string` let _ = [1].split(|x| *x == 2).next().unwrap(); //~^ ERROR: unnecessary use of `to_vec` diff --git a/tests/ui/unnecessary_to_owned_on_split.rs b/tests/ui/unnecessary_to_owned_on_split.rs index 62400e7eee1..db5719e5880 100644 --- a/tests/ui/unnecessary_to_owned_on_split.rs +++ b/tests/ui/unnecessary_to_owned_on_split.rs @@ -1,4 +1,18 @@ -#[allow(clippy::single_char_pattern)] +#![allow(clippy::single_char_pattern)] + +struct Issue12068; + +impl AsRef for Issue12068 { + fn as_ref(&self) -> &str { + "" + } +} + +impl ToString for Issue12068 { + fn to_string(&self) -> String { + String::new() + } +} fn main() { let _ = "a".to_string().split('a').next().unwrap(); @@ -9,6 +23,8 @@ fn main() { //~^ ERROR: unnecessary use of `to_owned` let _ = "a".to_owned().split("a").next().unwrap(); //~^ ERROR: unnecessary use of `to_owned` + let _ = Issue12068.to_string().split('a').next().unwrap(); + //~^ ERROR: unnecessary use of `to_string` let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); //~^ ERROR: unnecessary use of `to_vec` diff --git a/tests/ui/unnecessary_to_owned_on_split.stderr b/tests/ui/unnecessary_to_owned_on_split.stderr index cfb3766d15e..4cfaeed3384 100644 --- a/tests/ui/unnecessary_to_owned_on_split.stderr +++ b/tests/ui/unnecessary_to_owned_on_split.stderr @@ -1,5 +1,5 @@ error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned_on_split.rs:4:13 + --> $DIR/unnecessary_to_owned_on_split.rs:18:13 | LL | let _ = "a".to_string().split('a').next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')` @@ -8,46 +8,52 @@ LL | let _ = "a".to_string().split('a').next().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned_on_split.rs:6:13 + --> $DIR/unnecessary_to_owned_on_split.rs:20:13 | LL | let _ = "a".to_string().split("a").next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned_on_split.rs:8:13 + --> $DIR/unnecessary_to_owned_on_split.rs:22:13 | LL | let _ = "a".to_owned().split('a').next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned_on_split.rs:10:13 + --> $DIR/unnecessary_to_owned_on_split.rs:24:13 | LL | let _ = "a".to_owned().split("a").next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")` +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned_on_split.rs:26:13 + | +LL | let _ = Issue12068.to_string().split('a').next().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Issue12068.as_ref().split('a')` + error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned_on_split.rs:13:13 + --> $DIR/unnecessary_to_owned_on_split.rs:29:13 | LL | let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned_on_split.rs:15:13 + --> $DIR/unnecessary_to_owned_on_split.rs:31:13 | LL | let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned_on_split.rs:17:13 + --> $DIR/unnecessary_to_owned_on_split.rs:33:13 | LL | let _ = [1].to_owned().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned_on_split.rs:19:13 + --> $DIR/unnecessary_to_owned_on_split.rs:35:13 | LL | let _ = [1].to_owned().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From 28c133b4bc2795d78c0bc15d99af5e5f44093a2d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 6 Jan 2024 16:56:24 +0100 Subject: Extend `map_clone` lint to also work on non-explicit closures --- clippy_lints/src/methods/map_clone.rs | 98 +++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 34 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index cc6eeaa86e5..c8d5a358098 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; -use clippy_utils::{is_diag_trait_item, peel_blocks}; +use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -19,50 +19,63 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ && (cx.tcx.impl_of_method(method_id).map_or(false, |id| { is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option) }) || is_diag_trait_item(cx, method_id, sym::Iterator)) - && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(closure_body.value); - match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => { - if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind { - if ident_eq(name, closure_expr) { - lint_explicit_closure(cx, e.span, recv.span, true, msrv); - } - } - }, - hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { - match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { - if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { + match arg.kind { + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(closure_body.value); + match closure_body.params[0].pat.kind { + hir::PatKind::Ref(inner, hir::Mutability::Not) => { + if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind { + if ident_eq(name, closure_expr) { lint_explicit_closure(cx, e.span, recv.span, true, msrv); } } }, - hir::ExprKind::MethodCall(method, obj, [], _) => { - if ident_eq(name, obj) && method.ident.name == sym::clone - && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) - && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) - // no autoderefs - && !cx.typeck_results().expr_adjustments(obj).iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) - { - let obj_ty = cx.typeck_results().expr_ty(obj); - if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, *ty); - lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { + match closure_expr.kind { + hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { + if ident_eq(name, inner) { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } } - } else { - lint_needless_cloning(cx, e.span, recv.span); - } + }, + hir::ExprKind::MethodCall(method, obj, [], _) => { + if ident_eq(name, obj) && method.ident.name == sym::clone + && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) + && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) + && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) + // no autoderefs + && !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) + { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, *ty); + lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + } + } else { + lint_needless_cloning(cx, e.span, recv.span); + } + } + }, + _ => {}, } }, _ => {}, } }, + hir::ExprKind::Path(qpath) => { + if let Some(path_def_id) = cx.qpath_res(&qpath, arg.hir_id).opt_def_id() + && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD) + { + // FIXME: It would be better to infer the type to check if it's copyable or not + // to suggest to use `.copied()` instead of `.cloned()` where applicable. + lint_path(cx, e.span, recv.span); + } + }, _ => {}, } } @@ -88,6 +101,23 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { ); } +fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span) { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + MAP_CLONE, + replace, + "you are explicitly cloning with `.map()`", + "consider calling the dedicated `cloned` method", + format!( + "{}.cloned()", + snippet_with_applicability(cx, root, "..", &mut applicability), + ), + applicability, + ); +} + fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) { let mut applicability = Applicability::MachineApplicable; -- cgit 1.4.1-3-g733a5 From 78aa2e29e273fed22c53065ffc319ae75af0266c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 7 Jan 2024 13:13:29 +0100 Subject: Handle "calls" inside the closure as well in `map_clone` lint --- clippy_lints/src/methods/map_clone.rs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index c8d5a358098..652d2b80081 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -61,26 +61,39 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ } } }, + hir::ExprKind::Call(call, [_]) => { + if let hir::ExprKind::Path(qpath) = call.kind { + handle_path(cx, call, &qpath, e, recv); + } + }, _ => {}, } }, _ => {}, } }, - hir::ExprKind::Path(qpath) => { - if let Some(path_def_id) = cx.qpath_res(&qpath, arg.hir_id).opt_def_id() - && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD) - { - // FIXME: It would be better to infer the type to check if it's copyable or not - // to suggest to use `.copied()` instead of `.cloned()` where applicable. - lint_path(cx, e.span, recv.span); - } - }, + hir::ExprKind::Path(qpath) => handle_path(cx, arg, &qpath, e, recv), _ => {}, } } } +fn handle_path( + cx: &LateContext<'_>, + arg: &hir::Expr<'_>, + qpath: &hir::QPath<'_>, + e: &hir::Expr<'_>, + recv: &hir::Expr<'_>, +) { + if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id() + && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD) + { + // FIXME: It would be better to infer the type to check if it's copyable or not + // to suggest to use `.copied()` instead of `.cloned()` where applicable. + lint_path(cx, e.span, recv.span); + } +} + fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { path.segments.len() == 1 && path.segments[0].ident == name -- cgit 1.4.1-3-g733a5 From bbadce9ec0a8855ab72852af1a6ed1f68c9ce0c2 Mon Sep 17 00:00:00 2001 From: Quinn Sinclair Date: Wed, 3 Jan 2024 04:03:00 +0200 Subject: Fixed ICE introduced in #12004 Issue: in #12004, we emit a lint for `filter(Option::is_some)`. If the parent expression is a `.map` we don't emit that lint as there exists a more specialized lint for that. The ICE introduced in #12004 is a consequence of the assumption that a parent expression after a filter would be a method call with the filter call being the receiver. However, it is entirely possible to have a closure of the form ``` || { vec![Some(1), None].into_iter().filter(Option::is_some) } ``` The previous implementation looked at the parent expression; namely the closure, and tried to check the parameters by indexing [0] on an empty list. This commit is an overhaul of the lint with significantly more FP tests and checks. Impl details: 1. We verify that the filter method we are in is a proper trait method to avoid FPs. 2. We check that the parent expression is not a map by checking whether it exists; if is a trait method; and then a method call. 3. We check that we don't have comments in the span. 4. We verify that we are in an Iterator of Option and Result. 5. We check the contents of the filter. 1. For closures we peel it. If it is not a single expression, we don't lint. 2. For paths, we do a typecheck to avoid FPs for types that impl functions with the same names. 3. For calls, we verify the type, via the path, and that the param of the closure is the single argument to the call. 4. For method calls we verify that the receiver is the parameter of the closure. Since we handle single, non-block exprs, the parameter can't be shadowed, so no FP. This commit also adds additional FP tests. --- clippy_lints/src/methods/filter_map.rs | 3 +- clippy_lints/src/methods/iter_filter.rs | 206 +++++++++++++++++++++------- tests/ui/iter_filter_is_ok.fixed | 193 +++++++++++++++++++++++++- tests/ui/iter_filter_is_ok.rs | 193 +++++++++++++++++++++++++- tests/ui/iter_filter_is_ok.stderr | 74 ++++++++-- tests/ui/iter_filter_is_some.fixed | 231 ++++++++++++++++++++++++++++++-- tests/ui/iter_filter_is_some.rs | 231 ++++++++++++++++++++++++++++++-- tests/ui/iter_filter_is_some.stderr | 62 +++++++-- 8 files changed, 1092 insertions(+), 101 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 7cfd3d346b6..e489899c19e 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -26,13 +26,14 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); - let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if ident.name == method_name && let hir::ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) + && !body.params.is_empty() { + let arg_id = body.params[0].pat.hir_id; return arg_id == *local; } false diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index ade8e3155fa..9f84321ced4 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -1,87 +1,197 @@ +use clippy_utils::ty::get_iterator_item_ty; +use hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline}; -use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment}; +use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::QPath; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::borrow::Cow; -fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { - match &expr.kind { - hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, - hir::ExprKind::Path(QPath::Resolved(_, segments)) => { - segments.segments.last().unwrap().ident.name == method_name +/// +/// Returns true if the expression is a method call to `method_name` +/// e.g. `a.method_name()` or `Option::method_name`. +/// +/// The type-checker verifies for us that the method accepts the right kind of items +/// (e.g. `Option::is_some` accepts `Option<_>`), so we don't need to check that. +/// +/// How to capture each case: +/// +/// `.filter(|a| { std::option::Option::is_some(a) })` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a closure, getting unwrapped and +/// recursively checked. +/// `std::option::Option::is_some(a)` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a call. It unwraps to a path with +/// `QPath::TypeRelative`. Since this is a type relative path, we need to check the method name, the +/// type, and that the parameter of the closure is passed in the call. This part is the dual of +/// `receiver.method_name()` below. +/// +/// `filter(std::option::Option::is_some);` +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a type relative path, like above, we check the +/// type and the method name. +/// +/// `filter(|a| a.is_some());` +/// ^^^^^^^^^^^^^^^ <- this is a method call inside a closure, +/// we check that the parameter of the closure is the receiver of the method call and don't allow +/// any other parameters. +fn is_method( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + type_symbol: Symbol, + method_name: Symbol, + params: &[&hir::Pat<'_>], +) -> bool { + fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool { + match param.kind { + hir::PatKind::Binding(_, _, other, _) => ident == other, + hir::PatKind::Ref(pat, _) => pat_is_recv(ident, pat), + _ => false, + } + } + match expr.kind { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { + // compare the identifier of the receiver to the parameter + // we are in a filter => closure has a single parameter and a single, non-block + // expression, this means that the parameter shadows all outside variables with + // the same name => avoid FPs. If the parameter is not the receiver, then this hits + // outside variables => avoid FP + if ident.name == method_name + && let ExprKind::Path(QPath::Resolved(None, path)) = recv.kind + && let &[seg] = path.segments + && params.iter().any(|p| pat_is_recv(seg.ident, p)) + { + return true; + } + false + }, + // This is used to check for complete paths via `|a| std::option::Option::is_some(a)` + // this then unwraps to a path with `QPath::TypeRelative` + // we pass the params as they've been passed to the current call through the closure + hir::ExprKind::Call(expr, [param]) => { + // this will hit the `QPath::TypeRelative` case and check that the method name is correct + if is_method(cx, expr, type_symbol, method_name, params) + // we then check that this is indeed passing the parameter of the closure + && let ExprKind::Path(QPath::Resolved(None, path)) = param.kind + && let &[seg] = path.segments + && params.iter().any(|p| pat_is_recv(seg.ident, p)) + { + return true; + } + false + }, + hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => { + let ty = cx.typeck_results().node_type(ty.hir_id); + if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol) + && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def() + { + return mname.ident.name == method_name; + } + false }, - hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); - let arg_id = body.params[0].pat.hir_id; - match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { - if ident.name == method_name - && let hir::ExprKind::Path(path) = &receiver.kind - && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) - { - return arg_id == *local; - } - false - }, - _ => false, - } + let params = body.params.iter().map(|param| param.pat).collect::>(); + is_method(cx, closure_expr, type_symbol, method_name, params.as_slice()) }, _ => false, } } fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) { - is_method(cx, parent_expr, rustc_span::sym::map) - } else { - false + if let Some(expr) = get_parent_expr(cx, expr) + && is_trait_method(cx, expr, sym::Iterator) + && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind + && path.ident.name == rustc_span::sym::map + { + return true; } + false } -#[allow(clippy::too_many_arguments)] -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) { - let is_iterator = is_trait_method(cx, expr, sym::Iterator); - let parent_is_not_map = !parent_is_map(cx, expr); +enum FilterType { + IsSome, + IsOk, +} - if is_iterator - && parent_is_not_map - && is_method(cx, filter_arg, sym!(is_some)) - && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi())) +/// Returns the `FilterType` of the expression if it is a filter over an Iter, )" }; - let msg = &format!("called `map().unwrap_or({arg})` on an `Option` value"); + let msg = format!("called `map().unwrap_or({arg})` on an `Option` value"); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_arg.span; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 0602eeaa704..583e04fb4b1 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( cx, UNWRAP_OR_DEFAULT, method_span.with_hi(span.hi()), - &format!("use of `{name}` to construct default value"), + format!("use of `{name}` to construct default value"), "try", format!("{sugg}()"), Applicability::MachineApplicable, @@ -167,7 +167,7 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("{name}_{suffix}({sugg})"), app, diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 1148628b084..28ca76832eb 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' cx, RANGE_ZIP_WITH_LEN, expr.span, - &format!( + format!( "it is more idiomatic to use `{}.iter().enumerate()`", snippet(cx, recv.span, "_") ), diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 0c3b881b086..ac5cc2f01e5 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "consider using", format!( "any({})", @@ -76,7 +76,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, expr.span, - &msg, + msg, "consider using", format!( "!{iter}.any({})", @@ -94,7 +94,7 @@ pub(super) fn check<'tcx>( "" } ); - span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, &hint); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, msg, None, hint); } } // lint if `find()` is called by `String` or `&str` @@ -117,7 +117,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "consider using", format!("contains({find_arg})"), applicability, @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, expr.span, - &msg, + msg, "consider using", format!("!{string}.contains({find_arg})"), applicability, diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 0f4c97022db..aef14435d8a 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx cx, STABLE_SORT_PRIMITIVE, e.span, - &format!("used `sort` on primitive type `{slice_type}`"), + format!("used `sort` on primitive type `{slice_type}`"), |diag| { let mut app = Applicability::MachineApplicable; let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 55cd1a38ec9..955330237bf 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -53,7 +53,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_ cx, NEEDLESS_SPLITN, expr.span, - &format!("unnecessary use of `{r}splitn`"), + format!("unnecessary use of `{r}splitn`"), "try", format!( "{}.{r}split({})", @@ -154,7 +154,7 @@ fn check_manual_split_once_indirect( let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; - span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| { + span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, msg, |diag| { diag.span_label(first.span, "first usage here"); diag.span_label(second.span, "second usage here"); diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index c45212581ee..ff5c1d1a401 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -37,6 +37,6 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se ) }; - span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, &msg, None, note_msg); + span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, msg, None, note_msg); } } diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 60864902a48..ce7aefed01f 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -23,7 +23,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &with_forced_trimmed_paths!(format!( + with_forced_trimmed_paths!(format!( "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), |diag| { diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index 31e6ccb950a..6f9b38fcf83 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -55,7 +55,7 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) cx, TYPE_ID_ON_BOX, call_span, - &format!("calling `.type_id()` on `{ty_name}`"), + format!("calling `.type_id()` on `{ty_name}`"), |diag| { let derefs = recv_adjusts .iter() diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index fabf3fa0c0c..daf99d98614 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a UNNECESSARY_FIND_MAP }, expr.span, - &format!("this `.{name}` can be written more simply using `.{sugg}`"), + format!("this `.{name}` can be written more simply using `.{sugg}`"), ); } } diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index cc8053ef507..f6184222d8e 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -58,7 +58,7 @@ pub(super) fn check( cx, UNNECESSARY_GET_THEN_CHECK, both_calls_span, - &format!("unnecessary use of `{snippet}`"), + format!("unnecessary use of `{snippet}`"), "replace it with", suggestion, Applicability::MaybeIncorrect, @@ -70,7 +70,7 @@ pub(super) fn check( cx, UNNECESSARY_GET_THEN_CHECK, both_calls_span, - &format!("unnecessary use of `{snippet}`"), + format!("unnecessary use of `{snippet}`"), |diag| { diag.span_suggestion( full_span, diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 36497d59a5a..520dcb2d52d 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -61,7 +61,7 @@ pub fn check_for_loop_iter( cx, UNNECESSARY_TO_OWNED, expr.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), |diag| { // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to // a `to_owned`-like function was removed, then the next suggestion may be diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 1b2bfbf4090..494d71fc053 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -63,7 +63,7 @@ pub(super) fn check( let help_message = format!("used `{method}()` on `{constructor}` value"); let suggestion_message = format!("remove the `{constructor}` and `{method}()`"); - span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| { let suggestions = match (constructor, method, ty) { ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), ("None", "expect", _) => Some(vec![ diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index c234e4f9b11..0762115d212 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -138,7 +138,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!( "{:&>width$}{receiver_snippet}", @@ -163,7 +163,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", receiver_snippet, Applicability::MachineApplicable, @@ -173,7 +173,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "remove this", String::new(), Applicability::MachineApplicable, @@ -188,7 +188,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.as_ref()"), Applicability::MachineApplicable, @@ -232,7 +232,7 @@ fn check_into_iter_call_arg( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.iter().{cloned_or_copied}()"), Applicability::MaybeIncorrect, @@ -271,7 +271,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}{as_ref}.split({arg_snippet})"), Applicability::MaybeIncorrect, @@ -353,7 +353,7 @@ fn check_other_call_arg<'tcx>( cx, UNNECESSARY_TO_OWNED, maybe_arg.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{:&>n_refs$}{receiver_snippet}", ""), Applicability::MachineApplicable, @@ -645,7 +645,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx cx, UNNECESSARY_TO_OWNED, arg.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "replace it with", if original_arg_ty.is_array() { format!("{snippet}.as_slice()") diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 7bd16b473ce..516b8984ad7 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -69,7 +69,7 @@ pub(super) fn check( cx, variant.lint(), expr.span, - &format!("used `{}()` on {kind} value", variant.method_name(is_err)), + format!("used `{}()` on {kind} value", variant.method_name(is_err)), |diag| { diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic")); diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 474103fccd2..ae2b6e6347e 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -68,7 +68,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, cx, USELESS_ASREF, expr.span, - &format!("this call to `{call_name}` does nothing"), + format!("this call to `{call_name}` does nothing"), "try", snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, @@ -159,7 +159,7 @@ fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, ca cx, USELESS_ASREF, span, - &format!("this call to `{call_name}.map(...)` does nothing"), + format!("this call to `{call_name}.map(...)` does nothing"), "try", format!( "{}.clone()", diff --git a/clippy_lints/src/methods/verbose_file_reads.rs b/clippy_lints/src/methods/verbose_file_reads.rs index 2fe5ae9a9ad..181b413a182 100644 --- a/clippy_lints/src/methods/verbose_file_reads.rs +++ b/clippy_lints/src/methods/verbose_file_reads.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, - (msg, help): (&str, &str), + (msg, help): (&'static str, &'static str), ) { if is_trait_method(cx, expr, sym::IoRead) && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _))) diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 0a810a13f3f..28068c63473 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -137,7 +137,7 @@ pub(super) fn check<'tcx>( cx, WRONG_SELF_CONVENTION, first_arg_span, - &format!( + format!( "{suggestion} usually take {}", &self_kinds .iter() diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index 0016fb33517..c6b7f5b0ce2 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -181,7 +181,7 @@ fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str conf.min_ident_chars_threshold, )) }; - span_lint(cx, MIN_IDENT_CHARS, span, &help); + span_lint(cx, MIN_IDENT_CHARS, span, help); } /// Attempt to convert the node to an [`ItemKind::Use`] node. diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index ea6e662b4be..0c0d440a81b 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -246,7 +246,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { cx, USED_UNDERSCORE_BINDING, expr.span, - &format!( + format!( "used binding `{name}` which is prefixed with an underscore. A leading \ underscore signals that a binding will not be used" ), diff --git a/clippy_lints/src/misc_early/builtin_type_shadow.rs b/clippy_lints/src/misc_early/builtin_type_shadow.rs index 9f6b0bdc7a4..662f7cd8500 100644 --- a/clippy_lints/src/misc_early/builtin_type_shadow.rs +++ b/clippy_lints/src/misc_early/builtin_type_shadow.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) { cx, BUILTIN_TYPE_SHADOW, param.ident.span, - &format!("this generic shadows the built-in type `{}`", prim_ty.name()), + format!("this generic shadows the built-in type `{}`", prim_ty.name()), ); } } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs index eda4376f200..e0a5e401a50 100644 --- a/clippy_lints/src/misc_early/literal_suffix.rs +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi cx, SEPARATED_LITERAL_SUFFIX, lit_span, - &format!("{sugg_type} type suffix should not be separated by an underscore"), + format!("{sugg_type} type suffix should not be separated by an underscore"), "remove the underscore", format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), Applicability::MachineApplicable, @@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi cx, UNSEPARATED_LITERAL_SUFFIX, lit_span, - &format!("{sugg_type} type suffix should be separated by an underscore"), + format!("{sugg_type} type suffix should be separated by an underscore"), "add an underscore", format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), Applicability::MachineApplicable, diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index abe5b00e888..2f5499d7656 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -394,7 +394,7 @@ impl EarlyLintPass for MiscEarlyLints { cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondence, - &format!( + format!( "`{arg_name}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult" ), diff --git a/clippy_lints/src/misc_early/redundant_pattern.rs b/clippy_lints/src/misc_early/redundant_pattern.rs index d7bb0616acb..d5b5b2bf2dd 100644 --- a/clippy_lints/src/misc_early/redundant_pattern.rs +++ b/clippy_lints/src/misc_early/redundant_pattern.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { cx, REDUNDANT_PATTERN, pat.span, - &format!( + format!( "the `{} @ _` pattern can be written as just `{}`", ident.name, ident.name, ), diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 676e5d40bb7..cb305cf5582 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pat.span, "all the struct fields are matched to a wildcard pattern, consider using `..`", None, - &format!("try with `{type_name} {{ .. }}` instead"), + format!("try with `{type_name} {{ .. }}` instead"), ); return; } @@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` \ instead", None, - &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), + format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), ); } } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 0739b49fe19..0842a872824 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { "try `{}`, or a name that does not conflict with `{type_name}`'s generic params", type_param_names[i] ); - span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, &msg, None, &help); + span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, msg, None, help); } } } diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 39d4ea74b31..c29e46b941c 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -65,7 +65,7 @@ declare_clippy_lint! { } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); -fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &str, indexes: &[Span], f: F) +fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: &[Span], f: F) where F: FnOnce(&mut Diag<'_, ()>), { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 6878fb3349d..d9379ec89df 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -127,7 +127,7 @@ impl MissingDoc { cx, MISSING_DOCS_IN_PRIVATE_ITEMS, sp, - &format!("missing documentation for {article} {desc}"), + format!("missing documentation for {article} {desc}"), ); } } diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 7393b39c8f6..c6a76478806 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -64,7 +64,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, - &format!("missing `#[inline]` for {desc}"), + format!("missing `#[inline]` for {desc}"), ); } } diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 6bbf18d52d1..6f844bc646a 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx, MISSING_TRAIT_METHODS, source_map.guess_head_span(item.span), - &format!("missing trait method provided by default: `{}`", assoc.name), + format!("missing trait method provided by default: `{}`", assoc.name), Some(definition_span), "implement the method", ); diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 12c7c18afde..0a65c768c66 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -325,7 +325,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { self.cx, MIXED_READ_WRITE_IN_EXPRESSION, expr.span, - &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), + format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), Some(self.write_expr.span), "whether read occurs before this write depends on evaluation order", ); diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 0226b31dd19..6c031c08175 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -129,9 +129,9 @@ impl EarlyLintPass for ModStyle { cx, SELF_NAMED_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - &format!("`mod.rs` files are required, found `{}`", path.display()), + format!("`mod.rs` files are required, found `{}`", path.display()), None, - &format!("move `{}` to `{}`", path.display(), correct.display(),), + format!("move `{}` to `{}`", path.display(), correct.display(),), ); } } @@ -169,9 +169,9 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source cx, MOD_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - &format!("`mod.rs` files are not allowed, found `{}`", path.display()), + format!("`mod.rs` files are not allowed, found `{}`", path.display()), None, - &format!("move `{}` to `{}`", path.display(), mod_file.display()), + format!("move `{}` to `{}`", path.display(), mod_file.display()), ); } } diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 648d780ac09..0e138066780 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { cx, MULTIPLE_UNSAFE_OPS_PER_BLOCK, block.span, - &format!( + format!( "this `unsafe` block contains {} unsafe operations, expected only one", unsafe_ops.len() ), diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 7447a2287d3..11ab36bb056 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -92,7 +92,7 @@ fn check_arguments<'tcx>( cx, UNNECESSARY_MUT_PASSED, argument.span, - &format!("the {fn_kind} `{name}` doesn't need a mutable reference"), + format!("the {fn_kind} `{name}` doesn't need a mutable reference"), ); } }, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 2d7ce7b52ae..563ce2d82ea 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { cx, DEBUG_ASSERT_WITH_MUT_CALL, span, - &format!("do not call a function with mutable arguments inside of `{macro_name}!`"), + format!("do not call a function with mutable arguments inside of `{macro_name}!`"), ); } } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index b882e00dbdf..0c7f7e44edf 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -92,9 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { behavior and not the internal type, consider using `Mutex<()>`" ); match *mutex_param.kind() { - ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), + ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg), }; } } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 081d14c043c..f9ee4a3dc93 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -317,11 +317,11 @@ fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr fn check_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, - left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>, + left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>, ) { if let ExprKind::Binary(op, left_side, right_side) = e.kind { let (l_ty, r_ty) = ( @@ -391,7 +391,7 @@ fn check_comparison<'a, 'tcx>( binop_span, m, "try simplifying it as shown", - h(left_side, right_side).to_string(), + h(left_side, right_side).into_string(), applicability, ); }), @@ -406,7 +406,7 @@ fn suggest_bool_comparison<'a, 'tcx>( span: Span, expr: &Expr<'_>, mut app: Applicability, - message: &str, + message: &'static str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app); @@ -416,7 +416,7 @@ fn suggest_bool_comparison<'a, 'tcx>( span, message, "try simplifying it as shown", - conv_hint(hint).to_string(), + conv_hint(hint).into_string(), app, ); } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 4710a69443b..d91329eadcb 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { fn check_subpatterns<'tcx>( cx: &LateContext<'tcx>, - message: &str, + message: &'static str, ref_pat: &Pat<'_>, pat: &Pat<'_>, subpatterns: impl IntoIterator>, diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index ff72b5e69ef..8b4a12bb766 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -313,7 +313,7 @@ fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: L expr.span, message, None, - &format!("{header}\n{snip}"), + format!("{header}\n{snip}"), ); } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index d7adf22ff32..37463cfec9a 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -131,7 +131,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { NEEDLESS_QUESTION_MARK, expr.span, "question mark operator is useless here", - &format!("try removing question mark and `{sugg_remove}`"), + format!("try removing question mark and `{sugg_remove}`"), format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 627b4968d9f..78dd1e05162 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -134,9 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { NEW_WITHOUT_DEFAULT, id.into(), impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{self_type_snip}`" - ), + format!("you should consider adding a `Default` implementation for `{self_type_snip}`"), |diag| { diag.suggest_prepend_item( cx, diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index b8c3c7fa65a..7b26235291a 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { self.cx, MANY_SINGLE_CHAR_NAMES, span, - &format!("{num_single_char_names} bindings with single-character names in scope"), + format!("{num_single_char_names} bindings with single-character names in scope"), ); } } diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 793a3a9545c..d64190daecb 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { cx, NON_SEND_FIELDS_IN_SEND_TY, item.span, - &format!( + format!( "some fields in `{}` are not safe to be sent to another thread", snippet(cx, hir_impl.self_ty.span, "Unknown") ), diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 1c6069e9c65..88f2eabaccb 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -121,7 +121,7 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), spa cx, NONSTANDARD_MACRO_BRACES, span, - &format!("use of irregular braces for `{macro_name}!` macro"), + format!("use of irregular braces for `{macro_name}!` macro"), "consider writing", format!("{macro_name}!{open}{macro_args}{close}"), Applicability::MachineApplicable, diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 8822dfeeddd..2fc039ae886 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -94,7 +94,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { cx, OCTAL_ESCAPES, span, - &format!( + format!( "octal-looking escape in {} literal", if is_string { "string" } else { "byte string" } ), diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index f4863600ccc..9769da6d3e9 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( } ); - span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); + span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, help); } } diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs index 2e026c369ee..545e680ce0d 100644 --- a/clippy_lints/src/operators/bit_mask.rs +++ b/clippy_lints/src/operators/bit_mask.rs @@ -64,7 +64,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), ); } } else if mask_value == 0 { @@ -77,7 +77,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), ); } }, @@ -90,7 +90,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -102,7 +102,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), ); } else { check_ineffective_lt(cx, span, mask_value, cmp_value, "|"); @@ -118,7 +118,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -130,7 +130,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), ); } else { check_ineffective_gt(cx, span, mask_value, cmp_value, "|"); @@ -149,7 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), + format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } @@ -160,7 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), + format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index e278cf9835a..7bf9b8ef866 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -89,7 +89,7 @@ pub(super) fn check<'tcx>( span, "left-hand side of `&&` operator has no effect", Some(left_cond.span.until(right_cond.span)), - &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), + format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), ); } else { span_lint_and_note( @@ -98,7 +98,7 @@ pub(super) fn check<'tcx>( span, "right-hand side of `&&` operator has no effect", Some(and_op.span.to(right_cond.span)), - &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), + format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), ); } // We could autofix this error but choose not to, @@ -124,7 +124,7 @@ pub(super) fn check<'tcx>( span, "boolean expression will never evaluate to 'true'", None, - ¬e, + note, ); }; } diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index f120be13836..ca3112ce5c4 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -31,7 +31,7 @@ pub(crate) fn check<'tcx>( cx, DURATION_SUBSEC, expr.span, - &format!("calling `{suggested_fn}()` is more concise than this calculation"), + format!("calling `{suggested_fn}()` is more concise than this calculation"), "try", format!( "{}.{suggested_fn}()", diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 01dd418c38b..1421893274f 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -24,7 +24,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { cx, EQ_OP, lhs.span.to(rhs.span), - &format!("identical args used in this `{macro_name}!` macro call"), + format!("identical args used in this `{macro_name}!` macro call"), ); } } @@ -41,7 +41,7 @@ pub(crate) fn check<'tcx>( cx, EQ_OP, e.span, - &format!("equal expressions as operands to `{}`", op.as_str()), + format!("equal expressions as operands to `{}`", op.as_str()), |diag| { if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index 2a933a11e12..c56518ac72a 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -113,7 +113,7 @@ fn check_const_operands<'tcx>( cx, MODULO_ARITHMETIC, expr.span, - &format!( + format!( "you are using modulo operator on constants with different signs: `{} % {}`", lhs_operand.string_representation.as_ref().unwrap(), rhs_operand.string_representation.as_ref().unwrap() diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index a69989e400b..607930561e0 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( cx, PTR_EQ, expr.span, - &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), + format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, diff --git a/clippy_lints/src/operators/self_assignment.rs b/clippy_lints/src/operators/self_assignment.rs index 7c9d5320a3a..a932378fbb5 100644 --- a/clippy_lints/src/operators/self_assignment.rs +++ b/clippy_lints/src/operators/self_assignment.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx cx, SELF_ASSIGNMENT, e.span, - &format!("self-assignment of `{rhs}` to `{lhs}`"), + format!("self-assignment of `{rhs}` to `{lhs}`"), ); } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 556c493d36c..3cbd03a58c5 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -304,7 +304,7 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { cx, OPTION_IF_LET_ELSE, expr.span, - format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(), + format!("use Option::{} instead of an if let/else", det.method_sugg), "try", format!( "{}.{}({}, {})", diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index ec03ab0e41a..bb4a1de9f77 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -206,7 +206,7 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!( + format!( "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size ), @@ -236,7 +236,7 @@ impl<'tcx> PassByRefOrValue { cx, LARGE_TYPES_PASSED_BY_VALUE, input.span, - &format!( + format!( "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size ), diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index fbca4329342..582b9de43ae 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -138,7 +138,7 @@ fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible span, "type of pattern does not match the expression type", None, - &format!( + format!( "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings", match (deref_possible, level) { (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ", diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 6f20b5ec150..d180d4fe327 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { ) .filter(|arg| arg.mutability() == Mutability::Not) { - span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, &arg.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, arg.build_msg(), |diag| { diag.span_suggestion( arg.span, "change this to", @@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { let results = check_ptr_arg_usage(cx, body, &lint_args); for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { - span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, &args.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| { diag.multipart_suggestion( "change this to", iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx)))) diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index ff8ec2ad57c..7c82895d609 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -64,13 +64,13 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { cx, PTR_OFFSET_WITH_CAST, expr.span, - &msg, + msg, "try", sugg, Applicability::MachineApplicable, ); } else { - span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg); + span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg); } } } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 6b54258dd61..186e548d373 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -242,7 +242,7 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `{range_type}::contains` implementation"), + format!("manual `{range_type}::contains` implementation"), "use", format!("({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, @@ -272,7 +272,7 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `!{range_type}::contains` implementation"), + format!("manual `!{range_type}::contains` implementation"), "use", format!("!({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 6528a7b369f..8bc5d081a20 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -77,9 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { cx, REDUNDANT_LOCALS, local.span, - &format!("redundant redefinition of a binding `{ident}`"), + format!("redundant redefinition of a binding `{ident}`"), Some(binding_pat.span), - &format!("`{ident}` is initially defined here"), + format!("`{ident}` is initially defined here"), ); } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 0e43e4a7ee5..1b557730eca 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { cx, REDUNDANT_PUB_CRATE, span, - &format!("pub(crate) {descr} inside private module"), + format!("pub(crate) {descr} inside private module"), |diag| { diag.span_suggestion( item.vis_span, diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 07b604f2326..136e7db83bd 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -48,7 +48,7 @@ impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); impl RedundantStaticLifetimes { // Recursively visit types - fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) { + fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &'static str) { match ty.kind { // Be careful of nested structures (arrays and tuples) TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 687bad35a36..e925ec0271c 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -134,13 +134,13 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape vec![convert_span(primary)] }; - span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}")); + span_lint(cx, INVALID_REGEX, spans, format!("regex syntax error: {kind}")); } else { span_lint_and_help( cx, INVALID_REGEX, base, - &error.to_string(), + error.to_string(), None, "consider using a raw string literal: `r\"..\"`", ); @@ -223,7 +223,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, - Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()), + Err(e) => span_lint(cx, INVALID_REGEX, expr.span, e.to_string()), } } } diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index fcb79f6d694..a358881bf80 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -55,7 +55,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s cx, REPEAT_VEC_WITH_CAPACITY, span, - &format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), + format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), |diag| { diag.note(note); diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect); diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 85a2b1a6735..23b47606f8a 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { cx, SELF_NAMED_CONSTRUCTORS, impl_item.span, - &format!("constructor `{}` has the same name as the type", impl_item.ident.name), + format!("constructor `{}` has the same name as the type", impl_item.ident.name), ); } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index c74364d89d6..0fb7666dd9c 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -194,7 +194,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) cx, lint, span, - &msg, + msg, Some(cx.tcx.hir().span(shadowed)), "previous binding is here", ); diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 95b4a11a783..0a9a3c6307a 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -122,7 +122,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { cx, SINGLE_RANGE_IN_VEC_INIT, span, - &format!("{suggested_type} of `Range` that is only one element"), + format!("{suggested_type} of `Range` that is only one element"), |diag| { if should_emit_every_value { diag.span_suggestion( diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index ff8e8fe7021..8a9f02b6dcb 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -196,7 +196,7 @@ impl SlowVectorInit { }; } - fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) { + fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &'static str) { let len_expr = Sugg::hir( cx, match vec_alloc.size_expr { diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index cf839941123..926c56332cc 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -128,8 +128,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { cx, lint, first_segment.ident.span, - &format!("used import from `{used_mod}` instead of `{replace_with}`"), - &format!("consider importing the item from `{replace_with}`"), + format!("used import from `{used_mod}` instead of `{replace_with}`"), + format!("consider importing the item from `{replace_with}`"), replace_with.to_string(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 13ae1ff52dd..b3c729dacdd 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -495,8 +495,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { cx, TRIM_SPLIT_WHITESPACE, trim_span.with_hi(split_ws_span.lo()), - &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), - &format!("remove `{trim_fn_name}()`"), + format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), + format!("remove `{trim_fn_name}()`"), String::new(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 8eab3f5874e..3f030b80331 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { cx, lint, binop.span, - &format!( + format!( "suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id) diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index be590aede15..78c99e0c0a3 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -103,7 +103,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping elements of `{slice}` manually"), + format!("this looks like you are swapping elements of `{slice}` manually"), "try", format!( "{}.swap({}, {});", @@ -126,7 +126,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping `{first}` and `{second}` manually"), + format!("this looks like you are swapping `{first}` and `{second}` manually"), |diag| { diag.span_suggestion( span, @@ -201,7 +201,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { cx, ALMOST_SWAPPED, span, - &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), + format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index cbdf31c9336..462084e96a8 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", None, - &format!( + format!( "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute", cx.tcx.def_path_str(item.owner_id) ), diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 768623b5d03..9468d367a92 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -293,7 +293,7 @@ impl TraitBounds { p.span, "this type has already been used as a bound predicate", None, - &hint_string, + hint_string, ); } } @@ -420,7 +420,11 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ) } -fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> { +fn rollup_traits( + cx: &LateContext<'_>, + bounds: &[GenericBound<'_>], + msg: &'static str, +) -> Vec<(ComparableTraitRef, Span)> { let mut map = FxHashMap::default(); let mut repeated_res = false; diff --git a/clippy_lints/src/transmute/crosspointer_transmute.rs b/clippy_lints/src/transmute/crosspointer_transmute.rs index c4b9d82fc73..72f1529eb00 100644 --- a/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), + format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), ); true }, @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), + format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), ); true }, diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index aef520923e4..ab3bb5e1062 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_FLOAT_TO_INT, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let mut sugg = sugg::Sugg::hir(cx, arg, ".."); diff --git a/clippy_lints/src/transmute/transmute_int_to_bool.rs b/clippy_lints/src/transmute/transmute_int_to_bool.rs index 58227c53de2..a7192809077 100644 --- a/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_BOOL, e.span, - &format!("transmute from a `{from_ty}` to a `bool`"), + format!("transmute from a `{from_ty}` to a `bool`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let zero = sugg::Sugg::NonParen(Cow::from("0")); diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 2a6c2481254..81d10a7d5bd 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_CHAR, e.span, - &format!("transmute from a `{from_ty}` to a `char`"), + format!("transmute from a `{from_ty}` to a `char`"), |diag| { let Some(top_crate) = std_or_core(cx) else { return }; let arg = sugg::Sugg::hir(cx, arg, ".."); diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index cc3422edbbf..d51888e3097 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_FLOAT, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(int_ty) = from_ty.kind() { diff --git a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 97068efd43c..234021f0f47 100644 --- a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_NON_ZERO, e.span, - &format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), + format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 009d5a7c8ae..88b0ac5a368 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_NUM_TO_BYTES, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 4ab3afbe714..65d89c1fe43 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_PTR_TO_REF, e.span, - &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), + format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = if *mutbl == Mutability::Mut { diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 6c885ebdea1..5de2d7fc2e5 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_BYTES_TO_STR, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index a6f03c85b4f..275cab2af9b 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -71,7 +71,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{from_ty_orig}` which has an undefined layout"), + format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { diag.note(format!("the contained type `{from_ty}` has an undefined layout")); @@ -85,7 +85,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute to `{to_ty_orig}` which has an undefined layout"), + format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { diag.note(format!("the contained type `{to_ty}` has an undefined layout")); @@ -111,7 +111,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!( + format!( "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout" ), |diag| { @@ -140,7 +140,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{from_ty_orig}` which has an undefined layout"), + format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { diag.note(format!("the contained type `{from_ty}` has an undefined layout")); @@ -157,7 +157,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute into `{to_ty_orig}` which has an undefined layout"), + format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { diag.note(format!("the contained type `{to_ty}` has an undefined layout")); diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 043c9c88601..6f5ac625e35 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -53,7 +53,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), + format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), "try", sugg, app, diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 891fefc17a6..35e93830766 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, UNSOUND_COLLECTION_TRANSMUTE, e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), + format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), ); true } else { diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 088c8fda87a..0d5fbff0605 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( cx, USELESS_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to itself"), + format!("transmute from a type (`{from_ty}`) to itself"), ); true }, diff --git a/clippy_lints/src/transmute/wrong_transmute.rs b/clippy_lints/src/transmute/wrong_transmute.rs index d1965565b92..53c479b54d5 100644 --- a/clippy_lints/src/transmute/wrong_transmute.rs +++ b/clippy_lints/src/transmute/wrong_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, WRONG_TRANSMUTE, e.span, - &format!("transmute from a `{from_ty}` to a pointer"), + format!("transmute from a `{from_ty}` to a pointer"), ); true }, diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index fc3420af020..9ac73394548 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -21,9 +21,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, BOX_COLLECTION, hir_ty.span, - &format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), + format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), None, - &format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), + format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), ); true } else { diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index a0d609501a0..893faafc2c0 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{generic_snippet}>`"), + format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); diag.note(format!( @@ -73,7 +73,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), + format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.span_suggestion( hir_ty.span, @@ -92,7 +92,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), + format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 1dedb4510bd..8106694c43b 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { cx, UNNECESSARY_SAFETY_COMMENT, span, - &format!("{} has unnecessary safety comment", item.kind.descr()), + format!("{} has unnecessary safety comment", item.kind.descr()), Some(help_span), "consider removing the safety comment", ); @@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { cx, UNNECESSARY_SAFETY_COMMENT, span, - &format!("{} has unnecessary safety comment", item.kind.descr()), + format!("{} has unnecessary safety comment", item.kind.descr()), Some(help_span), "consider removing the safety comment", ); diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 729972de6e6..214b69dc925 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { cx, UNIT_RETURN_EXPECTING_ORD, span, - &format!( + format!( "this closure returns \ the unit type which also implements {trait_name}" ), @@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { cx, UNIT_RETURN_EXPECTING_ORD, span, - &format!( + format!( "this closure returns \ the unit type which also implements {trait_name}" ), diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 7fd17e332e4..afc53e6f32d 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -69,7 +69,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp cx, UNIT_ARG, expr.span, - &format!("passing {singular}unit value{plural} to a function"), + format!("passing {singular}unit value{plural} to a function"), |db| { let mut or = ""; args_to_recover diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index d4342ec5169..6dcc1195a70 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, macro_call.span, - &format!("`{macro_name}` of unit values detected. This will always {result}"), + format!("`{macro_name}` of unit values detected. This will always {result}"), ); } return; @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, expr.span, - &format!( + format!( "{}-comparison of unit values detected. This will always be {result}", op.as_str() ), diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index c332cf076ae..bfcefb26153 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -88,7 +88,7 @@ impl UnnecessaryBoxReturns { cx, UNNECESSARY_BOX_RETURNS, return_ty_hir.span, - format!("boxed return of the sized type `{boxed_ty}`").as_str(), + format!("boxed return of the sized type `{boxed_ty}`"), |diagnostic| { diagnostic.span_suggestion( return_ty_hir.span, diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 252e5e4dd7c..8f1eb5019f0 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { cx, UNNECESSARY_MAP_ON_CONSTRUCTOR, expr.span, - &format!( + format!( "unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name ), diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 9c8b0ae1727..5c7fbbab988 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) }; - span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg.as_str(), |diag| { + span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| { diag.span_suggestion( fn_decl.output.span(), return_type_sugg_msg, diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 3f2f765f751..51b3ea93b6d 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -65,7 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, cx, UNSAFE_REMOVED_FROM_NAME, span, - &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), + format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), ); } } diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index d5ca844b9e2..3e5afec541c 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -55,8 +55,8 @@ impl EarlyLintPass for UnusedRounding { cx, UNUSED_ROUNDING, expr.span, - &format!("used the `{method_name}` method with a whole number float"), - &format!("remove the `{method_name}` method call"), + format!("used the `{method_name}` method with a whole number float"), + format!("remove the `{method_name}` method call"), float, Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index f2eb774b5cb..2622abd59cb 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -338,7 +338,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { UNNECESSARY_UNWRAP, expr.hir_id, expr.span, - &format!( + format!( "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", method_name.ident.name, unwrappable.check_name.ident.as_str(), @@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { PANICKING_UNWRAP, expr.hir_id, expr.span, - &format!("this call to `{}()` will always panic", method_name.ident.name), + format!("this call to `{}()` will always panic", method_name.ident.name), |diag| { diag.span_label(unwrappable.check.span, "because of this check"); }, diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index d2a1d42f279..f376d349646 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -94,7 +94,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive UPPER_CASE_ACRONYMS, hir_id, span, - &format!("name `{ident}` contains a capitalized acronym"), + format!("name `{ident}` contains a capitalized acronym"), |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index f7a455977fa..75541766156 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", sugg.into_owned(), app, @@ -301,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), None, "consider removing `.try_into()`", ); @@ -346,9 +346,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), None, - &hint, + hint, ); } @@ -360,8 +360,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), - &sugg_msg, + format!("useless conversion to the same type: `{b}`"), + sugg_msg, sugg.to_string(), app, ); diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 4822970e47e..5483e80f932 100644 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { ident.span, "non-standard lint formulation", None, - &format!("consider using `{}`", formulation.correction), + format!("consider using `{}`", formulation.correction), ); } return; diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index df37619227c..9b6b6871818 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { path.ident.span, "usage of a compiler lint function", None, - &format!("please use the Clippy variant of this function: `{sugg}`"), + format!("please use the Clippy variant of this function: `{sugg}`"), ); } } diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 370ed430bcf..9be225759df 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, DEFAULT_LINT, item.span, - &format!("the lint `{}` has the default lint description", item.ident.name), + format!("the lint `{}` has the default lint description", item.ident.name), ); } @@ -191,7 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, DEFAULT_DEPRECATION_REASON, item.span, - &format!("the lint `{}` has the default deprecation reason", item.ident.name), + format!("the lint `{}` has the default deprecation reason", item.ident.name), ); } } @@ -247,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, LINT_WITHOUT_LINT_PASS, lint_span, - &format!("the lint `{lint_name}` is not added to any `LintPass`"), + format!("the lint `{lint_name}` is not added to any `LintPass`"), ); } } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index d6a541a1eff..5fb80059e03 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -822,7 +822,7 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s cx, METADATA_COLLECTOR, item.ident.span, - &format!("metadata collection error for `{}`: {message}", item.ident.name), + format!("metadata collection error for `{}`: {message}", item.ident.name), ); } diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 6d5240db832..777fe544b24 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -51,8 +51,8 @@ impl LateLintPass<'_> for MsrvAttrImpl { cx, MISSING_MSRV_ATTR_IMPL, span, - &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), - &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), + format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), + format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 5fb643854dc..2fa55c5ff52 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -78,9 +78,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { cx, UNNECESSARY_DEF_PATH, span, - &format!("hardcoded path to a {msg}"), + format!("hardcoded path to a {msg}"), None, - &format!("convert all references to use `{sugg}`"), + format!("convert all references to use `{sugg}`"), ); } } diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 83369c66367..9818b98dd5b 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -89,7 +89,7 @@ impl EarlyLintPass for Visibility { cx, NEEDLESS_PUB_SELF, item.vis.span, - &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), + format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), "remove it", String::new(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index be16d2e5cc3..26c6859233d 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -297,11 +297,11 @@ impl<'tcx> LateLintPass<'tcx> for Write { match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { - span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`")); + span_lint(cx, PRINT_STDOUT, macro_call.span, format!("use of `{name}!`")); } }, sym::eprint_macro | sym::eprintln_macro if !allowed_in_tests => { - span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`")); + span_lint(cx, PRINT_STDERR, macro_call.span, format!("use of `{name}!`")); }, sym::write_macro | sym::writeln_macro => {}, _ => return, @@ -390,7 +390,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma cx, lint, macro_call.span, - &format!("using `{name}!()` with a format string that ends in a single newline"), + format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); let Some(format_snippet) = snippet_opt(cx, format_string_span) else { @@ -440,7 +440,7 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call cx, lint, macro_call.span, - &format!("empty string literal in `{name}!`"), + format!("empty string literal in `{name}!`"), |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index d3623d6fda4..662242f6196 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { expr.span, "constant division of `0.0` with `0.0` will always result in NaN", None, - &format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), + format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), ); } } -- cgit 1.4.1-3-g733a5 From b2ea5eef445f16f02b9aea08a0bb8ff3e193762e Mon Sep 17 00:00:00 2001 From: Yuxiang Qiu Date: Thu, 4 Jan 2024 14:41:38 -0500 Subject: fix: incorrect suggestions when `.then` and `.then_some` is used --- clippy_lints/src/methods/search_is_some.rs | 35 ++++++++++++++++++++++++----- tests/ui/search_is_some_fixable_none.fixed | 16 +++++++++++++ tests/ui/search_is_some_fixable_none.rs | 16 +++++++++++++ tests/ui/search_is_some_fixable_none.stderr | 14 +++++++++++- 4 files changed, 74 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ac5cc2f01e5..1ea2e93c9de 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{is_trait_method, strip_pat_refs}; +use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; @@ -72,16 +73,24 @@ pub(super) fn check<'tcx>( ); } else { let iter = snippet(cx, search_recv.span, ".."); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!( + "(!{iter}.any({}))", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + } else { + format!( + "!{iter}.any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!( - "!{iter}.any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), + sugg, applicability, ); } @@ -127,13 +136,18 @@ pub(super) fn check<'tcx>( let string = snippet(cx, search_recv.span, ".."); let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!("(!{string}.contains({find_arg}))") + } else { + format!("!{string}.contains({find_arg})") + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!("!{string}.contains({find_arg})"), + sugg, applicability, ); }, @@ -142,3 +156,12 @@ pub(super) fn check<'tcx>( } } } + +fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(..) = parent_expr.kind + { + return true; + } + false +} diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 51636392f2b..3e5b3fab5ff 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -213,3 +213,19 @@ mod issue7392 { let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + fn test_then() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then(computations); + } + + fn test_then_some() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index c7d773e18a3..e77ae5cecc2 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -219,3 +219,19 @@ mod issue7392 { let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + fn test_then() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then(computations); + } + + fn test_then_some() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 4ad1e2508c4..240eb245cdd 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -282,5 +282,17 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` -error: aborting due to 43 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:230:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `(!v.iter().any(|x| *x == 42))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:235:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `(!v.iter().any(|x| *x == 42))` + +error: aborting due to 45 previous errors -- cgit 1.4.1-3-g733a5 From 9d1f824878b08f7ad631b21b2c8bf42522af65c0 Mon Sep 17 00:00:00 2001 From: Yuxiang Qiu Date: Thu, 4 Jan 2024 20:29:41 -0500 Subject: fix: check if receiver's hir_id matches expr's hir_id --- clippy_lints/src/methods/search_is_some.rs | 3 ++- tests/ui/search_is_some_fixable_none.fixed | 9 +++++++++ tests/ui/search_is_some_fixable_none.rs | 9 +++++++++ tests/ui/search_is_some_fixable_none.stderr | 12 +++++++++--- 4 files changed, 29 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 1ea2e93c9de..1e1a8f9060b 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -159,7 +159,8 @@ pub(super) fn check<'tcx>( fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { if let Some(parent_expr) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(..) = parent_expr.kind + && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind + && receiver.hir_id == expr.hir_id { return true; } diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 3e5b3fab5ff..e5c540e6723 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -219,6 +219,13 @@ mod issue_11910 { 0 } + struct Foo; + impl Foo{ + fn bar(&self, _ : bool) { + + } + } + fn test_then() { let v = vec![3, 2, 1, 0, -1, -2, -3]; (!v.iter().any(|x| *x == 42)).then(computations); @@ -227,5 +234,7 @@ mod issue_11910 { fn test_then_some() { let v = vec![3, 2, 1, 0, -1, -2, -3]; (!v.iter().any(|x| *x == 42)).then_some(0); + + Foo.bar(!v.iter().any(|x| *x == 42)); } } diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index e77ae5cecc2..aeb2be168f3 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -225,6 +225,13 @@ mod issue_11910 { 0 } + struct Foo; + impl Foo{ + fn bar(&self, _ : bool) { + + } + } + fn test_then() { let v = vec![3, 2, 1, 0, -1, -2, -3]; v.iter().find(|x| **x == 42).is_none().then(computations); @@ -233,5 +240,7 @@ mod issue_11910 { fn test_then_some() { let v = vec![3, 2, 1, 0, -1, -2, -3]; v.iter().find(|x| **x == 42).is_none().then_some(0); + + Foo.bar(v.iter().find(|x| **x == 42).is_none()); } } diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 240eb245cdd..61a1f996d65 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -283,16 +283,22 @@ LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:230:9 + --> $DIR/search_is_some_fixable_none.rs:237:9 | LL | v.iter().find(|x| **x == 42).is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:235:9 + --> $DIR/search_is_some_fixable_none.rs:242:9 | LL | v.iter().find(|x| **x == 42).is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `(!v.iter().any(|x| *x == 42))` -error: aborting due to 45 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:244:17 + | +LL | Foo.bar(v.iter().find(|x| **x == 42).is_none()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 42)` + +error: aborting due to 46 previous errors -- cgit 1.4.1-3-g733a5 From b89fa5364f3de5fe17e65f6b42865e5b95f1ad9a Mon Sep 17 00:00:00 2001 From: Yuxiang Qiu Date: Mon, 1 Apr 2024 16:59:46 -0400 Subject: fix: fix ci errors --- clippy_lints/src/methods/search_is_some.rs | 2 +- tests/ui/search_is_some_fixable_none.stderr | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 1e1a8f9060b..f5f1e94bbf4 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()` let mut applicability = Applicability::MachineApplicable; let any_search_snippet = if search_method == "find" - && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind + && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind && let closure_body = cx.tcx.hir().body(body) && let Some(closure_arg) = closure_body.params.first() { diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index a1d37daf825..2c858b9fb10 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -283,73 +283,73 @@ LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:235:17 + --> tests/ui/search_is_some_fixable_none.rs:235:17 | LL | let _ = v.iter().find(|x| **x == 42).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:236:17 + --> tests/ui/search_is_some_fixable_none.rs:236:17 | LL | Foo.bar(v.iter().find(|x| **x == 42).is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:241:9 + --> tests/ui/search_is_some_fixable_none.rs:241:9 | LL | v.iter().find(|x| **x == 42).is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some_fixable_none.rs:246:9 + --> tests/ui/search_is_some_fixable_none.rs:246:9 | LL | v.iter().find(|x| **x == 42).is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:251:17 + --> tests/ui/search_is_some_fixable_none.rs:251:17 | LL | let _ = s.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:252:17 + --> tests/ui/search_is_some_fixable_none.rs:252:17 | LL | Foo.bar(s.find("world").is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:254:17 + --> tests/ui/search_is_some_fixable_none.rs:254:17 | LL | let _ = s.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:255:17 + --> tests/ui/search_is_some_fixable_none.rs:255:17 | LL | Foo.bar(s.find("world").is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:260:17 + --> tests/ui/search_is_some_fixable_none.rs:260:17 | LL | let _ = s.find("world").is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:262:17 + --> tests/ui/search_is_some_fixable_none.rs:262:17 | LL | let _ = s.find("world").is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:267:17 + --> tests/ui/search_is_some_fixable_none.rs:267:17 | LL | let _ = s.find("world").is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> $DIR/search_is_some_fixable_none.rs:269:17 + --> tests/ui/search_is_some_fixable_none.rs:269:17 | LL | let _ = s.find("world").is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` -- cgit 1.4.1-3-g733a5 From db3a927432586c33a4aaad54951056b8ced30439 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Mon, 8 Apr 2024 12:50:28 -0700 Subject: Fix markdown syntax in str_split_at_newline docs --- clippy_lints/src/methods/mod.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2fb317c8c68..0939c028564 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3938,7 +3938,6 @@ declare_clippy_lint! { /// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is /// valid. - /// ``` #[clippy::version = "1.77.0"] pub STR_SPLIT_AT_NEWLINE, pedantic, -- cgit 1.4.1-3-g733a5 From 58c53e8ea9fd56e1caea002f2a43b7a631508ba7 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 21 Nov 2023 14:35:02 +0100 Subject: reduce `single_char_pattern` to only lint on ascii chars --- clippy_lints/src/methods/mod.rs | 9 ++++++--- clippy_lints/src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_pattern.rs | 6 ++---- clippy_lints/src/methods/single_char_push_string.rs | 2 +- clippy_lints/src/methods/utils.rs | 8 +++++++- tests/ui/single_char_pattern.fixed | 12 +++++++----- tests/ui/single_char_pattern.rs | 6 ++++-- 7 files changed, 28 insertions(+), 17 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0939c028564..609deba7352 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1145,11 +1145,14 @@ declare_clippy_lint! { /// `str` as an argument, e.g., `_.split("x")`. /// /// ### Why is this bad? - /// Performing these methods using a `char` is faster than - /// using a `str`. + /// Performing these methods using a `char` can be faster than + /// using a `str` because it needs one less indirection. /// /// ### Known problems - /// Does not catch multi-byte unicode characters. + /// Does not catch multi-byte unicode characters. This is by + /// design, on many machines, splitting by a non-ascii char is + /// actually slower. Please do your own measurements instead of + /// relying solely on the results of this lint. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 44a7ad394fa..20ec2b74d81 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index 363b1f2b812..982a7901c45 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; -const PATTERN_METHODS: [(&str, usize); 24] = [ +const PATTERN_METHODS: [(&str, usize); 22] = [ ("contains", 0), ("starts_with", 0), ("ends_with", 0), @@ -27,8 +27,6 @@ const PATTERN_METHODS: [(&str, usize); 24] = [ ("rmatches", 0), ("match_indices", 0), ("rmatch_indices", 0), - ("strip_prefix", 0), - ("strip_suffix", 0), ("trim_start_matches", 0), ("trim_end_matches", 0), ("replace", 0), @@ -50,7 +48,7 @@ pub(super) fn check( && args.len() > pos && let arg = &args[pos] && let mut applicability = Applicability::MachineApplicable - && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) + && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 0698bd6a0c5..97c13825bc1 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{base_string_snippet}.push({extension_string})"); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index ef00c812d51..c50f24f824a 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -52,11 +52,17 @@ pub(super) fn get_hint_if_single_char_arg( cx: &LateContext<'_>, arg: &Expr<'_>, applicability: &mut Applicability, + ascii_only: bool, ) -> Option { if let ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(r, style) = lit.node && let string = r.as_str() - && string.chars().count() == 1 + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 { let snip = snippet_with_applicability(cx, arg.span, string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 9573fdbcfde..3ffdf474196 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -10,9 +10,9 @@ fn main() { let y = "x"; x.split(y); - x.split('ß'); - x.split('ℝ'); - x.split('💣'); + x.split("ß"); + x.split("ℝ"); + x.split("💣"); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.split_inclusive('x'); @@ -34,8 +34,6 @@ fn main() { x.rmatch_indices('x'); x.trim_start_matches('x'); x.trim_end_matches('x'); - x.strip_prefix('x'); - x.strip_suffix('x'); x.replace('x', "y"); x.replacen('x', "y", 3); // Make sure we escape characters correctly. @@ -64,4 +62,8 @@ fn main() { // Must escape backslash in raw strings when converting to char #8060 x.split('\\'); x.split('\\'); + + // should not warn, the char versions are actually slower in some cases + x.strip_prefix("x"); + x.strip_suffix("x"); } diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 8a04480dbc6..74ab3aa5fb0 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -34,8 +34,6 @@ fn main() { x.rmatch_indices("x"); x.trim_start_matches("x"); x.trim_end_matches("x"); - x.strip_prefix("x"); - x.strip_suffix("x"); x.replace("x", "y"); x.replacen("x", "y", 3); // Make sure we escape characters correctly. @@ -64,4 +62,8 @@ fn main() { // Must escape backslash in raw strings when converting to char #8060 x.split(r#"\"#); x.split(r"\"); + + // should not warn, the char versions are actually slower in some cases + x.strip_prefix("x"); + x.strip_suffix("x"); } -- cgit 1.4.1-3-g733a5 From 54de78a2128ce1b9019f2bf2380c581e054bfe37 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 28 Nov 2023 22:31:24 +0100 Subject: downgrade to pedantic --- clippy_lints/src/methods/mod.rs | 8 +++-- tests/ui/single_char_pattern.fixed | 2 +- tests/ui/single_char_pattern.rs | 2 +- tests/ui/single_char_pattern.stderr | 62 ++++++++++--------------------------- 4 files changed, 23 insertions(+), 51 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 609deba7352..16e508bf4e1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1145,8 +1145,10 @@ declare_clippy_lint! { /// `str` as an argument, e.g., `_.split("x")`. /// /// ### Why is this bad? - /// Performing these methods using a `char` can be faster than - /// using a `str` because it needs one less indirection. + /// While this can make a perf difference on some systems, + /// benchmarks have proven inconclusive. But at least using a + /// char literal makes it clear that we are looking at a single + /// character. /// /// ### Known problems /// Does not catch multi-byte unicode characters. This is by @@ -1165,7 +1167,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub SINGLE_CHAR_PATTERN, - perf, + pedantic, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" } diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 3ffdf474196..a18d6319f89 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -1,5 +1,5 @@ #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] - +#![warn(clippy::single_char_pattern)] use std::collections::HashSet; fn main() { diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 74ab3aa5fb0..b52e6fb2fdf 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,5 +1,5 @@ #![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] - +#![warn(clippy::single_char_pattern)] use std::collections::HashSet; fn main() { diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 5a2ec6c764b..b2deed23cbd 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -7,24 +7,6 @@ LL | x.split("x"); = note: `-D clippy::single-char-pattern` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:13:13 - | -LL | x.split("ß"); - | ^^^ help: consider using a `char`: `'ß'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:14:13 - | -LL | x.split("ℝ"); - | ^^^ help: consider using a `char`: `'ℝ'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:15:13 - | -LL | x.split("💣"); - | ^^^^ help: consider using a `char`: `'💣'` - error: single-character string constant used as pattern --> tests/ui/single_char_pattern.rs:18:23 | @@ -140,106 +122,94 @@ LL | x.trim_end_matches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:37:20 - | -LL | x.strip_prefix("x"); - | ^^^ help: consider using a `char`: `'x'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:38:20 - | -LL | x.strip_suffix("x"); - | ^^^ help: consider using a `char`: `'x'` - -error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:39:15 + --> tests/ui/single_char_pattern.rs:37:15 | LL | x.replace("x", "y"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:40:16 + --> tests/ui/single_char_pattern.rs:38:16 | LL | x.replacen("x", "y", 3); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:42:13 + --> tests/ui/single_char_pattern.rs:40:13 | LL | x.split("\n"); | ^^^^ help: consider using a `char`: `'\n'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:43:13 + --> tests/ui/single_char_pattern.rs:41:13 | LL | x.split("'"); | ^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:44:13 + --> tests/ui/single_char_pattern.rs:42:13 | LL | x.split("\'"); | ^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:46:13 + --> tests/ui/single_char_pattern.rs:44:13 | LL | x.split("\""); | ^^^^ help: consider using a `char`: `'"'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:51:31 + --> tests/ui/single_char_pattern.rs:49:31 | LL | x.replace(';', ",").split(","); // issue #2978 | ^^^ help: consider using a `char`: `','` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:52:19 + --> tests/ui/single_char_pattern.rs:50:19 | LL | x.starts_with("\x03"); // issue #2996 | ^^^^^^ help: consider using a `char`: `'\x03'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:59:13 + --> tests/ui/single_char_pattern.rs:57:13 | LL | x.split(r"a"); | ^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:60:13 + --> tests/ui/single_char_pattern.rs:58:13 | LL | x.split(r#"a"#); | ^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:61:13 + --> tests/ui/single_char_pattern.rs:59:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:62:13 + --> tests/ui/single_char_pattern.rs:60:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:63:13 + --> tests/ui/single_char_pattern.rs:61:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: consider using a `char`: `'#'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:65:13 + --> tests/ui/single_char_pattern.rs:63:13 | LL | x.split(r#"\"#); | ^^^^^^ help: consider using a `char`: `'\\'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:66:13 + --> tests/ui/single_char_pattern.rs:64:13 | LL | x.split(r"\"); | ^^^^ help: consider using a `char`: `'\\'` -error: aborting due to 40 previous errors +error: aborting due to 35 previous errors -- cgit 1.4.1-3-g733a5 From 666e2f286854cc3a4dbdb3cc8c934f986765c72b Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Wed, 10 Apr 2024 15:53:36 +0800 Subject: fix [`large_stack_arrays`] linting in `vec` macro & add `matching_root_macro_call` function in `clippy_utils` --- clippy_lints/src/format_args.rs | 6 ++--- clippy_lints/src/large_stack_arrays.rs | 25 ++++++++++++----- clippy_lints/src/manual_assert.rs | 5 ++-- clippy_lints/src/manual_is_ascii_check.rs | 15 ++--------- clippy_lints/src/methods/filter_map.rs | 5 ++-- clippy_lints/src/repeat_vec_with_capacity.rs | 5 ++-- clippy_lints/src/slow_vector_initialization.rs | 6 ++--- clippy_utils/src/macros.rs | 10 +++++++ tests/ui/large_stack_arrays.rs | 34 +++++++++++++++++++++++ tests/ui/large_stack_arrays.stderr | 37 +++++++++++++++++++++++++- 10 files changed, 110 insertions(+), 38 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 80db617c639..003a9995c15 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, - is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, + is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -271,9 +271,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = root_macro_call(arg_span) - && self.cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) - { + if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) { diag.span_suggestion( self.cx.sess().source_map().span_until_char(mac_call.span, '!'), message, diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index afcb6745947..9214e870e92 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,10 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::macro_backtrace; use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::impl_lint_pass; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -39,6 +41,7 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind + && !is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) @@ -54,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { }) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { - span_lint_and_help( + span_lint_and_then( cx, LARGE_STACK_ARRAYS, expr.span, @@ -62,12 +65,20 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { "allocating a local array larger than {} bytes", self.maximum_allowed_size ), - None, - format!( - "consider allocating on the heap with `vec!{}.into_boxed_slice()`", - snippet(cx, expr.span, "[...]") - ), + |diag| { + if !expr.span.from_expansion() { + diag.help(format!( + "consider allocating on the heap with `vec!{}.into_boxed_slice()`", + snippet(cx, expr.span, "[...]") + )); + } + }, ); } } } + +/// We shouldn't lint messages if the expr is already in a `vec!` call +fn is_from_vec_macro(cx: &LateContext<'_>, expr_span: Span) -> bool { + macro_backtrace(expr_span).any(|mac| cx.tcx.is_diagnostic_item(sym::vec_macro, mac.def_id)) +} diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 76edbe8b755..d76b94eba23 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -1,12 +1,11 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::{is_panic, root_macro_call}; use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -42,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { && !expr.span.from_expansion() && let then = peel_blocks_with_stmt(then) && let Some(macro_call) = root_macro_call(then.span) - && cx.tcx.item_name(macro_call.def_id) == sym::panic + && is_panic(cx, macro_call.def_id) && !cx.tcx.sess.source_map().is_multiline(cond.span) && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span) && let Some(panic_snippet) = panic_snippet.strip_suffix(')') diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 338a299740a..ed7eabd9b99 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, in_constant}; use rustc_ast::ast::RangeLimits; @@ -9,7 +9,6 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::DefId; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -97,9 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { return; } - if let Some(macro_call) = root_macro_call(expr.span) - && is_matches_macro(cx, macro_call.def_id) - { + if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) { if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { let range = check_pat(&arm.pat.kind); check_is_ascii(cx, macro_call.span, recv, &range); @@ -187,11 +184,3 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { CharRange::Otherwise } } - -fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool { - if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) { - return sym::matches_macro == name; - } - - false -} diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 581e3b308c3..02a11257007 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::macros::{is_panic, root_macro_call}; +use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; @@ -247,8 +247,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> { } else { None } - } else if let Some(macro_call) = root_macro_call(expr.span) - && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro) + } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some() // we know for a fact that the wildcard pattern is the second arm && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind && path_to_local_id(scrutinee, filter_param_id) diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index a358881bf80..792d8fc88f0 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths}; use rustc_errors::Applicability; @@ -65,8 +65,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s /// Checks `vec![Vec::with_capacity(x); n]` fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(mac_call) = root_macro_call(expr.span) - && cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id) + if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some() && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr) && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) && !len_expr.span.from_expansion() diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 8a9f02b6dcb..8a01f9d3e0a 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::root_macro_call; +use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local, @@ -145,9 +145,7 @@ impl SlowVectorInit { // Generally don't warn if the vec initializer comes from an expansion, except for the vec! macro. // This lets us still warn on `vec![]`, while ignoring other kinds of macros that may output an // empty vec - if expr.span.from_expansion() - && root_macro_call(expr.span).map(|m| m.def_id) != cx.tcx.get_diagnostic_item(sym::vec_macro) - { + if expr.span.from_expansion() && matching_root_macro_call(cx, expr.span, sym::vec_macro).is_none() { return None; } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index f166087dc3c..257dd76ab15 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -119,10 +119,20 @@ pub fn macro_backtrace(span: Span) -> impl Iterator { /// If the macro backtrace of `span` has a macro call at the root expansion /// (i.e. not a nested macro call), returns `Some` with the `MacroCall` +/// +/// If you only want to check whether the root macro has a specific name, +/// consider using [`matching_root_macro_call`] instead. pub fn root_macro_call(span: Span) -> Option { macro_backtrace(span).last() } +/// A combination of [`root_macro_call`] and +/// [`is_diagnostic_item`](rustc_middle::ty::TyCtxt::is_diagnostic_item) that returns a `MacroCall` +/// at the root expansion if only it matches the given name. +pub fn matching_root_macro_call(cx: &LateContext<'_>, span: Span, name: Symbol) -> Option { + root_macro_call(span).filter(|mc| cx.tcx.is_diagnostic_item(name, mc.def_id)) +} + /// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node" /// produced by the macro call, as in [`first_node_in_macro`]. pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option { diff --git a/tests/ui/large_stack_arrays.rs b/tests/ui/large_stack_arrays.rs index d5c4f95f8c4..f41423962a1 100644 --- a/tests/ui/large_stack_arrays.rs +++ b/tests/ui/large_stack_arrays.rs @@ -55,3 +55,37 @@ fn main() { [(); 20_000_000], ); } + +#[allow(clippy::useless_vec)] +fn issue_12586() { + macro_rules! dummy { + ($n:expr) => { + $n + }; + // Weird rule to test help messages. + ($a:expr => $b:expr) => { + [$a, $b, $a, $b] + //~^ ERROR: allocating a local array larger than 512000 bytes + }; + ($id:ident; $n:literal) => { + dummy!(::std::vec![$id;$n]) + }; + ($($id:expr),+ $(,)?) => { + ::std::vec![$($id),*] + } + } + + let x = [0u32; 50_000]; + let y = vec![x, x, x, x, x]; + let y = vec![dummy![x, x, x, x, x]]; + let y = vec![dummy![[x, x, x, x, x]]]; + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = dummy![x, x, x, x, x]; + let y = [x, x, dummy!(x), x, x]; + //~^ ERROR: allocating a local array larger than 512000 bytes + let y = dummy![x => x]; + let y = dummy![x;5]; + let y = dummy!(vec![dummy![x, x, x, x, x]]); + let y = dummy![[x, x, x, x, x]]; + //~^ ERROR: allocating a local array larger than 512000 bytes +} diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr index 007ca61c2de..ac4097a463f 100644 --- a/tests/ui/large_stack_arrays.stderr +++ b/tests/ui/large_stack_arrays.stderr @@ -56,5 +56,40 @@ LL | [0u8; usize::MAX], | = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` -error: aborting due to 7 previous errors +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:81:25 + | +LL | let y = vec![dummy![[x, x, x, x, x]]]; + | ^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:84:13 + | +LL | let y = [x, x, dummy!(x), x, x]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, dummy!(x), x, x].into_boxed_slice()` + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:67:13 + | +LL | [$a, $b, $a, $b] + | ^^^^^^^^^^^^^^^^ +... +LL | let y = dummy![x => x]; + | -------------- in this macro invocation + | + = note: this error originates in the macro `dummy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: allocating a local array larger than 512000 bytes + --> tests/ui/large_stack_arrays.rs:89:20 + | +LL | let y = dummy![[x, x, x, x, x]]; + | ^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![x, x, x, x, x].into_boxed_slice()` + +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From d55e5b45007569c53bb86732d05ada08a1cd8ebd Mon Sep 17 00:00:00 2001 From: forcedebug Date: Tue, 23 Apr 2024 20:31:26 +0800 Subject: chore: fix some typos in comments Signed-off-by: forcedebug --- clippy_lints/src/implied_bounds_in_impls.rs | 2 +- clippy_lints/src/methods/unused_enumerate_index.rs | 2 +- clippy_lints/src/size_of_ref.rs | 2 +- tests/ui/mistyped_literal_suffix.fixed | 2 +- tests/ui/mistyped_literal_suffix.rs | 2 +- tests/ui/type_id_on_box_unfixable.rs | 2 +- util/gh-pages/script.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 7b97fc15caa..3bf8d618955 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// /// ### Limitations /// This lint does not check for implied bounds transitively. Meaning that - /// it does't check for implied bounds from supertraits of supertraits + /// it doesn't check for implied bounds from supertraits of supertraits /// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`) /// /// ### Example diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs index e5cc898612e..92f3ac5ff99 100644 --- a/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, && match_def_path(cx, enumerate_defid, &CORE_ITER_ENUMERATE_METHOD) { // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element - // that would be explicited in the closure. + // that would be explicitly in the closure. let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) { // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`. // Fallback to `..` if we fail getting either snippet. diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 14ca7a3f004..8d7f12af86e 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// fn size(&self) -> usize { /// // Note that `&self` as an argument is a `&&Foo`: Because `self` /// // is already a reference, `&self` is a double-reference. - /// // The return value of `size_of_val()` therefor is the + /// // The return value of `size_of_val()` therefore is the /// // size of the reference-type, not the size of `self`. /// std::mem::size_of_val(&self) /// } diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index 861764a2aee..b84b3dc349e 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -32,7 +32,7 @@ fn main() { // testing that the suggestion actually fits in its type let fail30 = 127_i8; // should be i8 let fail31 = 240_u8; // should be u8 - let ok32 = 360_8; // doesnt fit in either, should be ignored + let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_i16; let fail34 = 0xABCD_u16; let ok35 = 0x12345_16; diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index 4a15c335fd8..a47a736067a 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -32,7 +32,7 @@ fn main() { // testing that the suggestion actually fits in its type let fail30 = 127_8; // should be i8 let fail31 = 240_8; // should be u8 - let ok32 = 360_8; // doesnt fit in either, should be ignored + let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_16; let fail34 = 0xABCD_16; let ok35 = 0x12345_16; diff --git a/tests/ui/type_id_on_box_unfixable.rs b/tests/ui/type_id_on_box_unfixable.rs index f6d09834adb..67e398e604b 100644 --- a/tests/ui/type_id_on_box_unfixable.rs +++ b/tests/ui/type_id_on_box_unfixable.rs @@ -19,7 +19,7 @@ where impl NormalTrait for T {} fn main() { - // (currently we don't look deeper than one level into the supertrait hierachy, but we probably + // (currently we don't look deeper than one level into the supertrait hierarchy, but we probably // could) let b: Box = Box::new(1); let _ = b.type_id(); diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index f59245e556c..c63edd5bf70 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -415,7 +415,7 @@ let terms = searchStr.split(" "); let docsLowerCase = lint.docs.toLowerCase(); for (index = 0; index < terms.length; index++) { - // This is more likely and will therefor be checked first + // This is more likely and will therefore be checked first if (docsLowerCase.indexOf(terms[index]) !== -1) { continue; } -- cgit 1.4.1-3-g733a5 From f0beaedf832c574042bb8ec1957e462b97373758 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:27:40 +0200 Subject: suppress `readonly_write_lock` for underscore-prefixed bindings --- clippy_lints/src/methods/readonly_write_lock.rs | 7 ++++++- tests/ui/readonly_write_lock.fixed | 4 ++++ tests/ui/readonly_write_lock.rs | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/readonly_write_lock.rs b/clippy_lints/src/methods/readonly_write_lock.rs index 9b0180d9369..774aaec1afd 100644 --- a/clippy_lints/src/methods/readonly_write_lock.rs +++ b/clippy_lints/src/methods/readonly_write_lock.rs @@ -4,7 +4,7 @@ use clippy_utils::mir::{enclosing_mir, visit_local_usage}; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Node}; +use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::mir::{Location, START_BLOCK}; use rustc_span::sym; @@ -25,6 +25,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver && is_unwrap_call(cx, unwrap_call_expr) && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id) && let Node::LetStmt(local) = parent + && let PatKind::Binding(.., ident, _) = local.pat.kind + // if the binding is prefixed with `_`, it typically means + // that this guard only exists to protect a section of code + // rather than the contained data + && !ident.as_str().starts_with('_') && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) && let Some((local, _)) = mir .local_decls diff --git a/tests/ui/readonly_write_lock.fixed b/tests/ui/readonly_write_lock.fixed index 76f4a43ae53..4db13482ac7 100644 --- a/tests/ui/readonly_write_lock.fixed +++ b/tests/ui/readonly_write_lock.fixed @@ -43,3 +43,7 @@ fn main() { *writer1 = *writer2; } } + +fn issue12733(rw: &RwLock<()>) { + let _write_guard = rw.write().unwrap(); +} diff --git a/tests/ui/readonly_write_lock.rs b/tests/ui/readonly_write_lock.rs index 3d1d3855fe1..66ba1b2d696 100644 --- a/tests/ui/readonly_write_lock.rs +++ b/tests/ui/readonly_write_lock.rs @@ -43,3 +43,7 @@ fn main() { *writer1 = *writer2; } } + +fn issue12733(rw: &RwLock<()>) { + let _write_guard = rw.write().unwrap(); +} -- cgit 1.4.1-3-g733a5 From b1fa2842b10308b1ac3d482cef2f6ec316b2e98f Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 29 Apr 2024 21:26:14 +0200 Subject: Update version attribute for 1.78 lints --- clippy_lints/src/assigning_clones.rs | 2 +- clippy_lints/src/cargo/mod.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/multiple_bound_locations.rs | 2 +- clippy_lints/src/to_string_trait_impl.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index d88ca84fb97..f0dafb1ae0d 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// a.clone_from(&b); /// } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub ASSIGNING_CLONES, perf, "assigning the result of cloning may be inefficient" diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index ca7fa4e5a41..593bc6c81ee 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -197,7 +197,7 @@ declare_clippy_lint! { /// pedantic = { level = "warn", priority = -1 } /// similar_names = "allow" /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.78.0"] pub LINT_GROUPS_PRIORITY, correctness, "a lint group in `Cargo.toml` at the same priority as a lint" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d14898a8196..bd2c96f01f6 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -708,7 +708,7 @@ declare_clippy_lint! { /// let a_ref = &1; /// let a_ptr = std::ptr::from_ref(a_ref); /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub REF_AS_PTR, pedantic, "using `as` to cast a reference to pointer" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 16e508bf4e1..63545d6c503 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3993,7 +3993,7 @@ declare_clippy_lint! { /// let x: Result = Ok(0); /// let y = x.unwrap_or_else(|err| handle_error(err)); /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub UNNECESSARY_RESULT_MAP_OR_ELSE, suspicious, "making no use of the \"map closure\" when calling `.map_or_else(|err| handle_error(err), |n| n)`" @@ -4027,7 +4027,7 @@ declare_clippy_lint! { /// needs_cstr(c"Hello"); /// unsafe { libc::puts(c"World".as_ptr()) } /// ``` - #[clippy::version = "1.76.0"] + #[clippy::version = "1.78.0"] pub MANUAL_C_STR_LITERALS, pedantic, r#"creating a `CStr` through functions when `c""` literals can be used"# diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 191b32408ef..d608f3bf7b4 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// F: Sized + std::fmt::Debug, /// {} /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub MULTIPLE_BOUND_LOCATIONS, suspicious, "defining generic bounds in multiple locations" diff --git a/clippy_lints/src/to_string_trait_impl.rs b/clippy_lints/src/to_string_trait_impl.rs index 59ae185c9de..0361836cdec 100644 --- a/clippy_lints/src/to_string_trait_impl.rs +++ b/clippy_lints/src/to_string_trait_impl.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub TO_STRING_TRAIT_IMPL, style, "check for direct implementations of `ToString`" -- cgit 1.4.1-3-g733a5 From c187bff864234e869dabcb41d2336639e29e2511 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 26 Mar 2024 17:16:01 +0000 Subject: Fix `FormatArgs` storage when `-Zthreads` > 1 --- clippy_lints/src/explicit_write.rs | 20 +++++-- clippy_lints/src/format.rs | 19 ++++-- clippy_lints/src/format_args.rs | 13 +++-- clippy_lints/src/format_impl.rs | 10 +++- clippy_lints/src/lib.rs | 42 +++++++++---- clippy_lints/src/methods/expect_fun_call.rs | 7 ++- clippy_lints/src/methods/mod.rs | 15 ++++- clippy_lints/src/utils/format_args_collector.rs | 27 +++++---- clippy_lints/src/write.rs | 14 +++-- clippy_utils/src/macros.rs | 78 +++++++++++-------------- 10 files changed, 151 insertions(+), 94 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 33bd5a5a9d3..df11ee36fc0 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_args, format_args_inputs_span}; +use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{sym, ExpnId}; declare_clippy_lint! { @@ -38,7 +38,17 @@ declare_clippy_lint! { "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work" } -declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); +pub struct ExplicitWrite { + format_args: FormatArgsStorage, +} + +impl ExplicitWrite { + pub fn new(format_args: FormatArgsStorage) -> Self { + Self { format_args } + } +} + +impl_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -57,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { Some(sym::io_stderr) => ("stderr", "e"), _ => return, }; - let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { + let Some(format_args) = self.format_args.get(cx, write_arg, ExpnId::root()) else { return; }; @@ -83,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { }; let mut applicability = Applicability::MachineApplicable; let inputs_snippet = - snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability); + snippet_with_applicability(cx, format_args_inputs_span(format_args), "..", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_WRITE, diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8a0cd155d21..0b248f784b7 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node}; +use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -39,13 +39,24 @@ declare_clippy_lint! { "useless use of `format!`" } -declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); +#[allow(clippy::module_name_repetitions)] +pub struct UselessFormat { + format_args: FormatArgsStorage, +} + +impl UselessFormat { + pub fn new(format_args: FormatArgsStorage) -> Self { + Self { format_args } + } +} + +impl_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(cx, expr) && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) - && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) + && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { let mut applicability = Applicability::MachineApplicable; let call_site = macro_call.span; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 003a9995c15..86115807aa4 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -3,8 +3,8 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ - find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, - is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, + find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, + is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -167,15 +167,18 @@ impl_lint_pass!(FormatArgs => [ UNUSED_FORMAT_SPECS, ]); +#[allow(clippy::struct_field_names)] pub struct FormatArgs { + format_args: FormatArgsStorage, msrv: Msrv, ignore_mixed: bool, } impl FormatArgs { #[must_use] - pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self { + pub fn new(format_args: FormatArgsStorage, msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self { Self { + format_args, msrv, ignore_mixed: allow_mixed_uninlined_format_args, } @@ -186,13 +189,13 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(macro_call) = root_macro_call_first_node(cx, expr) && is_format_macro(cx, macro_call.def_id) - && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) + && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { let linter = FormatArgsExpr { cx, expr, macro_call: ¯o_call, - format_args: &format_args, + format_args, ignore_mixed: self.ignore_mixed, }; diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 0a52347940a..09be7237b5c 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node}; +use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; @@ -99,13 +99,15 @@ struct FormatTraitNames { #[derive(Default)] pub struct FormatImpl { + format_args: FormatArgsStorage, // Whether we are inside Display or Debug trait impl - None for neither format_trait_impl: Option, } impl FormatImpl { - pub fn new() -> Self { + pub fn new(format_args: FormatArgsStorage) -> Self { Self { + format_args, format_trait_impl: None, } } @@ -129,6 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { if let Some(format_trait_impl) = self.format_trait_impl { let linter = FormatImplExpr { cx, + format_args: &self.format_args, expr, format_trait_impl, }; @@ -141,6 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { struct FormatImplExpr<'a, 'tcx> { cx: &'a LateContext<'tcx>, + format_args: &'a FormatArgsStorage, expr: &'tcx Expr<'tcx>, format_trait_impl: FormatTraitNames, } @@ -175,7 +179,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { if let Some(outer_macro) = root_macro_call_first_node(self.cx, self.expr) && let macro_def_id = outer_macro.def_id && is_format_macro(self.cx, macro_def_id) - && let Some(format_args) = find_format_args(self.cx, self.expr, outer_macro.expn) + && let Some(format_args) = self.format_args.get(self.cx, self.expr, outer_macro.expn) { for piece in &format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e2aac58bf97..c3c2f63424d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -60,11 +60,6 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; -use std::collections::BTreeMap; - -use rustc_data_structures::fx::FxHashSet; -use rustc_lint::{Lint, LintId}; - #[cfg(feature = "internal")] pub mod deprecated_lints; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] @@ -384,6 +379,10 @@ mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` use clippy_config::{get_configuration_metadata, Conf}; +use clippy_utils::macros::FormatArgsStorage; +use rustc_data_structures::fx::FxHashSet; +use rustc_lint::{Lint, LintId}; +use std::collections::BTreeMap; /// Register all pre expansion lints /// @@ -614,6 +613,14 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { } } + let format_args_storage = FormatArgsStorage::default(); + let format_args = format_args_storage.clone(); + store.register_early_pass(move || { + Box::new(utils::format_args_collector::FormatArgsCollector::new( + format_args.clone(), + )) + }); + // all the internal lints #[cfg(feature = "internal")] { @@ -654,7 +661,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { .collect(), )) }); - store.register_early_pass(|| Box::::default()); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); store.register_late_pass(move |_| { @@ -696,6 +702,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv()))); + let format_args = format_args_storage.clone(); store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, @@ -703,6 +710,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_expect_in_tests, allow_unwrap_in_tests, allowed_dotfiles.clone(), + format_args.clone(), )) }); store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv()))); @@ -766,7 +774,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); - store.register_late_pass(|_| Box::new(format::UselessFormat)); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone()))); store.register_late_pass(|_| Box::new(swap::Swap)); store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|_| Box::::default()); @@ -790,7 +799,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)); store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount)); store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); - store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite)); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone()))); store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue)); store.register_late_pass(move |tcx| { Box::new(pass_by_ref_or_value::PassByRefOrValue::new( @@ -832,7 +842,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone()))); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); - store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new())); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone()))); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); @@ -958,8 +969,14 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { accept_comment_above_attributes, )) }); - store - .register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined_format_args))); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| { + Box::new(format_args::FormatArgs::new( + format_args.clone(), + msrv(), + allow_mixed_uninlined_format_args, + )) + }); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); @@ -970,7 +987,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); - store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests))); + let format_args = format_args_storage.clone(); + store.register_late_pass(move |_| Box::new(write::Write::new(format_args.clone(), allow_print_in_tests))); store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index fba76852344..c9f56e1d980 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node}; +use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; @@ -16,6 +16,7 @@ use super::EXPECT_FUN_CALL; #[allow(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, + format_args_storage: &FormatArgsStorage, expr: &hir::Expr<'_>, method_span: Span, name: &str, @@ -134,9 +135,9 @@ pub(super) fn check<'tcx>( // Special handling for `format!` as arg_root if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) { if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) - && let Some(format_args) = find_format_args(cx, arg_root, macro_call.expn) + && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn) { - let span = format_args_inputs_span(&format_args); + let span = format_args_inputs_span(format_args); let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 16e508bf4e1..1ced448c18b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -133,6 +133,7 @@ use bind_instead_of_map::BindInsteadOfMap; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::macros::FormatArgsStorage; 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, peel_blocks, return_ty}; pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES; @@ -4087,12 +4088,14 @@ declare_clippy_lint! { suspicious, "is_empty() called on strings known at compile time" } + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, allowed_dotfiles: FxHashSet, + format_args: FormatArgsStorage, } impl Methods { @@ -4103,6 +4106,7 @@ impl Methods { allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, mut allowed_dotfiles: FxHashSet, + format_args: FormatArgsStorage, ) -> Self { allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string)); @@ -4112,6 +4116,7 @@ impl Methods { allow_expect_in_tests, allow_unwrap_in_tests, allowed_dotfiles, + format_args, } } } @@ -4281,7 +4286,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); - expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + expect_fun_call::check( + cx, + &self.format_args, + expr, + method_span, + method_call.ident.as_str(), + receiver, + args, + ); clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args); clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args); inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 58e66c9f9b9..5acfd35fd6a 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,4 +1,4 @@ -use clippy_utils::macros::AST_FORMAT_ARGS; +use clippy_utils::macros::FormatArgsStorage; use clippy_utils::source::snippet_opt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; @@ -9,13 +9,20 @@ use rustc_session::impl_lint_pass; use rustc_span::{hygiene, Span}; use std::iter::once; use std::mem; -use std::rc::Rc; -/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call -/// [`clippy_utils::macros::find_format_args`] -#[derive(Default)] +/// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes pub struct FormatArgsCollector { - format_args: FxHashMap>, + format_args: FxHashMap, + storage: FormatArgsStorage, +} + +impl FormatArgsCollector { + pub fn new(storage: FormatArgsStorage) -> Self { + Self { + format_args: FxHashMap::default(), + storage, + } + } } impl_lint_pass!(FormatArgsCollector => []); @@ -27,16 +34,12 @@ impl EarlyLintPass for FormatArgsCollector { return; } - self.format_args - .insert(expr.span.with_parent(None), Rc::new((**args).clone())); + self.format_args.insert(expr.span.with_parent(None), (**args).clone()); } } fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) { - AST_FORMAT_ARGS.with(|ast_format_args| { - let result = ast_format_args.set(mem::take(&mut self.format_args)); - debug_assert!(result.is_ok()); - }); + self.storage.set(mem::take(&mut self.format_args)); } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 26c6859233d..ff6ee0d10ad 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro_call_first_node, MacroCall}; +use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; @@ -236,13 +236,15 @@ declare_clippy_lint! { #[derive(Default)] pub struct Write { + format_args: FormatArgsStorage, in_debug_impl: bool, allow_print_in_tests: bool, } impl Write { - pub fn new(allow_print_in_tests: bool) -> Self { + pub fn new(format_args: FormatArgsStorage, allow_print_in_tests: bool) -> Self { Self { + format_args, allow_print_in_tests, ..Default::default() } @@ -307,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { _ => return, } - if let Some(format_args) = find_format_args(cx, expr, macro_call.expn) { + if let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { // ignore `writeln!(w)` and `write!(v, some_macro!())` if format_args.span.from_expansion() { return; @@ -315,15 +317,15 @@ impl<'tcx> LateLintPass<'tcx> for Write { match diag_name { sym::print_macro | sym::eprint_macro | sym::write_macro => { - check_newline(cx, &format_args, ¯o_call, name); + check_newline(cx, format_args, ¯o_call, name); }, sym::println_macro | sym::eprintln_macro | sym::writeln_macro => { - check_empty_string(cx, &format_args, ¯o_call, name); + check_empty_string(cx, format_args, ¯o_call, name); }, _ => {}, } - check_literal(cx, &format_args, name); + check_literal(cx, format_args, name); if !self.in_debug_impl { for piece in &format_args.template { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 257dd76ab15..8daab9b0d92 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -5,15 +5,13 @@ use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{Lrc, OnceLock}; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; -use std::cell::OnceCell; use std::ops::ControlFlow; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ sym::assert_eq_macro, @@ -388,50 +386,44 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> } } -thread_local! { - /// We preserve the [`FormatArgs`] structs from the early pass for use in the late pass to be - /// able to access the many features of a [`LateContext`]. - /// - /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an - /// assumption that the early pass that populates the map and the later late passes will all be - /// running on the same thread. - #[doc(hidden)] - pub static AST_FORMAT_ARGS: OnceCell>> = { - static CALLED: AtomicBool = AtomicBool::new(false); - debug_assert!( - !CALLED.swap(true, Ordering::SeqCst), - "incorrect assumption: `AST_FORMAT_ARGS` should only be accessed by a single thread", - ); - - OnceCell::new() - }; -} +/// Stores AST [`FormatArgs`] nodes for use in late lint passes, as they are in a desugared form in +/// the HIR +#[derive(Default, Clone)] +pub struct FormatArgsStorage(Lrc>>); -/// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of -/// `expn_id` -pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option> { - let format_args_expr = for_each_expr(start, |expr| { - let ctxt = expr.span.ctxt(); - if ctxt.outer_expn().is_descendant_of(expn_id) { - if macro_backtrace(expr.span) - .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) - .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl)) - { - ControlFlow::Break(expr) +impl FormatArgsStorage { + /// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of + /// `expn_id` + /// + /// See also [`find_format_arg_expr`] + pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> { + let format_args_expr = for_each_expr(start, |expr| { + let ctxt = expr.span.ctxt(); + if ctxt.outer_expn().is_descendant_of(expn_id) { + if macro_backtrace(expr.span) + .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) + .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl)) + { + ControlFlow::Break(expr) + } else { + ControlFlow::Continue(Descend::Yes) + } } else { - ControlFlow::Continue(Descend::Yes) + ControlFlow::Continue(Descend::No) } - } else { - ControlFlow::Continue(Descend::No) - } - })?; + })?; - AST_FORMAT_ARGS.with(|ast_format_args| { - ast_format_args - .get()? - .get(&format_args_expr.span.with_parent(None)) - .cloned() - }) + debug_assert!(self.0.get().is_some(), "`FormatArgsStorage` not yet populated"); + + self.0.get()?.get(&format_args_expr.span.with_parent(None)) + } + + /// Should only be called by `FormatArgsCollector` + pub fn set(&self, format_args: FxHashMap) { + self.0 + .set(format_args) + .expect("`FormatArgsStorage::set` should only be called once"); + } } /// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if -- cgit 1.4.1-3-g733a5 From afedaf6a269027d5504acf898cbe1914ddf7672c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 6 May 2024 15:33:55 -0700 Subject: Update doc comments to avoid lazy continuations --- clippy_lints/src/casts/cast_sign_loss.rs | 4 ++++ clippy_lints/src/manual_clamp.rs | 7 +++++++ clippy_lints/src/methods/iter_filter.rs | 8 ++++---- clippy_lints/src/methods/iter_kv_map.rs | 2 ++ clippy_lints/src/methods/utils.rs | 1 + clippy_lints/src/needless_continue.rs | 3 +-- clippy_utils/src/lib.rs | 3 +++ clippy_utils/src/source.rs | 2 +- clippy_utils/src/sugg.rs | 3 +-- 9 files changed, 24 insertions(+), 9 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 2b6e17dc103..864489ee3fc 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -255,8 +255,10 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { /// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`], /// where the result depends on: +/// /// - the number of negative values in the entire expression, or /// - the number of negative values on the left hand side of the expression. +/// /// Ignores overflow. /// /// @@ -303,8 +305,10 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { } /// Peels binary operators such as [`BinOpKind::Add`], where the result depends on: +/// /// - all the expressions being positive, or /// - all the expressions being negative. +/// /// Ignores overflow. /// /// Expressions using other operators are preserved, so we can try to evaluate them later. diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 1eadc200bed..e2ab4415518 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -611,15 +611,22 @@ impl<'tcx> BinaryOp<'tcx> { /// The clamp meta pattern is a pattern shared between many (but not all) patterns. /// In summary, this pattern consists of two if statements that meet many criteria, +/// /// - binary operators that are one of [`>`, `<`, `>=`, `<=`]. +/// /// - Both binary statements must have a shared argument +/// /// - Which can appear on the left or right side of either statement +/// /// - The binary operators must define a finite range for the shared argument. To put this in /// the terms of Rust `std` library, the following ranges are acceptable +/// /// - `Range` /// - `RangeInclusive` +/// /// And all other range types are not accepted. For the purposes of `clamp` it's irrelevant /// whether the range is inclusive or not, the output is the same. +/// /// - The result of each if statement must be equal to the argument unique to that if statement. The /// result can not be the shared argument in either case. fn is_clamp_meta_pattern<'tcx>( diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index 12647ea1ffc..b93d51eac64 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -126,15 +126,15 @@ enum FilterType { /// /// How this is done: /// 1. we know that this is invoked in a method call with `filter` as the method name via `mod.rs` -/// 2. we check that we are in a trait method. Therefore we are in an -/// `(x as Iterator).filter({filter_arg})` method call. +/// 2. we check that we are in a trait method. Therefore we are in an `(x as +/// Iterator).filter({filter_arg})` method call. /// 3. we check that the parent expression is not a map. This is because we don't want to lint /// twice, and we already have a specialized lint for that. /// 4. we check that the span of the filter does not contain a comment. /// 5. we get the type of the `Item` in the `Iterator`, and compare against the type of Option and -/// Result. +/// Result. /// 6. we finally check the contents of the filter argument to see if it is a call to `is_some` or -/// `is_ok`. +/// `is_ok`. /// 7. if all of the above are true, then we return the `FilterType` fn expression_type( cx: &LateContext<'_>, diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 7c852a3768d..05e77386128 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -12,8 +12,10 @@ use rustc_middle::ty; use rustc_span::{sym, Span}; /// lint use of: +/// /// - `hashmap.iter().map(|(_, v)| v)` /// - `hashmap.into_iter().map(|(_, v)| v)` +/// /// on `HashMaps` and `BTreeMaps` in std pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index c50f24f824a..34d7b9acbe4 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -120,6 +120,7 @@ fn pat_bindings(pat: &Pat<'_>) -> Vec { /// operations performed on `binding_hir_ids` are: /// * to take non-mutable references to them /// * to use them as non-mutable `&self` in method calls +/// /// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true /// when `CloneOrCopyVisitor` is done visiting. struct CloneOrCopyVisitor<'cx, 'tcx> { diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 8b4a12bb766..b97cb4579ca 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -178,8 +178,7 @@ impl EarlyLintPass for NeedlessContinue { /// Given an expression, returns true if either of the following is true /// /// - The expression is a `continue` node. -/// - The expression node is a block with the first statement being a -/// `continue`. +/// - The expression node is a block with the first statement being a `continue`. fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool { match else_expr.kind { ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label), diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 0ef732f9268..1f7edabcf01 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1513,15 +1513,18 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. +/// /// For the lower bound, this means that: /// - either there is none /// - or it is the smallest value that can be represented by the range's integer type +/// /// For the upper bound, this means that: /// - either there is none /// - or it is the largest value that can be represented by the range's integer type and is /// inclusive /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to /// a method call on that same container (e.g. `v.drain(..v.len())`) +/// /// If the given `Expr` is not some kind of range, the function returns `false`. pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { let ty = cx.typeck_results().expr_ty(expr); diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index a4a6f8e15f9..69f593fe04a 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -250,7 +250,7 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow< /// - Applicability level `Unspecified` will never be changed. /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. /// - If the default value is used and the applicability level is `MachineApplicable`, change it to -/// `HasPlaceholders` +/// `HasPlaceholders` pub fn snippet_with_applicability<'a, T: LintContext>( cx: &T, span: Span, diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 8d6057272c4..1d49634aff3 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -68,8 +68,7 @@ impl<'a> Sugg<'a> { /// - Applicability level `Unspecified` will never be changed. /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. /// - If the default value is used and the applicability level is `MachineApplicable`, change it - /// to - /// `HasPlaceholders` + /// to `HasPlaceholders` pub fn hir_with_applicability( cx: &LateContext<'_>, expr: &hir::Expr<'_>, -- cgit 1.4.1-3-g733a5 From a8c35cbbda8bc274cd41146a44956fcb691e6277 Mon Sep 17 00:00:00 2001 From: cocodery Date: Tue, 7 May 2024 16:07:13 +0800 Subject: Check inner caller for clone and judge whether they are mutable if immutbale -> lint delete redudant clone if mutable -> lint check whether clone is needed --- .../src/methods/unnecessary_iter_cloned.rs | 53 +++++++++++++++++++++- tests/ui/unnecessary_iter_cloned.fixed | 32 +++++++++++++ tests/ui/unnecessary_iter_cloned.rs | 32 +++++++++++++ tests/ui/unnecessary_iter_cloned.stderr | 4 +- 4 files changed, 117 insertions(+), 4 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 520dcb2d52d..7431dc1cf0b 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -3,10 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; -use clippy_utils::{fn_def_id, get_parent_expr}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; +use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::{sym, Symbol}; @@ -40,6 +42,53 @@ pub fn check_for_loop_iter( && !clone_or_copy_needed && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) { + // Issue 12098 + // https://github.com/rust-lang/rust-clippy/issues/12098 + // if the assignee have `mut borrow` conflict with the iteratee + // the lint should not execute, former didn't consider the mut case + + // check whether `expr` is mutable + fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) + && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) + } else { + true + } + } + + fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool { + let mut change = false; + if let ExprKind::Block(block, ..) = body.kind { + for_each_expr(block, |e| { + match e.kind { + ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => { + change |= !can_mut_borrow_both(cx, caller, assignee); + }, + _ => {}, + } + // the return value has no effect but the function need one return value + ControlFlow::<()>::Continue(()) + }); + } + change + } + + if let ExprKind::Call(_, [child, ..]) = expr.kind { + // filter first layer of iterator + let mut child = child; + // get inner real caller requests for clone + while let ExprKind::MethodCall(_, caller, _, _) = child.kind { + child = caller; + } + if is_mutable(cx, child) && is_caller_or_fields_change(cx, body, child) { + // skip lint + return true; + } + }; + + // the lint should not be executed if no violation happens let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind && maybe_iter_method_name.ident.name == sym::iter && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator) diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed index ad0e5fab029..2c582c90ba8 100644 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -21,6 +21,8 @@ fn main() { let _ = check_files_ref_mut(&[(FileType::Account, path)]); let _ = check_files_self_and_arg(&[(FileType::Account, path)]); let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); + + check_mut_iteratee_and_modify_inner_variable(); } // `check_files` and its variants are based on: @@ -138,3 +140,33 @@ fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { fn get_file_path(_file_type: &FileType) -> Result { Ok(std::path::PathBuf::new()) } + +// Issue 12098 +// https://github.com/rust-lang/rust-clippy/issues/12098 +// no message emits +fn check_mut_iteratee_and_modify_inner_variable() { + struct Test { + list: Vec, + mut_this: bool, + } + + impl Test { + fn list(&self) -> &[String] { + &self.list + } + } + + let mut test = Test { + list: vec![String::from("foo"), String::from("bar")], + mut_this: false, + }; + + for _item in test.list().to_vec() { + println!("{}", _item); + + test.mut_this = true; + { + test.mut_this = true; + } + } +} diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index d3d59c4c70f..a28ccd1efef 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -21,6 +21,8 @@ fn main() { let _ = check_files_ref_mut(&[(FileType::Account, path)]); let _ = check_files_self_and_arg(&[(FileType::Account, path)]); let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]); + + check_mut_iteratee_and_modify_inner_variable(); } // `check_files` and its variants are based on: @@ -138,3 +140,33 @@ fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool { fn get_file_path(_file_type: &FileType) -> Result { Ok(std::path::PathBuf::new()) } + +// Issue 12098 +// https://github.com/rust-lang/rust-clippy/issues/12098 +// no message emits +fn check_mut_iteratee_and_modify_inner_variable() { + struct Test { + list: Vec, + mut_this: bool, + } + + impl Test { + fn list(&self) -> &[String] { + &self.list + } + } + + let mut test = Test { + list: vec![String::from("foo"), String::from("bar")], + mut_this: false, + }; + + for _item in test.list().to_vec() { + println!("{}", _item); + + test.mut_this = true; + { + test.mut_this = true; + } + } +} diff --git a/tests/ui/unnecessary_iter_cloned.stderr b/tests/ui/unnecessary_iter_cloned.stderr index 9d3591e0dbf..fb98cfddc26 100644 --- a/tests/ui/unnecessary_iter_cloned.stderr +++ b/tests/ui/unnecessary_iter_cloned.stderr @@ -1,5 +1,5 @@ error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:29:22 + --> tests/ui/unnecessary_iter_cloned.rs:31:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL + let other = match get_file_path(t) { | error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:44:22 + --> tests/ui/unnecessary_iter_cloned.rs:46:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From e6040437ef5e6f2ac8110fd160c58ec2fa8ad202 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 17 May 2024 16:45:00 +0000 Subject: Swap `for_each_expr` and `for_each_expr_with_closures` --- clippy_lints/src/blocks_in_conditions.rs | 4 ++-- clippy_lints/src/casts/cast_sign_loss.rs | 6 +++--- clippy_lints/src/casts/unnecessary_cast.rs | 4 ++-- clippy_lints/src/cognitive_complexity.rs | 4 ++-- clippy_lints/src/collection_is_never_read.rs | 4 ++-- clippy_lints/src/copies.rs | 6 +++--- clippy_lints/src/functions/must_use.rs | 4 ++-- clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs | 4 ++-- clippy_lints/src/implicit_return.rs | 4 ++-- clippy_lints/src/matches/redundant_guards.rs | 4 ++-- clippy_lints/src/matches/redundant_pattern_match.rs | 4 ++-- clippy_lints/src/methods/collapsible_str_replace.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 4 ++-- clippy_lints/src/methods/unnecessary_filter_map.rs | 4 ++-- clippy_lints/src/methods/unnecessary_iter_cloned.rs | 4 ++-- clippy_lints/src/missing_asserts_for_indexing.rs | 4 ++-- clippy_lints/src/missing_fields_in_debug.rs | 6 +++--- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 4 ++-- clippy_lints/src/needless_late_init.rs | 6 +++--- clippy_lints/src/needless_pass_by_ref_mut.rs | 4 ++-- clippy_lints/src/operators/assign_op_pattern.rs | 4 ++-- clippy_lints/src/panic_in_result_fn.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 4 ++-- clippy_lints/src/returns.rs | 4 ++-- clippy_lints/src/suspicious_trait_impl.rs | 4 ++-- clippy_lints/src/undocumented_unsafe_blocks.rs | 4 ++-- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 4 ++-- clippy_lints/src/zero_repeat_side_effects.rs | 4 ++-- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/macros.rs | 10 +++++----- clippy_utils/src/ptr.rs | 4 ++-- clippy_utils/src/usage.rs | 8 ++++---- clippy_utils/src/visitors.rs | 14 +++++++------- 34 files changed, 81 insertions(+), 81 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/blocks_in_conditions.rs b/clippy_lints/src/blocks_in_conditions.rs index 171f3031860..869ed332b9c 100644 --- a/clippy_lints/src/blocks_in_conditions.rs +++ b/clippy_lints/src/blocks_in_conditions.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{get_parent_expr, higher, is_from_proc_macro}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { } } } else { - let _: Option = for_each_expr(cond, |e| { + let _: Option = for_each_expr_without_closures(cond, |e| { if let ExprKind::Closure(closure) = e.kind { // do not lint if the closure is called using an iterator (see #1141) if let Some(parent) = get_parent_expr(cx, e) diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 864489ee3fc..8bbd41b0db1 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -266,7 +266,7 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - for_each_expr(expr, |sub_expr| -> ControlFlow { + for_each_expr_without_closures(expr, |sub_expr| -> ControlFlow { // We don't check for mul/div/rem methods here, but we could. if let ExprKind::Binary(op, lhs, _rhs) = sub_expr.kind { if matches!(op.node, BinOpKind::Mul | BinOpKind::Div) { @@ -315,7 +315,7 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { fn exprs_with_add_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - for_each_expr(expr, |sub_expr| -> ControlFlow { + for_each_expr_without_closures(expr, |sub_expr| -> ControlFlow { // We don't check for add methods here, but we could. if let ExprKind::Binary(op, _lhs, _rhs) = sub_expr.kind { if matches!(op.node, BinOpKind::Add) { diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index a7f7bf7854e..fb0b0cba6a6 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; @@ -245,7 +245,7 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { /// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark, /// dark path reimplementing this (or something similar). fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool { - for_each_expr(expr, |expr| { + for_each_expr_without_closures(expr, |expr| { // Calls are a `Path`, and usage of locals are a `Path`. So, this checks // - call() as i32 // - local as i32 diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index ee1bb63b50d..e41abf42234 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; @@ -65,7 +65,7 @@ impl CognitiveComplexity { let mut cc = 1u64; let mut returns = 0u64; - let _: Option = for_each_expr(expr, |e| { + let _: Option = for_each_expr_without_closures(expr, |e| { match e.kind { ExprKind::If(_, _, _) => { cc += 1; diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 70856b80881..28d9f68d504 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::visitors::{for_each_expr_with_closures, Visitable}; +use clippy_utils::visitors::{for_each_expr, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; @@ -82,7 +82,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI let mut has_read_access = false; // Inspect all expressions and sub-expressions in the block. - for_each_expr_with_closures(cx, block, |expr| { + for_each_expr(cx, block, |expr| { // Ignore expressions that are not simply `id`. if !path_to_local_id(expr, id) { return ControlFlow::Continue(()); diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index ccf1d9d6f8c..480df675d75 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, @@ -362,7 +362,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { /// Checks if the statement modifies or moves any of the given locals. fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: &HirIdSet) -> bool { - for_each_expr(s, |e| { + for_each_expr_without_closures(s, |e| { if let Some(id) = path_to_local(e) && locals.contains(&id) && !capture_local_usage(cx, e).is_imm_ref() @@ -413,7 +413,7 @@ fn scan_block_for_eq<'tcx>( let mut cond_locals = HirIdSet::default(); for &cond in conds { - let _: Option = for_each_expr(cond, |e| { + let _: Option = for_each_expr_without_closures(cond, |e| { if let Some(id) = path_to_local(e) { cond_locals.insert(id); } diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index e7ec2b3151e..cce8617821e 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -14,7 +14,7 @@ use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use core::ops::ControlFlow; @@ -226,7 +226,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool { } fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { - for_each_expr(body.value, |e| { + for_each_expr_without_closures(body.value, |e| { use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; match e.kind { diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 995dd782cbb..466d38c52d7 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -5,7 +5,7 @@ use rustc_span::def_id::LocalDefId; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::type_is_unsafe_function; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{iter_input_pats, path_to_local}; use core::ops::ControlFlow; @@ -49,7 +49,7 @@ fn check_raw_ptr<'tcx>( if !raw_ptrs.is_empty() { let typeck = cx.tcx.typeck_body(body.id()); - let _: Option = for_each_expr_with_closures(cx, body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { match e.kind { hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => { for arg in args { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 5288efd8df8..b54c147e4d8 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -152,7 +152,7 @@ fn lint_implicit_returns( ExprKind::Loop(block, ..) => { let mut add_return = false; - let _: Option = for_each_expr(block, |e| { + let _: Option = for_each_expr_without_closures(block, |e| { if let ExprKind::Break(dest, sub_expr) = e.kind { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && e.span.ctxt() == ctxt { diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index a75cf37945f..c2c0fbf439d 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; -use clippy_utils::visitors::{for_each_expr, is_local_used}; +use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; use clippy_utils::{in_constant, path_to_local}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; @@ -249,7 +249,7 @@ fn emit_redundant_guards<'tcx>( /// an error in the future, and rustc already actively warns against this (see rust#41620), /// so we don't consider those as usable within patterns for linting purposes. fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - for_each_expr(expr, |expr| { + for_each_expr_without_closures(expr, |expr| { if match expr.kind { ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat, ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => { diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 78973984fb0..0e4b2d9d34a 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::{make_unop, Sugg}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; -use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr}; +use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; use clippy_utils::{higher, is_expn_of, is_trait_method}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -283,7 +283,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op // to see that there aren't any let chains anywhere in the guard, as that would break // if we suggest `t.is_none() && (let X = y && z)` for: // `match t { None if let X = y && z => true, _ => false }` - let has_nested_let_chain = for_each_expr(guard, |expr| { + let has_nested_let_chain = for_each_expr_without_closures(guard, |expr| { if matches!(expr.kind, ExprKind::Let(..)) { ControlFlow::Break(()) } else { diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 5409ede6008..1fab6c0e499 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, get_parent_expr}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -46,7 +46,7 @@ fn collect_replace_calls<'tcx>( let mut methods = VecDeque::new(); let mut from_args = VecDeque::new(); - let _: Option<()> = for_each_expr(expr, |e| { + let _: Option<()> = for_each_expr_without_closures(expr, |e| { if let Some(("replace", _, [from, to], _, _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index e8c12bbeea0..4f42fb73547 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -209,7 +209,7 @@ fn indirect_usage<'tcx>( }) = stmt.kind { let mut path_to_binding = None; - let _: Option = for_each_expr_with_closures(cx, init_expr, |e| { + let _: Option = for_each_expr(cx, init_expr, |e| { if path_to_local_id(e, binding) { path_to_binding = Some(e); } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index daf99d98614..c9b9d98dbe6 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { if let hir::ExprKind::Ret(Some(e)) = &e.kind { let (found_mapping_res, found_filtering_res) = check_expression(cx, arg_id, e); found_mapping |= found_mapping_res; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 7431dc1cf0b..e23ea54867f 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -61,7 +61,7 @@ pub fn check_for_loop_iter( fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool { let mut change = false; if let ExprKind::Block(block, ..) = body.kind { - for_each_expr(block, |e| { + for_each_expr_without_closures(block, |e| { match e.kind { ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => { change |= !can_mut_borrow_both(cx, caller, assignee); diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index c29e46b941c..a95b567ef5f 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use clippy_utils::comparisons::{normalize_comparison, Rel}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; @@ -405,7 +405,7 @@ impl LateLintPass<'_> for MissingAssertsForIndexing { fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { let mut map = UnhashMap::default(); - for_each_expr(body.value, |expr| { + for_each_expr_without_closures(body.value, |expr| { check_index(cx, expr, &mut map); check_assert(cx, expr, &mut map); ControlFlow::::Continue(()) diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index a64faa124f0..10f6cb7c0d3 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -110,7 +110,7 @@ fn should_lint<'tcx>( // Is there a call to `DebugStruct::debug_struct`? Do lint if there is. let mut has_debug_struct = false; - for_each_expr(block, |expr| { + for_each_expr_without_closures(block, |expr| { if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); @@ -165,7 +165,7 @@ fn check_struct<'tcx>( let mut has_direct_field_access = false; let mut field_accesses = FxHashSet::default(); - for_each_expr(block, |expr| { + for_each_expr_without_closures(block, |expr| { if let ExprKind::Field(target, ident) = expr.kind && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs() && target_ty == self_ty diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 0e138066780..ca995cc76da 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable}; +use clippy_utils::visitors::{for_each_expr, Descend, Visitable}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp, Unsafety}; @@ -96,7 +96,7 @@ fn collect_unsafe_exprs<'tcx>( node: impl Visitable<'tcx>, unsafe_ops: &mut Vec<(&'static str, Span)>, ) { - for_each_expr_with_closures(cx, node, |expr| { + for_each_expr(cx, node, |expr| { match expr.kind { ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 5a0ae1a4d6d..4bfc30fa5cf 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; use clippy_utils::source::snippet_opt; use clippy_utils::ty::needs_ordered_drop; -use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used}; +use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ @@ -63,7 +63,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - for_each_expr_with_closures(cx, stmt, |e| { + for_each_expr(cx, stmt, |e| { if matches!(e.kind, ExprKind::Assign(..)) { ControlFlow::Break(()) } else { @@ -74,7 +74,7 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> } fn contains_let(cond: &Expr<'_>) -> bool { - for_each_expr(cond, |e| { + for_each_expr_without_closures(cond, |e| { if matches!(e.kind, ExprKind::Let(_)) { ControlFlow::Break(()) } else { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index da6ed5fb96f..57ba0da5331 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,7 +1,7 @@ use super::needless_pass_by_value::requires_exact_signature; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; @@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // We retrieve all the closures declared in the function because they will not be found // by `euv::Delegate`. let mut closures: FxHashSet = FxHashSet::default(); - for_each_expr_with_closures(cx, body, |expr| { + for_each_expr(cx, body, |expr| { if let ExprKind::Closure(closure) = expr.kind { closures.insert(closure.def_id); } diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 910e584a7a0..641d881d974 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( }; let mut found = false; - let found_multiple = for_each_expr(e, |e| { + let found_multiple = for_each_expr_without_closures(e, |e| { if eq_expr_value(cx, assignee, e) { if found { return ControlFlow::Break(()); diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index f821a4efee7..6d43143abab 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 0ed957f1f2f..313e4083256 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use rustc_errors::Applicability; use rustc_hir::{ Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource, @@ -107,7 +107,7 @@ fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && let ExprKind::Call(_, [into_future_arg]) = match_value.kind && let ctxt = expr.span.ctxt() - && for_each_expr(into_future_arg, |e| { + && for_each_expr_without_closures(into_future_arg, |e| { walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) }) .is_none() diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index e8f9d438104..bf0903a6b1b 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{ fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -444,7 +444,7 @@ fn emit_return_lint( } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - for_each_expr_with_closures(cx, expr, |e| { + for_each_expr(cx, expr, |e| { if let Some(def_id) = fn_def_id(cx, e) && cx .tcx diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 3f030b80331..744d6392e06 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { fn count_binops(expr: &hir::Expr<'_>) -> u32 { let mut count = 0u32; - let _: Option = for_each_expr(expr, |e| { + let _: Option = for_each_expr_without_closures(expr, |e| { if matches!( e.kind, hir::ExprKind::Binary(..) diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index cbd16180077..6ab9d641bdb 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; @@ -297,7 +297,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>( } // this should roughly be the reverse of `block_parents_have_safety_comment` - if for_each_expr_with_closures(cx, expr, |expr| match expr.kind { + if for_each_expr(cx, expr, |expr| match expr.kind { hir::ExprKind::Block( Block { rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index a67f53f00ae..3e6102f5982 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let parent_item = cx.tcx.hir().expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { - clippy_utils::visitors::for_each_expr(body.value, |e| { + clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { if let Some(macro_call) = root_macro_call_first_node(cx, e) { if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { ControlFlow::Break(()) diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index aca500590ce..a4142a30ea4 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{method_chain_args, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -75,7 +75,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let body = cx.tcx.hir().body(body_id); let typeck = cx.tcx.typeck(impl_item.owner_id.def_id); let mut result = Vec::new(); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { // check for `expect` if let Some(arglists) = method_chain_args(e, &["expect"]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 143fecdd237..da198b78d2e 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Node}; @@ -66,7 +66,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) { // check if expr is a call or has a call inside it - if for_each_expr(inner_expr, |x| { + if for_each_expr_without_closures(inner_expr, |x| { if let ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _) = x.kind { std::ops::ControlFlow::Break(()) } else { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 4c603bda770..3bd09525d5a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -126,7 +126,7 @@ use visitors::Visitable; use crate::consts::{constant, mir_to_const, Constant}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; -use crate::visitors::for_each_expr; +use crate::visitors::for_each_expr_without_closures; use rustc_middle::hir::nested_filter; @@ -1313,7 +1313,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext< /// Returns `true` if `expr` contains a return expression pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Ret(..)) { ControlFlow::Break(()) } else { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 8daab9b0d92..455239cc37f 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::visitors::{for_each_expr, Descend}; +use crate::visitors::{for_each_expr_without_closures, Descend}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -323,7 +323,7 @@ fn find_assert_args_inner<'a, const N: usize>( Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?, }; let mut args = ArrayVec::new(); - let panic_expn = for_each_expr(expr, |e| { + let panic_expn = for_each_expr_without_closures(expr, |e| { if args.is_full() { match PanicExpn::parse(e) { Some(expn) => ControlFlow::Break(expn), @@ -349,7 +349,7 @@ fn find_assert_within_debug_assert<'a>( expn: ExpnId, assert_name: Symbol, ) -> Option<(&'a Expr<'a>, ExpnId)> { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if !e.span.from_expansion() { return ControlFlow::Continue(Descend::No); } @@ -397,7 +397,7 @@ impl FormatArgsStorage { /// /// See also [`find_format_arg_expr`] pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> { - let format_args_expr = for_each_expr(start, |expr| { + let format_args_expr = for_each_expr_without_closures(start, |expr| { let ctxt = expr.span.ctxt(); if ctxt.outer_expn().is_descendant_of(expn_id) { if macro_backtrace(expr.span) @@ -439,7 +439,7 @@ pub fn find_format_arg_expr<'hir, 'ast>( parent: _, } = target.expr.span.data(); - for_each_expr(start, |expr| { + for_each_expr_without_closures(start, |expr| { // When incremental compilation is enabled spans gain a parent during AST to HIR lowering, // since we're comparing an AST span to a HIR one we need to ignore the parent field let data = expr.span.data(); diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 88837d8a143..991ea428dc3 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,5 +1,5 @@ use crate::source::snippet; -use crate::visitors::{for_each_expr, Descend}; +use crate::visitors::{for_each_expr_without_closures, Descend}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; @@ -31,7 +31,7 @@ fn extract_clone_suggestions<'tcx>( body: &'tcx Body<'_>, ) -> Option)>> { let mut spans = Vec::new(); - for_each_expr(body, |e| { + for_each_expr_without_closures(body, |e| { if let ExprKind::MethodCall(seg, recv, [], _) = e.kind && path_to_local_id(recv, id) { diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 2a25d51d8e5..fbf3d95365a 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,4 +1,4 @@ -use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable}; +use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; use hir::def::Res; @@ -145,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { } pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { - for_each_expr(expression, |e| { + for_each_expr_without_closures(expression, |e| { match e.kind { ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), // Something special could be done here to handle while or for loop @@ -159,7 +159,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { } pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool { - for_each_expr_with_closures(cx, v, |e| { + for_each_expr(cx, v, |e| { if utils::path_to_local_id(e, local_id) { ControlFlow::Break(()) } else { @@ -184,7 +184,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id); let mut past_expr = false; - for_each_expr_with_closures(cx, block, |e| { + for_each_expr(cx, block, |e| { if past_expr { if utils::path_to_local_id(e, local_id) { ControlFlow::Break(()) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index a3f3b32ed37..00a97822e49 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -100,7 +100,7 @@ visitable_ref!(Stmt, visit_stmt); /// Calls the given function once for each expression contained. This does not enter any bodies or /// nested items. -pub fn for_each_expr<'tcx, B, C: Continue>( +pub fn for_each_expr_without_closures<'tcx, B, C: Continue>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { @@ -134,7 +134,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>( /// Calls the given function once for each expression contained. This will enter bodies, but not /// nested items. -pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( +pub fn for_each_expr<'tcx, B, C: Continue>( cx: &LateContext<'tcx>, node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, @@ -181,7 +181,7 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) { ControlFlow::Break(()) } else { @@ -286,7 +286,7 @@ where /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { - for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| { + for_each_expr(cx, cx.tcx.hir().body(body).value, |e| { if let ExprKind::Path(p) = &e.kind { if cx.qpath_res(p, e.hir_id) == res { return ControlFlow::Break(()); @@ -299,7 +299,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { /// Checks if the given local is used. pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { - for_each_expr_with_closures(cx, visitable, |e| { + for_each_expr(cx, visitable, |e| { if path_to_local_id(e, id) { ControlFlow::Break(()) } else { @@ -757,7 +757,7 @@ pub fn for_each_local_assignment<'tcx, B>( } pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { ControlFlow::Break(()) } else { @@ -776,7 +776,7 @@ pub fn local_used_once<'tcx>( ) -> Option<&'tcx Expr<'tcx>> { let mut expr = None; - let cf = for_each_expr_with_closures(cx, visitable, |e| { + let cf = for_each_expr(cx, visitable, |e| { if path_to_local_id(e, id) && expr.replace(e).is_some() { ControlFlow::Break(()) } else { -- cgit 1.4.1-3-g733a5 From 9d311b5c2b29936349acdc9dfddafc8ea919b51e Mon Sep 17 00:00:00 2001 From: schvv31n Date: Sun, 19 May 2024 21:41:13 +0100 Subject: initial fix --- .../methods/iter_on_single_or_empty_collections.rs | 43 +++++++++++++++++++++- tests/ui/iter_on_empty_collections.fixed | 13 +++++++ tests/ui/iter_on_empty_collections.rs | 13 +++++++ tests/ui/iter_on_empty_collections.stderr | 8 +++- 4 files changed, 75 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 6c9bdcff826..0e929cfe798 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -1,8 +1,12 @@ +use std::iter::once; + use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; +use rustc_hir::hir_id::HirId; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; @@ -25,7 +29,25 @@ impl IterType { } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { +fn is_arg_ty_unified_in_fn<'tcx>( + cx: &LateContext<'tcx>, + fn_id: DefId, + arg_id: HirId, + args: impl Iterator> + Clone, +) -> bool { + let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity(); + let arg_id_in_args = args.clone().position(|e| e.hir_id == arg_id).unwrap(); + let arg_ty_in_args = fn_sig.input(arg_id_in_args); + + cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| { + clause + .as_projection_clause() + .and_then(|p| p.map_bound(|p| p.term.ty()).transpose()) + .is_some_and(|ty| ty == arg_ty_in_args) + }) +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) { let item = match recv.kind { ExprKind::Array([]) => None, ExprKind::Array([e]) => Some(e), @@ -43,6 +65,25 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { Some((Node::Expr(parent), child_id)) => match parent.kind { ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::Call( + Expr { + kind: ExprKind::Path(path), + hir_id, + .. + }, + args, + ) => is_arg_ty_unified_in_fn( + cx, + cx.typeck_results().qpath_res(path, *hir_id).def_id(), + expr.hir_id, + args.iter(), + ), + ExprKind::MethodCall(_name, recv, args, _span) => is_arg_ty_unified_in_fn( + cx, + cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(), + expr.hir_id, + once(recv).chain(args.iter()), + ), ExprKind::If(_, _, _) | ExprKind::Match(_, _, _) | ExprKind::Closure(_) diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed index 794629f240e..871cc18d7c2 100644 --- a/tests/ui/iter_on_empty_collections.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -20,6 +20,19 @@ fn array() { }; let _ = if false { ["test"].iter() } else { [].iter() }; + + let smth = Some(vec![1, 2, 3]); + + // Don't trigger when the empty collection iter is relied upon for its concrete type + // But do trigger if it is just an iterator, despite being an argument to a method + for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain(std::iter::empty()) { + println!("{i}"); + } + + // Same as above, but for regular function calls + for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { + println!("{i}"); + } } macro_rules! in_macros { diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs index a6461a702eb..7e3df49eefc 100644 --- a/tests/ui/iter_on_empty_collections.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -20,6 +20,19 @@ fn array() { }; let _ = if false { ["test"].iter() } else { [].iter() }; + + let smth = Some(vec![1, 2, 3]); + + // Don't trigger when the empty collection iter is relied upon for its concrete type + // But do trigger if it is just an iterator, despite being an argument to a method + for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain([].iter()) { + println!("{i}"); + } + + // Same as above, but for regular function calls + for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { + println!("{i}"); + } } macro_rules! in_macros { diff --git a/tests/ui/iter_on_empty_collections.stderr b/tests/ui/iter_on_empty_collections.stderr index ade20ff26a0..da9caa6925b 100644 --- a/tests/ui/iter_on_empty_collections.stderr +++ b/tests/ui/iter_on_empty_collections.stderr @@ -37,5 +37,11 @@ error: `iter` call on an empty collection LL | assert_eq!(None.iter().next(), Option::<&i32>::None); | ^^^^^^^^^^^ help: try: `std::iter::empty()` -error: aborting due to 6 previous errors +error: `iter` call on an empty collection + --> tests/ui/iter_on_empty_collections.rs:28:66 + | +LL | for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain([].iter()) { + | ^^^^^^^^^ help: try: `std::iter::empty()` + +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 36293727238d2559f594d7019a551853cb0c57b3 Mon Sep 17 00:00:00 2001 From: schvv31n Date: Mon, 20 May 2024 08:05:49 +0100 Subject: Lint on closure calls, suppress on callable constants calls --- .../src/methods/iter_on_single_or_empty_collections.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 0e929cfe798..f16385b5f95 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -33,10 +33,10 @@ fn is_arg_ty_unified_in_fn<'tcx>( cx: &LateContext<'tcx>, fn_id: DefId, arg_id: HirId, - args: impl Iterator> + Clone, + args: impl IntoIterator>, ) -> bool { let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity(); - let arg_id_in_args = args.clone().position(|e| e.hir_id == arg_id).unwrap(); + let arg_id_in_args = args.into_iter().position(|e| e.hir_id == arg_id).unwrap(); let arg_ty_in_args = fn_sig.input(arg_id_in_args); cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| { @@ -72,12 +72,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method .. }, args, - ) => is_arg_ty_unified_in_fn( - cx, - cx.typeck_results().qpath_res(path, *hir_id).def_id(), - expr.hir_id, - args.iter(), - ), + ) => { + cx.typeck_results().qpath_res(path, *hir_id).opt_def_id() + .filter(|fn_id| cx.tcx.def_kind(fn_id).is_fn_like()) + .is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, expr.hir_id, args)) + } ExprKind::MethodCall(_name, recv, args, _span) => is_arg_ty_unified_in_fn( cx, cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(), -- cgit 1.4.1-3-g733a5 From 3955bd4c98a61ada7041c028a5d0c749c3c0ee11 Mon Sep 17 00:00:00 2001 From: schvv31n Date: Mon, 20 May 2024 08:07:48 +0100 Subject: fixed formatting --- .../src/methods/iter_on_single_or_empty_collections.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index f16385b5f95..e8bba0dfe74 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -72,11 +72,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method .. }, args, - ) => { - cx.typeck_results().qpath_res(path, *hir_id).opt_def_id() - .filter(|fn_id| cx.tcx.def_kind(fn_id).is_fn_like()) - .is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, expr.hir_id, args)) - } + ) => cx + .typeck_results() + .qpath_res(path, *hir_id) + .opt_def_id() + .filter(|fn_id| cx.tcx.def_kind(fn_id).is_fn_like()) + .is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, expr.hir_id, args)), ExprKind::MethodCall(_name, recv, args, _span) => is_arg_ty_unified_in_fn( cx, cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(), -- cgit 1.4.1-3-g733a5 From b31625cdc7034df5fae32c4d6d6ff0e7d43496d8 Mon Sep 17 00:00:00 2001 From: schvv31n Date: Mon, 20 May 2024 21:27:30 +0100 Subject: Accounted for possible extra layers before the consuming parent expr --- clippy_lints/src/methods/iter_on_single_or_empty_collections.rs | 4 ++-- tests/ui/iter_on_empty_collections.fixed | 5 +++++ tests/ui/iter_on_empty_collections.rs | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index e8bba0dfe74..1bf323cf3c7 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -77,11 +77,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method .qpath_res(path, *hir_id) .opt_def_id() .filter(|fn_id| cx.tcx.def_kind(fn_id).is_fn_like()) - .is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, expr.hir_id, args)), + .is_some_and(|fn_id| is_arg_ty_unified_in_fn(cx, fn_id, child_id, args)), ExprKind::MethodCall(_name, recv, args, _span) => is_arg_ty_unified_in_fn( cx, cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(), - expr.hir_id, + child_id, once(recv).chain(args.iter()), ), ExprKind::If(_, _, _) diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed index 871cc18d7c2..4b5746c7b6f 100644 --- a/tests/ui/iter_on_empty_collections.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -29,6 +29,11 @@ fn array() { println!("{i}"); } + // Same as above, but for empty collection iters with extra layers + for i in smth.as_ref().map_or({ [].iter() }, |s| s.iter()) { + println!("{y}", y = i + 1); + } + // Same as above, but for regular function calls for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { println!("{i}"); diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs index 7e3df49eefc..737192d556d 100644 --- a/tests/ui/iter_on_empty_collections.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -29,6 +29,11 @@ fn array() { println!("{i}"); } + // Same as above, but for empty collection iters with extra layers + for i in smth.as_ref().map_or({ [].iter() }, |s| s.iter()) { + println!("{y}", y = i + 1); + } + // Same as above, but for regular function calls for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { println!("{i}"); -- cgit 1.4.1-3-g733a5 From 7439ecb07c85bcb148b3b62b2de0be746d5beac2 Mon Sep 17 00:00:00 2001 From: schvv31n Date: Tue, 21 May 2024 22:21:33 +0100 Subject: Added check for type unification with the iter --- .../src/methods/iter_on_single_or_empty_collections.rs | 10 +++++++--- tests/ui/iter_on_empty_collections.fixed | 4 ++++ tests/ui/iter_on_empty_collections.rs | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 1bf323cf3c7..f4397212cf6 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -37,14 +37,18 @@ fn is_arg_ty_unified_in_fn<'tcx>( ) -> bool { let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity(); let arg_id_in_args = args.into_iter().position(|e| e.hir_id == arg_id).unwrap(); - let arg_ty_in_args = fn_sig.input(arg_id_in_args); + let arg_ty_in_args = fn_sig.input(arg_id_in_args).skip_binder(); cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| { clause .as_projection_clause() .and_then(|p| p.map_bound(|p| p.term.ty()).transpose()) - .is_some_and(|ty| ty == arg_ty_in_args) - }) + .is_some_and(|ty| ty.skip_binder() == arg_ty_in_args) + }) || fn_sig + .inputs() + .iter() + .enumerate() + .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args))) } pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) { diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed index 4b5746c7b6f..0f28b48d9ab 100644 --- a/tests/ui/iter_on_empty_collections.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -38,6 +38,10 @@ fn array() { for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { println!("{i}"); } + + // Same as above, but when there are no predicates that mention the collection iter type. + let mut iter = [34, 228, 35].iter(); + let _ = std::mem::replace(&mut iter, [].iter()); } macro_rules! in_macros { diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs index 737192d556d..702da514df7 100644 --- a/tests/ui/iter_on_empty_collections.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -38,6 +38,10 @@ fn array() { for i in Option::map_or(smth.as_ref(), [].iter(), |s| s.iter()) { println!("{i}"); } + + // Same as above, but when there are no predicates that mention the collection iter type. + let mut iter = [34, 228, 35].iter(); + let _ = std::mem::replace(&mut iter, [].iter()); } macro_rules! in_macros { -- cgit 1.4.1-3-g733a5 From 0f5338cd903c715d411dee6af95f076177914e42 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 22 May 2024 22:21:01 -0700 Subject: For restriction lints, replace “Why is this bad?” with “Why restrict this?” MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `restriction` group contains many lints which are not about necessarily “bad” things, but style choices — perhaps even style choices which contradict conventional Rust style — or are otherwise very situational. This results in silly wording like “Why is this bad? It isn't, but ...”, which I’ve seen confuse a newcomer at least once. To improve this situation, this commit replaces the “Why is this bad?” section heading with “Why restrict this?”, for most, but not all, restriction lints. I left alone the ones whose placement in the restriction group is more incidental. In order to make this make sense, I had to remove the “It isn't, but” texts from the contents of the sections. Sometimes further changes were needed, or there were obvious fixes to make, and I went ahead and made those changes without attempting to split them into another commit, even though many of them are not strictly necessary for the “Why restrict this?” project. --- book/src/development/adding_lints.md | 5 +++++ clippy_dev/src/new_lint.rs | 7 +++++- clippy_lints/src/absolute_paths.rs | 2 +- clippy_lints/src/allow_attributes.rs | 7 +++--- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/asm_syntax.rs | 10 ++++----- clippy_lints/src/assertions_on_result_states.rs | 20 ++++++++++++----- clippy_lints/src/attrs/mod.rs | 6 ++--- clippy_lints/src/casts/mod.rs | 6 ++--- clippy_lints/src/create_dir.rs | 6 +++-- clippy_lints/src/dbg_macro.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 5 ++--- clippy_lints/src/default_union_representation.rs | 2 +- clippy_lints/src/disallowed_script_idents.rs | 4 ++-- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 7 +++--- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_drop.rs | 2 +- clippy_lints/src/empty_with_brackets.rs | 24 +++++++++++++++----- clippy_lints/src/endian_bytes.rs | 15 ++++++------- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/exhaustive_items.rs | 16 ++++++------- clippy_lints/src/exit.rs | 12 +++++----- clippy_lints/src/float_literal.rs | 6 ++--- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/functions/mod.rs | 11 ++++----- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/implicit_return.rs | 13 ++++++----- clippy_lints/src/indexing_slicing.rs | 7 +++--- clippy_lints/src/inherent_impl.rs | 2 +- .../src/integer_division_remainder_used.rs | 6 ++--- clippy_lints/src/iter_over_hash_type.rs | 4 ++-- clippy_lints/src/large_include_file.rs | 8 ++++--- clippy_lints/src/let_underscore.rs | 9 ++++---- clippy_lints/src/literal_representation.rs | 4 ++-- clippy_lints/src/loops/mod.rs | 6 ++--- clippy_lints/src/matches/mod.rs | 6 ++--- clippy_lints/src/methods/mod.rs | 21 ++++++++--------- clippy_lints/src/min_ident_chars.rs | 7 +++--- clippy_lints/src/misc_early/mod.rs | 6 ++--- clippy_lints/src/missing_assert_message.rs | 2 +- clippy_lints/src/missing_asserts_for_indexing.rs | 2 +- clippy_lints/src/missing_doc.rs | 4 ++-- clippy_lints/src/missing_inline.rs | 19 ++++++++++------ clippy_lints/src/missing_trait_methods.rs | 10 ++++----- clippy_lints/src/mixed_read_write_in_expression.rs | 9 +++++--- clippy_lints/src/module_style.rs | 6 ++--- clippy_lints/src/multiple_unsafe_ops_per_block.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/operators/mod.rs | 12 +++++----- clippy_lints/src/panic_in_result_fn.rs | 4 ++-- clippy_lints/src/panic_unimplemented.rs | 18 +++++++-------- clippy_lints/src/partial_pub_fields.rs | 9 ++++---- clippy_lints/src/pattern_type_mismatch.rs | 5 ++--- clippy_lints/src/pub_use.rs | 8 +++---- clippy_lints/src/question_mark_used.rs | 2 +- clippy_lints/src/raw_strings.rs | 6 +++-- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/redundant_type_annotations.rs | 2 +- clippy_lints/src/ref_patterns.rs | 4 +++- clippy_lints/src/same_name_method.rs | 2 +- clippy_lints/src/semicolon_block.rs | 6 ++--- clippy_lints/src/shadow.rs | 26 +++++++++++++--------- clippy_lints/src/single_call_fn.rs | 19 +++++++++++----- clippy_lints/src/single_char_lifetime_names.rs | 5 ++--- clippy_lints/src/std_instead_of_core.rs | 12 +++------- clippy_lints/src/strings.rs | 19 ++++++++-------- clippy_lints/src/suspicious_xor_used_as_pow.rs | 4 +++- clippy_lints/src/tests_outside_test_module.rs | 4 +++- clippy_lints/src/types/mod.rs | 4 ++-- clippy_lints/src/undocumented_unsafe_blocks.rs | 9 ++++---- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/unnecessary_self_imports.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 6 +++-- clippy_lints/src/visibility.rs | 4 ++-- clippy_lints/src/write.rs | 13 ++++++----- 76 files changed, 306 insertions(+), 245 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 415022612ca..48c00bcbf34 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -587,6 +587,11 @@ declare_clippy_lint! { } ``` +If the lint is in the `restriction` group because it lints things that are not +necessarily “bad” but are more of a style choice, then replace the +“Why is this bad?” section heading with “Why restrict this?”, to avoid writing +“Why is this bad? It isn't, but ...”. + Once your lint is merged, this documentation will show up in the [lint list][lint_list]. diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index b6481dde4dd..2e56eb8ec15 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -331,12 +331,17 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { } fn get_lint_declaration(name_upper: &str, category: &str) -> String { + let justification_heading = if category == "restriction" { + "Why restrict this?" + } else { + "Why is this bad?" + }; formatdoc!( r#" declare_clippy_lint! {{ /// ### What it does /// - /// ### Why is this bad? + /// ### {justification_heading} /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 8ba661afeeb..461117cf965 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of items through absolute paths, like `std::env::current_dir`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Many codebases have their own style when it comes to importing, but one that is seldom used /// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you /// should add a `use` statement. diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 39fc49dee37..123d0e51eee 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -19,10 +19,11 @@ declare_clippy_lint! { /// This lint only warns outer attributes (`#[allow]`), as inner attributes /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// - /// ### Why is this bad? - /// `#[expect]` attributes suppress the lint emission, but emit a warning, if + /// ### Why restrict this? + /// `#[allow]` attributes can linger after their reason for existence is gone. + /// `#[expect]` attributes suppress the lint emission, but emit a warning if /// the expectation is unfulfilled. This can be useful to be notified when the - /// lint is no longer triggered. + /// lint is no longer triggered, which may indicate the attribute can be removed. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index e3daf75c3eb..cfa25005a05 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// There is a good explanation the reason why this lint should work in this way and how it is useful /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). /// - /// ### Why is this bad? + /// ### Why restrict this? /// `as` conversions will perform many kinds of /// conversions, including silently lossy conversions and dangerous coercions. /// There are cases when it makes sense to use `as`, so the lint is diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 7c88bfc97ca..0db1456d40b 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -65,9 +65,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of Intel x86 assembly syntax. /// - /// ### Why is this bad? - /// The lint has been enabled to indicate a preference - /// for AT&T x86 assembly syntax. + /// ### Why restrict this? + /// To enforce consistent use of AT&T x86 assembly syntax. /// /// ### Example /// @@ -114,9 +113,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of AT&T x86 assembly syntax. /// - /// ### Why is this bad? - /// The lint has been enabled to indicate a preference - /// for Intel x86 assembly syntax. + /// ### Why restrict this? + /// To enforce consistent use of Intel x86 assembly syntax. /// /// ### Example /// diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index aec22965b1b..7217686dcca 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -16,23 +16,33 @@ declare_clippy_lint! { /// ### What it does /// Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls. /// - /// ### Why is this bad? - /// An assertion failure cannot output an useful message of the error. + /// ### Why restrict this? + /// This form of assertion does not show any of the information present in the `Result` + /// other than which variant it isn’t. /// /// ### Known problems /// The suggested replacement decreases the readability of code and log output. /// /// ### Example - /// ```rust,ignore + /// ```rust,no_run /// # let r = Ok::<_, ()>(()); /// assert!(r.is_ok()); - /// # let r = Err::<_, ()>(()); + /// # let r = Err::<(), _>(()); /// assert!(r.is_err()); /// ``` + /// + /// Use instead: + /// + /// ```rust,no_run + /// # let r = Ok::<_, ()>(()); + /// r.unwrap(); + /// # let r = Err::<(), _>(()); + /// r.unwrap_err(); + /// ``` #[clippy::version = "1.64.0"] pub ASSERTIONS_ON_RESULT_STATES, restriction, - "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`" + "`assert!(r.is_ok())` or `assert!(r.is_err())` gives worse panic messages than directly calling `r.unwrap()` or `r.unwrap_err()`" } declare_lint_pass!(AssertionsOnResultStates => [ASSERTIONS_ON_RESULT_STATES]); diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 39f40607799..a24bd5ed44b 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -309,9 +309,9 @@ declare_clippy_lint! { /// /// (This requires the `lint_reasons` feature) /// - /// ### Why is this bad? - /// Allowing a lint should always have a reason. This reason should be documented to - /// ensure that others understand the reasoning + /// ### Why restrict this? + /// Justifying each `allow` helps readers understand the reasoning, + /// and may allow removing `allow` attributes if their purpose is obsolete. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index bd2c96f01f6..e60c36ced75 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -303,7 +303,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for casts of a function pointer to any integer type. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Casting a function pointer to an integer can have surprising results and can occur /// accidentally if parentheses are omitted from a function call. If you aren't doing anything /// low-level with function pointers then you can opt-out of casting functions to integers in @@ -535,8 +535,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of `as _` conversion using inferred type. /// - /// ### Why is this bad? - /// The conversion might include lossy conversion and dangerous cast that might go + /// ### Why restrict this? + /// The conversion might include lossy conversion or a dangerous cast that might go /// undetected due to the type being inferred. /// /// The lint is allowed by default as using `_` is less wordy than always specifying the type. diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 7a3d5a07091..27c00948a8f 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -10,8 +10,10 @@ declare_clippy_lint! { /// ### What it does /// Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. /// - /// ### Why is this bad? - /// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// ### Why restrict this? + /// Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`, + /// resulting in failure when more than one directory needs to be created or when the directory already exists. + /// Crates which never need to specifically create a single directory may wish to prevent this mistake. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index db593726604..b0590b0a71c 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `dbg!` macro is intended as a debugging tool. It should not be present in released /// software or committed to a version control system. /// diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 1d6c4ce72e1..fbc4ede37b1 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -22,9 +22,8 @@ declare_clippy_lint! { /// /// See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback. /// - /// ### Why is this bad? - /// For those who are very careful about types, default numeric fallback - /// can be a pitfall that cause unexpected runtime behavior. + /// ### Why restrict this? + /// To ensure that every numeric type is chosen explicitly rather than implicitly. /// /// ### Known problems /// This lint can only be allowed at the function level or above. diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index b4290b6437f..3fa9bad0d03 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -10,7 +10,7 @@ declare_clippy_lint! { /// ### What it does /// Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute). /// - /// ### Why is this bad? + /// ### Why restrict this? /// Unions in Rust have unspecified layout by default, despite many people thinking that they /// lay out each field at the start of the union (like C does). That is, there are no guarantees /// about the offset of the fields for unions with multiple non-ZST fields without an explicitly diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index def4b5932b4..a995f06fb73 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -20,11 +20,11 @@ declare_clippy_lint! { /// [aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases /// [supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html /// - /// ### Why is this bad? + /// ### Why restrict this? /// It may be not desired to have many different scripts for /// identifiers in the codebase. /// - /// Note that if you only want to allow plain English, you might want to use + /// Note that if you only want to allow typical English, you might want to use /// built-in [`non_ascii_idents`] lint instead. /// /// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 81c47d07c35..e9c4559ff4d 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -261,7 +261,7 @@ declare_clippy_lint! { /// Checks for the doc comments of publicly visible /// safe functions and traits and warns if there is a `# Safety` section. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Safe functions and traits are safe to implement and therefore do not /// need to describe safety preconditions that users are required to uphold. /// diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 119473c2454..4a6ffcd9a78 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -52,9 +52,10 @@ declare_clippy_lint! { /// Checks for usage of `std::mem::forget(t)` where `t` is /// `Drop` or has a field that implements `Drop`. /// - /// ### Why is this bad? - /// `std::mem::forget(t)` prevents `t` from running its - /// destructor, possibly causing leaks. + /// ### Why restrict this? + /// `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks. + /// It is not possible to detect all means of creating leaks, but it may be desirable to + /// prohibit the simple ones. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index a6ca7fe9e0b..bb6f9aac223 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// /// ### Example diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 74db250b3ae..c5fc72b5e2d 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for empty `Drop` implementations. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Empty `Drop` implementations have no effect when dropping an instance of the type. They are /// most likely useless. However, an empty `Drop` implementation prevents a type from being /// destructured, which might be the intention behind adding the implementation as a marker. diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index 969df6d85b5..745599b0e57 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -11,16 +11,23 @@ declare_clippy_lint! { /// ### What it does /// Finds structs without fields (a so-called "empty struct") that are declared with brackets. /// - /// ### Why is this bad? - /// Empty brackets after a struct declaration can be omitted. + /// ### Why restrict this? + /// Empty brackets after a struct declaration can be omitted, + /// and it may be desirable to do so consistently for style. + /// + /// However, removing the brackets also introduces a public constant named after the struct, + /// so this is not just a syntactic simplification but an an API change, and adding them back + /// is a *breaking* API change. /// /// ### Example /// ```no_run /// struct Cookie {} + /// struct Biscuit(); /// ``` /// Use instead: /// ```no_run /// struct Cookie; + /// struct Biscuit; /// ``` #[clippy::version = "1.62.0"] pub EMPTY_STRUCTS_WITH_BRACKETS, @@ -32,14 +39,20 @@ declare_clippy_lint! { /// ### What it does /// Finds enum variants without fields that are declared with empty brackets. /// - /// ### Why is this bad? - /// Empty brackets while defining enum variants are redundant and can be omitted. + /// ### Why restrict this? + /// Empty brackets after a enum variant declaration are redundant and can be omitted, + /// and it may be desirable to do so consistently for style. + /// + /// However, removing the brackets also introduces a public constant named after the variant, + /// so this is not just a syntactic simplification but an an API change, and adding them back + /// is a *breaking* API change. /// /// ### Example /// ```no_run /// enum MyEnum { /// HasData(u8), - /// HasNoData(), // redundant parentheses + /// HasNoData(), // redundant parentheses + /// NoneHereEither {}, // redundant braces /// } /// ``` /// @@ -48,6 +61,7 @@ declare_clippy_lint! { /// enum MyEnum { /// HasData(u8), /// HasNoData, + /// NoneHereEither, /// } /// ``` #[clippy::version = "1.77.0"] diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index dd03df797de..bb766e96338 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -13,8 +13,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`. /// - /// ### Why is this bad? - /// It's not, but some may prefer to specify the target endianness explicitly. + /// ### Why restrict this? + /// To ensure use of explicitly chosen endianness rather than the target’s endianness, + /// such as when implementing network protocols or file formats rather than FFI. /// /// ### Example /// ```rust,ignore @@ -31,9 +32,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. /// - /// ### Why is this bad? - /// It's not, but some may wish to lint usage of this method, either to suggest using the host - /// endianness or big endian. + /// ### Why restrict this? + /// To ensure use of big endian or the target’s endianness rather than little endian. /// /// ### Example /// ```rust,ignore @@ -50,9 +50,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. /// - /// ### Why is this bad? - /// It's not, but some may wish to lint usage of this method, either to suggest using the host - /// endianness or little endian. + /// ### Why restrict this? + /// To ensure use of little endian or the target’s endianness rather than big endian. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index 8dbb47fadc5..8e49138cd26 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for types named `Error` that implement `Error`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// It can become confusing when a codebase has 20 types all named `Error`, requiring either /// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This /// hinders comprehension, as it requires you to memorize every variation of importing `Error` diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 9ffda645742..436dc8611bd 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -10,10 +10,10 @@ declare_clippy_lint! { /// ### What it does /// Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` /// - /// ### Why is this bad? - /// Exhaustive enums are typically fine, but a project which does - /// not wish to make a stability commitment around exported enums may wish to - /// disable them by default. + /// ### Why restrict this? + /// Making an `enum` exhaustive is a stability commitment: adding a variant is a breaking change. + /// A project may wish to ensure that there are no exhaustive enums or that every exhaustive + /// `enum` is explicitly `#[allow]`ed. /// /// ### Example /// ```no_run @@ -40,10 +40,10 @@ declare_clippy_lint! { /// ### What it does /// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]` /// - /// ### Why is this bad? - /// Exhaustive structs are typically fine, but a project which does - /// not wish to make a stability commitment around exported structs may wish to - /// disable them by default. + /// ### Why restrict this? + /// Making a `struct` exhaustive is a stability commitment: adding a field is a breaking change. + /// A project may wish to ensure that there are no exhaustive structs or that every exhaustive + /// `struct` is explicitly `#[allow]`ed. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 106844dd434..91c94d66458 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -9,11 +9,13 @@ declare_clippy_lint! { /// ### What it does /// Detects calls to the `exit()` function which terminates the program. /// - /// ### Why is this bad? - /// Exit terminates the program at the location it is called. For unrecoverable - /// errors `panics` should be used to provide a stacktrace and potentially other - /// information. A normal termination or one with an error code should happen in - /// the main function. + /// ### Why restrict this? + /// `exit()` immediately terminates the program with no information other than an exit code. + /// This provides no means to troubleshoot a problem, and may be an unexpected side effect. + /// + /// Codebases may use this lint to require that all exits are performed either by panicking + /// (which produces a message, a code location, and optionally a backtrace) + /// or by returning from `main()` (which is a single place to look). /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 2cd4e9e99a5..4ec9bd757ff 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -38,9 +38,9 @@ declare_clippy_lint! { /// Checks for whole number float literals that /// cannot be represented as the underlying type without loss. /// - /// ### Why is this bad? - /// Rust will silently lose precision during - /// conversion to a float. + /// ### Why restrict this? + /// If the value was intended to be exact, it will not be. + /// This may be especially surprising when the lost precision is to the left of the decimal point. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 2b08437d827..a75538dd329 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// Detects cases where the result of a `format!` call is /// appended to an existing `String`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Introduces an extra, avoidable heap allocation. /// /// ### Known problems diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index dfcaac9abef..26534492ddd 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -338,8 +338,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Lints when `impl Trait` is being used in a function's parameters. - /// ### Why is this bad? - /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. + /// + /// ### Why restrict this? + /// Turbofish syntax (`::<>`) cannot be used to specify the type of an `impl Trait` parameter, + /// making `impl Trait` less powerful. Readability may also be a factor. /// /// ### Example /// ```no_run @@ -366,9 +368,8 @@ declare_clippy_lint! { /// Lints when the name of function parameters from trait impl is /// different than its default implementation. /// - /// ### Why is this bad? - /// Using the default name for parameters of a trait method is often - /// more desirable for consistency's sake. + /// ### Why restrict this? + /// Using the default name for parameters of a trait method is more consistent. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index f5ba62ae432..0b200815219 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for if-else that could be written using either `bool::then` or `bool::then_some`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity. /// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated /// in comparison to `bool::then`. diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 5288efd8df8..cc342007ec6 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -16,12 +16,13 @@ declare_clippy_lint! { /// ### What it does /// Checks for missing return statements at the end of a block. /// - /// ### Why is this bad? - /// Actually omitting the return keyword is idiomatic Rust code. Programmers - /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss - /// the last returning statement because the only difference is a missing `;`. Especially in bigger - /// code with multiple return paths having a `return` keyword makes it easier to find the - /// corresponding statements. + /// ### Why restrict this? + /// Omitting the return keyword whenever possible is idiomatic Rust code, but: + /// + /// * Programmers coming from other languages might prefer the expressiveness of `return`. + /// * It's possible to miss the last returning statement because the only difference is a missing `;`. + /// * Especially in bigger code with multiple return paths, having a `return` keyword makes it easier to find the + /// corresponding statements. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 35fcd8cdd35..e3e79749bea 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -45,9 +45,10 @@ declare_clippy_lint! { /// does report on arrays if we can tell that slicing operations are in bounds and does not /// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint. /// - /// ### Why is this bad? - /// Indexing and slicing can panic at runtime and there are - /// safe alternatives. + /// ### Why restrict this? + /// To avoid implicit panics from indexing and slicing. + /// There are “checked” alternatives which do not panic, and can be used with `unwrap()` to make + /// an explicit panic when it is desired. /// /// ### Example /// ```rust,no_run diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 1127f00abde..95ae591884b 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for multiple inherent implementations of a struct /// - /// ### Why is this bad? + /// ### Why restrict this? /// Splitting the implementation of a type makes the code harder to navigate. /// /// ### Example diff --git a/clippy_lints/src/integer_division_remainder_used.rs b/clippy_lints/src/integer_division_remainder_used.rs index a3577b765c0..cf598d5045e 100644 --- a/clippy_lints/src/integer_division_remainder_used.rs +++ b/clippy_lints/src/integer_division_remainder_used.rs @@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for the usage of division (/) and remainder (%) operations - /// when performed on any integer types using the default Div and Rem trait implementations. + /// Checks for the usage of division (`/`) and remainder (`%`) operations + /// when performed on any integer types using the default `Div` and `Rem` trait implementations. /// - /// ### Why is this bad? + /// ### Why restrict this? /// In cryptographic contexts, division can result in timing sidechannel vulnerabilities, /// and needs to be replaced with constant-time code instead (e.g. Barrett reduction). /// diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index 6c6eff9ba48..fb29d982417 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// ### What it does /// This is a restriction lint which prevents the use of hash types (i.e., `HashSet` and `HashMap`) in for loops. /// - /// ### Why is this bad? - /// Because hash types are unordered, when iterated through such as in a for loop, the values are returned in + /// ### Why restrict this? + /// Because hash types are unordered, when iterated through such as in a `for` loop, the values are returned in /// an undefined order. As a result, on redundant systems this may cause inconsistencies and anomalies. /// In addition, the unknown order of the elements may reduce readability or introduce other undesired /// side effects. diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 790bed580fd..07efee159aa 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -10,10 +10,12 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does /// Checks for the inclusion of large files via `include_bytes!()` - /// and `include_str!()` + /// or `include_str!()`. /// - /// ### Why is this bad? - /// Including large files can increase the size of the binary + /// ### Why restrict this? + /// Including large files can undesirably increase the size of the binary produced by the compiler. + /// This lint may be used to catch mistakes where an unexpectedly large file is included, or + /// temporarily to obtain a list of all large files. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 619e933b4ff..9fd4f509aa4 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -12,9 +12,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for `let _ = ` where expr is `#[must_use]` /// - /// ### Why is this bad? - /// It's better to explicitly handle the value of a `#[must_use]` - /// expr + /// ### Why restrict this? + /// To ensure that all `#[must_use]` types are used rather than ignored. /// /// ### Example /// ```no_run @@ -96,8 +95,8 @@ declare_clippy_lint! { /// Checks for `let _ = ` without a type annotation, and suggests to either provide one, /// or remove the `let` keyword altogether. /// - /// ### Why is this bad? - /// The `let _ = ` expression ignores the value of `` but will remain doing so even + /// ### Why restrict this? + /// The `let _ = ` expression ignores the value of ``, but will continue to do so even /// if the type were to change, thus potentially introducing subtle bugs. By supplying a type /// annotation, one will be forced to re-visit the decision to ignore the value in such cases. /// diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 2348dd18220..d2a140a36a8 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -132,8 +132,8 @@ declare_clippy_lint! { /// ### What it does /// Warns if there is a better representation for a numeric literal. /// - /// ### Why is this bad? - /// Especially for big powers of 2 a hexadecimal representation is more + /// ### Why restrict this? + /// Especially for big powers of 2, a hexadecimal representation is usually more /// readable than a decimal representation. /// /// ### Example diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 3dcb050d77e..08682942153 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -675,9 +675,9 @@ declare_clippy_lint! { /// Checks for infinite loops in a function where the return type is not `!` /// and lint accordingly. /// - /// ### Why is this bad? - /// A loop should be gently exited somewhere, or at least mark its parent function as - /// never return (`!`). + /// ### Why restrict this? + /// Making the return type `!` serves as documentation that the function does not return. + /// If the function is not intended to loop infinitely, then this lint may detect a bug. /// /// ### Example /// ```no_run,ignore diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index ee9f48d71ad..691ecd57535 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -260,7 +260,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for wildcard enum matches using `_`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// New enum variants added by library updates can be missed. /// /// ### Known problems @@ -435,7 +435,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Correctness and readability. It's like having a wildcard pattern after /// matching all enum variants explicitly. /// @@ -861,7 +861,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `Err(x)?`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `?` operator is designed to allow calls that /// can fail to be easily chained. For example, `foo()?.bar()` or /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 60666445d08..13c5f537ca4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -257,7 +257,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. /// - /// ### Why is this bad? + /// ### Why restrict this? /// It is better to handle the `None` or `Err` case, /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is @@ -333,7 +333,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Usually it is better to handle the `None` or `Err` case. /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why /// this lint is `Allow` by default. @@ -1029,8 +1029,8 @@ declare_clippy_lint! { /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified /// function syntax instead (e.g., `Rc::clone(foo)`). /// - /// ### Why is this bad? - /// Calling '.clone()' on an Rc, Arc, or Weak + /// ### Why restrict this? + /// Calling `.clone()` on an `Rc`, `Arc`, or `Weak` /// can obscure the fact that only the pointer is being cloned, not the underlying /// data. /// @@ -1051,7 +1051,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub CLONE_ON_REF_PTR, restriction, - "using 'clone' on a ref-counted pointer" + "using `clone` on a ref-counted pointer" } declare_clippy_lint! { @@ -1359,7 +1359,7 @@ declare_clippy_lint! { /// Checks for usage of `.get().unwrap()` (or /// `.get_mut().unwrap`) on a standard library type which implements `Index` /// - /// ### Why is this bad? + /// ### Why restrict this? /// Using the Index trait (`[]`) is more clear and more /// concise. /// @@ -1743,7 +1743,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `FileType::is_file()`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// When people testing a file type with `FileType::is_file` /// they are testing whether a path is something they can get bytes from. But /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover @@ -2688,8 +2688,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for instances of `map_err(|_| Some::Enum)` /// - /// ### Why is this bad? - /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + /// ### Why restrict this? + /// This `map_err` throws away the original error rather than allowing the enum to + /// contain and report the cause of the error. /// /// ### Example /// Before: @@ -3145,7 +3146,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of File::read_to_end and File::read_to_string. /// - /// ### Why is this bad? + /// ### Why restrict this? /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) /// diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index c6b7f5b0ce2..e43b712021a 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -12,14 +12,13 @@ use std::borrow::Cow; declare_clippy_lint! { /// ### What it does - /// Checks for idents which comprise of a single letter. + /// Checks for identifiers which consist of a single character (or fewer than the configured threshold). /// /// Note: This lint can be very noisy when enabled; it may be desirable to only enable it /// temporarily. /// - /// ### Why is this bad? - /// In many cases it's not, but at times it can severely hinder readability. Some codebases may - /// wish to disallow this to improve readability. + /// ### Why restrict this? + /// To improve readability by requiring that every variable has a name more specific than a single letter can be. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 2f5499d7656..fedcfd11fdc 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for structure field patterns bound to wildcards. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Using `..` instead is shorter and leaves the focus on /// the fields that are actually bound. /// @@ -138,7 +138,7 @@ declare_clippy_lint! { /// To enforce unseparated literal suffix style, /// see the `separated_literal_suffix` lint. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Suffix style should be consistent. /// /// ### Example @@ -166,7 +166,7 @@ declare_clippy_lint! { /// To enforce separated literal suffix style, /// see the `unseparated_literal_suffix` lint. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Suffix style should be consistent. /// /// ### Example diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 04df7b7a7e5..dd98352da86 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -10,7 +10,7 @@ declare_clippy_lint! { /// ### What it does /// Checks assertions without a custom panic message. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Without a good custom message, it'd be hard to understand what went wrong when the assertion fails. /// A good custom message should be more about why the failure of the assertion is problematic /// and not what is failed because the assertion already conveys that. diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index c29e46b941c..752723a0c68 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// Checks for repeated slice indexing without asserting beforehand that the length /// is greater than the largest index used to index into the slice. /// - /// ### Why is this bad? + /// ### Why restrict this? /// In the general case where the compiler does not have a lot of information /// about the length of a slice, indexing it repeatedly will generate a bounds check /// for every single index. diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 2fb784dae1c..ca344dc5c81 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -20,9 +20,9 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Warns if there is missing doc for any private documentable item + /// Warns if there is missing documentation for any private documentable item. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Doc is good. *rustc* has a `MISSING_DOCS` /// allowed-by-default lint for /// public members, but has no way to enforce documentation of private items. diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index c6a76478806..33a14d8b7fe 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -10,13 +10,16 @@ declare_clippy_lint! { /// It lints if an exported function, method, trait method with default impl, /// or trait method impl is not `#[inline]`. /// - /// ### Why is this bad? - /// In general, it is not. Functions can be inlined across - /// crates when that's profitable as long as any form of LTO is used. When LTO is disabled, - /// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates - /// might intend for most of the methods in their public API to be able to be inlined across - /// crates even when LTO is disabled. For these types of crates, enabling this lint might make - /// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and + /// ### Why restrict this? + /// When a function is not marked `#[inline]`, it is not + /// [a “small” candidate for automatic inlining][small], and LTO is not in use, then it is not + /// possible for the function to be inlined into the code of any crate other than the one in + /// which it is defined. Depending on the role of the function and the relationship of the crates, + /// this could significantly reduce performance. + /// + /// Certain types of crates might intend for most of the methods in their public API to be able + /// to be inlined across crates even when LTO is disabled. + /// This lint allows those crates to require all exported methods to be `#[inline]` by default, and /// then opt out for specific methods where this might not make sense. /// /// ### Example @@ -51,6 +54,8 @@ declare_clippy_lint! { /// fn def_bar() {} // missing #[inline] /// } /// ``` + /// + /// [small]: https://github.com/rust-lang/rust/pull/116505 #[clippy::version = "pre 1.29.0"] pub MISSING_INLINE_IN_PUBLIC_ITEMS, restriction, diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 6f844bc646a..85029a5e6a0 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -10,16 +10,16 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does /// Checks if a provided method is used implicitly by a trait - /// implementation. A usage example would be a wrapper where every method - /// should perform some operation before delegating to the inner type's /// implementation. /// + /// ### Why restrict this? + /// To ensure that a certain implementation implements every method; for example, + /// a wrapper type where every method should delegate to the corresponding method of + /// the inner type's implementation. + /// /// This lint should typically be enabled on a specific trait `impl` item /// rather than globally. /// - /// ### Why is this bad? - /// Indicates that a method is missing. - /// /// ### Example /// ```no_run /// trait Trait { diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 181351910db..9c5a8a0cfcd 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -12,9 +12,10 @@ declare_clippy_lint! { /// whether the read occurs before or after the write depends on the evaluation /// order of sub-expressions. /// - /// ### Why is this bad? - /// It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands), - /// the operands of these expressions are evaluated before applying the effects of the expression. + /// ### Why restrict this? + /// While [the evaluation order of sub-expressions] is fully specified in Rust, + /// it still may be confusing to read an expression where the evaluation order + /// affects its behavior. /// /// ### Known problems /// Code which intentionally depends on the evaluation @@ -40,6 +41,8 @@ declare_clippy_lint! { /// }; /// let a = tmp + x; /// ``` + /// + /// [order]: (https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands) #[clippy::version = "pre 1.29.0"] pub MIXED_READ_WRITE_IN_EXPRESSION, restriction, diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 6c031c08175..305499f9da4 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -10,9 +10,9 @@ use std::path::{Component, Path}; declare_clippy_lint! { /// ### What it does - /// Checks that module layout uses only self named module files, bans `mod.rs` files. + /// Checks that module layout uses only self named module files; bans `mod.rs` files. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Having multiple module layout styles in a project can be confusing. /// /// ### Example @@ -41,7 +41,7 @@ declare_clippy_lint! { /// ### What it does /// Checks that module layout uses only `mod.rs` files. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Having multiple module layout styles in a project can be confusing. /// /// ### Example diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 0e138066780..6830d48cfd8 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `unsafe` blocks that contain more than one unsafe operation. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Combined with `undocumented_unsafe_blocks`, /// this lint ensures that each unsafe operation must be independently justified. /// Combined with `unused_unsafe`, this lint also ensures diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 7ecc8617694..853e476a006 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `Mutex` where an atomic will do. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Using a mutex just to make access to a plain bool or /// reference sequential is shooting flies with cannons. /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index e002429e3a4..0948973df5a 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -70,7 +70,7 @@ declare_clippy_lint! { /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant /// environments, allowed types and non-constant operations that won't overflow are ignored. /// - /// ### Why is this bad? + /// ### Why restrict this? /// For integers, overflow will trigger a panic in debug builds or wrap the result in /// release mode; division by zero will cause a panic in either mode. As a result, it is /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. @@ -100,7 +100,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for float arithmetic. /// - /// ### Why is this bad? + /// ### Why restrict this? /// For some embedded systems or kernel development, it /// can be useful to rule out floating-point numbers. /// @@ -502,7 +502,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for division of integers /// - /// ### Why is this bad? + /// ### Why restrict this? /// When outside of some very specific algorithms, /// integer division is very often a mistake because it discards the /// remainder. @@ -596,7 +596,7 @@ declare_clippy_lint! { /// value and constant, except in functions called `*eq*` (which probably /// implement equality for a type involving floats). /// - /// ### Why is this bad? + /// ### Why restrict this? /// Floating point calculations are usually imprecise, so /// asking if two values are *exactly* equal is asking for trouble. For a good /// guide on what to do, see [the floating point @@ -653,8 +653,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for modulo arithmetic. /// - /// ### Why is this bad? - /// The results of modulo (%) operation might differ + /// ### Why restrict this? + /// The results of modulo (`%`) operation might differ /// depending on the language, when negative numbers are involved. /// If you interop with different languages it might be beneficial /// to double check all places that use modulo arithmetic. diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index f821a4efee7..806638c0505 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -13,9 +13,9 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for usage of `panic!` or assertions in a function of type result. + /// Checks for usage of `panic!` or assertions in a function whose return type is `Result`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. /// /// ### Known problems diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 75066c1f0d2..80ef761906e 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `panic!`. /// - /// ### Why is this bad? - /// `panic!` will stop the execution of the executable. + /// ### Why restrict this? + /// This macro, or panics in general, may be unwanted in production code. /// /// ### Example /// ```no_run @@ -31,8 +31,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `unimplemented!`. /// - /// ### Why is this bad? - /// This macro should not be present in production code. + /// ### Why restrict this? + /// This macro, or panics in general, may be unwanted in production code. /// /// ### Example /// ```no_run @@ -48,9 +48,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `todo!`. /// - /// ### Why is this bad? - /// The `todo!` macro is often used for unfinished code, and it causes - /// code to panic. It should not be present in production code. + /// ### Why restrict this? + /// The `todo!` macro indicates the presence of unfinished code, + /// so it should not be present in production code. /// /// ### Example /// ```no_run @@ -70,8 +70,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `unreachable!`. /// - /// ### Why is this bad? - /// This macro can cause code to panic. + /// ### Why restrict this? + /// This macro, or panics in general, may be unwanted in production code. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/partial_pub_fields.rs b/clippy_lints/src/partial_pub_fields.rs index ffa403e27ca..2d20cbea698 100644 --- a/clippy_lints/src/partial_pub_fields.rs +++ b/clippy_lints/src/partial_pub_fields.rs @@ -5,15 +5,16 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks whether partial fields of a struct are public. + /// Checks whether some but not all fields of a `struct` are public. /// /// Either make all fields of a type public, or make none of them public /// - /// ### Why is this bad? + /// ### Why restrict this? /// Most types should either be: /// * Abstract data types: complex objects with opaque implementation which guard - /// interior invariants and expose intentionally limited API to the outside world. - /// * Data: relatively simple objects which group a bunch of related attributes together. + /// interior invariants and expose intentionally limited API to the outside world. + /// * Data: relatively simple objects which group a bunch of related attributes together, + /// but have no invariants. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index 44db061b8be..9661a57b8b9 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -30,9 +30,8 @@ declare_clippy_lint! { /// this lint can still be used to highlight areas of interest and ensure a good understanding /// of ownership semantics. /// - /// ### Why is this bad? - /// It isn't bad in general. But in some contexts it can be desirable - /// because it increases ownership hints in the code, and will guard against some changes + /// ### Why restrict this? + /// It increases ownership hints in the code, and will guard against some changes /// in ownership. /// /// ### Example diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs index c0e999e76ef..ab8f8a1689d 100644 --- a/clippy_lints/src/pub_use.rs +++ b/clippy_lints/src/pub_use.rs @@ -5,13 +5,11 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// /// Restricts the usage of `pub use ...` /// - /// ### Why is this bad? - /// - /// `pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent - /// unintentional exports or to encourage placing exported items directly in public modules + /// ### Why restrict this? + /// A project may wish to limit `pub use` instances to prevent + /// unintentional exports, or to encourage placing exported items directly in public modules. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index ddfc53083c4..f5e6cb804da 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for expressions that use the question mark operator and rejects them. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Sometimes code wants to avoid the question mark operator because for instance a local /// block requires a macro to re-throw errors to attach additional information to the /// error. diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 7e71f48c6d9..3a004245459 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -15,8 +15,10 @@ declare_clippy_lint! { /// ### What it does /// Checks for raw string literals where a string literal can be used instead. /// - /// ### Why is this bad? - /// It's just unnecessary, but there are many cases where using a raw string literal is more + /// ### Why restrict this? + /// For consistent style by using simpler string literals whenever possible. + /// + /// However, there are many cases where using a raw string literal is more /// idiomatic than a string literal, so it's opt-in. /// /// ### Example diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index c99b657c23a..7f87d18e502 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { /// Checks for slicing expressions which are equivalent to dereferencing the /// value. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Some people may prefer to dereference rather than slice. /// /// ### Example diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 11b95ee3a54..81556f39614 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// ### What it does /// Warns about needless / redundant type annotations. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Code without type annotations is shorter and in most cases /// more idiomatic and easier to modify. /// diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index 607a0740b84..467038523b4 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -6,9 +6,11 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does /// Checks for usages of the `ref` keyword. - /// ### Why is this bad? + /// + /// ### Why restrict this? /// The `ref` keyword can be confusing for people unfamiliar with it, and often /// it is more concise to use `&` instead. + /// /// ### Example /// ```no_run /// let opt = Some(5); diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 7e27f70bcf9..8fdd19c549f 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -14,7 +14,7 @@ declare_clippy_lint! { /// It lints if a struct has two methods with the same name: /// one from a trait, another not from trait. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Confusing. /// /// ### Example diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 0b3adfb7a4b..0e77acdfd77 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -11,8 +11,7 @@ declare_clippy_lint! { /// Suggests moving the semicolon after a block to the inside of the block, after its last /// expression. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine /// and this lint suggests inside the block. /// Take a look at `semicolon_outside_block` for the other alternative. @@ -40,8 +39,7 @@ declare_clippy_lint! { /// /// Suggests moving the semicolon from a block's final expression outside of the block. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine /// and this lint suggests outside the block. /// Take a look at `semicolon_inside_block` for the other alternative. diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 9db08acb03b..80f5fd0b494 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -15,10 +15,10 @@ declare_clippy_lint! { /// Checks for bindings that shadow other bindings already in /// scope, while just changing reference level or mutability. /// - /// ### Why is this bad? - /// Not much, in fact it's a very common pattern in Rust - /// code. Still, some may opt to avoid it in their code base, they can set this - /// lint to `Warn`. + /// ### Why restrict this? + /// To require that what are formally distinct variables be given distinct names. + /// + /// See also `shadow_reuse` and `shadow_unrelated` for other restrictions on shadowing. /// /// ### Example /// ```no_run @@ -42,12 +42,13 @@ declare_clippy_lint! { /// Checks for bindings that shadow other bindings already in /// scope, while reusing the original value. /// - /// ### Why is this bad? - /// Not too much, in fact it's a common pattern in Rust - /// code. Still, some argue that name shadowing like this hurts readability, + /// ### Why restrict this? + /// Some argue that name shadowing like this hurts readability, /// because a value may be bound to different things depending on position in /// the code. /// + /// See also `shadow_same` and `shadow_unrelated` for other restrictions on shadowing. + /// /// ### Example /// ```no_run /// let x = 2; @@ -70,11 +71,14 @@ declare_clippy_lint! { /// scope, either without an initialization or with one that does not even use /// the original value. /// - /// ### Why is this bad? - /// Name shadowing can hurt readability, especially in + /// ### Why restrict this? + /// Shadowing a binding with a closely related one is part of idiomatic Rust, + /// but shadowing a binding by accident with an unrelated one may indicate a mistake. + /// + /// Additionally, name shadowing in general can hurt readability, especially in /// large code bases, because it is easy to lose track of the active binding at - /// any place in the code. This can be alleviated by either giving more specific - /// names to bindings or introducing more scopes to contain the bindings. + /// any place in the code. If linting against all shadowing is desired, you may wish + /// to use the `shadow_same` and `shadow_reuse` lints as well. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index 2ce7e714c64..c71bc3f7fcd 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -13,13 +13,20 @@ declare_clippy_lint! { /// ### What it does /// Checks for functions that are only used once. Does not lint tests. /// - /// ### Why is this bad? - /// It's usually not, splitting a function into multiple parts often improves readability and in - /// the case of generics, can prevent the compiler from duplicating the function dozens of - /// time; instead, only duplicating a thunk. But this can prevent segmentation across a - /// codebase, where many small functions are used only once. + /// ### Why restrict this? + /// If a function is only used once (perhaps because it used to be used more widely), + /// then the code could be simplified by moving that function's code into its caller. /// - /// Note: If this lint is used, prepare to allow this a lot. + /// However, there are reasons not to do this everywhere: + /// + /// * Splitting a large function into multiple parts often improves readability + /// by giving names to its parts. + /// * A function’s signature might serve a necessary purpose, such as constraining + /// the type of a closure passed to it. + /// * Generic functions might call non-generic functions to reduce duplication + /// in the produced machine code. + /// + /// If this lint is used, prepare to `#[allow]` it a lot. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 42f1564db35..72feb977c31 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -9,11 +9,10 @@ declare_clippy_lint! { /// Checks for lifetimes with names which are one character /// long. /// - /// ### Why is this bad? + /// ### Why restrict this? /// A single character is likely not enough to express the /// purpose of a lifetime. Using a longer name can make code - /// easier to understand, especially for those who are new to - /// Rust. + /// easier to understand. /// /// ### Known problems /// Rust programmers and learning resources tend to use single diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 926c56332cc..12b70075a3d 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -12,11 +12,9 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// /// Finds items imported through `std` when available through `core`. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure /// disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates /// migrating to become `no_std` compatible. @@ -37,11 +35,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// /// Finds items imported through `std` when available through `alloc`. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from /// alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful /// for crates migrating to become `no_std` compatible. @@ -63,11 +59,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// /// Finds items imported through `alloc` when available through `core`. /// - /// ### Why is this bad? - /// + /// ### Why restrict this? /// Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint /// is also useful for crates migrating to become `no_std` compatible. diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 292124196ff..f8d36d6b92f 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -45,10 +45,10 @@ declare_clippy_lint! { /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not* /// match. /// - /// ### Why is this bad? - /// It's not bad in and of itself. However, this particular + /// ### Why restrict this? + /// This particular /// `Add` implementation is asymmetric (the other operand need not be `String`, - /// but `x` does), while addition as mathematically defined is symmetric, also + /// but `x` does), while addition as mathematically defined is symmetric, and /// the `String::push_str(_)` function is a perfectly good replacement. /// Therefore, some dislike it and wish not to have it in their code. /// @@ -123,7 +123,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for slice operations on strings /// - /// ### Why is this bad? + /// ### Why restrict this? /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character /// counts and string indices. This may lead to panics, and should warrant some test cases /// containing wide UTF-8 characters. This lint is most useful in code that should avoid @@ -364,10 +364,10 @@ declare_clippy_lint! { /// ### What it does /// This lint checks for `.to_string()` method calls on values of type `&str`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `to_string` method is also used on other types to convert them to a string. - /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better - /// expressed with `.to_owned()`. + /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be + /// more specifically expressed with `.to_owned()`. /// /// ### Example /// ```no_run @@ -415,9 +415,10 @@ declare_clippy_lint! { /// ### What it does /// This lint checks for `.to_string()` method calls on values of type `String`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// The `to_string` method is also used on other types to convert them to a string. - /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. + /// When called on a `String` it only clones the `String`, which can be more specifically + /// expressed with `.clone()`. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 1cc27670fa8..d150a5f858a 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -11,8 +11,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does /// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal. - /// ### Why is this bad? + /// + /// ### Why restrict this? /// It's most probably a typo and may lead to unexpected behaviours. + /// /// ### Example /// ```no_run /// let x = 3_i32 ^ 4_i32; diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index da557582647..58e42892c41 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -11,9 +11,11 @@ declare_clippy_lint! { /// ### What it does /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module /// (marked with `#[cfg(test)]`). - /// ### Why is this bad? + /// + /// ### Why restrict this? /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), /// having test functions outside of this module is confusing and may lead to them being "hidden". + /// /// ### Example /// ```no_run /// #[test] diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 5e45ab211ef..62ef65ca122 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -217,7 +217,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Expressions such as `Rc` usually have no advantage over `Rc`, since /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow`. /// @@ -274,7 +274,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `Rc>`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// `Rc` is used in single thread and `Mutex` is used in multi thread. /// Consider using `Rc>` in single thread or `Arc>` in multi thread. /// diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index cbd16180077..7e8c11cf25a 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -38,10 +38,9 @@ declare_clippy_lint! { /// ); /// ``` /// - /// ### Why is this bad? - /// Undocumented unsafe blocks and impls can make it difficult to - /// read and maintain code, as well as uncover unsoundness - /// and bugs. + /// ### Why restrict this? + /// Undocumented unsafe blocks and impls can make it difficult to read and maintain code. + /// Writing out the safety justification may help in discovering unsoundness or bugs. /// /// ### Example /// ```no_run @@ -67,7 +66,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for `// SAFETY: ` comments on safe code. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Safe code has no safety requirements, so there is no need to /// describe safety invariants. /// diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 3d319b9fe76..d42697b31d1 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for non-ASCII characters in string and char literals. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Yeah, we know, the 90's called and wanted their charset /// back. Even so, there still are editors and other programs out there that /// don't work well with Unicode. So if the code is meant to be used diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 528a1dfcfc1..93dff1b8579 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for imports ending in `::{self}`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// In most cases, this can be written much more cleanly by omitting `::{self}`. /// /// ### Known problems diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index aca500590ce..197ab0f173b 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -13,8 +13,10 @@ declare_clippy_lint! { /// ### What it does /// Checks for functions of type `Result` that contain `expect()` or `unwrap()` /// - /// ### Why is this bad? - /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. + /// ### Why restrict this? + /// These functions promote recoverable errors to non-recoverable errors, + /// which may be undesirable in code bases which wish to avoid panics, + /// or be a bug in the specific function. /// /// ### Known problems /// This can cause false positives in functions that handle both recoverable and non recoverable errors. diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 9818b98dd5b..11dcceca7ab 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ### What it does /// Checks for usage of `pub()` with `in`. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Consistency. Use it or don't, just be consistent about it. /// /// Also see the `pub_without_shorthand` lint for an alternative. @@ -57,7 +57,7 @@ declare_clippy_lint! { /// Note: As you cannot write a module's path in `pub()`, this will only trigger on /// `pub(super)` and the like. /// - /// ### Why is this bad? + /// ### Why restrict this? /// Consistency. Use it or don't, just be consistent about it. /// /// Also see the `pub_with_shorthand` lint for an alternative. diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index ff6ee0d10ad..652ce88bd95 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { /// Checks for printing on *stdout*. The purpose of this lint /// is to catch debugging remnants. /// - /// ### Why is this bad? + /// ### Why restrict this? /// People often print on *stdout* while debugging an /// application and might forget to remove those prints afterward. /// @@ -88,7 +88,7 @@ declare_clippy_lint! { /// Checks for printing on *stderr*. The purpose of this lint /// is to catch debugging remnants. /// - /// ### Why is this bad? + /// ### Why restrict this? /// People often print on *stderr* while debugging an /// application and might forget to remove those prints afterward. /// @@ -110,15 +110,18 @@ declare_clippy_lint! { /// Checks for usage of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. /// - /// ### Why is this bad? - /// The purpose of the `Debug` trait is to facilitate - /// debugging Rust code. It should not be used in user-facing output. + /// ### Why restrict this? + /// The purpose of the `Debug` trait is to facilitate debugging Rust code, + /// and [no guarantees are made about its output][stability]. + /// It should not be used in user-facing output. /// /// ### Example /// ```no_run /// # let foo = "bar"; /// println!("{:?}", foo); /// ``` + /// + /// [stability]: https://doc.rust-lang.org/stable/std/fmt/trait.Debug.html#stability #[clippy::version = "pre 1.29.0"] pub USE_DEBUG, restriction, -- cgit 1.4.1-3-g733a5 From 4a64180dd5cc48a26b2af3fbe0ddd3da0cccfb82 Mon Sep 17 00:00:00 2001 From: Marc Dominik Migge Date: Fri, 24 May 2024 17:59:09 +0200 Subject: `unnecessary_to_owned` should not suggest to remove `&` in macro expansion --- .../src/methods/unnecessary_iter_cloned.rs | 16 ++++---- clippy_lints/src/methods/utils.rs | 16 +++++--- tests/ui/unnecessary_iter_cloned.fixed | 29 ++++++++++++++ tests/ui/unnecessary_iter_cloned.rs | 29 ++++++++++++++ tests/ui/unnecessary_iter_cloned.stderr | 44 ++++++++++++++++++++-- tests/ui/unnecessary_to_owned.stderr | 2 +- 6 files changed, 117 insertions(+), 19 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 7431dc1cf0b..d1300dd43c2 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -38,7 +38,7 @@ pub fn check_for_loop_iter( ) -> bool { if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent)) && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) - && let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body) + && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && !clone_or_copy_needed && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) { @@ -123,14 +123,12 @@ pub fn check_for_loop_iter( Applicability::MachineApplicable }; diag.span_suggestion(expr.span, "use", snippet, applicability); - for addr_of_expr in addr_of_exprs { - match addr_of_expr.kind { - ExprKind::AddrOf(_, _, referent) => { - let span = addr_of_expr.span.with_hi(referent.span.lo()); - diag.span_suggestion(span, "remove this `&`", "", applicability); - }, - _ => unreachable!(), - } + if !references_to_binding.is_empty() { + diag.multipart_suggestion( + "remove any references to the binding", + references_to_binding, + applicability, + ); } }, ); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 34d7b9acbe4..1a55b7160fb 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -9,6 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; +use rustc_span::Span; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, @@ -96,15 +97,15 @@ pub(super) fn clone_or_copy_needed<'tcx>( cx: &LateContext<'tcx>, pat: &Pat<'tcx>, body: &'tcx Expr<'tcx>, -) -> (bool, Vec<&'tcx Expr<'tcx>>) { +) -> (bool, Vec<(Span, String)>) { let mut visitor = CloneOrCopyVisitor { cx, binding_hir_ids: pat_bindings(pat), clone_or_copy_needed: false, - addr_of_exprs: Vec::new(), + references_to_binding: Vec::new(), }; visitor.visit_expr(body); - (visitor.clone_or_copy_needed, visitor.addr_of_exprs) + (visitor.clone_or_copy_needed, visitor.references_to_binding) } /// Returns a vector of all `HirId`s bound by the pattern. @@ -127,7 +128,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, binding_hir_ids: Vec, clone_or_copy_needed: bool, - addr_of_exprs: Vec<&'tcx Expr<'tcx>>, + references_to_binding: Vec<(Span, String)>, } impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { @@ -142,8 +143,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { if self.is_binding(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { match parent.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => { - self.addr_of_exprs.push(parent); + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, referent) => { + if !parent.span.from_expansion() { + self.references_to_binding + .push((parent.span.until(referent.span), String::new())); + } return; }, ExprKind::MethodCall(.., args, _) => { diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed index 2c582c90ba8..dc5e163ff04 100644 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -170,3 +170,32 @@ fn check_mut_iteratee_and_modify_inner_variable() { } } } + +mod issue_12821 { + fn foo() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter() { + //~^ ERROR: unnecessary use of `cloned` + println!("{c}"); // should not suggest to remove `&` + } + } + + fn bar() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = c; //~ HELP: remove any references to the binding + println!("{ref_c}"); + } + } + + fn baz() { + let v: Vec<_> = "hello".chars().enumerate().collect(); + for (i, c) in v.iter() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = c; //~ HELP: remove any references to the binding + let ref_i = i; + println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` + } + } +} diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index a28ccd1efef..8f797ac717f 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -170,3 +170,32 @@ fn check_mut_iteratee_and_modify_inner_variable() { } } } + +mod issue_12821 { + fn foo() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter().cloned() { + //~^ ERROR: unnecessary use of `cloned` + println!("{c}"); // should not suggest to remove `&` + } + } + + fn bar() { + let v: Vec<_> = "hello".chars().collect(); + for c in v.iter().cloned() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = &c; //~ HELP: remove any references to the binding + println!("{ref_c}"); + } + } + + fn baz() { + let v: Vec<_> = "hello".chars().enumerate().collect(); + for (i, c) in v.iter().cloned() { + //~^ ERROR: unnecessary use of `cloned` + let ref_c = &c; //~ HELP: remove any references to the binding + let ref_i = &i; + println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` + } + } +} diff --git a/tests/ui/unnecessary_iter_cloned.stderr b/tests/ui/unnecessary_iter_cloned.stderr index fb98cfddc26..0bdb37a521f 100644 --- a/tests/ui/unnecessary_iter_cloned.stderr +++ b/tests/ui/unnecessary_iter_cloned.stderr @@ -10,7 +10,7 @@ help: use | LL | for (t, path) in files { | ~~~~~ -help: remove this `&` +help: remove any references to the binding | LL - let other = match get_file_path(&t) { LL + let other = match get_file_path(t) { @@ -26,11 +26,49 @@ help: use | LL | for (t, path) in files.iter() { | ~~~~~~~~~~~~ -help: remove this `&` +help: remove any references to the binding | LL - let other = match get_file_path(&t) { LL + let other = match get_file_path(t) { | -error: aborting due to 2 previous errors +error: unnecessary use of `cloned` + --> tests/ui/unnecessary_iter_cloned.rs:177:18 + | +LL | for c in v.iter().cloned() { + | ^^^^^^^^^^^^^^^^^ help: use: `v.iter()` + +error: unnecessary use of `cloned` + --> tests/ui/unnecessary_iter_cloned.rs:185:18 + | +LL | for c in v.iter().cloned() { + | ^^^^^^^^^^^^^^^^^ + | +help: use + | +LL | for c in v.iter() { + | ~~~~~~~~ +help: remove any references to the binding + | +LL - let ref_c = &c; +LL + let ref_c = c; + | + +error: unnecessary use of `cloned` + --> tests/ui/unnecessary_iter_cloned.rs:194:23 + | +LL | for (i, c) in v.iter().cloned() { + | ^^^^^^^^^^^^^^^^^ + | +help: use + | +LL | for (i, c) in v.iter() { + | ~~~~~~~~ +help: remove any references to the binding + | +LL ~ let ref_c = c; +LL ~ let ref_i = i; + | + +error: aborting due to 5 previous errors diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 5475df9c7b9..2829f3cd6e9 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -487,7 +487,7 @@ help: use | LL | for t in file_types { | ~~~~~~~~~~ -help: remove this `&` +help: remove any references to the binding | LL - let path = match get_file_path(&t) { LL + let path = match get_file_path(t) { -- cgit 1.4.1-3-g733a5 From 566dfd90082d709aa2d42b354349bfd2b4b895b2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 May 2024 18:05:46 +0200 Subject: Add `needless_character_iteration` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 24 +++++ .../src/methods/needless_character_iteration.rs | 108 +++++++++++++++++++++ .../src/methods/unnecessary_result_map_or_else.rs | 19 +--- clippy_lints/src/methods/utils.rs | 18 +++- tests/ui/needless_character_iteration.fixed | 51 ++++++++++ tests/ui/needless_character_iteration.rs | 59 +++++++++++ tests/ui/needless_character_iteration.stderr | 67 +++++++++++++ 9 files changed, 330 insertions(+), 18 deletions(-) create mode 100644 clippy_lints/src/methods/needless_character_iteration.rs create mode 100644 tests/ui/needless_character_iteration.fixed create mode 100644 tests/ui/needless_character_iteration.rs create mode 100644 tests/ui/needless_character_iteration.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index cfff0bb50a6..9f1d0e56745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5567,6 +5567,7 @@ Released 2018-09-13 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference [`needless_borrows_for_generic_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrows_for_generic_args +[`needless_character_iteration`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_character_iteration [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect [`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 6850ec821e8..2e436f0f767 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -418,6 +418,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MAP_UNWRAP_OR_INFO, crate::methods::MUT_MUTEX_LOCK_INFO, crate::methods::NAIVE_BYTECOUNT_INFO, + crate::methods::NEEDLESS_CHARACTER_ITERATION_INFO, crate::methods::NEEDLESS_COLLECT_INFO, crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO, crate::methods::NEEDLESS_OPTION_TAKE_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 60666445d08..b85218d3ca2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -66,6 +66,7 @@ mod map_flatten; mod map_identity; mod map_unwrap_or; mod mut_mutex_lock; +mod needless_character_iteration; mod needless_collect; mod needless_option_as_deref; mod needless_option_take; @@ -4089,6 +4090,27 @@ declare_clippy_lint! { "is_empty() called on strings known at compile time" } +declare_clippy_lint! { + /// ### What it does + /// Checks if an iterator is used to check if a string is ascii. + /// + /// ### Why is this bad? + /// The `str` type already implements the `is_ascii` method. + /// + /// ### Example + /// ```no_run + /// "foo".chars().all(|c| c.is_ascii()); + /// ``` + /// Use instead: + /// ```no_run + /// "foo".is_ascii(); + /// ``` + #[clippy::version = "1.80.0"] + pub NEEDLESS_CHARACTER_ITERATION, + suspicious, + "is_ascii() called on a char iterator" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4254,6 +4276,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, + NEEDLESS_CHARACTER_ITERATION, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4461,6 +4484,7 @@ impl Methods { }, ("all", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg); if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { iter_overeager_cloned::check( cx, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs new file mode 100644 index 00000000000..f4467af4de8 --- /dev/null +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -0,0 +1,108 @@ +use rustc_errors::Applicability; +use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::Span; + +use super::utils::get_last_chain_binding_hir_id; +use super::NEEDLESS_CHARACTER_ITERATION; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; + +fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { + while let ExprKind::AddrOf(_, _, e) = expr.kind { + expr = e; + } + expr +} + +fn handle_expr( + cx: &LateContext<'_>, + expr: &Expr<'_>, + first_param: HirId, + span: Span, + before_chars: Span, + revert: bool, +) { + match expr.kind { + ExprKind::MethodCall(method, receiver, [], _) => { + if method.ident.name.as_str() == "is_ascii" + && path_to_local_id(receiver, first_param) + && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() + && *char_arg_ty.kind() == ty::Char + && let Some(snippet) = snippet_opt(cx, before_chars) + { + span_lint_and_sugg( + cx, + NEEDLESS_CHARACTER_ITERATION, + span, + "checking if a string is ascii using iterators", + "try", + format!("{}{snippet}.is_ascii()", if revert { "!" } else { "" }), + Applicability::MachineApplicable, + ); + } + }, + ExprKind::Block(block, _) => { + if block.stmts.iter().any(|stmt| !matches!(stmt.kind, StmtKind::Let(_))) { + // If there is something else than let bindings, then better not emit the lint. + return; + } + if let Some(block_expr) = block.expr + // First we ensure that this is a "binding chain" (each statement is a binding + // of the previous one) and that it is a binding of the closure argument. + && let Some(last_chain_binding_id) = + get_last_chain_binding_hir_id(first_param, block.stmts) + { + handle_expr(cx, block_expr, last_chain_binding_id, span, before_chars, revert); + } + }, + ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert), + ExprKind::Call(fn_path, [arg]) => { + if let ExprKind::Path(path) = fn_path.kind + && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() + && match_def_path(cx, fn_def_id, &["core", "char", "methods", "", "is_ascii"]) + && path_to_local_id(peels_expr_ref(arg), first_param) + && let Some(snippet) = snippet_opt(cx, before_chars) + { + span_lint_and_sugg( + cx, + NEEDLESS_CHARACTER_ITERATION, + span, + "checking if a string is ascii using iterators", + "try", + format!("{}{snippet}.is_ascii()", if revert { "!" } else { "" }), + Applicability::MachineApplicable, + ); + } + }, + _ => {}, + } +} + +pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { + if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind + && let body = cx.tcx.hir().body(body) + && let Some(first_param) = body.params.first() + && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind + && method.ident.name.as_str() == "chars" + && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() + && *str_ty.kind() == ty::Str + { + let expr_start = recv.span; + while let ExprKind::MethodCall(_, new_recv, _, _) = recv.kind { + recv = new_recv; + } + let body_expr = peel_blocks(body.value); + + handle_expr( + cx, + body_expr, + first_param.pat.hir_id, + recv.span.with_hi(call_expr.span.hi()), + recv.span.with_hi(expr_start.hi()), + false, + ); + } +} diff --git a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index cdfaa690d5f..c14a87c1534 100644 --- a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -4,10 +4,11 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath, Stmt, StmtKind}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use super::utils::get_last_chain_binding_hir_id; use super::UNNECESSARY_RESULT_MAP_OR_ELSE; fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { @@ -25,22 +26,6 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &E ); } -fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { - for stmt in statements { - if let StmtKind::Let(local) = stmt.kind - && let Some(init) = local.init - && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind - && let hir::def::Res::Local(local_hir_id) = path.res - && local_hir_id == hir_id - { - hir_id = local.pat.hir_id; - } else { - return None; - } - } - Some(hir_id) -} - fn handle_qpath( cx: &LateContext<'_>, expr: &Expr<'_>, diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 34d7b9acbe4..a379f477995 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -4,7 +4,7 @@ use clippy_utils::{get_parent_expr, path_to_local_id, usage}; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -171,3 +171,19 @@ impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { .any(|hir_id| path_to_local_id(expr, *hir_id)) } } + +pub(super) fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { + for stmt in statements { + if let StmtKind::Let(local) = stmt.kind + && let Some(init) = local.init + && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind + && let rustc_hir::def::Res::Local(local_hir_id) = path.res + && local_hir_id == hir_id + { + hir_id = local.pat.hir_id; + } else { + return None; + } + } + Some(hir_id) +} diff --git a/tests/ui/needless_character_iteration.fixed b/tests/ui/needless_character_iteration.fixed new file mode 100644 index 00000000000..5a5da592987 --- /dev/null +++ b/tests/ui/needless_character_iteration.fixed @@ -0,0 +1,51 @@ +#![warn(clippy::needless_character_iteration)] +#![allow(clippy::map_identity, clippy::unnecessary_operation)] + +#[derive(Default)] +struct S { + field: &'static str, +} + +impl S { + fn field(&self) -> &str { + self.field + } +} + +fn magic(_: char) {} + +fn main() { + "foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + "foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + let s = String::new(); + s.is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".to_string().is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + "foo".is_ascii(); + !"foo".is_ascii(); + + S::default().field().is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + // Should not lint! + "foo".chars().all(|c| { + let x = c; + magic(x); + x.is_ascii() + }); + + // Should not lint! + "foo".chars().all(|c| c.is_ascii() && c.is_alphabetic()); + + // Should not lint! + "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); +} diff --git a/tests/ui/needless_character_iteration.rs b/tests/ui/needless_character_iteration.rs new file mode 100644 index 00000000000..f6320ff22b7 --- /dev/null +++ b/tests/ui/needless_character_iteration.rs @@ -0,0 +1,59 @@ +#![warn(clippy::needless_character_iteration)] +#![allow(clippy::map_identity, clippy::unnecessary_operation)] + +#[derive(Default)] +struct S { + field: &'static str, +} + +impl S { + fn field(&self) -> &str { + self.field + } +} + +fn magic(_: char) {} + +fn main() { + "foo".chars().all(|c| c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| !c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| char::is_ascii(&c)); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| !char::is_ascii(&c)); + //~^ ERROR: checking if a string is ascii using iterators + + let s = String::new(); + s.chars().all(|c| c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".to_string().chars().all(|c| !c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + + "foo".chars().all(|c| { + //~^ ERROR: checking if a string is ascii using iterators + let x = c; + x.is_ascii() + }); + "foo".chars().all(|c| { + //~^ ERROR: checking if a string is ascii using iterators + let x = c; + !x.is_ascii() + }); + + S::default().field().chars().all(|x| x.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + + // Should not lint! + "foo".chars().all(|c| { + let x = c; + magic(x); + x.is_ascii() + }); + + // Should not lint! + "foo".chars().all(|c| c.is_ascii() && c.is_alphabetic()); + + // Should not lint! + "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); +} diff --git a/tests/ui/needless_character_iteration.stderr b/tests/ui/needless_character_iteration.stderr new file mode 100644 index 00000000000..05055f75aa7 --- /dev/null +++ b/tests/ui/needless_character_iteration.stderr @@ -0,0 +1,67 @@ +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:18:5 + | +LL | "foo".chars().all(|c| c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` + | + = note: `-D clippy::needless-character-iteration` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_character_iteration)]` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:20:5 + | +LL | "foo".chars().all(|c| !c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:22:5 + | +LL | "foo".chars().all(|c| char::is_ascii(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:24:5 + | +LL | "foo".chars().all(|c| !char::is_ascii(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:28:5 + | +LL | s.chars().all(|c| c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:30:5 + | +LL | "foo".to_string().chars().all(|c| !c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:33:5 + | +LL | / "foo".chars().all(|c| { +LL | | +LL | | let x = c; +LL | | x.is_ascii() +LL | | }); + | |______^ help: try: `"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:38:5 + | +LL | / "foo".chars().all(|c| { +LL | | +LL | | let x = c; +LL | | !x.is_ascii() +LL | | }); + | |______^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:44:5 + | +LL | S::default().field().chars().all(|x| x.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `S::default().field().is_ascii()` + +error: aborting due to 9 previous errors + -- cgit 1.4.1-3-g733a5 From 158b65889cb5e5be2b367c1acb349c966e70543f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 3 Jun 2024 21:57:47 +0200 Subject: Fix false positive for `needless_character_iteration` lint --- clippy_lints/src/methods/mod.rs | 3 ++- .../src/methods/needless_character_iteration.rs | 26 +++++++++++++++++----- tests/ui/needless_character_iteration.fixed | 6 +++++ tests/ui/needless_character_iteration.rs | 14 ++++++++---- tests/ui/needless_character_iteration.stderr | 8 +++---- 5 files changed, 43 insertions(+), 14 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1572f6fb601..6a535c11a98 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4485,7 +4485,7 @@ impl Methods { }, ("all", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); - needless_character_iteration::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg, true); if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { iter_overeager_cloned::check( cx, @@ -4506,6 +4506,7 @@ impl Methods { }, ("any", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg, false); match method_call(recv) { Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index f4467af4de8..e3d78207715 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -24,10 +24,14 @@ fn handle_expr( span: Span, before_chars: Span, revert: bool, + is_all: bool, ) { match expr.kind { ExprKind::MethodCall(method, receiver, [], _) => { - if method.ident.name.as_str() == "is_ascii" + // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is + // `is_ascii`, then only `.all()` should warn. + if revert != is_all + && method.ident.name.as_str() == "is_ascii" && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char @@ -55,12 +59,23 @@ fn handle_expr( && let Some(last_chain_binding_id) = get_last_chain_binding_hir_id(first_param, block.stmts) { - handle_expr(cx, block_expr, last_chain_binding_id, span, before_chars, revert); + handle_expr( + cx, + block_expr, + last_chain_binding_id, + span, + before_chars, + revert, + is_all, + ); } }, - ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert), + ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert, is_all), ExprKind::Call(fn_path, [arg]) => { - if let ExprKind::Path(path) = fn_path.kind + // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is + // `is_ascii`, then only `.all()` should warn. + if revert != is_all + && let ExprKind::Path(path) = fn_path.kind && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() && match_def_path(cx, fn_def_id, &["core", "char", "methods", "", "is_ascii"]) && path_to_local_id(peels_expr_ref(arg), first_param) @@ -81,7 +96,7 @@ fn handle_expr( } } -pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { +pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) { if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind && let body = cx.tcx.hir().body(body) && let Some(first_param) = body.params.first() @@ -103,6 +118,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, recv.span.with_hi(call_expr.span.hi()), recv.span.with_hi(expr_start.hi()), false, + is_all, ); } } diff --git a/tests/ui/needless_character_iteration.fixed b/tests/ui/needless_character_iteration.fixed index 5a5da592987..f0bf84a41d7 100644 --- a/tests/ui/needless_character_iteration.fixed +++ b/tests/ui/needless_character_iteration.fixed @@ -48,4 +48,10 @@ fn main() { // Should not lint! "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); + + // Should not lint! + "foo".chars().all(|c| !c.is_ascii()); + + // Should not lint! + "foo".chars().any(|c| c.is_ascii()); } diff --git a/tests/ui/needless_character_iteration.rs b/tests/ui/needless_character_iteration.rs index f6320ff22b7..2805d2438b4 100644 --- a/tests/ui/needless_character_iteration.rs +++ b/tests/ui/needless_character_iteration.rs @@ -17,17 +17,17 @@ fn magic(_: char) {} fn main() { "foo".chars().all(|c| c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators - "foo".chars().all(|c| !c.is_ascii()); + "foo".chars().any(|c| !c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators "foo".chars().all(|c| char::is_ascii(&c)); //~^ ERROR: checking if a string is ascii using iterators - "foo".chars().all(|c| !char::is_ascii(&c)); + "foo".chars().any(|c| !char::is_ascii(&c)); //~^ ERROR: checking if a string is ascii using iterators let s = String::new(); s.chars().all(|c| c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators - "foo".to_string().chars().all(|c| !c.is_ascii()); + "foo".to_string().chars().any(|c| !c.is_ascii()); //~^ ERROR: checking if a string is ascii using iterators "foo".chars().all(|c| { @@ -35,7 +35,7 @@ fn main() { let x = c; x.is_ascii() }); - "foo".chars().all(|c| { + "foo".chars().any(|c| { //~^ ERROR: checking if a string is ascii using iterators let x = c; !x.is_ascii() @@ -56,4 +56,10 @@ fn main() { // Should not lint! "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); + + // Should not lint! + "foo".chars().all(|c| !c.is_ascii()); + + // Should not lint! + "foo".chars().any(|c| c.is_ascii()); } diff --git a/tests/ui/needless_character_iteration.stderr b/tests/ui/needless_character_iteration.stderr index 05055f75aa7..7966033555f 100644 --- a/tests/ui/needless_character_iteration.stderr +++ b/tests/ui/needless_character_iteration.stderr @@ -10,7 +10,7 @@ LL | "foo".chars().all(|c| c.is_ascii()); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:20:5 | -LL | "foo".chars().all(|c| !c.is_ascii()); +LL | "foo".chars().any(|c| !c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators @@ -22,7 +22,7 @@ LL | "foo".chars().all(|c| char::is_ascii(&c)); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:24:5 | -LL | "foo".chars().all(|c| !char::is_ascii(&c)); +LL | "foo".chars().any(|c| !char::is_ascii(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators @@ -34,7 +34,7 @@ LL | s.chars().all(|c| c.is_ascii()); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:30:5 | -LL | "foo".to_string().chars().all(|c| !c.is_ascii()); +LL | "foo".to_string().chars().any(|c| !c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()` error: checking if a string is ascii using iterators @@ -50,7 +50,7 @@ LL | | }); error: checking if a string is ascii using iterators --> tests/ui/needless_character_iteration.rs:38:5 | -LL | / "foo".chars().all(|c| { +LL | / "foo".chars().any(|c| { LL | | LL | | let x = c; LL | | !x.is_ascii() -- cgit 1.4.1-3-g733a5 From d47ab9f9c9b52167e8abf68d3a1d8722c4c395c2 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 5 Jun 2024 13:51:29 +0200 Subject: Update version attribute for 1.79 lints --- clippy_lints/src/attrs/mod.rs | 2 +- clippy_lints/src/integer_division_remainder_used.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/manual_unwrap_or_default.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/zero_repeat_side_effects.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 83c828e8e22..e4c98a32fd6 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -463,7 +463,7 @@ declare_clippy_lint! { /// #[allow(dead_code)] /// fn foo() {} /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub DUPLICATED_ATTRIBUTES, suspicious, "duplicated attribute" diff --git a/clippy_lints/src/integer_division_remainder_used.rs b/clippy_lints/src/integer_division_remainder_used.rs index cf598d5045e..a1215491b48 100644 --- a/clippy_lints/src/integer_division_remainder_used.rs +++ b/clippy_lints/src/integer_division_remainder_used.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```no_run /// let my_div = 10 >> 1; /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub INTEGER_DIVISION_REMAINDER_USED, restriction, "use of disallowed default division and remainder operations" diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 00124dcdd91..eadfeb6e341 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ```rust /// let eps = f32::EPSILON; /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.79.0"] pub LEGACY_NUMERIC_CONSTANTS, style, "checks for usage of legacy std numeric constants and methods" diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index 84fb183e3f7..70ec6478a25 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// let x: Option> = Some(Vec::new()); /// let y: Vec = x.unwrap_or_default(); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub MANUAL_UNWRAP_OR_DEFAULT, suspicious, "check if a `match` or `if let` can be simplified with `unwrap_or_default`" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1572f6fb601..8ef68262571 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4085,7 +4085,7 @@ declare_clippy_lint! { /// ```no_run /// println!("the string is empty"); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub CONST_IS_EMPTY, suspicious, "is_empty() called on strings known at compile time" diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 598032ccdeb..aa329ec3366 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -546,7 +546,7 @@ declare_clippy_lint! { /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); /// # } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.79.0"] pub MISSING_TRANSMUTE_ANNOTATIONS, suspicious, "warns if a transmute call doesn't have all generics specified" diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs index 143fecdd237..1450975835a 100644 --- a/clippy_lints/src/zero_repeat_side_effects.rs +++ b/clippy_lints/src/zero_repeat_side_effects.rs @@ -36,7 +36,7 @@ declare_clippy_lint! { /// side_effect(); /// let a: [i32; 0] = []; /// ``` - #[clippy::version = "1.75.0"] + #[clippy::version = "1.79.0"] pub ZERO_REPEAT_SIDE_EFFECTS, suspicious, "usage of zero-sized initializations of arrays or vecs causing side effects" -- cgit 1.4.1-3-g733a5 From 1e23449678e4c986b609ed7a82ae6497e7b6ddd1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 25 May 2024 18:15:14 +0200 Subject: Move `is_receiver_of_method_call` to `clippy_utils` for reuse --- clippy_lints/src/methods/search_is_some.rs | 12 +----------- clippy_utils/src/lib.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index f5f1e94bbf4..3b2dd285b8c 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs}; use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; @@ -156,13 +156,3 @@ pub(super) fn check<'tcx>( } } } - -fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - if let Some(parent_expr) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind - && receiver.hir_id == expr.hir_id - { - return true; - } - false -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 6d6c4ffbe5d..6b00e793eaa 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3401,3 +3401,14 @@ pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool { contains_block(expr, false) } + +/// Returns true if the specified expression is in a receiver position. +pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind + && receiver.hir_id == expr.hir_id + { + return true; + } + false +} -- cgit 1.4.1-3-g733a5 From 55344c84a59412afeb6965945e24cbae7389ecab Mon Sep 17 00:00:00 2001 From: Artem Belyakov Date: Sun, 9 Jun 2024 21:01:00 +0300 Subject: Handle single chars with `to_string()` for `single_char_add_str` --- .../src/methods/single_char_insert_string.rs | 42 +++++++++++++++- .../src/methods/single_char_push_string.rs | 41 ++++++++++++++- tests/ui/single_char_add_str.fixed | 10 ++++ tests/ui/single_char_add_str.rs | 10 ++++ tests/ui/single_char_add_str.stderr | 58 ++++++++++++++++++---- 5 files changed, 148 insertions(+), 13 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 20ec2b74d81..f2af793a869 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,8 +1,9 @@ use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use rustc_ast::BorrowKind; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; @@ -25,4 +26,43 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: applicability, ); } + + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind + && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind + && path_segment.ident.as_str() == "to_string" + && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) + { + let base_string_snippet = + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); + let extension_string = + snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); + let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" }; + + let sugg = format!("{base_string_snippet}.insert({pos_arg}, {deref_string}{extension_string})"); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `insert_str()` using a single-character converted to string", + "consider using `insert` without `to_string()`", + sugg, + applicability, + ); + } +} + +fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(expr).is_ref() + && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind() + && ty.is_char() + { + return true; + } + + false +} + +fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_char() } diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 97c13825bc1..8c6e490a38f 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,8 +1,9 @@ use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use rustc_ast::BorrowKind; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; @@ -24,4 +25,42 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: applicability, ); } + + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind + && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind + && path_segment.ident.as_str() == "to_string" + && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) + { + let base_string_snippet = + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); + let extension_string = + snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability); + let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" }; + + let sugg = format!("{base_string_snippet}.push({deref_string}{extension_string})"); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `push_str()` using a single-character converted to string", + "consider using `push` without `to_string()`", + sugg, + applicability, + ); + } +} + +fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(expr).is_ref() + && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind() + && ty.is_char() + { + return true; + } + + false +} + +fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_char() } diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed index eafd17f5387..aef15252b1b 100644 --- a/tests/ui/single_char_add_str.fixed +++ b/tests/ui/single_char_add_str.fixed @@ -21,6 +21,12 @@ fn main() { string.push('\u{0052}'); string.push('a'); + let c_ref = &'a'; + string.push(*c_ref); + let c = 'a'; + string.push(c); + string.push('a'); + get_string!().push('ö'); // `insert_str` tests @@ -41,5 +47,9 @@ fn main() { string.insert(Y, '"'); string.insert(Y, '\''); + string.insert(0, *c_ref); + string.insert(0, c); + string.insert(0, 'a'); + get_string!().insert(1, '?'); } diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs index 5326c7cf24c..7f97250dacd 100644 --- a/tests/ui/single_char_add_str.rs +++ b/tests/ui/single_char_add_str.rs @@ -21,6 +21,12 @@ fn main() { string.push_str("\u{0052}"); string.push_str(r##"a"##); + let c_ref = &'a'; + string.push_str(&c_ref.to_string()); + let c = 'a'; + string.push_str(&c.to_string()); + string.push_str(&'a'.to_string()); + get_string!().push_str("ö"); // `insert_str` tests @@ -41,5 +47,9 @@ fn main() { string.insert_str(Y, r##"""##); string.insert_str(Y, r##"'"##); + string.insert_str(0, &c_ref.to_string()); + string.insert_str(0, &c.to_string()); + string.insert_str(0, &'a'.to_string()); + get_string!().insert_str(1, "?"); } diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr index 89d75f20f55..7791c67578a 100644 --- a/tests/ui/single_char_add_str.stderr +++ b/tests/ui/single_char_add_str.stderr @@ -31,65 +31,101 @@ error: calling `push_str()` using a single-character string literal LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:25:5 + | +LL | string.push_str(&c_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(*c_ref)` + +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:27:5 + | +LL | string.push_str(&c.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(c)` + +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:28:5 + | +LL | string.push_str(&'a'.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push('a')` + error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:24:5 + --> tests/ui/single_char_add_str.rs:30:5 | LL | get_string!().push_str("ö"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:29:5 + --> tests/ui/single_char_add_str.rs:35:5 | LL | string.insert_str(0, "R"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:30:5 + --> tests/ui/single_char_add_str.rs:36:5 | LL | string.insert_str(1, "'"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '\'')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:35:5 + --> tests/ui/single_char_add_str.rs:41:5 | LL | string.insert_str(0, "\x52"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\x52')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:36:5 + --> tests/ui/single_char_add_str.rs:42:5 | LL | string.insert_str(0, "\u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\u{0052}')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:38:5 + --> tests/ui/single_char_add_str.rs:44:5 | LL | string.insert_str(x, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:40:5 + --> tests/ui/single_char_add_str.rs:46:5 | LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:41:5 + --> tests/ui/single_char_add_str.rs:47:5 | LL | string.insert_str(Y, r##"""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:42:5 + --> tests/ui/single_char_add_str.rs:48:5 | LL | string.insert_str(Y, r##"'"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '\'')` +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:50:5 + | +LL | string.insert_str(0, &c_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, *c_ref)` + +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:51:5 + | +LL | string.insert_str(0, &c.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, c)` + +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:52:5 + | +LL | string.insert_str(0, &'a'.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, 'a')` + error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:44:5 + --> tests/ui/single_char_add_str.rs:54:5 | LL | get_string!().insert_str(1, "?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` -error: aborting due to 15 previous errors +error: aborting due to 21 previous errors -- cgit 1.4.1-3-g733a5 From f7723cada7191fba2313d410ea5a4327a878d589 Mon Sep 17 00:00:00 2001 From: Artem Belyakov Date: Sun, 9 Jun 2024 21:23:59 +0300 Subject: Fix dogfood test --- clippy_lints/src/methods/single_char_insert_string.rs | 2 +- clippy_lints/src/methods/single_char_push_string.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index f2af793a869..ba9ef9c84f9 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind - && path_segment.ident.as_str() == "to_string" + && path_segment.ident.name == rustc_span::sym::to_string && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) { let base_string_snippet = diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 8c6e490a38f..f00a5ab455e 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind - && path_segment.ident.as_str() == "to_string" + && path_segment.ident.name == rustc_span::sym::to_string && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) { let base_string_snippet = -- cgit 1.4.1-3-g733a5 From c86b19f1ef262eeb1992a91879b38ffbed07a1a7 Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Tue, 11 Jun 2024 21:56:14 +0200 Subject: Add lint to check manual pattern char comparison and merge its code with single_char_pattern lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 3 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/mod.rs | 35 ---- .../src/methods/path_buf_push_overwrite.rs | 2 +- .../src/methods/single_char_insert_string.rs | 5 +- clippy_lints/src/methods/single_char_pattern.rs | 64 ------ .../src/methods/single_char_push_string.rs | 5 +- clippy_lints/src/methods/utils.rs | 45 ---- .../src/misc_early/zero_prefixed_literal.rs | 4 +- clippy_lints/src/string_patterns.rs | 227 +++++++++++++++++++++ clippy_utils/src/source.rs | 45 ++++ tests/ui/manual_pattern_char_comparison.fixed | 49 +++++ tests/ui/manual_pattern_char_comparison.rs | 49 +++++ tests/ui/manual_pattern_char_comparison.stderr | 59 ++++++ tests/ui/search_is_some.rs | 1 + tests/ui/search_is_some.stderr | 16 +- 18 files changed, 451 insertions(+), 163 deletions(-) delete mode 100644 clippy_lints/src/methods/single_char_pattern.rs create mode 100644 clippy_lints/src/string_patterns.rs create mode 100644 tests/ui/manual_pattern_char_comparison.fixed create mode 100644 tests/ui/manual_pattern_char_comparison.rs create mode 100644 tests/ui/manual_pattern_char_comparison.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 711b7fb7914..d7bcd7a1968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5532,6 +5532,7 @@ Released 2018-09-13 [`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or +[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a9f2dd4499a..7e43a99e9f2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -448,7 +448,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO, crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, - crate::methods::SINGLE_CHAR_PATTERN_INFO, crate::methods::SKIP_WHILE_NEXT_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, @@ -656,6 +655,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO, + crate::string_patterns::MANUAL_PATTERN_CHAR_COMPARISON_INFO, + crate::string_patterns::SINGLE_CHAR_PATTERN_INFO, crate::strings::STRING_ADD_INFO, crate::strings::STRING_ADD_ASSIGN_INFO, crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO, diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 4ec9bd757ff..4d301daabe4 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { return; } - if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { + if is_whole && !sym_str.contains(['e', 'E']) { // Normalize the literal by stripping the fractional portion if sym_str.split('.').next().unwrap() != float_str { // If the type suffix is missing the suggestion would be diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6946c2986f4..c65581d5203 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -326,6 +326,7 @@ mod size_of_in_element_count; mod size_of_ref; mod slow_vector_initialization; mod std_instead_of_core; +mod string_patterns; mod strings; mod strlen_on_c_strings; mod suspicious_operation_groupings; @@ -1167,6 +1168,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ..Default::default() }) }); + store.register_late_pass(|_| Box::new(string_patterns::StringPatterns)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c3699d6341a..6200716afbe 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -94,7 +94,6 @@ 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; mod single_char_push_string; mod skip_while_next; mod stable_sort_primitive; @@ -1141,38 +1140,6 @@ declare_clippy_lint! { "not returning type containing `Self` in a `new` method" } -declare_clippy_lint! { - /// ### What it does - /// Checks for string methods that receive a single-character - /// `str` as an argument, e.g., `_.split("x")`. - /// - /// ### Why is this bad? - /// While this can make a perf difference on some systems, - /// benchmarks have proven inconclusive. But at least using a - /// char literal makes it clear that we are looking at a single - /// character. - /// - /// ### Known problems - /// Does not catch multi-byte unicode characters. This is by - /// design, on many machines, splitting by a non-ascii char is - /// actually slower. Please do your own measurements instead of - /// relying solely on the results of this lint. - /// - /// ### Example - /// ```rust,ignore - /// _.split("x"); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// _.split('x'); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub SINGLE_CHAR_PATTERN, - pedantic, - "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" -} - declare_clippy_lint! { /// ### What it does /// Checks for calling `.step_by(0)` on iterators which panics. @@ -4169,7 +4136,6 @@ impl_lint_pass!(Methods => [ FLAT_MAP_OPTION, INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, - SINGLE_CHAR_PATTERN, SINGLE_CHAR_ADD_STR, SEARCH_IS_SOME, FILTER_NEXT, @@ -4324,7 +4290,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); 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); }, ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs index 04a27cc98f3..2d3007e50b8 100644 --- a/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t lit.span, "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", "try", - format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + format!("\"{}\"", pushed_path_lit.trim_start_matches(['/', '\\'])), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index ba9ef9c84f9..e2f76ac114c 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,6 +1,5 @@ -use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal}; use rustc_ast::BorrowKind; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -11,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) { + if let Some(extension_string) = str_literal_to_char_literal(cx, &args[1], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs deleted file mode 100644 index 982a7901c45..00000000000 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::utils::get_hint_if_single_char_arg; -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_span::symbol::Symbol; - -use super::SINGLE_CHAR_PATTERN; - -const PATTERN_METHODS: [(&str, usize); 22] = [ - ("contains", 0), - ("starts_with", 0), - ("ends_with", 0), - ("find", 0), - ("rfind", 0), - ("split", 0), - ("split_inclusive", 0), - ("rsplit", 0), - ("split_terminator", 0), - ("rsplit_terminator", 0), - ("splitn", 1), - ("rsplitn", 1), - ("split_once", 0), - ("rsplit_once", 0), - ("matches", 0), - ("rmatches", 0), - ("match_indices", 0), - ("rmatch_indices", 0), - ("trim_start_matches", 0), - ("trim_end_matches", 0), - ("replace", 0), - ("replacen", 0), -]; - -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check( - cx: &LateContext<'_>, - _expr: &hir::Expr<'_>, - method_name: Symbol, - receiver: &hir::Expr<'_>, - args: &[hir::Expr<'_>], -) { - for &(method, pos) in &PATTERN_METHODS { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() - && ty.is_str() - && method_name.as_str() == method - && args.len() > pos - && let arg = &args[pos] - && let mut applicability = Applicability::MachineApplicable - && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true) - { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "consider using a `char`", - hint, - applicability, - ); - } - } -} diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index f00a5ab455e..4ae8634305d 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -1,6 +1,5 @@ -use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal}; use rustc_ast::BorrowKind; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -11,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) { + if let Some(extension_string) = str_literal_to_char_literal(cx, &args[0], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{base_string_snippet}.push({extension_string})"); diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 5d58c73f8b2..0d2b0a31317 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,8 +1,5 @@ -use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use rustc_ast::ast; -use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; @@ -49,48 +46,6 @@ pub(super) fn derefs_to_slice<'tcx>( } } -pub(super) fn get_hint_if_single_char_arg( - cx: &LateContext<'_>, - arg: &Expr<'_>, - applicability: &mut Applicability, - ascii_only: bool, -) -> Option { - if let ExprKind::Lit(lit) = &arg.kind - && let ast::LitKind::Str(r, style) = lit.node - && let string = r.as_str() - && let len = if ascii_only { - string.len() - } else { - string.chars().count() - } - && len == 1 - { - let snip = snippet_with_applicability(cx, arg.span, string, applicability); - let ch = if let ast::StrStyle::Raw(nhash) = style { - let nhash = nhash as usize; - // for raw string: r##"a"## - &snip[(nhash + 2)..(snip.len() - 1 - nhash)] - } else { - // for regular string: "a" - &snip[1..(snip.len() - 1)] - }; - - let hint = format!( - "'{}'", - match ch { - "'" => "\\'", - r"\" => "\\\\", - "\\\"" => "\"", // no need to escape `"` in `'"'` - _ => ch, - } - ); - - Some(hint) - } else { - None - } -} - /// The core logic of `check_for_loop_iter` in `unnecessary_iter_cloned.rs`, this function wraps a /// use of `CloneOrCopyVisitor`. pub(super) fn clone_or_copy_needed<'tcx>( diff --git a/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/clippy_lints/src/misc_early/zero_prefixed_literal.rs index 4f9578d1b25..61f4684c9e3 100644 --- a/clippy_lints/src/misc_early/zero_prefixed_literal.rs +++ b/clippy_lints/src/misc_early/zero_prefixed_literal.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use super::ZERO_PREFIXED_LITERAL; pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) { - let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0'); + let trimmed_lit_snip = lit_snip.trim_start_matches(['_', '0']); span_lint_and_then( cx, ZERO_PREFIXED_LITERAL, @@ -20,7 +20,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) { Applicability::MaybeIncorrect, ); // do not advise to use octal form if the literal cannot be expressed in base 8. - if !lit_snip.contains(|c| c == '8' || c == '9') { + if !lit_snip.contains(['8', '9']) { diag.span_suggestion( lit_span, "if you mean to use an octal constant, use `0o`", diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs new file mode 100644 index 00000000000..64b5b8f9f27 --- /dev/null +++ b/clippy_lints/src/string_patterns.rs @@ -0,0 +1,227 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::path_to_local_id; +use clippy_utils::source::{snippet, str_literal_to_char_literal}; +use clippy_utils::visitors::{for_each_expr, Descend}; +use itertools::Itertools; +use rustc_ast::{BinOpKind, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for manual `char` comparison in string patterns + /// + /// ### Why is this bad? + /// This can be written more concisely using a `char` or an array of `char`. + /// This is more readable and more optimized when comparing to only one `char`. + /// + /// ### Example + /// ```no_run + /// "Hello World!".trim_end_matches(|c| c == '.' || c == ',' || c == '!' || c == '?'); + /// ``` + /// Use instead: + /// ```no_run + /// "Hello World!".trim_end_matches(['.', ',', '!', '?']); + /// ``` + #[clippy::version = "1.80.0"] + pub MANUAL_PATTERN_CHAR_COMPARISON, + style, + "manual char comparison in string patterns" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for string methods that receive a single-character + /// `str` as an argument, e.g., `_.split("x")`. + /// + /// ### Why is this bad? + /// While this can make a perf difference on some systems, + /// benchmarks have proven inconclusive. But at least using a + /// char literal makes it clear that we are looking at a single + /// character. + /// + /// ### Known problems + /// Does not catch multi-byte unicode characters. This is by + /// design, on many machines, splitting by a non-ascii char is + /// actually slower. Please do your own measurements instead of + /// relying solely on the results of this lint. + /// + /// ### Example + /// ```rust,ignore + /// _.split("x"); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// _.split('x'); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub SINGLE_CHAR_PATTERN, + pedantic, + "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" +} + +declare_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); + +const PATTERN_METHODS: [(&str, usize); 22] = [ + ("contains", 0), + ("starts_with", 0), + ("ends_with", 0), + ("find", 0), + ("rfind", 0), + ("split", 0), + ("split_inclusive", 0), + ("rsplit", 0), + ("split_terminator", 0), + ("rsplit_terminator", 0), + ("splitn", 1), + ("rsplitn", 1), + ("split_once", 0), + ("rsplit_once", 0), + ("matches", 0), + ("rmatches", 0), + ("match_indices", 0), + ("rmatch_indices", 0), + ("trim_start_matches", 0), + ("trim_end_matches", 0), + ("replace", 0), + ("replacen", 0), +]; + +fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = str_literal_to_char_literal(cx, arg, &mut applicability, true) { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "consider using a `char`", + hint, + applicability, + ); + } +} + +fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + if cx.typeck_results().expr_ty_adjusted(expr).is_char() + && !expr.span.from_expansion() + && switch_to_eager_eval(cx, expr) + { + Some(expr.span) + } else { + None + } +} + +fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>) { + if let ExprKind::Closure(closure) = method_arg.kind + && let body = cx.tcx.hir().body(closure.body) + && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) + { + let mut set_char_spans: Vec = Vec::new(); + + // We want to retrieve all the comparisons done. + // They are ordered in a nested way and so we need to traverse the AST to collect them all. + if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> { + match sub_expr.kind { + ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => { + if path_to_local_id(left, binding) + && let Some(span) = get_char_span(cx, right) + { + set_char_spans.push(span); + ControlFlow::Continue(Descend::No) + } else if path_to_local_id(right, binding) + && let Some(span) = get_char_span(cx, left) + { + set_char_spans.push(span); + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Break(()) + } + }, + ExprKind::Binary(op, _, _) if op.node == BinOpKind::Or => ControlFlow::Continue(Descend::Yes), + ExprKind::Match(match_value, [arm, _], _) => { + if matching_root_macro_call(cx, sub_expr.span, sym::matches_macro).is_none() + || arm.guard.is_some() + || !path_to_local_id(match_value, binding) + { + return ControlFlow::Break(()); + } + if arm.pat.walk_short(|pat| match pat.kind { + PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => { + if let LitKind::Char(_) = lit.node { + set_char_spans.push(lit.span); + } + true + }, + PatKind::Or(_) => true, + _ => false, + }) { + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Break(()) + } + }, + _ => ControlFlow::Break(()), + } + }) + .is_some() + { + return; + } + span_lint_and_then( + cx, + MANUAL_PATTERN_CHAR_COMPARISON, + method_arg.span, + "this manual char comparison can be written more succinctly", + |diag| { + if let [set_char_span] = set_char_spans[..] { + diag.span_suggestion( + method_arg.span, + "consider using a `char`", + snippet(cx, set_char_span, "c"), + Applicability::MachineApplicable, + ); + } else { + diag.span_suggestion( + method_arg.span, + "consider using an array of `char`", + format!( + "[{}]", + set_char_spans.into_iter().map(|span| snippet(cx, span, "c")).join(", ") + ), + Applicability::MachineApplicable, + ); + } + }, + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for StringPatterns { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !expr.span.from_expansion() + && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind + && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() + && ty.is_str() + && let method_name = method.ident.name.as_str() + && let Some(&(_, pos)) = PATTERN_METHODS + .iter() + .find(|(array_method_name, _)| *array_method_name == method_name) + && let Some(arg) = args.get(pos) + { + check_single_char_pattern_lint(cx, arg); + + check_manual_pattern_char_comparison(cx, arg); + } + } +} diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 69f593fe04a..b7ff7ebe910 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -2,6 +2,7 @@ #![allow(clippy::module_name_repetitions)] +use rustc_ast::{LitKind, StrStyle}; use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; @@ -500,6 +501,50 @@ pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { extended.with_lo(extended.lo() - BytePos(1)) } +/// Converts `expr` to a `char` literal if it's a `str` literal containing a single +/// character (or a single byte with `ascii_only`) +pub fn str_literal_to_char_literal( + cx: &LateContext<'_>, + expr: &Expr<'_>, + applicability: &mut Applicability, + ascii_only: bool, +) -> Option { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(r, style) = lit.node + && let string = r.as_str() + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 + { + let snip = snippet_with_applicability(cx, expr.span, string, applicability); + let ch = if let StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; + + let hint = format!( + "'{}'", + match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + } + ); + + Some(hint) + } else { + None + } +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/tests/ui/manual_pattern_char_comparison.fixed b/tests/ui/manual_pattern_char_comparison.fixed new file mode 100644 index 00000000000..588226b87e8 --- /dev/null +++ b/tests/ui/manual_pattern_char_comparison.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::manual_pattern_char_comparison)] + +struct NotStr; + +impl NotStr { + fn find(&self, _: impl FnMut(char) -> bool) {} +} + +fn main() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(['.', ',', '!', '?']); + sentence.split(['\n', 'X']); + sentence.split(['\n', 'X']); + sentence.splitn(3, 'X'); + sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); + let char_compare = 'X'; + sentence.splitn(3, char_compare); + sentence.split(['\n', 'X', 'Y']); + sentence.splitn(3, 'X'); + sentence.splitn(3, ['X', 'W']); + sentence.find('🎈'); + + let not_str = NotStr; + not_str.find(|c: char| c == 'X'); + + "".find(|c| c == 'a' || c > 'z'); + + let x = true; + "".find(|c| c == 'a' || x || c == 'b'); + + let d = 'd'; + "".find(|c| c == 'a' || d == 'b'); + + "".find(|c| match c { + 'a' | 'b' => true, + _ => c.is_ascii(), + }); + + "".find(|c| matches!(c, 'a' | 'b' if false)); + + "".find(|c| matches!(c, 'a' | '1'..'4')); + "".find(|c| c == 'a' || matches!(c, '1'..'4')); + macro_rules! m { + ($e:expr) => { + $e == '?' + }; + } + "".find(|c| m!(c)); +} diff --git a/tests/ui/manual_pattern_char_comparison.rs b/tests/ui/manual_pattern_char_comparison.rs new file mode 100644 index 00000000000..5078f3ee27f --- /dev/null +++ b/tests/ui/manual_pattern_char_comparison.rs @@ -0,0 +1,49 @@ +#![warn(clippy::manual_pattern_char_comparison)] + +struct NotStr; + +impl NotStr { + fn find(&self, _: impl FnMut(char) -> bool) {} +} + +fn main() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + sentence.split(|c: char| c == '\n' || c == 'X'); + sentence.split(|c| c == '\n' || c == 'X'); + sentence.splitn(3, |c: char| c == 'X'); + sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); + let char_compare = 'X'; + sentence.splitn(3, |c: char| c == char_compare); + sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + sentence.splitn(3, |c: char| matches!(c, 'X')); + sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + sentence.find(|c| c == '🎈'); + + let not_str = NotStr; + not_str.find(|c: char| c == 'X'); + + "".find(|c| c == 'a' || c > 'z'); + + let x = true; + "".find(|c| c == 'a' || x || c == 'b'); + + let d = 'd'; + "".find(|c| c == 'a' || d == 'b'); + + "".find(|c| match c { + 'a' | 'b' => true, + _ => c.is_ascii(), + }); + + "".find(|c| matches!(c, 'a' | 'b' if false)); + + "".find(|c| matches!(c, 'a' | '1'..'4')); + "".find(|c| c == 'a' || matches!(c, '1'..'4')); + macro_rules! m { + ($e:expr) => { + $e == '?' + }; + } + "".find(|c| m!(c)); +} diff --git a/tests/ui/manual_pattern_char_comparison.stderr b/tests/ui/manual_pattern_char_comparison.stderr new file mode 100644 index 00000000000..b6b51794a11 --- /dev/null +++ b/tests/ui/manual_pattern_char_comparison.stderr @@ -0,0 +1,59 @@ +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:11:31 + | +LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']` + | + = note: `-D clippy::manual-pattern-char-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_pattern_char_comparison)]` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:12:20 + | +LL | sentence.split(|c: char| c == '\n' || c == 'X'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:13:20 + | +LL | sentence.split(|c| c == '\n' || c == 'X'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:14:24 + | +LL | sentence.splitn(3, |c: char| c == 'X'); + | ^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:17:24 + | +LL | sentence.splitn(3, |c: char| c == char_compare); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `char_compare` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:18:20 + | +LL | sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X', 'Y']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:19:24 + | +LL | sentence.splitn(3, |c: char| matches!(c, 'X')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:20:24 + | +LL | sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['X', 'W']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:21:19 + | +LL | sentence.find(|c| c == '🎈'); + | ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index e8a0920b645..9a9aaba56ad 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,5 +1,6 @@ //@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] +#![allow(clippy::manual_pattern_char_comparison)] #![allow(clippy::useless_vec)] #![allow(dead_code)] extern crate option_helpers; diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index b5f84d23284..b5ef5534177 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:15:13 + --> tests/ui/search_is_some.rs:16:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -13,7 +13,7 @@ LL | | ).is_some(); = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:21:13 + --> tests/ui/search_is_some.rs:22:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -25,7 +25,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:27:13 + --> tests/ui/search_is_some.rs:28:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -37,13 +37,13 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:42:20 + --> tests/ui/search_is_some.rs:43:20 | LL | let _ = (0..1).find(some_closure).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:52:13 + --> tests/ui/search_is_some.rs:53:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -55,7 +55,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:58:13 + --> tests/ui/search_is_some.rs:59:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -67,7 +67,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:64:13 + --> tests/ui/search_is_some.rs:65:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -79,7 +79,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:79:13 + --> tests/ui/search_is_some.rs:80:13 | LL | let _ = (0..1).find(some_closure).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(some_closure)` -- cgit 1.4.1-3-g733a5 From 22710f33a8ad99be51bb69f91339f8d815bd9e92 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 12 Feb 2024 18:33:22 -0500 Subject: Add lint `manual_inspect` --- CHANGELOG.md | 1 + clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/manual_inspect.rs | 233 +++++++++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 24 +++ clippy_utils/src/source.rs | 27 +++- clippy_utils/src/ty.rs | 14 ++ tests/ui/copy_iterator.rs | 1 + tests/ui/copy_iterator.stderr | 2 +- tests/ui/manual_inspect.fixed | 174 +++++++++++++++++++++ tests/ui/manual_inspect.rs | 186 +++++++++++++++++++++++ tests/ui/manual_inspect.stderr | 182 ++++++++++++++++++++++ 12 files changed, 844 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/methods/manual_inspect.rs create mode 100644 tests/ui/manual_inspect.fixed create mode 100644 tests/ui/manual_inspect.rs create mode 100644 tests/ui/manual_inspect.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de3124bd3d..3973edddb6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5521,6 +5521,7 @@ Released 2018-09-13 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one +[`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index a3e7d0c3fa5..5327a125647 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -18,7 +18,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,77,0 { C_STR_LITERALS } - 1,76,0 { PTR_FROM_REF } + 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 88986f9ad72..8abe5d47b65 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -403,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MANUAL_C_STR_LITERALS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_INSPECT_INFO, crate::methods::MANUAL_IS_VARIANT_AND_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs new file mode 100644 index 00000000000..2f9b951c6a7 --- /dev/null +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -0,0 +1,233 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{get_source_text, with_leading_whitespace, SpanRange}; +use clippy_utils::ty::get_field_by_name; +use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; +use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; +use core::ops::ControlFlow; +use rustc_errors::Applicability; +use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_span::{sym, BytePos, Span, Symbol, DUMMY_SP}; + +use super::MANUAL_INSPECT; + +#[expect(clippy::too_many_lines)] +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: &Msrv) { + if let ExprKind::Closure(c) = arg.kind + && matches!(c.kind, ClosureKind::Closure) + && let typeck = cx.typeck_results() + && let Some(fn_id) = typeck.type_dependent_def_id(expr.hir_id) + && (is_diag_trait_item(cx, fn_id, sym::Iterator) + || (msrv.meets(msrvs::OPTION_RESULT_INSPECT) + && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result)))) + && let body = cx.tcx.hir().body(c.body) + && let [param] = body.params + && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind + && let arg_ty = typeck.node_type(arg_id) + && let ExprKind::Block(block, _) = body.value.kind + && let Some(final_expr) = block.expr + && !block.stmts.is_empty() + && path_to_local_id(final_expr, arg_id) + && typeck.expr_adjustments(final_expr).is_empty() + { + let mut requires_copy = false; + let mut requires_deref = false; + + // The number of unprocessed return expressions. + let mut ret_count = 0u32; + + // The uses for which processing is delayed until after the visitor. + let mut delayed = vec![]; + + let ctxt = arg.span.ctxt(); + let can_lint = for_each_expr_without_closures(block.stmts, |e| { + if let ExprKind::Closure(c) = e.kind { + // Nested closures don't need to treat returns specially. + let _: Option = for_each_expr(cx, cx.tcx.hir().body(c.body).value, |e| { + if path_to_local_id(e, arg_id) { + let (kind, same_ctxt) = check_use(cx, e); + match (kind, same_ctxt && e.span.ctxt() == ctxt) { + (_, false) | (UseKind::Deref | UseKind::Return(..), true) => { + requires_copy = true; + requires_deref = true; + }, + (UseKind::AutoBorrowed, true) => {}, + (UseKind::WillAutoDeref, true) => { + requires_copy = true; + }, + (kind, true) => delayed.push(kind), + } + } + ControlFlow::Continue(()) + }); + } else if matches!(e.kind, ExprKind::Ret(_)) { + ret_count += 1; + } else if path_to_local_id(e, arg_id) { + let (kind, same_ctxt) = check_use(cx, e); + match (kind, same_ctxt && e.span.ctxt() == ctxt) { + (UseKind::Return(..), false) => { + return ControlFlow::Break(()); + }, + (_, false) | (UseKind::Deref, true) => { + requires_copy = true; + requires_deref = true; + }, + (UseKind::AutoBorrowed, true) => {}, + (UseKind::WillAutoDeref, true) => { + requires_copy = true; + }, + (kind @ UseKind::Return(_), true) => { + ret_count -= 1; + delayed.push(kind); + }, + (kind, true) => delayed.push(kind), + } + } + ControlFlow::Continue(()) + }) + .is_none(); + + if ret_count != 0 { + // A return expression that didn't return the original value was found. + return; + } + + let mut edits = Vec::with_capacity(delayed.len() + 3); + let mut addr_of_edits = Vec::with_capacity(delayed.len()); + for x in delayed { + match x { + UseKind::Return(s) => edits.push((with_leading_whitespace(cx, s).set_span_pos(s), String::new())), + UseKind::Borrowed(s) => { + if let Some(src) = get_source_text(cx, s) + && let Some(src) = src.as_str() + && let trim_src = src.trim_start_matches([' ', '\t', '\n', '\r', '(']) + && trim_src.starts_with('&') + { + let range = s.into_range(); + #[expect(clippy::cast_possible_truncation)] + let start = BytePos(range.start.0 + (src.len() - trim_src.len()) as u32); + addr_of_edits.push(((start..BytePos(start.0 + 1)).set_span_pos(s), String::new())); + } else { + requires_copy = true; + requires_deref = true; + } + }, + UseKind::FieldAccess(name, e) => { + let Some(mut ty) = get_field_by_name(cx.tcx, arg_ty.peel_refs(), name) else { + requires_copy = true; + continue; + }; + let mut prev_expr = e; + + for (_, parent) in cx.tcx.hir().parent_iter(e.hir_id) { + if let Node::Expr(e) = parent { + match e.kind { + ExprKind::Field(_, name) + if let Some(fty) = get_field_by_name(cx.tcx, ty.peel_refs(), name.name) => + { + ty = fty; + prev_expr = e; + continue; + }, + ExprKind::AddrOf(BorrowKind::Ref, ..) => break, + _ if matches!( + typeck.expr_adjustments(prev_expr).first(), + Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)) + | Adjust::Deref(_), + .. + }) + ) => + { + break; + }, + _ => {}, + } + } + requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + break; + } + }, + // Already processed uses. + UseKind::AutoBorrowed | UseKind::WillAutoDeref | UseKind::Deref => {}, + } + } + + if can_lint + && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)) + // This case could be handled, but a fair bit of care would need to be taken. + && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env)) + { + if requires_deref { + edits.push((param.span.shrink_to_lo(), "&".into())); + } else { + edits.extend(addr_of_edits); + } + edits.push(( + name_span, + String::from(match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }), + )); + edits.push(( + with_leading_whitespace(cx, final_expr.span).set_span_pos(final_expr.span), + String::new(), + )); + let app = if edits.iter().any(|(s, _)| s.from_expansion()) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { + diag.multipart_suggestion("try", edits, app); + }); + } + } +} + +enum UseKind<'tcx> { + AutoBorrowed, + WillAutoDeref, + Deref, + Return(Span), + Borrowed(Span), + FieldAccess(Symbol, &'tcx Expr<'tcx>), +} + +/// Checks how the value is used, and whether it was used in the same `SyntaxContext`. +fn check_use<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (UseKind<'tcx>, bool) { + let use_cx = expr_use_ctxt(cx, e); + if use_cx + .adjustments + .first() + .is_some_and(|a| matches!(a.kind, Adjust::Deref(_))) + { + return (UseKind::AutoBorrowed, use_cx.same_ctxt); + } + let res = match use_cx.use_node(cx) { + ExprUseNode::Return(_) => { + if let ExprKind::Ret(Some(e)) = use_cx.node.expect_expr().kind { + UseKind::Return(e.span) + } else { + return (UseKind::Return(DUMMY_SP), false); + } + }, + ExprUseNode::FieldAccess(name) => UseKind::FieldAccess(name.name, use_cx.node.expect_expr()), + ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) + if use_cx + .adjustments + .first() + .is_some_and(|a| matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)))) => + { + UseKind::AutoBorrowed + }, + ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) => UseKind::WillAutoDeref, + ExprUseNode::AddrOf(BorrowKind::Ref, _) => UseKind::Borrowed(use_cx.node.expect_expr().span), + _ => UseKind::Deref, + }; + (res, use_cx.same_ctxt) +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6200716afbe..01438b8e8db 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -53,6 +53,7 @@ mod iter_with_drain; mod iterator_step_by_zero; mod join_absolute_paths; mod manual_c_str_literals; +mod manual_inspect; mod manual_is_variant_and; mod manual_next_back; mod manual_ok_or; @@ -4079,6 +4080,27 @@ declare_clippy_lint! { "is_ascii() called on a char iterator" } +declare_clippy_lint! { + /// ### What it does + /// Checks for uses of `map` which return the original item. + /// + /// ### Why is this bad? + /// `inspect` is both clearer in intent and shorter. + /// + /// ### Example + /// ```no_run + /// let x = Some(0).map(|x| { println!("{x}"); x }); + /// ``` + /// Use instead: + /// ```no_run + /// let x = Some(0).inspect(|x| println!("{x}")); + /// ``` + #[clippy::version = "1.78.0"] + pub MANUAL_INSPECT, + complexity, + "use of `map` returning the original item" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4244,6 +4266,7 @@ impl_lint_pass!(Methods => [ MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, + MANUAL_INSPECT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4747,6 +4770,7 @@ impl Methods { } } map_identity::check(cx, expr, recv, m_arg, name, span); + manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv); }, ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index b7ff7ebe910..69b122cbfad 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -14,8 +14,17 @@ use std::borrow::Cow; use std::ops::Range; /// A type which can be converted to the range portion of a `Span`. -pub trait SpanRange { +pub trait SpanRange: Sized { fn into_range(self) -> Range; + fn set_span_pos(self, sp: Span) -> Span { + let range = self.into_range(); + SpanData { + lo: range.start, + hi: range.end, + ..sp.data() + } + .span() + } } impl SpanRange for Span { fn into_range(self) -> Range { @@ -61,6 +70,22 @@ pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option Range { + #[expect(clippy::needless_pass_by_value, clippy::cast_possible_truncation)] + fn f(src: SourceFileRange, sp: Range) -> Range { + let Some(text) = &src.sf.src else { + return sp; + }; + let len = src.range.start - text[..src.range.start].trim_end().len(); + BytePos(sp.start.0 - len as u32)..sp.end + } + let sp = sp.into_range(); + match get_source_text(cx, sp.clone()) { + Some(src) => f(src, sp), + None => sp, + } +} + /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. pub fn expr_block( cx: &T, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 7d4332a3d9d..3f5ed73c3ef 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1349,3 +1349,17 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n None } } + +/// Get's the type of a field by name. +pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option> { + match *ty.kind() { + ty::Adt(def, args) if def.is_union() || def.is_struct() => def + .non_enum_variant() + .fields + .iter() + .find(|f| f.name == name) + .map(|f| f.ty(tcx, args)), + ty::Tuple(args) => name.as_str().parse::().ok().and_then(|i| args.get(i).copied()), + _ => None, + } +} diff --git a/tests/ui/copy_iterator.rs b/tests/ui/copy_iterator.rs index c0e5fc3e446..ea3a4face93 100644 --- a/tests/ui/copy_iterator.rs +++ b/tests/ui/copy_iterator.rs @@ -1,4 +1,5 @@ #![warn(clippy::copy_iterator)] +#![allow(clippy::manual_inspect)] #[derive(Copy, Clone)] struct Countdown(u8); diff --git a/tests/ui/copy_iterator.stderr b/tests/ui/copy_iterator.stderr index 533bddaadb5..990b1ce628d 100644 --- a/tests/ui/copy_iterator.stderr +++ b/tests/ui/copy_iterator.stderr @@ -1,5 +1,5 @@ error: you are implementing `Iterator` on a `Copy` type - --> tests/ui/copy_iterator.rs:6:1 + --> tests/ui/copy_iterator.rs:7:1 | LL | / impl Iterator for Countdown { LL | | diff --git a/tests/ui/manual_inspect.fixed b/tests/ui/manual_inspect.fixed new file mode 100644 index 00000000000..0e1b8fe3edb --- /dev/null +++ b/tests/ui/manual_inspect.fixed @@ -0,0 +1,174 @@ +#![warn(clippy::manual_inspect)] +#![allow(clippy::no_effect, clippy::op_ref)] + +fn main() { + let _ = Some(0).inspect(|&x| { + println!("{}", x); + }); + + let _ = Some(0).inspect(|&x| { + println!("{x}"); + }); + + let _ = Some(0).inspect(|&x| { + println!("{}", x * 5 + 1); + }); + + let _ = Some(0).inspect(|&x| { + if x == 0 { + panic!(); + } + }); + + let _ = Some(0).inspect(|&x| { + if &x == &0 { + let _y = x; + panic!(); + } + }); + + let _ = Some(0).map(|x| { + let y = x + 1; + if y > 5 { + return y; + } + x + }); + + { + #[derive(PartialEq)] + struct Foo(i32); + + let _ = Some(Foo(0)).map(|x| { + if x == Foo(0) { + panic!(); + } + x + }); + + let _ = Some(Foo(0)).map(|x| { + if &x == &Foo(0) { + let _y = x; + panic!(); + } + x + }); + } + + { + macro_rules! maybe_ret { + ($e:expr) => { + if $e == 0 { + return $e; + } + }; + } + + let _ = Some(0).map(|x| { + maybe_ret!(x); + x + }); + } + + let _ = Some((String::new(), 0u32)).inspect(|x| { + if x.1 == 0 { + let _x = x.1; + panic!(); + } + }); + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.0; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + let _ = Some(String::new()).inspect(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + return; + } + println!("test"); + }); + + let _ = Some(0).inspect(|&x| { + if x == 0 { + let _ = || { + let _x = x; + }; + panic!(); + } + }); + + { + use core::cell::Cell; + #[derive(Debug)] + struct Cell2(core::cell::Cell); + + let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { + x.0.set(1); + }); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + let y = &x; + if x.0.get() == 0 { + y.0.set(1) + } else { + println!("{x:?}"); + } + x + }); + } + + let _: Result<_, ()> = Ok(0).inspect(|&x| { + println!("{}", x); + }); + + let _: Result<(), _> = Err(0).inspect_err(|&x| { + println!("{}", x); + }); + + let _ = [0] + .into_iter() + .inspect(|&x| { + println!("{}", x); + }) + .count(); + + { + struct S(T); + impl S { + fn map(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + + fn map_err(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + } + + let _ = S(0).map(|x| { + println!("{}", x); + x + }); + + let _ = S(0).map_err(|x| { + println!("{}", x); + x + }); + } +} diff --git a/tests/ui/manual_inspect.rs b/tests/ui/manual_inspect.rs new file mode 100644 index 00000000000..94cdfe39140 --- /dev/null +++ b/tests/ui/manual_inspect.rs @@ -0,0 +1,186 @@ +#![warn(clippy::manual_inspect)] +#![allow(clippy::no_effect, clippy::op_ref)] + +fn main() { + let _ = Some(0).map(|x| { + println!("{}", x); + x + }); + + let _ = Some(0).map(|x| { + println!("{x}"); + x + }); + + let _ = Some(0).map(|x| { + println!("{}", x * 5 + 1); + x + }); + + let _ = Some(0).map(|x| { + if x == 0 { + panic!(); + } + x + }); + + let _ = Some(0).map(|x| { + if &x == &0 { + let _y = x; + panic!(); + } + x + }); + + let _ = Some(0).map(|x| { + let y = x + 1; + if y > 5 { + return y; + } + x + }); + + { + #[derive(PartialEq)] + struct Foo(i32); + + let _ = Some(Foo(0)).map(|x| { + if x == Foo(0) { + panic!(); + } + x + }); + + let _ = Some(Foo(0)).map(|x| { + if &x == &Foo(0) { + let _y = x; + panic!(); + } + x + }); + } + + { + macro_rules! maybe_ret { + ($e:expr) => { + if $e == 0 { + return $e; + } + }; + } + + let _ = Some(0).map(|x| { + maybe_ret!(x); + x + }); + } + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.1; + panic!(); + } + x + }); + + let _ = Some((String::new(), 0u32)).map(|x| { + if x.1 == 0 { + let _x = x.0; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + let _ = Some(String::new()).map(|x| { + if x.is_empty() { + let _ = || { + let _x = &x; + }; + return x; + } + println!("test"); + x + }); + + let _ = Some(0).map(|x| { + if x == 0 { + let _ = || { + let _x = x; + }; + panic!(); + } + x + }); + + { + use core::cell::Cell; + #[derive(Debug)] + struct Cell2(core::cell::Cell); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + x.0.set(1); + x + }); + + let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + let y = &x; + if x.0.get() == 0 { + y.0.set(1) + } else { + println!("{x:?}"); + } + x + }); + } + + let _: Result<_, ()> = Ok(0).map(|x| { + println!("{}", x); + x + }); + + let _: Result<(), _> = Err(0).map_err(|x| { + println!("{}", x); + x + }); + + let _ = [0] + .into_iter() + .map(|x| { + println!("{}", x); + x + }) + .count(); + + { + struct S(T); + impl S { + fn map(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + + fn map_err(self, f: impl FnOnce(T) -> U) -> S { + S(f(self.0)) + } + } + + let _ = S(0).map(|x| { + println!("{}", x); + x + }); + + let _ = S(0).map_err(|x| { + println!("{}", x); + x + }); + } +} diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr new file mode 100644 index 00000000000..efdf115b84e --- /dev/null +++ b/tests/ui/manual_inspect.stderr @@ -0,0 +1,182 @@ +error: + --> tests/ui/manual_inspect.rs:5:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | + = note: `-D clippy::manual-inspect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_inspect)]` +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{}", x); + | + +error: + --> tests/ui/manual_inspect.rs:10:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{x}"); + | + +error: + --> tests/ui/manual_inspect.rs:15:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL ~ println!("{}", x * 5 + 1); + | + +error: + --> tests/ui/manual_inspect.rs:20:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if x == 0 { +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:27:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if &x == &0 { +LL | let _y = x; +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:78:41 + | +LL | let _ = Some((String::new(), 0u32)).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some((String::new(), 0u32)).inspect(|x| { +LL | if x.1 == 0 { +LL | let _x = x.1; +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:104:33 + | +LL | let _ = Some(String::new()).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(String::new()).inspect(|x| { +LL | if x.is_empty() { +LL | let _ = || { +LL ~ let _x = x; +LL | }; +LL ~ return; +LL | } +LL ~ println!("test"); + | + +error: + --> tests/ui/manual_inspect.rs:115:21 + | +LL | let _ = Some(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(0).inspect(|&x| { +LL | if x == 0 { + ... +LL | panic!(); +LL ~ } + | + +error: + --> tests/ui/manual_inspect.rs:130:46 + | +LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { +LL ~ x.0.set(1); + | + +error: + --> tests/ui/manual_inspect.rs:146:34 + | +LL | let _: Result<_, ()> = Ok(0).map(|x| { + | ^^^ + | +help: try + | +LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { +LL ~ println!("{}", x); + | + +error: + --> tests/ui/manual_inspect.rs:151:35 + | +LL | let _: Result<(), _> = Err(0).map_err(|x| { + | ^^^^^^^ + | +help: try + | +LL ~ let _: Result<(), _> = Err(0).inspect_err(|&x| { +LL ~ println!("{}", x); + | + +error: this call to `map()` won't have an effect on the call to `count()` + --> tests/ui/manual_inspect.rs:156:13 + | +LL | let _ = [0] + | _____________^ +LL | | .into_iter() +LL | | .map(|x| { +LL | | println!("{}", x); +LL | | x +LL | | }) +LL | | .count(); + | |________________^ + | + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` + = note: `-D clippy::suspicious-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` + +error: + --> tests/ui/manual_inspect.rs:158:10 + | +LL | .map(|x| { + | ^^^ + | +help: try + | +LL ~ .inspect(|&x| { +LL ~ println!("{}", x); + | + +error: aborting due to 13 previous errors + -- cgit 1.4.1-3-g733a5 From ed9ccf66e9b61406176d57499e91c3bf773e95da Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 20 Jun 2024 00:09:31 +0200 Subject: [`unnecessary_to_owned`]: catch to_owned from byte slice to string --- clippy_lints/src/methods/unnecessary_to_owned.rs | 70 +++++++++++++++++++++++- clippy_utils/src/paths.rs | 1 + tests/ui/unnecessary_to_owned.fixed | 19 +++++++ tests/ui/unnecessary_to_owned.rs | 19 +++++++ tests/ui/unnecessary_to_owned.stderr | 60 ++++++++++++++++---- 5 files changed, 154 insertions(+), 15 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index ae9aa83efd6..5d899415d77 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,13 +1,15 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs, }; use clippy_utils::visitors::find_all_ret_expressions; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; +use clippy_utils::{ + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty, +}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -52,6 +54,9 @@ pub fn check<'tcx>( if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) { return; } + if check_string_from_utf8(cx, expr, receiver) { + return; + } check_other_call_arg(cx, expr, method_name, receiver); } } else { @@ -240,6 +245,65 @@ fn check_into_iter_call_arg( false } +/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`, +/// which can be written as just `std::str::from_utf8(bytes).unwrap()`. +fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool { + if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr) + && !arg.span.from_expansion() + && let ExprKind::Call(callee, _) = call.kind + && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8)) + && let Some(unwrap_call) = get_parent_expr(cx, call) + && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind + && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect) + && let Some(ref_string) = get_parent_expr(cx, unwrap_call) + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind + && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string) + // `&...` creates a `&String`, so only actually lint if this coerces to a `&str` + && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) + { + span_lint_and_then( + cx, + UNNECESSARY_TO_OWNED, + ref_string.span, + "allocating a new `String` only to create a temporary `&str` from it", + |diag| { + let arg_suggestion = format!( + "{borrow}{recv_snippet}", + recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."), + borrow = if cx.typeck_results().expr_ty(receiver).is_ref() { + "" + } else { + // If not already a reference, prefix with a borrow so that it can coerce to one + "&" + } + ); + + diag.multipart_suggestion( + "convert from `&[u8]` to `&str` directly", + vec![ + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^^^^ + (callee.span, "core::str::from_utf8".into()), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^ + ( + ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()), + String::new(), + ), + // `&String::from_utf8(bytes.to_vec()).unwrap()` + // ^^^^^^^^^^^^^^ + (arg.span, arg_suggestion), + ], + Applicability::MachineApplicable, + ); + }, + ); + true + } else { + false + } +} + /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9bf068ee3cd..bf72194f370 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -88,6 +88,7 @@ pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern" pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"]; pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; +pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 1afa5ab54c4..fdcac8fb08d 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x")); require_str(&String::from("x")); require_slice(&[String::from("x")]); + + let slice = [0u8; 1024]; + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index aa88dde43bf..10a9727a9a7 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -157,6 +157,25 @@ fn main() { require_path(&std::path::PathBuf::from("x").to_path_buf()); require_str(&String::from("x").to_string()); require_slice(&[String::from("x")].to_owned()); + + let slice = [0u8; 1024]; + let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + // Expression is of type `&String`, can't suggest `str::from_utf8` here + let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); + macro_rules! arg_from_macro { + () => { + b"foo".to_vec() + }; + } + macro_rules! string_from_utf8_from_macro { + () => { + &String::from_utf8(b"foo".to_vec()).unwrap() + }; + } + let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap(); + let _ref_str: &str = string_from_utf8_from_macro!(); } fn require_c_str(_: &CStr) {} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 2829f3cd6e9..511b4ae119f 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -477,8 +477,44 @@ error: unnecessary use of `to_owned` LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:162:26 + | +LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); +LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + | + +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:163:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); +LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + | + +error: allocating a new `String` only to create a temporary `&str` from it + --> tests/ui/unnecessary_to_owned.rs:164:26 + | +LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert from `&[u8]` to `&str` directly + | +LL - let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); +LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + | + error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:202:14 + --> tests/ui/unnecessary_to_owned.rs:221:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -494,64 +530,64 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:225:14 + --> tests/ui/unnecessary_to_owned.rs:244:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:230:14 + --> tests/ui/unnecessary_to_owned.rs:249:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:278:24 + --> tests/ui/unnecessary_to_owned.rs:297:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:387:12 + --> tests/ui/unnecessary_to_owned.rs:406:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:530:37 + --> tests/ui/unnecessary_to_owned.rs:549:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:540:18 + --> tests/ui/unnecessary_to_owned.rs:559:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:544:14 + --> tests/ui/unnecessary_to_owned.rs:563:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:545:14 + --> tests/ui/unnecessary_to_owned.rs:564:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:550:14 + --> tests/ui/unnecessary_to_owned.rs:569:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:551:14 + --> tests/ui/unnecessary_to_owned.rs:570:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 85 previous errors +error: aborting due to 88 previous errors -- cgit 1.4.1-3-g733a5 From 2f9f204123b857606e7b65d217a3b71920fccf20 Mon Sep 17 00:00:00 2001 From: vohoanglong0107 Date: Wed, 28 Feb 2024 04:31:41 +0000 Subject: feat: unnecessary_min_max lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 30 ++++ clippy_lints/src/methods/unnecessary_min_or_max.rs | 90 ++++++++++ clippy_utils/src/consts.rs | 17 +- tests/ui/auxiliary/external_consts.rs | 1 + tests/ui/cast.rs | 1 + tests/ui/cast.stderr | 184 ++++++++++----------- tests/ui/unnecessary_min_or_max.fixed | 67 ++++++++ tests/ui/unnecessary_min_or_max.rs | 67 ++++++++ tests/ui/unnecessary_min_or_max.stderr | 107 ++++++++++++ 11 files changed, 472 insertions(+), 94 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_min_or_max.rs create mode 100644 tests/ui/auxiliary/external_consts.rs create mode 100644 tests/ui/unnecessary_min_or_max.fixed create mode 100644 tests/ui/unnecessary_min_or_max.rs create mode 100644 tests/ui/unnecessary_min_or_max.stderr (limited to 'clippy_lints/src/methods') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3973edddb6d..fe9fbd486c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5917,6 +5917,7 @@ Released 2018-09-13 [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor +[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 8abe5d47b65..3b3d0db79dc 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -471,6 +471,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, + crate::methods::UNNECESSARY_MIN_OR_MAX_INFO, crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 01438b8e8db..1408f454820 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -117,6 +117,7 @@ mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; +mod unnecessary_min_or_max; mod unnecessary_result_map_or_else; mod unnecessary_sort_by; mod unnecessary_to_owned; @@ -3945,6 +3946,31 @@ declare_clippy_lint! { "cloning an `Option` via `as_ref().cloned()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for unnecessary calls to `min()` or `max()` in the following cases + /// - Either both side is constant + /// - One side is clearly larger than the other, like i32::MIN and an i32 variable + /// + /// ### Why is this bad? + /// + /// In the aformentioned cases it is not necessary to call `min()` or `max()` + /// to compare values, it may even cause confusion. + /// + /// ### Example + /// ```no_run + /// let _ = 0.min(7_u32); + /// ``` + /// Use instead: + /// ```no_run + /// let _ = 0; + /// ``` + #[clippy::version = "1.78.0"] + pub UNNECESSARY_MIN_OR_MAX, + complexity, + "using 'min()/max()' when there is no need for it" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `.map_or_else()` "map closure" for `Result` type. @@ -4267,6 +4293,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_GET_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, MANUAL_INSPECT, + UNNECESSARY_MIN_OR_MAX, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4566,6 +4593,9 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, + ("min" | "max", [arg]) => { + unnecessary_min_or_max::check(cx, expr, name, recv, arg); + }, ("drain", ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs new file mode 100644 index 00000000000..78851d4122f --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -0,0 +1,90 @@ +use std::cmp::Ordering; + +use super::UNNECESSARY_MIN_OR_MAX; +use clippy_utils::diagnostics::span_lint_and_sugg; + +use clippy_utils::consts::{constant, constant_with_source, Constant, ConstantSource, FullInt}; +use clippy_utils::source::snippet; + +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::Span; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + name: &str, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) { + let typeck_results = cx.typeck_results(); + if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = + constant_with_source(cx, typeck_results, recv) + && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = + constant_with_source(cx, typeck_results, arg) + { + let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { + return; + }; + + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, recv) { + let ord = match extrema { + Extrema::Minimum => Ordering::Less, + Extrema::Maximum => Ordering::Greater, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, arg) { + let ord = match extrema { + Extrema::Minimum => Ordering::Greater, + Extrema::Maximum => Ordering::Less, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } +} + +fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) { + let cmp_str = if order.is_ge() { "smaller" } else { "greater" }; + + let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) { + snippet(cx, rhs, "..") + } else { + snippet(cx, lhs, "..") + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_MIN_OR_MAX, + expr.span, + format!( + "`{}` is never {} than `{}` and has therefore no effect", + snippet(cx, lhs, ".."), + cmp_str, + snippet(cx, rhs, "..") + ), + "try", + suggested_value.to_string(), + Applicability::MachineApplicable, + ); +} + +#[derive(Debug)] +enum Extrema { + Minimum, + Maximum, +} +fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + let ty = cx.typeck_results().expr_ty(expr); + + let cv = constant(cx, cx.typeck_results(), expr)?; + + match (cv.int_value(cx, ty)?, ty.kind()) { + (FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum), + (FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(0), &ty::Uint(_)) => Some(Extrema::Minimum), + _ => None, + } +} diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index cfd142fe1ff..8f6389ee077 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1,5 +1,6 @@ #![allow(clippy::float_cmp)] +use crate::macros::HirNode; use crate::source::{get_source_text, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; @@ -15,7 +16,7 @@ use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::SyntaxContext; +use rustc_span::{sym, SyntaxContext}; use rustc_target::abi::Size; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; @@ -302,6 +303,8 @@ pub enum ConstantSource { Local, /// The value is dependent on a defined constant. Constant, + /// The value is dependent on a constant defined in `core` crate. + CoreConstant, } impl ConstantSource { pub fn is_local(&self) -> bool { @@ -415,9 +418,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { + let is_core_crate = if let Some(def_id) = self.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() { + self.lcx.tcx.crate_name(def_id.krate) == sym::core + } else { + false + }; self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; - this.source = ConstantSource::Constant; + // If source is already Constant we wouldn't want to override it with CoreConstant + this.source = if is_core_crate && !matches!(this.source, ConstantSource::Constant) { + ConstantSource::CoreConstant + } else { + ConstantSource::Constant + }; Some(result) }) }, diff --git a/tests/ui/auxiliary/external_consts.rs b/tests/ui/auxiliary/external_consts.rs new file mode 100644 index 00000000000..1885ba341f5 --- /dev/null +++ b/tests/ui/auxiliary/external_consts.rs @@ -0,0 +1 @@ +pub const MAGIC_NUMBER: i32 = 1; diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 453d62ce607..351325e9b00 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -12,6 +12,7 @@ #![allow( clippy::cast_abs_to_unsigned, clippy::no_effect, + clippy::unnecessary_min_or_max, clippy::unnecessary_operation, clippy::unnecessary_literal_unwrap, clippy::identity_op diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 43c0d8f4ed7..f14c3c8d81d 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:23:5 + --> tests/ui/cast.rs:24:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:27:5 + --> tests/ui/cast.rs:28:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:29:5 + --> tests/ui/cast.rs:30:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:32:5 + --> tests/ui/cast.rs:33:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:35:5 + --> tests/ui/cast.rs:36:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:37:5 + --> tests/ui/cast.rs:38:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:41:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:43:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:43:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:46:5 + --> tests/ui/cast.rs:47:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:48:5 + --> tests/ui/cast.rs:49:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:50:5 + --> tests/ui/cast.rs:51:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:52:5 + --> tests/ui/cast.rs:53:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:55:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:55:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:58:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:58:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:58:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:62:22 + --> tests/ui/cast.rs:63:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:64:9 + --> tests/ui/cast.rs:65:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:66:9 + --> tests/ui/cast.rs:67:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:68:9 + --> tests/ui/cast.rs:69:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:68:9 + --> tests/ui/cast.rs:69:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:73:5 + --> tests/ui/cast.rs:74:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:76:5 + --> tests/ui/cast.rs:77:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:78:5 + --> tests/ui/cast.rs:79:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:80:5 + --> tests/ui/cast.rs:81:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:83:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:85:5 + --> tests/ui/cast.rs:86:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:89:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:89:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:93:5 + --> tests/ui/cast.rs:94:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:93:5 + --> tests/ui/cast.rs:94:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:97:5 + --> tests/ui/cast.rs:98:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:102:5 + --> tests/ui/cast.rs:103:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:106:5 + --> tests/ui/cast.rs:107:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:110:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:110:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:114:5 + --> tests/ui/cast.rs:115:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:117:5 + --> tests/ui/cast.rs:118:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:128:5 + --> tests/ui/cast.rs:129:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:132:5 + --> tests/ui/cast.rs:133:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:133:5 + --> tests/ui/cast.rs:134:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:140:5 + --> tests/ui/cast.rs:141:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:155:5 + --> tests/ui/cast.rs:156:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:206:5 + --> tests/ui/cast.rs:207:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:220:5 + --> tests/ui/cast.rs:221:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:243:21 + --> tests/ui/cast.rs:244:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:245:21 + --> tests/ui/cast.rs:246:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:287:21 + --> tests/ui/cast.rs:288:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:289:21 + --> tests/ui/cast.rs:290:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:306:21 + --> tests/ui/cast.rs:307:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:325:21 + --> tests/ui/cast.rs:326:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:372:21 + --> tests/ui/cast.rs:373:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:383:13 + --> tests/ui/cast.rs:384:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:387:13 + --> tests/ui/cast.rs:388:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:399:9 + --> tests/ui/cast.rs:400:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:404:32 + --> tests/ui/cast.rs:405:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:5 + --> tests/ui/cast.rs:407:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:407:5 + --> tests/ui/cast.rs:408:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:412:5 + --> tests/ui/cast.rs:413:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:414:5 + --> tests/ui/cast.rs:415:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:417:5 + --> tests/ui/cast.rs:418:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:421:5 + --> tests/ui/cast.rs:422:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:422:5 + --> tests/ui/cast.rs:423:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:426:5 + --> tests/ui/cast.rs:427:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:429:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:429:5 + --> tests/ui/cast.rs:430:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:432:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:431:6 + --> tests/ui/cast.rs:432:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:434:5 + --> tests/ui/cast.rs:435:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:436:5 + --> tests/ui/cast.rs:437:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:440:5 + --> tests/ui/cast.rs:441:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:442:5 + --> tests/ui/cast.rs:443:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:445:9 + --> tests/ui/cast.rs:446:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:446:9 + --> tests/ui/cast.rs:447:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:449:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:451:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:451:9 + --> tests/ui/cast.rs:452:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:454:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:456:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:9 + --> tests/ui/cast.rs:457:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:459:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:460:9 + --> tests/ui/cast.rs:461:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:462:9 + --> tests/ui/cast.rs:463:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:470:21 + --> tests/ui/cast.rs:471:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:471:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:472:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:481:5 + --> tests/ui/cast.rs:482:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:481:5 + --> tests/ui/cast.rs:482:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:496:5 + --> tests/ui/cast.rs:497:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:498:5 + --> tests/ui/cast.rs:499:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_min_or_max.fixed b/tests/ui/unnecessary_min_or_max.fixed new file mode 100644 index 00000000000..392f6dd1fee --- /dev/null +++ b/tests/ui/unnecessary_min_or_max.fixed @@ -0,0 +1,67 @@ +//@aux-build:external_consts.rs + +#![allow(unused)] +#![warn(clippy::unnecessary_min_or_max)] +#![allow(clippy::identity_op)] + +extern crate external_consts; + +const X: i32 = 1; + +fn main() { + // Both are Literals + let _ = (-6_i32); + let _ = 9; + let _ = 6; + let _ = 9_u32; + let _ = 6; + let _ = 7_u8; + + let x: u32 = 42; + // unsigned with zero + let _ = 0; + let _ = x; + let _ = 0_u32; + let _ = x; + + let x: i32 = 42; + // signed MIN + let _ = i32::MIN; + let _ = x; + let _ = i32::MIN; + let _ = x; + + let _ = i32::MIN - 0; + let _ = x; + + let _ = i32::MIN - 0; + + // The below cases shouldn't be lint + let mut min = u32::MAX; + for _ in 0..1000 { + min = min.min(random_u32()); + } + + let _ = 2.min(external_consts::MAGIC_NUMBER); + let _ = 2.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(2); + let _ = external_consts::MAGIC_NUMBER.max(2); + + let _ = X.min(external_consts::MAGIC_NUMBER); + let _ = X.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(X); + let _ = external_consts::MAGIC_NUMBER.max(X); + + let _ = X.max(12); + let _ = X.min(12); + let _ = 12.min(X); + let _ = 12.max(X); + let _ = (X + 1).max(12); + let _ = (X + 1).min(12); + let _ = 12.min(X - 1); + let _ = 12.max(X - 1); +} +fn random_u32() -> u32 { + // random number generator + 0 +} diff --git a/tests/ui/unnecessary_min_or_max.rs b/tests/ui/unnecessary_min_or_max.rs new file mode 100644 index 00000000000..b03755e6d23 --- /dev/null +++ b/tests/ui/unnecessary_min_or_max.rs @@ -0,0 +1,67 @@ +//@aux-build:external_consts.rs + +#![allow(unused)] +#![warn(clippy::unnecessary_min_or_max)] +#![allow(clippy::identity_op)] + +extern crate external_consts; + +const X: i32 = 1; + +fn main() { + // Both are Literals + let _ = (-6_i32).min(9); + let _ = (-6_i32).max(9); + let _ = 9_u32.min(6); + let _ = 9_u32.max(6); + let _ = 6.min(7_u8); + let _ = 6.max(7_u8); + + let x: u32 = 42; + // unsigned with zero + let _ = 0.min(x); + let _ = 0.max(x); + let _ = x.min(0_u32); + let _ = x.max(0_u32); + + let x: i32 = 42; + // signed MIN + let _ = i32::MIN.min(x); + let _ = i32::MIN.max(x); + let _ = x.min(i32::MIN); + let _ = x.max(i32::MIN); + + let _ = x.min(i32::MIN - 0); + let _ = x.max(i32::MIN); + + let _ = x.min(i32::MIN - 0); + + // The below cases shouldn't be lint + let mut min = u32::MAX; + for _ in 0..1000 { + min = min.min(random_u32()); + } + + let _ = 2.min(external_consts::MAGIC_NUMBER); + let _ = 2.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(2); + let _ = external_consts::MAGIC_NUMBER.max(2); + + let _ = X.min(external_consts::MAGIC_NUMBER); + let _ = X.max(external_consts::MAGIC_NUMBER); + let _ = external_consts::MAGIC_NUMBER.min(X); + let _ = external_consts::MAGIC_NUMBER.max(X); + + let _ = X.max(12); + let _ = X.min(12); + let _ = 12.min(X); + let _ = 12.max(X); + let _ = (X + 1).max(12); + let _ = (X + 1).min(12); + let _ = 12.min(X - 1); + let _ = 12.max(X - 1); +} +fn random_u32() -> u32 { + // random number generator + 0 +} diff --git a/tests/ui/unnecessary_min_or_max.stderr b/tests/ui/unnecessary_min_or_max.stderr new file mode 100644 index 00000000000..f5cd31fbaf2 --- /dev/null +++ b/tests/ui/unnecessary_min_or_max.stderr @@ -0,0 +1,107 @@ +error: `(-6_i32)` is never greater than `9` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:13:13 + | +LL | let _ = (-6_i32).min(9); + | ^^^^^^^^^^^^^^^ help: try: `(-6_i32)` + | + = note: `-D clippy::unnecessary-min-or-max` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min_or_max)]` + +error: `(-6_i32)` is never greater than `9` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:14:13 + | +LL | let _ = (-6_i32).max(9); + | ^^^^^^^^^^^^^^^ help: try: `9` + +error: `9_u32` is never smaller than `6` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:15:13 + | +LL | let _ = 9_u32.min(6); + | ^^^^^^^^^^^^ help: try: `6` + +error: `9_u32` is never smaller than `6` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:16:13 + | +LL | let _ = 9_u32.max(6); + | ^^^^^^^^^^^^ help: try: `9_u32` + +error: `6` is never greater than `7_u8` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:17:13 + | +LL | let _ = 6.min(7_u8); + | ^^^^^^^^^^^ help: try: `6` + +error: `6` is never greater than `7_u8` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:18:13 + | +LL | let _ = 6.max(7_u8); + | ^^^^^^^^^^^ help: try: `7_u8` + +error: `0` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:22:13 + | +LL | let _ = 0.min(x); + | ^^^^^^^^ help: try: `0` + +error: `0` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:23:13 + | +LL | let _ = 0.max(x); + | ^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `0_u32` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:24:13 + | +LL | let _ = x.min(0_u32); + | ^^^^^^^^^^^^ help: try: `0_u32` + +error: `x` is never smaller than `0_u32` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:25:13 + | +LL | let _ = x.max(0_u32); + | ^^^^^^^^^^^^ help: try: `x` + +error: `i32::MIN` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:29:13 + | +LL | let _ = i32::MIN.min(x); + | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: `i32::MIN` is never greater than `x` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:30:13 + | +LL | let _ = i32::MIN.max(x); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:31:13 + | +LL | let _ = x.min(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:32:13 + | +LL | let _ = x.max(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:34:13 + | +LL | let _ = x.min(i32::MIN - 0); + | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` + +error: `x` is never smaller than `i32::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:35:13 + | +LL | let _ = x.max(i32::MIN); + | ^^^^^^^^^^^^^^^ help: try: `x` + +error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:37:13 + | +LL | let _ = x.min(i32::MIN - 0); + | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` + +error: aborting due to 17 previous errors + -- cgit 1.4.1-3-g733a5 From 4baae5d8b3f5b681097c5afe9ad3e1494f223b1b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 19 Jun 2024 20:43:33 -0400 Subject: Add new `Span` utils to avoid both allocating and compressing/decompressing spans. --- clippy_lints/src/cognitive_complexity.rs | 22 +-- clippy_lints/src/copies.rs | 16 +- clippy_lints/src/implicit_hasher.rs | 40 ++--- clippy_lints/src/matches/single_match.rs | 4 +- clippy_lints/src/methods/manual_inspect.rs | 31 ++-- clippy_lints/src/missing_doc.rs | 7 +- clippy_lints/src/multiple_bound_locations.rs | 8 +- clippy_lints/src/needless_else.rs | 16 +- clippy_lints/src/needless_if.rs | 24 ++- clippy_lints/src/non_octal_unix_permissions.rs | 12 +- clippy_lints/src/octal_escapes.rs | 15 +- clippy_lints/src/ranges.rs | 19 ++- clippy_utils/src/consts.rs | 8 +- clippy_utils/src/hir_utils.rs | 6 +- clippy_utils/src/source.rs | 224 ++++++++++++++++++++----- 15 files changed, 296 insertions(+), 156 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index e41abf42234..60815f4f2af 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,7 +1,7 @@ //! calculate cognitive complexity and warn about overly complex functions use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; @@ -12,7 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -50,7 +50,6 @@ impl CognitiveComplexity { impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl CognitiveComplexity { - #[expect(clippy::cast_possible_truncation)] fn check<'tcx>( &mut self, cx: &LateContext<'tcx>, @@ -100,17 +99,12 @@ impl CognitiveComplexity { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { let header_span = body_span.with_hi(decl.output.span().lo()); - let pos = snippet_opt(cx, header_span).and_then(|snip| { - let low_offset = snip.find('|')?; - let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?; - let low = header_span.lo() + BytePos(low_offset as u32); - let high = low + BytePos(high_offset as u32 + 1); - - Some((low, high)) - }); - - if let Some((low, high)) = pos { - Span::new(low, high, header_span.ctxt(), header_span.parent()) + #[expect(clippy::range_plus_one)] + if let Some(range) = header_span.map_range(cx, |src, range| { + let mut idxs = src.get(range.clone())?.match_indices('|'); + Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) + }) { + range.with_ctxt(header_span.ctxt()) } else { return; } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 480df675d75..d896452be92 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; -use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; +use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Span, Symbol}; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; declare_clippy_lint! { @@ -266,12 +266,12 @@ fn lint_branches_sharing_code<'tcx>( let span = span.with_hi(last_block.span.hi()); // Improve formatting if the inner block has indention (i.e. normal Rust formatting) - let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent()); - let span = if snippet_opt(cx, test_span).map_or(false, |snip| snip == " ") { - span.with_lo(test_span.lo()) - } else { - span - }; + let span = span + .map_range(cx, |src, range| { + (range.start > 4 && src.get(range.start - 4..range.start)? == " ") + .then_some(range.start - 4..range.end) + }) + .map_or(span, |range| range.with_ctxt(span.ctxt())); (span, suggestion.to_string()) }); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index ca830af3b2f..344a04e6e7e 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -59,10 +59,8 @@ declare_clippy_lint! { declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]); impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { - #[expect(clippy::cast_possible_truncation, clippy::too_many_lines)] + #[expect(clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - use rustc_span::BytePos; - fn suggestion( cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, @@ -123,10 +121,11 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { } let generics_suggestion_span = impl_.generics.span.substitute_dummy({ - let pos = snippet_opt(cx, item.span.until(target.span())) - .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4))); - if let Some(pos) = pos { - Span::new(pos, pos, item.span.ctxt(), item.span.parent()) + let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| { + Some(src.get(range.clone())?.find("impl")? + 4..range.end) + }); + if let Some(range) = range { + range.with_ctxt(item.span.ctxt()) } else { return; } @@ -163,21 +162,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ - let pos = snippet_opt( - cx, - Span::new( - item.span.lo(), - body.params[0].pat.span.lo(), - item.span.ctxt(), - item.span.parent(), - ), - ) - .and_then(|snip| { - let i = snip.find("fn")?; - Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32)) - }) - .expect("failed to create span for type parameters"); - Span::new(pos, pos, item.span.ctxt(), item.span.parent()) + let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| { + let (pre, post) = src.get(range.clone())?.split_once("fn")?; + let pos = post.find('(')? + pre.len() + 2; + Some(pos..pos) + }); + if let Some(range) = range { + range.with_ctxt(item.span.ctxt()) + } else { + return; + } }); let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 69791414f72..99fdbcff890 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, get_source_text, snippet}; +use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; use core::cmp::max; @@ -17,7 +17,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - if let Some(ff) = get_source_text(cx, span) + if let Some(ff) = span.get_source_text(cx) && let Some(text) = ff.as_str() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index 2f9b951c6a7..e3ce64c246a 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{get_source_text, with_leading_whitespace, SpanRange}; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_span::{sym, BytePos, Span, Symbol, DUMMY_SP}; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use super::MANUAL_INSPECT; @@ -98,17 +98,19 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: let mut addr_of_edits = Vec::with_capacity(delayed.len()); for x in delayed { match x { - UseKind::Return(s) => edits.push((with_leading_whitespace(cx, s).set_span_pos(s), String::new())), + UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), UseKind::Borrowed(s) => { - if let Some(src) = get_source_text(cx, s) - && let Some(src) = src.as_str() - && let trim_src = src.trim_start_matches([' ', '\t', '\n', '\r', '(']) - && trim_src.starts_with('&') - { - let range = s.into_range(); - #[expect(clippy::cast_possible_truncation)] - let start = BytePos(range.start.0 + (src.len() - trim_src.len()) as u32); - addr_of_edits.push(((start..BytePos(start.0 + 1)).set_span_pos(s), String::new())); + #[expect(clippy::range_plus_one)] + let range = s.map_range(cx, |src, range| { + let src = src.get(range.clone())?; + let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); + trimmed.starts_with('&').then(|| { + let pos = range.start + src.len() - trimmed.len(); + pos..pos + 1 + }) + }); + if let Some(range) = range { + addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new())); } else { requires_copy = true; requires_deref = true; @@ -174,7 +176,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: }), )); edits.push(( - with_leading_whitespace(cx, final_expr.span).set_span_pos(final_expr.span), + final_expr + .span + .with_leading_whitespace(cx) + .with_ctxt(final_expr.span.ctxt()), String::new(), )); let app = if edits.iter().any(|(s, _)| s.from_expansion()) { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ca344dc5c81..250fd5cbd48 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -8,7 +8,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -266,8 +266,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool { - let Some(snippet) = snippet_opt(cx, search_span) else { - return false; - }; - snippet.lines().rev().any(|line| line.trim().starts_with("///")) + search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///"))) } diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index d608f3bf7b4..d276e29bace 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; declare_clippy_lint! { /// ### What it does @@ -54,8 +54,10 @@ impl EarlyLintPass for MultipleBoundLocations { match clause { WherePredicate::BoundPredicate(pred) => { if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty()) - && let Some(name) = snippet_opt(cx, pred.bounded_ty.span) - && let Some(bound_span) = generic_params_with_bounds.get(name.as_str()) + && let Some(Some(bound_span)) = pred + .bounded_ty + .span + .with_source_text(cx, |src| generic_params_with_bounds.get(src)) { emit_lint(cx, *bound_span, pred.bounded_ty.span); } diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index b6aad69d166..f8bb72a16db 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, trim_span}; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -41,16 +41,16 @@ impl EarlyLintPass for NeedlessElse { && !expr.span.from_expansion() && !else_clause.span.from_expansion() && block.stmts.is_empty() - && let Some(trimmed) = expr.span.trim_start(then_block.span) - && let span = trim_span(cx.sess().source_map(), trimmed) - && let Some(else_snippet) = snippet_opt(cx, span) - // Ignore else blocks that contain comments or #[cfg]s - && !else_snippet.contains(['/', '#']) + && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) + && range.clone().check_source_text(cx, |src| { + // Ignore else blocks that contain comments or #[cfg]s + !src.contains(['/', '#']) + }) { span_lint_and_sugg( cx, NEEDLESS_ELSE, - span, + range.with_ctxt(expr.span.ctxt()), "this `else` branch is empty", "you can remove it", String::new(), diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 51bee4b51f6..1d6233d432a 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -39,18 +39,24 @@ declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]); impl LateLintPass<'_> for NeedlessIf { fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) { if let StmtKind::Expr(expr) = stmt.kind - && let Some(If {cond, then, r#else: None }) = If::hir(expr) + && let Some(If { + cond, + then, + r#else: None, + }) = If::hir(expr) && let ExprKind::Block(block, ..) = then.kind && block.stmts.is_empty() && block.expr.is_none() && !in_external_macro(cx.sess(), expr.span) - && let Some(then_snippet) = snippet_opt(cx, then.span) - // Ignore - // - empty macro expansions - // - empty reptitions in macro expansions - // - comments - // - #[cfg]'d out code - && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) + && then.span.check_source_text(cx, |src| { + // Ignore + // - empty macro expansions + // - empty reptitions in macro expansions + // - comments + // - #[cfg]'d out code + src.bytes() + .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) + }) && let Some(cond_snippet) = snippet_opt(cx, cond.span) && !is_from_proc_macro(cx, expr) { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 2701d6bdca3..b915df52762 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -53,8 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - && let Some(snip) = snippet_opt(cx, param.span) - && !(snip.starts_with("0o") || snip.starts_with("0b")) + && param + .span + .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } @@ -65,8 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) - && let Some(snip) = snippet_opt(cx, param.span) - && !(snip.starts_with("0o") || snip.starts_with("0b")) + && param + .span + .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 0a7a2cd616c..2eae9b23746 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::get_source_text; +use clippy_utils::source::SpanRangeExt; use rustc_ast::token::LitKind; use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; @@ -87,14 +87,11 @@ impl EarlyLintPass for OctalEscapes { // Last check to make sure the source text matches what we read from the string. // Macros are involved somehow if this doesn't match. - if let Some(src) = get_source_text(cx, span) - && let Some(src) = src.as_str() - && match *src.as_bytes() { - [b'\\', b'0', lo] => lo == c_lo, - [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, - _ => false, - } - { + if span.check_source_text(cx, |src| match *src.as_bytes() { + [b'\\', b'0', lo] => lo == c_lo, + [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, + _ => false, + }) { span_lint_and_then(cx, OCTAL_ESCAPES, span, "octal-looking escape in a literal", |diag| { diag.help_once("octal escapes are not supported, `\\0` is always null") .span_suggestion( diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 186e548d373..4fdaa9f00a1 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local}; use rustc_ast::ast::RangeLimits; @@ -285,9 +285,10 @@ fn check_possible_range_contains( if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && let Some(snip) = &snippet_opt(cx, new_span) - // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong - && snip.matches('(').count() == snip.matches(')').count() + && new_span.check_source_text(cx, |src| { + // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong + src.matches('(').count() == src.matches(')').count() + }) { check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); } @@ -363,17 +364,19 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { |diag| { let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); let end = Sugg::hir(cx, y, "y").maybe_par(); - if let Some(is_wrapped) = &snippet_opt(cx, span) { - if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { + match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { + Some(true) => { diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect); - } else { + }, + Some(false) => { diag.span_suggestion( span, "use", format!("{start}..={end}"), Applicability::MachineApplicable, // snippet ); - } + }, + None => {}, } }, ); diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 8f6389ee077..867c93c278e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1,7 +1,7 @@ #![allow(clippy::float_cmp)] use crate::macros::HirNode; -use crate::source::{get_source_text, walk_span_to_context}; +use crate::source::{walk_span_to_context, SpanRangeExt}; use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_ast::ast::{self, LitFloatType, LitKind}; @@ -15,8 +15,8 @@ use rustc_middle::mir::ConstValue; use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; +use rustc_span::sym; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, SyntaxContext}; use rustc_target::abi::Size; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; @@ -664,11 +664,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { { // Try to detect any `cfg`ed statements or empty macro expansions. let span = block.span.data(); - if span.ctxt == SyntaxContext::root() { + if span.ctxt.is_root() { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo) + && let Some(src) = (span.lo..expr_lo).get_source_text(self.lcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 50dd8430ac0..8706cec5d38 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::constant_simple; use crate::macros::macro_backtrace; -use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange}; +use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -1173,9 +1173,9 @@ fn eq_span_tokens( pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range, right: Range, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = get_source_text(cx, left) + if let Some(lsrc) = left.get_source_text(cx) && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = get_source_text(cx, right) + && let Some(rsrc) = right.get_source_text(cx) && let Some(rsrc) = rsrc.as_str() { let pred = |t: &(_, _)| pred(t.0); diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 69b122cbfad..496c8f5b553 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -9,22 +9,17 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; use rustc_span::source_map::{original_sp, SourceMap}; -use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{ + hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, + DUMMY_SP, +}; use std::borrow::Cow; +use std::fmt; use std::ops::Range; -/// A type which can be converted to the range portion of a `Span`. +/// Conversion of a value into the range portion of a `Span`. pub trait SpanRange: Sized { fn into_range(self) -> Range; - fn set_span_pos(self, sp: Span) -> Span { - let range = self.into_range(); - SpanData { - lo: range.start, - hi: range.end, - ..sp.data() - } - .span() - } } impl SpanRange for Span { fn into_range(self) -> Range { @@ -43,6 +38,182 @@ impl SpanRange for Range { } } +/// Conversion of a value into a `Span` +pub trait IntoSpan: Sized { + fn into_span(self) -> Span; + fn with_ctxt(self, ctxt: SyntaxContext) -> Span; +} +impl IntoSpan for Span { + fn into_span(self) -> Span { + self + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + self.with_ctxt(ctxt) + } +} +impl IntoSpan for SpanData { + fn into_span(self) -> Span { + self.span() + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + Span::new(self.lo, self.hi, ctxt, self.parent) + } +} +impl IntoSpan for Range { + fn into_span(self) -> Span { + Span::with_root_ctxt(self.start, self.end) + } + fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + Span::new(self.start, self.end, ctxt, None) + } +} + +pub trait SpanRangeExt: SpanRange { + /// Gets the source file, and range in the file, of the given span. Returns `None` if the span + /// extends through multiple files, or is malformed. + fn get_source_text(self, cx: &impl LintContext) -> Option { + get_source_text(cx.sess().source_map(), self.into_range()) + } + + /// Calls the given function with the source text referenced and returns the value. Returns + /// `None` if the source text cannot be retrieved. + fn with_source_text(self, cx: &impl LintContext, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { + with_source_text(cx.sess().source_map(), self.into_range(), f) + } + + /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the + /// source text cannot be retrieved. + fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + self.with_source_text(cx, pred).unwrap_or(false) + } + + /// Calls the given function with the both the text of the source file and the referenced range, + /// and returns the value. Returns `None` if the source text cannot be retrieved. + fn with_source_text_and_range( + self, + cx: &impl LintContext, + f: impl for<'a> FnOnce(&'a str, Range) -> T, + ) -> Option { + with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) + } + + /// Calls the given function with the both the text of the source file and the referenced range, + /// and creates a new span with the returned range. Returns `None` if the source text cannot be + /// retrieved, or no result is returned. + /// + /// The new range must reside within the same source file. + fn map_range( + self, + cx: &impl LintContext, + f: impl for<'a> FnOnce(&'a str, Range) -> Option>, + ) -> Option> { + map_range(cx.sess().source_map(), self.into_range(), f) + } + + /// Extends the range to include all preceding whitespace characters. + fn with_leading_whitespace(self, cx: &impl LintContext) -> Range { + with_leading_whitespace(cx.sess().source_map(), self.into_range()) + } + + /// Trims the leading whitespace from the range. + fn trim_start(self, cx: &impl LintContext) -> Range { + trim_start(cx.sess().source_map(), self.into_range()) + } + + /// Writes the referenced source text to the given writer. Will return `Err` if the source text + /// could not be retrieved. + fn write_source_text_to(self, cx: &impl LintContext, dst: &mut impl fmt::Write) -> fmt::Result { + write_source_text_to(cx.sess().source_map(), self.into_range(), dst) + } + + /// Extracts the referenced source text as an owned string. + fn source_text_to_string(self, cx: &impl LintContext) -> Option { + self.with_source_text(cx, ToOwned::to_owned) + } +} +impl SpanRangeExt for T {} + +fn get_source_text(sm: &SourceMap, sp: Range) -> Option { + let start = sm.lookup_byte_offset(sp.start); + let end = sm.lookup_byte_offset(sp.end); + if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { + return None; + } + let range = start.pos.to_usize()..end.pos.to_usize(); + Some(SourceFileRange { sf: start.sf, range }) +} + +fn with_source_text(sm: &SourceMap, sp: Range, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { + if let Some(src) = get_source_text(sm, sp) + && let Some(src) = src.as_str() + { + Some(f(src)) + } else { + None + } +} + +fn with_source_text_and_range( + sm: &SourceMap, + sp: Range, + f: impl for<'a> FnOnce(&'a str, Range) -> T, +) -> Option { + if let Some(src) = get_source_text(sm, sp) + && let Some(text) = &src.sf.src + { + Some(f(text, src.range)) + } else { + None + } +} + +#[expect(clippy::cast_possible_truncation)] +fn map_range( + sm: &SourceMap, + sp: Range, + f: impl for<'a> FnOnce(&'a str, Range) -> Option>, +) -> Option> { + if let Some(src) = get_source_text(sm, sp.clone()) + && let Some(text) = &src.sf.src + && let Some(range) = f(text, src.range.clone()) + { + debug_assert!( + range.start <= text.len() && range.end <= text.len(), + "Range `{range:?}` is outside the source file (file `{}`, length `{}`)", + src.sf.name.display(FileNameDisplayPreference::Local), + text.len(), + ); + debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds"); + let dstart = (range.start as u32).wrapping_sub(src.range.start as u32); + let dend = (range.end as u32).wrapping_sub(src.range.start as u32); + Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend))) + } else { + None + } +} + +fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range { + map_range(sm, sp.clone(), |src, range| { + Some(src.get(..range.start)?.trim_end().len()..range.end) + }) + .unwrap_or(sp) +} + +fn trim_start(sm: &SourceMap, sp: Range) -> Range { + map_range(sm, sp.clone(), |src, range| { + let src = src.get(range.clone())?; + Some(range.start + (src.len() - src.trim_start().len())..range.end) + }) + .unwrap_or(sp) +} + +fn write_source_text_to(sm: &SourceMap, sp: Range, dst: &mut impl fmt::Write) -> fmt::Result { + match with_source_text(sm, sp, |src| dst.write_str(src)) { + Some(x) => x, + None => Err(fmt::Error), + } +} + pub struct SourceFileRange { pub sf: Lrc, pub range: Range, @@ -55,37 +226,6 @@ impl SourceFileRange { } } -/// Gets the source file, and range in the file, of the given span. Returns `None` if the span -/// extends through multiple files, or is malformed. -pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option { - fn f(sm: &SourceMap, sp: Range) -> Option { - let start = sm.lookup_byte_offset(sp.start); - let end = sm.lookup_byte_offset(sp.end); - if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { - return None; - } - let range = start.pos.to_usize()..end.pos.to_usize(); - Some(SourceFileRange { sf: start.sf, range }) - } - f(cx.sess().source_map(), sp.into_range()) -} - -pub fn with_leading_whitespace(cx: &impl LintContext, sp: impl SpanRange) -> Range { - #[expect(clippy::needless_pass_by_value, clippy::cast_possible_truncation)] - fn f(src: SourceFileRange, sp: Range) -> Range { - let Some(text) = &src.sf.src else { - return sp; - }; - let len = src.range.start - text[..src.range.start].trim_end().len(); - BytePos(sp.start.0 - len as u32)..sp.end - } - let sp = sp.into_range(); - match get_source_text(cx, sp.clone()) { - Some(src) => f(src, sp), - None => sp, - } -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. pub fn expr_block( cx: &T, -- cgit 1.4.1-3-g733a5 From 625091d2368e3f0f6d0127b27b183d5d855c4d08 Mon Sep 17 00:00:00 2001 From: John Arundel Date: Sun, 23 Jun 2024 12:21:10 +0100 Subject: Fix doc nits --- clippy_lints/src/await_holding_invalid.rs | 46 +++++---- clippy_lints/src/casts/mod.rs | 113 +++++++++++---------- clippy_lints/src/endian_bytes.rs | 4 +- clippy_lints/src/methods/mod.rs | 8 +- clippy_lints/src/same_name_method.rs | 2 +- .../await_holding_invalid_type.stderr | 6 +- tests/ui/await_holding_lock.rs | 26 ++--- tests/ui/await_holding_lock.stderr | 78 +++++++------- tests/ui/await_holding_refcell_ref.rs | 12 +-- tests/ui/await_holding_refcell_ref.stderr | 24 ++--- 10 files changed, 163 insertions(+), 156 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index f25a474d9bb..dac1f4ed404 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -11,21 +11,25 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a non-async-aware MutexGuard. + /// Checks for calls to `await` while holding a non-async-aware + /// `MutexGuard`. /// /// ### Why is this bad? - /// The Mutex types found in std::sync and parking_lot - /// are not designed to operate in an async context across await points. + /// The Mutex types found in [`std::sync`] and + /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are + /// not designed to operate in an async context across await points. /// - /// There are two potential solutions. One is to use an async-aware Mutex - /// type. Many asynchronous foundation crates provide such a Mutex type. The - /// other solution is to ensure the mutex is unlocked before calling await, - /// either by introducing a scope or an explicit call to Drop::drop. + /// There are two potential solutions. One is to use an async-aware `Mutex` + /// type. Many asynchronous foundation crates provide such a `Mutex` type. + /// The other solution is to ensure the mutex is unlocked before calling + /// `await`, either by introducing a scope or an explicit call to + /// [`Drop::drop`]. /// /// ### Known problems /// Will report false positive for explicitly dropped guards - /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is - /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. + /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A + /// workaround for this is to wrap the `.lock()` call in a block instead of + /// explicitly dropping the guard. /// /// ### Example /// ```no_run @@ -73,11 +77,11 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. + /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`. /// /// ### Why is this bad? /// `RefCell` refs only check for exclusive mutable access - /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point + /// at runtime. Holding a `RefCell` ref across an await suspension point /// risks panics from a mutable ref shared while other refs are outstanding. /// /// ### Known problems @@ -131,13 +135,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Allows users to configure types which should not be held across `await` + /// Allows users to configure types which should not be held across await /// suspension points. /// /// ### Why is this bad? - /// There are some types which are perfectly "safe" to be used concurrently - /// from a memory access perspective but will cause bugs at runtime if they - /// are held in such a way. + /// There are some types which are perfectly safe to use concurrently from + /// a memory access perspective, but that will cause bugs at runtime if + /// they are held in such a way. /// /// ### Example /// @@ -228,15 +232,15 @@ impl AwaitHolding { cx, AWAIT_HOLDING_LOCK, ty_cause.source_info.span, - "this `MutexGuard` is held across an `await` point", + "this `MutexGuard` is held across an await point", |diag| { diag.help( "consider using an async-aware `Mutex` type or ensuring the \ - `MutexGuard` is dropped before calling await", + `MutexGuard` is dropped before calling `await`", ); diag.span_note( await_points(), - "these are all the `await` points this lock is held through", + "these are all the await points this lock is held through", ); }, ); @@ -245,12 +249,12 @@ impl AwaitHolding { cx, AWAIT_HOLDING_REFCELL_REF, ty_cause.source_info.span, - "this `RefCell` reference is held across an `await` point", + "this `RefCell` reference is held across an await point", |diag| { diag.help("ensure the reference is dropped before calling `await`"); diag.span_note( await_points(), - "these are all the `await` points this reference is held through", + "these are all the await points this reference is held through", ); }, ); @@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa AWAIT_HOLDING_INVALID_TYPE, span, format!( - "`{}` may not be held across an `await` point per `clippy.toml`", + "`{}` may not be held across an await point per `clippy.toml`", disallowed.path() ), |diag| { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index e60c36ced75..d8bae3b48bf 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for casts from any numerical to a float type where + /// Checks for casts from any numeric type to a float type where /// the receiving type cannot store all values from the original type without /// rounding errors. This possible rounding is to be expected, so this lint is /// `Allow` by default. @@ -58,14 +58,14 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts from a signed to an unsigned numerical + /// Checks for casts from a signed to an unsigned numeric /// type. In this case, negative values wrap around to large positive values, - /// which can be quite surprising in practice. However, as the cast works as + /// which can be quite surprising in practice. However, since the cast works as /// defined, this lint is `Allow` by default. /// /// ### Why is this bad? /// Possibly surprising results. You can activate this lint - /// as a one-time check to see where numerical wrapping can arise. + /// as a one-time check to see where numeric wrapping can arise. /// /// ### Example /// ```no_run @@ -80,7 +80,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may + /// Checks for casts between numeric types that may /// truncate large values. This is expected behavior, so the cast is `Allow` by /// default. It suggests user either explicitly ignore the lint, /// or use `try_from()` and handle the truncation, default, or panic explicitly. @@ -120,17 +120,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for casts from an unsigned type to a signed type of - /// the same size, or possibly smaller due to target dependent integers. - /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is - /// changed at the bit level, and the binary representation of the value is + /// the same size, or possibly smaller due to target-dependent integers. + /// Performing such a cast is a no-op for the compiler (that is, nothing is + /// changed at the bit level), and the binary representation of the value is /// reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. /// /// ### Why is this bad? /// While such a cast is not bad in itself, the results can - /// be surprising when this is not the intended behavior, as demonstrated by the - /// example below. + /// be surprising when this is not the intended behavior: /// /// ### Example /// ```no_run @@ -144,16 +143,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts between numerical types that may - /// be replaced by safe conversion functions. + /// Checks for casts between numeric types that can be replaced by safe + /// conversion functions. /// /// ### Why is this bad? - /// Rust's `as` keyword will perform many kinds of - /// conversions, including silently lossy conversions. Conversion functions such - /// as `i32::from` will only perform lossless conversions. Using the conversion - /// functions prevents conversions from turning into silent lossy conversions if - /// the types of the input expressions ever change, and make it easier for - /// people reading the code to know that the conversion is lossless. + /// Rust's `as` keyword will perform many kinds of conversions, including + /// silently lossy conversions. Conversion functions such as `i32::from` + /// will only perform lossless conversions. Using the conversion functions + /// prevents conversions from becoming silently lossy if the input types + /// ever change, and makes it clear for people reading the code that the + /// conversion is lossless. /// /// ### Example /// ```no_run @@ -177,19 +176,21 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts to the same type, casts of int literals to integer types, casts of float - /// literals to float types and casts between raw pointers without changing type or constness. + /// Checks for casts to the same type, casts of int literals to integer + /// types, casts of float literals to float types, and casts between raw + /// pointers that don't change type or constness. /// /// ### Why is this bad? /// It's just unnecessary. /// /// ### Known problems - /// When the expression on the left is a function call, the lint considers the return type to be - /// a type alias if it's aliased through a `use` statement - /// (like `use std::io::Result as IoResult`). It will not lint such cases. + /// When the expression on the left is a function call, the lint considers + /// the return type to be a type alias if it's aliased through a `use` + /// statement (like `use std::io::Result as IoResult`). It will not lint + /// such cases. /// - /// This check is also rather primitive. It will only work on primitive types without any - /// intermediate references, raw pointers and trait objects may or may not work. + /// This check will only work on primitive types without any intermediate + /// references: raw pointers and trait objects may or may not work. /// /// ### Example /// ```no_run @@ -211,17 +212,17 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts, using `as` or `pointer::cast`, - /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer + /// Checks for casts, using `as` or `pointer::cast`, from a + /// less strictly aligned pointer to a more strictly aligned pointer. /// /// ### Why is this bad? - /// Dereferencing the resulting pointer may be undefined - /// behavior. + /// Dereferencing the resulting pointer may be undefined behavior. /// /// ### Known problems - /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar - /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like - /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. + /// Using [`std::ptr::read_unaligned`] and [`std::ptr::write_unaligned`] or + /// similar on the resulting pointer is fine. Is over-zealous: casts with + /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be + /// fine. Miri is able to do a more in-depth analysis. /// /// ### Example /// ```no_run @@ -234,20 +235,21 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub CAST_PTR_ALIGNMENT, pedantic, - "cast from a pointer to a more-strictly-aligned pointer" + "cast from a pointer to a more strictly aligned pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of function pointers to something other than usize + /// Checks for casts of function pointers to something other than `usize`. /// /// ### Why is this bad? - /// Casting a function pointer to anything other than usize/isize is not portable across - /// architectures, because you end up losing bits if the target type is too small or end up with a - /// bunch of extra bits that waste space and add more instructions to the final binary than - /// strictly necessary for the problem + /// Casting a function pointer to anything other than `usize`/`isize` is + /// not portable across architectures. It either loses bits if the target + /// type is too small, or creates extra bits that waste space and bloat the + /// resulting binary. /// - /// Casting to isize also doesn't make sense since there are no signed addresses. + /// Casting to `isize` also doesn't make sense, since addresses are never + /// signed. /// /// ### Example /// ```no_run @@ -263,17 +265,17 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub FN_TO_NUMERIC_CAST, style, - "casting a function pointer to a numeric type other than usize" + "casting a function pointer to a numeric type other than `usize`" } declare_clippy_lint! { /// ### What it does /// Checks for casts of a function pointer to a numeric type not wide enough to - /// store address. + /// store an address. /// /// ### Why is this bad? /// Such a cast discards some bits of the function's address. If this is intended, it would be more - /// clearly expressed by casting to usize first, then casting the usize to the intended type (with + /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with /// a comment) to perform the truncation. /// /// ### Example @@ -306,7 +308,7 @@ declare_clippy_lint! { /// ### Why restrict this? /// Casting a function pointer to an integer can have surprising results and can occur /// accidentally if parentheses are omitted from a function call. If you aren't doing anything - /// low-level with function pointers then you can opt-out of casting functions to integers in + /// low-level with function pointers then you can opt out of casting functions to integers in /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function /// pointer casts in your code. /// @@ -349,8 +351,8 @@ declare_clippy_lint! { /// ### Why is this bad? /// In general, casting values to smaller types is /// error-prone and should be avoided where possible. In the particular case of - /// converting a character literal to u8, it is easy to avoid by just using a - /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter + /// converting a character literal to `u8`, it is easy to avoid by just using a + /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter /// than `'a' as u8`. /// /// ### Example @@ -371,12 +373,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers without changing its mutability, - /// namely `*const T` to `*const U` and `*mut T` to `*mut U`. + /// Checks for `as` casts on a raw pointer that don't change its + /// mutability, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? - /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because - /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. + /// Though `as` casts between raw pointers are not terrible, + /// `pointer::cast` is safer because it cannot accidentally change the + /// pointer's mutability, nor cast the pointer to other types like `usize`. /// /// ### Example /// ```no_run @@ -395,12 +398,12 @@ declare_clippy_lint! { #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, - "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" + "casting using `as` on a raw pointer that doesn't change its mutability, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to + /// Checks for `as` casts on a raw pointer that change its constness, namely `*const T` to /// `*mut T` and `*mut T` to `*const T`. /// /// ### Why is this bad? @@ -423,12 +426,12 @@ declare_clippy_lint! { #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, pedantic, - "casting using `as` from and to raw pointers to change constness when specialized methods apply" + "casting using `as` on raw pointers to change constness when specialized methods apply" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from an enum type to an integral type which will definitely truncate the + /// Checks for casts from an enum type to an integral type that will definitely truncate the /// value. /// /// ### Why is this bad? @@ -442,7 +445,7 @@ declare_clippy_lint! { #[clippy::version = "1.61.0"] pub CAST_ENUM_TRUNCATION, suspicious, - "casts from an enum type to an integral type which will truncate the value" + "casts from an enum type to an integral type that will truncate the value" } declare_clippy_lint! { @@ -621,7 +624,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer + /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. /// /// ### Why is this bad? /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index bb766e96338..99328e3e643 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. /// /// ### Why restrict this? - /// To ensure use of big endian or the target’s endianness rather than little endian. + /// To ensure use of big-endian or the target’s endianness rather than little-endian. /// /// ### Example /// ```rust,ignore @@ -51,7 +51,7 @@ declare_clippy_lint! { /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. /// /// ### Why restrict this? - /// To ensure use of little endian or the target’s endianness rather than big endian. + /// To ensure use of little-endian or the target’s endianness rather than big-endian. /// /// ### Example /// ```rust,ignore diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1408f454820..b8b24fe92ee 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -628,12 +628,12 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or - /// `_.or_else(|x| Err(y))`. + /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` + /// or `_.or_else(|x| Err(y))`. /// /// ### Why is this bad? - /// Readability, this can be written more concisely as - /// `_.map(|x| y)` or `_.map_err(|x| y)`. + /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| + /// y)`. /// /// ### Example /// ```no_run diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 8fdd19c549f..508f3ae6def 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { /// ### What it does /// It lints if a struct has two methods with the same name: - /// one from a trait, another not from trait. + /// one from a trait, another not from a trait. /// /// ### Why restrict this? /// Confusing. diff --git a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index a74d8757e4a..016ee502c24 100644 --- a/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -1,4 +1,4 @@ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9 | LL | let _x = String::from("hello"); @@ -8,13 +8,13 @@ LL | let _x = String::from("hello"); = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` -error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` +error: `std::net::Ipv4Addr` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ -error: `std::string::String` may not be held across an `await` point per `clippy.toml` +error: `std::string::String` may not be held across an await point per `clippy.toml` --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13 | LL | let _x = String::from("hi!"); diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs index 8e5510e6cd0..cecf00c934f 100644 --- a/tests/ui/await_holding_lock.rs +++ b/tests/ui/await_holding_lock.rs @@ -8,7 +8,7 @@ mod std_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -24,13 +24,13 @@ mod std_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -52,7 +52,7 @@ mod std_mutex { let first = baz().await; let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -66,7 +66,7 @@ mod std_mutex { let second = { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -79,7 +79,7 @@ mod std_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -92,7 +92,7 @@ mod parking_lot_mutex { pub async fn bad(x: &Mutex) -> u32 { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -108,13 +108,13 @@ mod parking_lot_mutex { pub async fn bad_rw(x: &RwLock) -> u32 { let guard = x.read(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } pub async fn bad_rw_write(x: &RwLock) -> u32 { let mut guard = x.write(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } @@ -136,7 +136,7 @@ mod parking_lot_mutex { let first = baz().await; let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point let second = baz().await; @@ -150,7 +150,7 @@ mod parking_lot_mutex { let second = { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await }; @@ -163,7 +163,7 @@ mod parking_lot_mutex { pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { async move { let guard = x.lock(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point baz().await } } @@ -184,7 +184,7 @@ async fn no_await(x: std::sync::Mutex) { // `*guard += 1` is removed it is picked up. async fn dropped_before_await(x: std::sync::Mutex) { let mut guard = x.lock().unwrap(); - //~^ ERROR: this `MutexGuard` is held across an `await` point + //~^ ERROR: this `MutexGuard` is held across an await point *guard += 1; drop(guard); baz().await; diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index 0af48a36acc..af61d893948 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,11 +1,11 @@ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:10:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:12:15 | LL | baz().await @@ -13,40 +13,40 @@ LL | baz().await = note: `-D clippy::await-holding-lock` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:26:13 | LL | let guard = x.read().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:28:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:32:13 | LL | let mut guard = x.write().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:34:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:54:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:57:28 | LL | let second = baz().await; @@ -55,79 +55,79 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:68:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:70:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:81:17 | LL | let guard = x.lock().unwrap(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:83:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:94:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:96:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:110:13 | LL | let guard = x.read(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:112:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:116:13 | LL | let mut guard = x.write(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:118:15 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:138:13 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:141:28 | LL | let second = baz().await; @@ -136,40 +136,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:152:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:154:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:165:17 | LL | let guard = x.lock(); | ^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:167:19 | LL | baz().await | ^^^^^ -error: this `MutexGuard` is held across an `await` point +error: this `MutexGuard` is held across an await point --> tests/ui/await_holding_lock.rs:186:9 | LL | let mut guard = x.lock().unwrap(); | ^^^^^^^^^ | - = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await -note: these are all the `await` points this lock is held through + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await` +note: these are all the await points this lock is held through --> tests/ui/await_holding_lock.rs:190:11 | LL | baz().await; diff --git a/tests/ui/await_holding_refcell_ref.rs b/tests/ui/await_holding_refcell_ref.rs index 5bd26c62836..b0c92d8c1f6 100644 --- a/tests/ui/await_holding_refcell_ref.rs +++ b/tests/ui/await_holding_refcell_ref.rs @@ -4,13 +4,13 @@ use std::cell::RefCell; async fn bad(x: &RefCell) -> u32 { let b = x.borrow(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } async fn bad_mut(x: &RefCell) -> u32 { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } @@ -32,7 +32,7 @@ async fn also_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -45,7 +45,7 @@ async fn less_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point let second = baz().await; @@ -61,7 +61,7 @@ async fn not_good(x: &RefCell) -> u32 { let second = { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await }; @@ -74,7 +74,7 @@ async fn not_good(x: &RefCell) -> u32 { fn block_bad(x: &RefCell) -> impl std::future::Future + '_ { async move { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an `await` point + //~^ ERROR: this `RefCell` reference is held across an await point baz().await } } diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index 6b474c27ddc..6c7209c9ff9 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -1,11 +1,11 @@ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:8:11 | LL | baz().await @@ -13,27 +13,27 @@ LL | baz().await = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:12:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:14:11 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:34:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:37:24 | LL | let second = baz().await; @@ -42,40 +42,40 @@ LL | LL | let third = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:47:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:50:24 | LL | let second = baz().await; | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:63:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:65:15 | LL | baz().await | ^^^^^ -error: this `RefCell` reference is held across an `await` point +error: this `RefCell` reference is held across an await point --> tests/ui/await_holding_refcell_ref.rs:76:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` -note: these are all the `await` points this reference is held through +note: these are all the await points this reference is held through --> tests/ui/await_holding_refcell_ref.rs:78:15 | LL | baz().await -- cgit 1.4.1-3-g733a5 From 01a6dfa29fce5fe0375318b6504526cbd41d277e Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 28 Jun 2024 10:29:18 +0200 Subject: Add error message to manual_inspect lint --- clippy_lints/src/methods/manual_inspect.rs | 26 +++++++++++++++----------- tests/ui/manual_inspect.stderr | 24 ++++++++++++------------ 2 files changed, 27 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index e3ce64c246a..cac2e11f591 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { edits.extend(addr_of_edits); } - edits.push(( - name_span, - String::from(match name { - "map" => "inspect", - "map_err" => "inspect_err", - _ => return, - }), - )); + let edit = match name { + "map" => "inspect", + "map_err" => "inspect_err", + _ => return, + }; + edits.push((name_span, edit.to_string())); edits.push(( final_expr .span @@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } else { Applicability::MachineApplicable }; - span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| { - diag.multipart_suggestion("try", edits, app); - }); + span_lint_and_then( + cx, + MANUAL_INSPECT, + name_span, + format!("using `{name}` over `{edit}`"), + |diag| { + diag.multipart_suggestion("try", edits, app); + }, + ); } } } diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr index 8548c0cd294..0559b3bd661 100644 --- a/tests/ui/manual_inspect.stderr +++ b/tests/ui/manual_inspect.stderr @@ -1,4 +1,4 @@ -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:5:21 | LL | let _ = Some(0).map(|x| { @@ -12,7 +12,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:10:21 | LL | let _ = Some(0).map(|x| { @@ -24,7 +24,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{x}"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:15:21 | LL | let _ = Some(0).map(|x| { @@ -36,7 +36,7 @@ LL ~ let _ = Some(0).inspect(|&x| { LL ~ println!("{}", x * 5 + 1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:20:21 | LL | let _ = Some(0).map(|x| { @@ -50,7 +50,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:27:21 | LL | let _ = Some(0).map(|x| { @@ -65,7 +65,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:78:41 | LL | let _ = Some((String::new(), 0u32)).map(|x| { @@ -80,7 +80,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:104:33 | LL | let _ = Some(String::new()).map(|x| { @@ -98,7 +98,7 @@ LL | } LL ~ println!("test"); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:115:21 | LL | let _ = Some(0).map(|x| { @@ -113,7 +113,7 @@ LL | panic!(); LL ~ } | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:130:46 | LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { @@ -125,7 +125,7 @@ LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { LL ~ x.0.set(1); | -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:146:34 | LL | let _: Result<_, ()> = Ok(0).map(|x| { @@ -137,7 +137,7 @@ LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { LL ~ println!("{}", x); | -error: +error: using `map_err` over `inspect_err` --> tests/ui/manual_inspect.rs:151:35 | LL | let _: Result<(), _> = Err(0).map_err(|x| { @@ -166,7 +166,7 @@ LL | | .count(); = note: `-D clippy::suspicious-map` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` -error: +error: using `map` over `inspect` --> tests/ui/manual_inspect.rs:158:10 | LL | .map(|x| { -- cgit 1.4.1-3-g733a5 From eb1b24a97a5794fe62e83964700ec233b8dd5f32 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 30 Jun 2024 23:56:39 +0200 Subject: `manual_inspect`: fix `clippy::version` from 1.78.0 to 1.81.0 Although `manual_inspect`'s PR started some months ago, the lint is only available in the current nightly (1.81.0), rather than 1.78.0. Signed-off-by: Miguel Ojeda --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1408f454820..c5d44e620f2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4121,7 +4121,7 @@ declare_clippy_lint! { /// ```no_run /// let x = Some(0).inspect(|x| println!("{x}")); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub MANUAL_INSPECT, complexity, "use of `map` returning the original item" -- cgit 1.4.1-3-g733a5 From 6d61bdabeaaf806cc9b45a85fc5231fc6cf2743a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 5 Jul 2024 02:29:23 -0400 Subject: Use `is_in_test` in more places. --- clippy_lints/src/functions/impl_trait_in_params.rs | 8 ++++---- clippy_lints/src/incompatible_msrv.rs | 4 ++-- clippy_lints/src/methods/unwrap_expect_used.rs | 4 ++-- clippy_lints/src/missing_assert_message.rs | 4 ++-- clippy_lints/src/write.rs | 5 ++--- clippy_utils/src/lib.rs | 10 ---------- 6 files changed, 12 insertions(+), 23 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index 6fb38a0d6dd..cf85c74e688 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { if let FnKind::ItemFn(_, generics, _) = kind && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, hir_id) + && !is_in_test(cx.tcx, hir_id) { for param in generics.params { if param.is_impl_trait() { @@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { && of_trait.is_none() && let body = cx.tcx.hir().body(body_id) && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() - && !is_in_test_function(cx.tcx, impl_item.hir_id()) + && !is_in_test(cx.tcx, impl_item.hir_id()) { for param in impl_item.generics.params { if param.is_impl_trait() { @@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id()) // ^^ (Will always be a trait) && !item.vis_span.is_empty() // Is public - && !is_in_test_function(cx.tcx, trait_item.hir_id()) + && !is_in_test(cx.tcx, trait_item.hir_id()) { for param in trait_item.generics.params { if param.is_impl_trait() { diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 35b4481bfee..5c63d48adaf 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test_function; +use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; @@ -88,7 +88,7 @@ impl IncompatibleMsrv { return; } let version = self.get_def_id_version(cx.tcx, def_id); - if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) { + if self.msrv.meets(version) || is_in_test(cx.tcx, node) { return; } if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind { diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 516b8984ad7..5b0bd0f716a 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{is_never_like, is_type_diagnostic_item}; -use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; +use clippy_utils::{is_in_test, is_lint_allowed}; use rustc_hir::Expr; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; @@ -61,7 +61,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { + if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index dd98352da86..935ed48dacc 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_in_test; use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage { }; // This lint would be very noisy in tests, so just ignore if we're in test context - if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) { + if is_in_test(cx.tcx, expr.hir_id) { return; } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 652ce88bd95..96e53b7ef0b 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::is_in_test; use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { .as_ref() .map_or(false, |crate_name| crate_name == "build_script_build"); - let allowed_in_tests = self.allow_print_in_tests - && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)); + let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 45a31fe442b..28d1eeb4e28 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2625,16 +2625,6 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { .any(|attr| attr.has_name(sym::cfg)) } -/// Checks whether item either has `test` attribute applied, or -/// is a module with `test` in its name. -/// -/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function -pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { - is_in_test_function(tcx, item.hir_id()) - || matches!(item.kind, ItemKind::Mod(..)) - && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") -} - /// Walks up the HIR tree from the given expression in an attempt to find where the value is /// consumed. /// -- cgit 1.4.1-3-g733a5 From f7050b0c784559a0eacbbfac9f7be95cb81dba66 Mon Sep 17 00:00:00 2001 From: John Arundel Date: Sun, 7 Jul 2024 10:44:27 +0100 Subject: resolve code review comments --- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/casts/mod.rs | 12 +++--- clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- clippy_lints/src/methods/mod.rs | 3 +- tests/ui/crashes/ice-12616.stderr | 2 +- tests/ui/ptr_as_ptr.stderr | 66 +++++++++++++++---------------- 6 files changed, 43 insertions(+), 44 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index dac1f4ed404..1a4dc38e7e9 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// `MutexGuard`. /// /// ### Why is this bad? - /// The Mutex types found in [`std::sync`] and + /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are /// not designed to operate in an async context across await points. /// diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d8bae3b48bf..7eaa802ecc2 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -244,9 +244,9 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Casting a function pointer to anything other than `usize`/`isize` is - /// not portable across architectures. It either loses bits if the target - /// type is too small, or creates extra bits that waste space and bloat the - /// resulting binary. + /// not portable across architectures. If the target type is too small the + /// address would be truncated, and target types larger than `usize` are + /// unnecessary. /// /// Casting to `isize` also doesn't make sense, since addresses are never /// signed. @@ -373,7 +373,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts on a raw pointer that don't change its + /// Checks for `as` casts between raw pointers that don't change their /// mutability, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? @@ -398,12 +398,12 @@ declare_clippy_lint! { #[clippy::version = "1.51.0"] pub PTR_AS_PTR, pedantic, - "casting using `as` on a raw pointer that doesn't change its mutability, where `pointer::cast` could take the place of `as`" + "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts on a raw pointer that change its constness, namely `*const T` to + /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to /// `*mut T` and `*mut T` to `*const T`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 2c168405ee2..86c5f6b9f0b 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { cx, PTR_AS_PTR, expr.span, - "`as` casting between raw pointers without changing its mutability", + "`as` casting between raw pointers without changing their constness", help, final_suggestion, app, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b8b24fe92ee..c29f81bf0fb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -632,8 +632,7 @@ declare_clippy_lint! { /// or `_.or_else(|x| Err(y))`. /// /// ### Why is this bad? - /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| - /// y)`. + /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// ### Example /// ```no_run diff --git a/tests/ui/crashes/ice-12616.stderr b/tests/ui/crashes/ice-12616.stderr index c7cf5cf5483..a84a945a429 100644 --- a/tests/ui/crashes/ice-12616.stderr +++ b/tests/ui/crashes/ice-12616.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/crashes/ice-12616.rs:6:5 | LL | s() as *const (); diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index e162f35baf5..18462620b0a 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,4 +1,4 @@ -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:18:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } @@ -7,37 +7,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:27:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:33:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:46:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:47:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:50:21 | LL | let _ = inline!($ptr as *const i32); @@ -45,157 +45,157 @@ LL | let _ = inline!($ptr as *const i32); | = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:71:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:79:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:83:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:92:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:97:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:101:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:106:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:110:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:117:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:121:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:126:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:130:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:135:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:144:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:148:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:155:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:159:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:164:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:168:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:173:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:177:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` -error: `as` casting between raw pointers without changing its mutability +error: `as` casting between raw pointers without changing their constness --> tests/ui/ptr_as_ptr.rs:186:9 | LL | core::ptr::null() as _ -- cgit 1.4.1-3-g733a5 From 983b4c37203e841c1a362e1cf3a16ef388269499 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Fri, 12 Jul 2024 17:23:08 +0800 Subject: [`unwrap_or_default`]: skip warning when calling inside of suggested method's implementation --- clippy_lints/src/methods/or_fun_call.rs | 23 ++++++++++++++++++----- tests/ui/or_fun_call.fixed | 12 ++++++++++++ tests/ui/or_fun_call.rs | 12 ++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 583e04fb4b1..baa60454419 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -70,18 +70,31 @@ pub(super) fn check<'tcx>( }; let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs(); - let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| { + let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) .into_iter() .flatten() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) - .any(|assoc| { - assoc.fn_has_self_parameter + .find_map(|assoc| { + if assoc.fn_has_self_parameter && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 + { + Some(assoc.def_id) + } else { + None + } }) - }); - if !has_suggested_method { + }) else { + return false; + }; + let in_sugg_method_implementation = { + matches!( + suggested_method_def_id.as_local(), + Some(local_def_id) if local_def_id == cx.tcx.hir().get_parent_item(receiver.hir_id).def_id + ) + }; + if in_sugg_method_implementation { return false; } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index c76f7a81843..35015592971 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -318,4 +318,16 @@ fn host_effect() { Add::::add(1, 1).add(i32::MIN); } +mod issue_10228 { + struct Entry; + + impl Entry { + fn or_insert(self, _default: i32) {} + fn or_default(self) { + // Don't lint, suggested code is an infinite recursion + self.or_insert(Default::default()) + } + } +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 97cf496d3ac..3dcf657d743 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -318,4 +318,16 @@ fn host_effect() { Add::::add(1, 1).add(i32::MIN); } +mod issue_10228 { + struct Entry; + + impl Entry { + fn or_insert(self, _default: i32) {} + fn or_default(self) { + // Don't lint, suggested code is an infinite recursion + self.or_insert(Default::default()) + } + } +} + fn main() {} -- cgit 1.4.1-3-g733a5 From cc1bb8f57a167d2e01db4c2175bfea1a8f48e772 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Thu, 11 Jul 2024 15:08:22 +0800 Subject: make [`or_fun_call`] and [`unwrap_or_default`] recursive. --- clippy_lints/src/methods/or_fun_call.rs | 110 +++++++++++++++++++------------- tests/ui/or_fun_call.fixed | 35 ++++++++++ tests/ui/or_fun_call.rs | 35 ++++++++++ tests/ui/or_fun_call.stderr | 50 ++++++++++++++- 4 files changed, 183 insertions(+), 47 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index baa60454419..e4326cb958e 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,8 +1,13 @@ +use std::ops::ControlFlow; + use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item}; -use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{ + contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, +}; use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; @@ -13,7 +18,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; /// Checks for the `OR_FUN_CALL` lint. -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, @@ -26,7 +31,6 @@ pub(super) fn check<'tcx>( /// `or_insert(T::new())` or `or_insert(T::default())`. /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`, /// `or_insert_with(T::new)` or `or_insert_with(T::default)`. - #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, name: &str, @@ -123,8 +127,8 @@ pub(super) fn check<'tcx>( } /// Checks for `*or(foo())`. - #[allow(clippy::too_many_arguments)] - fn check_general_case<'tcx>( + #[expect(clippy::too_many_arguments)] + fn check_or_fn_call<'tcx>( cx: &LateContext<'tcx>, name: &str, method_span: Span, @@ -135,7 +139,7 @@ pub(super) fn check<'tcx>( span: Span, // None if lambda is required fun_span: Option, - ) { + ) -> bool { // (path, fn_has_argument, methods, suffix) const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [ (sym::BTreeEntry, false, &["or_insert"], "with"), @@ -185,54 +189,68 @@ pub(super) fn check<'tcx>( format!("{name}_{suffix}({sugg})"), app, ); - } - } - - let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| { - if let hir::ExprKind::Block( - hir::Block { - stmts: [], - expr: Some(expr), - .. - }, - _, - ) = arg.kind - { - expr + true } else { - arg + false } - }; + } if let [arg] = args { - let inner_arg = extract_inner_arg(arg); - match inner_arg.kind { - hir::ExprKind::Call(fun, or_args) => { - let or_has_args = !or_args.is_empty(); - if or_has_args - || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span) - { - let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span); - } - }, - hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => { - check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span); - }, - hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None); - }, - _ => (), - } + let inner_arg = peel_blocks(arg); + for_each_expr(cx, inner_arg, |ex| { + // `or_fun_call` lint needs to take nested expr into account, + // but `unwrap_or_default` lint doesn't, we don't want something like: + // `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by + // `opt.unwrap_or_default()`. + let is_nested_expr = ex.hir_id != inner_arg.hir_id; + + let is_triggered = match ex.kind { + hir::ExprKind::Call(fun, fun_args) => { + let inner_fun_has_args = !fun_args.is_empty(); + let fun_span = if inner_fun_has_args || is_nested_expr { + None + } else { + Some(fun.span) + }; + (!inner_fun_has_args + && !is_nested_expr + && check_unwrap_or_default(cx, name, receiver, fun, Some(ex), expr.span, method_span)) + || check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, fun_span) + }, + hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) if !is_nested_expr => { + check_unwrap_or_default(cx, name, receiver, ex, None, expr.span, method_span) + }, + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_or_fn_call(cx, name, method_span, receiver, arg, None, expr.span, None) + }, + _ => false, + }; + + if is_triggered { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }); } // `map_or` takes two arguments if let [arg, lambda] = args { - let inner_arg = extract_inner_arg(arg); - if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind { - let fun_span = if or_args.is_empty() { Some(fun.span) } else { None }; - check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span); - } + let inner_arg = peel_blocks(arg); + for_each_expr(cx, inner_arg, |ex| { + let is_top_most_expr = ex.hir_id == inner_arg.hir_id; + if let hir::ExprKind::Call(fun, fun_args) = ex.kind { + let fun_span = if fun_args.is_empty() && is_top_most_expr { + Some(fun.span) + } else { + None + }; + if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) { + return ControlFlow::Break(()); + } + } + ControlFlow::Continue(()) + }); } } diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 35015592971..7452eb77688 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -330,4 +330,39 @@ mod issue_10228 { } } +// issue #12973 +fn fn_call_in_nested_expr() { + struct Foo { + val: String, + } + + fn f() -> i32 { + 1 + } + let opt: Option = Some(1); + + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or_else(f); // suggest `.unwrap_or_else(f)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or_else(|| f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or_else(|| { + let x = f(); + x + 1 + }); + //~v ERROR: use of `map_or` followed by a function call + let _ = opt.map_or_else(|| f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` + // + //~v ERROR: use of `unwrap_or` to construct default value + let _ = opt.unwrap_or_default(); + + let opt_foo = Some(Foo { + val: String::from("123"), + }); + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt_foo.unwrap_or_else(|| Foo { val: String::default() }); +} + fn main() {} diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 3dcf657d743..cd6f7bb2070 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -330,4 +330,39 @@ mod issue_10228 { } } +// issue #12973 +fn fn_call_in_nested_expr() { + struct Foo { + val: String, + } + + fn f() -> i32 { + 1 + } + let opt: Option = Some(1); + + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` + // + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt.unwrap_or({ + let x = f(); + x + 1 + }); + //~v ERROR: use of `map_or` followed by a function call + let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` + // + //~v ERROR: use of `unwrap_or` to construct default value + let _ = opt.unwrap_or({ i32::default() }); + + let opt_foo = Some(Foo { + val: String::from("123"), + }); + //~v ERROR: use of `unwrap_or` followed by a function call + let _ = opt_foo.unwrap_or(Foo { val: String::default() }); +} + fn main() {} diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 3070db22fc5..06f804fb41e 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -196,5 +196,53 @@ error: use of `unwrap_or_else` to construct default value LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` -error: aborting due to 32 previous errors +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:345:17 + | +LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` + +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:348:17 + | +LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` + +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:351:17 + | +LL | let _ = opt.unwrap_or({ + | _________________^ +LL | | let x = f(); +LL | | x + 1 +LL | | }); + | |______^ + | +help: try + | +LL ~ let _ = opt.unwrap_or_else(|| { +LL + let x = f(); +LL + x + 1 +LL ~ }); + | + +error: use of `map_or` followed by a function call + --> tests/ui/or_fun_call.rs:356:17 + | +LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)` + +error: use of `unwrap_or` to construct default value + --> tests/ui/or_fun_call.rs:359:17 + | +LL | let _ = opt.unwrap_or({ i32::default() }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` + +error: use of `unwrap_or` followed by a function call + --> tests/ui/or_fun_call.rs:365:21 + | +LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })` + +error: aborting due to 38 previous errors -- cgit 1.4.1-3-g733a5 From a5fd2c98bdf1881e553500cad4d8ce3b970a0a97 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 17 Jul 2024 12:51:08 +0700 Subject: Remove duplicated peel_middle_ty_refs TODO: Should we move `ty::peel_mid_ty_refs_is_mutable` to super module too? --- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/matches/single_match.rs | 8 +++++--- clippy_lints/src/methods/implicit_clone.rs | 6 +++--- clippy_lints/src/methods/unnecessary_to_owned.rs | 13 ++++++------- clippy_lints/src/redundant_slicing.rs | 8 ++++---- clippy_lints/src/size_of_ref.rs | 5 ++--- clippy_utils/src/ty.rs | 13 ------------- 7 files changed, 22 insertions(+), 35 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 253f9959e13..d0cb2488468 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; +use clippy_utils::ty::{implements_trait, is_manually_drop}; use clippy_utils::{ expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, ExprUseNode, @@ -947,7 +947,7 @@ fn report<'tcx>( let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); let ty = typeck.expr_ty(expr); - let (_, ref_count) = peel_mid_ty_refs(ty); + let (_, ref_count) = peel_middle_ty_refs(ty); let deref_str = if ty_changed_count >= ref_count && ref_count != 0 { // a deref call changing &T -> &U requires two deref operators the first time // this occurs. One to remove the reference, a second to call the deref impl. diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 99fdbcff890..d4330400cd0 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; -use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{ + is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, +}; use core::cmp::max; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingMode, Block, Expr, ExprKind, Pat, PatKind}; @@ -82,7 +84,7 @@ fn report_single_pattern( let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind - && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex)) + && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait() && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait() && (ty.is_integral() diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index c510cd915d0..519091406cc 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{implements_trait, peel_mid_ty_refs}; -use clippy_utils::{is_diag_item_method, is_diag_trait_item}; +use clippy_utils::ty::implements_trait; +use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -14,7 +14,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv && is_clone_like(cx, method_name, method_def_id) && let return_type = cx.typeck_results().expr_ty(expr) && let input_type = cx.typeck_results().expr_ty(recv) - && let (input_type, ref_count) = peel_mid_ty_refs(input_type) + && let (input_type, ref_count) = peel_middle_ty_refs(input_type) && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned)) && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())) && return_type == input_type diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 5d899415d77..fed2b128dcf 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,12 +3,11 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt}; -use clippy_utils::ty::{ - get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs, -}; +use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ - fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty, + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, peel_middle_ty_refs, + return_ty, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -120,8 +119,8 @@ fn check_addr_of_expr( }, ] = adjustments[..] && let receiver_ty = cx.typeck_results().expr_ty(receiver) - && let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty) - && let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty) + && let (target_ty, n_target_refs) = peel_middle_ty_refs(*target_ty) + && let (receiver_ty, n_receiver_refs) = peel_middle_ty_refs(receiver_ty) // Only flag cases satisfying at least one of the following three conditions: // * the referent and receiver types are distinct // * the referent/receiver type is a copyable array @@ -382,7 +381,7 @@ fn check_other_call_arg<'tcx>( && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder() && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id) && let Some(input) = fn_sig.inputs().get(i) - && let (input, n_refs) = peel_mid_ty_refs(*input) + && let (input, n_refs) = peel_middle_ty_refs(*input) && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input) && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait() && let [trait_predicate] = trait_predicates diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 82f22ad693d..97b2f99299a 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs}; +use clippy_utils::ty::is_type_lang_item; +use clippy_utils::{get_parent_expr, peel_middle_ty_refs}; use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; @@ -82,8 +82,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { && let ExprKind::Index(indexed, range, _) = addressee.kind && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull) { - let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); - let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed)); + let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr)); + let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX); let mut app = Applicability::MachineApplicable; diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 8d7f12af86e..b3d32a6d7d8 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::path_def_id; -use clippy_utils::ty::peel_mid_ty_refs; +use clippy_utils::{path_def_id, peel_middle_ty_refs}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -60,7 +59,7 @@ impl LateLintPass<'_> for SizeOfRef { && let Some(def_id) = path_def_id(cx, path) && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id) && let arg_ty = cx.typeck_results().expr_ty(arg) - && peel_mid_ty_refs(arg_ty).1 > 1 + && peel_middle_ty_refs(arg_ty).1 > 1 { span_lint_and_help( cx, diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index fc02b974ee1..29ea03f7bb1 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -525,19 +525,6 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default()) } -/// Peels off all references on the type. Returns the underlying type and the number of references -/// removed. -pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { - fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(*ty, count + 1) - } else { - (ty, count) - } - } - peel(ty, 0) -} - /// Peels off all references on the type. Returns the underlying type, the number of references /// removed, and whether the pointer is ultimately mutable or not. pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { -- cgit 1.4.1-3-g733a5 From e34c6dbae5768b5dce90c02465f3492376327c65 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 12 Jul 2024 00:00:03 -0400 Subject: Refactor for using config values: * Construct lint passes by taking `Conf` by reference. * Use `HashSet` configs in less places * Move some `check_crate` code into the pass constructor when possible. --- book/src/development/adding_lints.md | 14 +- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 14 +- clippy_config/src/types.rs | 14 +- clippy_dev/src/new_lint.rs | 8 +- clippy_lints/src/absolute_paths.rs | 12 +- clippy_lints/src/almost_complete_range.rs | 7 +- clippy_lints/src/approx_const.rs | 8 +- clippy_lints/src/assigning_clones.rs | 8 +- clippy_lints/src/attrs/mod.rs | 19 +- clippy_lints/src/await_holding_invalid.rs | 39 +- clippy_lints/src/cargo/mod.rs | 16 +- clippy_lints/src/casts/mod.rs | 8 +- clippy_lints/src/checked_conversions.rs | 8 +- clippy_lints/src/cognitive_complexity.rs | 6 +- clippy_lints/src/copies.rs | 14 +- clippy_lints/src/dbg_macro.rs | 6 +- clippy_lints/src/derivable_impls.rs | 8 +- clippy_lints/src/disallowed_macros.rs | 31 +- clippy_lints/src/disallowed_methods.rs | 42 +- clippy_lints/src/disallowed_names.rs | 11 +- clippy_lints/src/disallowed_script_idents.rs | 18 +- clippy_lints/src/disallowed_types.rs | 91 ++-- clippy_lints/src/doc/mod.rs | 12 +- clippy_lints/src/escape.rs | 12 +- clippy_lints/src/excessive_bools.rs | 8 +- clippy_lints/src/excessive_nesting.rs | 9 +- clippy_lints/src/extra_unused_type_parameters.rs | 5 +- clippy_lints/src/format_args.rs | 8 +- clippy_lints/src/format_impl.rs | 1 - clippy_lints/src/from_over_into.rs | 8 +- clippy_lints/src/functions/mod.rs | 35 +- clippy_lints/src/if_then_some_else_none.rs | 8 +- clippy_lints/src/incompatible_msrv.rs | 5 +- clippy_lints/src/index_refutable_slice.rs | 7 +- clippy_lints/src/indexing_slicing.rs | 6 +- clippy_lints/src/instant_subtraction.rs | 8 +- clippy_lints/src/item_name_repetitions.rs | 20 +- clippy_lints/src/large_const_arrays.rs | 12 +- clippy_lints/src/large_enum_variant.rs | 7 +- clippy_lints/src/large_futures.rs | 8 +- clippy_lints/src/large_include_file.rs | 8 +- clippy_lints/src/large_stack_arrays.rs | 10 +- clippy_lints/src/large_stack_frames.rs | 6 +- clippy_lints/src/legacy_numeric_constants.rs | 8 +- clippy_lints/src/lib.rs | 460 +++++---------------- clippy_lints/src/literal_representation.rs | 18 +- clippy_lints/src/loops/mod.rs | 7 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 20 +- clippy_lints/src/manual_bits.rs | 9 +- clippy_lints/src/manual_clamp.rs | 7 +- clippy_lints/src/manual_hash_one.rs | 8 +- clippy_lints/src/manual_is_ascii_check.rs | 8 +- clippy_lints/src/manual_main_separator_str.rs | 8 +- clippy_lints/src/manual_non_exhaustive.rs | 13 +- clippy_lints/src/manual_rem_euclid.rs | 8 +- clippy_lints/src/manual_retain.rs | 8 +- clippy_lints/src/manual_strip.rs | 8 +- clippy_lints/src/matches/mod.rs | 6 +- clippy_lints/src/mem_replace.rs | 8 +- clippy_lints/src/methods/mod.rs | 24 +- clippy_lints/src/methods/path_ends_with_ext.rs | 2 +- clippy_lints/src/min_ident_chars.rs | 13 +- clippy_lints/src/missing_const_for_fn.rs | 8 +- clippy_lints/src/missing_const_for_thread_local.rs | 8 +- clippy_lints/src/missing_doc.rs | 13 +- clippy_lints/src/missing_enforced_import_rename.rs | 29 +- clippy_lints/src/mut_key.rs | 13 +- .../src/needless_borrows_for_generic_args.rs | 6 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 9 +- clippy_lints/src/non_copy_const.rs | 11 +- clippy_lints/src/non_expressive_names.rs | 23 +- clippy_lints/src/non_send_fields_in_send_ty.rs | 6 +- clippy_lints/src/nonstandard_macro_braces.rs | 7 +- .../src/operators/arithmetic_side_effects.rs | 55 +-- clippy_lints/src/operators/mod.rs | 21 +- clippy_lints/src/panic_unimplemented.rs | 12 +- clippy_lints/src/pass_by_ref_or_value.rs | 19 +- clippy_lints/src/pub_underscore_fields.rs | 11 +- clippy_lints/src/question_mark.rs | 8 +- clippy_lints/src/ranges.rs | 8 +- clippy_lints/src/raw_strings.rs | 14 +- clippy_lints/src/redundant_field_names.rs | 8 +- clippy_lints/src/redundant_static_lifetimes.rs | 8 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/semicolon_block.rs | 12 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/single_call_fn.rs | 13 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/string_patterns.rs | 8 +- clippy_lints/src/trait_bounds.rs | 10 +- clippy_lints/src/transmute/mod.rs | 8 +- clippy_lints/src/tuple_array_conversions.rs | 11 +- clippy_lints/src/types/mod.rs | 9 +- clippy_lints/src/undocumented_unsafe_blocks.rs | 8 +- clippy_lints/src/unnecessary_box_returns.rs | 7 +- clippy_lints/src/unnecessary_wraps.rs | 5 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/unused_self.rs | 5 +- clippy_lints/src/upper_case_acronyms.rs | 8 +- clippy_lints/src/use_self.rs | 6 +- .../internal_lints/interning_defined_symbol.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 2 +- .../utils/internal_lints/unnecessary_def_path.rs | 4 +- clippy_lints/src/vec.rs | 20 +- clippy_lints/src/wildcard_imports.rs | 12 +- clippy_lints/src/write.rs | 8 +- clippy_utils/src/lib.rs | 27 +- clippy_utils/src/ty.rs | 8 +- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- tests/ui-internal/disallow_span_lint.stderr | 4 +- .../await_holding_invalid_type.stderr | 10 +- .../disallowed_macros/disallowed_macros.stderr | 2 +- .../conf_disallowed_methods.stderr | 2 +- .../conf_disallowed_types.stderr | 44 +- 115 files changed, 824 insertions(+), 994 deletions(-) (limited to 'clippy_lints/src/methods') diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 48c00bcbf34..a71d94daca7 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -458,9 +458,8 @@ pub struct ManualStrip { } impl ManualStrip { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv.clone() } } } ``` @@ -689,7 +688,6 @@ for some users. Adding a configuration is done in the following steps: ]); // New manual definition struct - #[derive(Copy, Clone)] pub struct StructName {} impl_lint_pass!(StructName => [ @@ -700,7 +698,6 @@ for some users. Adding a configuration is done in the following steps: 2. Next add the configuration value and a corresponding creation method like this: ```rust - #[derive(Copy, Clone)] pub struct StructName { configuration_ident: Type, } @@ -708,9 +705,9 @@ for some users. Adding a configuration is done in the following steps: // ... impl StructName { - pub fn new(configuration_ident: Type) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - configuration_ident, + configuration_ident: conf.configuration_ident, } } } @@ -726,8 +723,7 @@ for some users. Adding a configuration is done in the following steps: store.register_*_pass(|| box module::StructName); // New registration with configuration value - let configuration_ident = conf.configuration_ident.clone(); - store.register_*_pass(move || box module::StructName::new(configuration_ident)); + store.register_*_pass(move || box module::StructName::new(conf)); ``` Congratulations the work is almost done. The configuration value can now be diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index a750f3619d0..ce6cbc62a50 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 18e481b7af9..7eec3d4945a 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -238,7 +238,7 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed: Vec = <_>::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type pair names in binary operations like addition or @@ -265,7 +265,7 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` - (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed_unary: Vec = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. @@ -314,7 +314,7 @@ define_Conf! { /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - (doc_valid_idents: Vec = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + (doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), /// Lint: TOO_MANY_ARGUMENTS. /// /// The maximum number of argument a function or method can have @@ -550,7 +550,7 @@ define_Conf! { /// Lint: PATH_ENDS_WITH_EXT. /// /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: FxHashSet = FxHashSet::default()), + (allowed_dotfiles: Vec = Vec::default()), /// Lint: MULTIPLE_CRATE_VERSIONS. /// /// A list of crate names to allow duplicates of @@ -703,7 +703,6 @@ pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { fn deserialize(file: &SourceFile) -> TryConf { match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { Ok(mut conf) => { - extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES); extend_vec_if_indicator_present( @@ -716,6 +715,11 @@ fn deserialize(file: &SourceFile) -> TryConf { .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); } + if conf.conf.doc_valid_idents.contains("..") { + conf.conf + .doc_valid_idents + .extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string)); + } conf }, diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 435aa9244c5..d47e34bb5bc 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -2,13 +2,13 @@ use serde::de::{self, Deserializer, Visitor}; use serde::{ser, Deserialize, Serialize}; use std::fmt; -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] pub struct Rename { pub path: String, pub rename: String, } -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] #[serde(untagged)] pub enum DisallowedPath { Simple(String), @@ -22,12 +22,10 @@ impl DisallowedPath { path } - pub fn reason(&self) -> Option { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, + pub fn reason(&self) -> Option<&str> { + match &self { + Self::WithReason { reason, .. } => reason.as_deref(), + Self::Simple(_) => None, } } } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index d762e30ef02..de91233d196 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -140,7 +140,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf)));\n ", lint_pass = lint.pass, ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, @@ -274,6 +274,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { formatdoc!( r#" use clippy_config::msrvs::{{self, Msrv}}; + use clippy_config::Conf; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -301,9 +302,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} impl {name_camel} {{ - #[must_use] - pub fn new(msrv: Msrv) -> Self {{ - Self {{ msrv }} + pub fn new(conf: &'static Conf) -> Self {{ + Self {{ msrv: conf.msrv.clone() }} }} }} diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 461117cf965..c0a9d888e0b 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; use rustc_data_structures::fx::FxHashSet; @@ -47,7 +48,16 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { pub absolute_paths_max_segments: u64, - pub absolute_paths_allowed_crates: FxHashSet, + pub absolute_paths_allowed_crates: &'static FxHashSet, +} + +impl AbsolutePaths { + pub fn new(conf: &'static Conf) -> Self { + Self { + absolute_paths_max_segments: conf.absolute_paths_max_segments, + absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates, + } + } } impl LateLintPass<'_> for AbsolutePaths { diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 96e9c949b75..451bae95987 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; @@ -34,8 +35,10 @@ pub struct AlmostCompleteRange { msrv: Msrv, } impl AlmostCompleteRange { - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } impl EarlyLintPass for AlmostCompleteRange { diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index ec28fd46111..e6d52bcef71 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; @@ -67,9 +68,10 @@ pub struct ApproxConstant { } impl ApproxConstant { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 0de0031ed24..03f777600f0 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; @@ -57,9 +58,10 @@ pub struct AssigningClones { } impl AssigningClones { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 8ec60314cc9..8f430ae601a 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -16,6 +16,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -499,7 +500,6 @@ declare_clippy_lint! { "duplicated attribute" } -#[derive(Clone)] pub struct Attributes { msrv: Msrv, } @@ -517,9 +517,10 @@ impl_lint_pass!(Attributes => [ ]); impl Attributes { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -589,7 +590,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } pub struct EarlyAttributes { - pub msrv: Msrv, + msrv: Msrv, +} + +impl EarlyAttributes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } } impl_lint_pass!(EarlyAttributes => [ diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index d4a1e2780d0..d5f017b2650 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,11 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; +use clippy_utils::{create_disallowed_map, match_def_path, paths}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; @@ -172,31 +172,19 @@ declare_clippy_lint! { impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]); -#[derive(Debug)] pub struct AwaitHolding { - conf_invalid_types: Vec, - def_ids: FxHashMap, + def_ids: DefIdMap<(&'static str, Option<&'static str>)>, } impl AwaitHolding { - pub(crate) fn new(conf_invalid_types: Vec) -> Self { + pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_invalid_types, - def_ids: FxHashMap::default(), + def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types), } } } impl<'tcx> LateLintPass<'tcx> for AwaitHolding { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for conf in &self.conf_invalid_types { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.def_ids.insert(id, conf.clone()); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)), @@ -258,25 +246,22 @@ impl AwaitHolding { ); }, ); - } else if let Some(disallowed) = self.def_ids.get(&adt.did()) { - emit_invalid_type(cx, ty_cause.source_info.span, disallowed); + } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) { + emit_invalid_type(cx, ty_cause.source_info.span, path, reason); } } } } } -fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) { +fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) { span_lint_and_then( cx, AWAIT_HOLDING_INVALID_TYPE, span, - format!( - "`{}` may not be held across an await point per `clippy.toml`", - disallowed.path() - ), + format!("holding a disallowed type across an await point `{path}`"), |diag| { - if let Some(reason) = disallowed.reason() { + if let Some(reason) = reason { diag.note(reason); } }, diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 593bc6c81ee..312ad4c2990 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -5,6 +5,7 @@ mod multiple_crate_versions; mod wildcard_dependencies; use cargo_metadata::MetadataCommand; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashSet; @@ -204,8 +205,8 @@ declare_clippy_lint! { } pub struct Cargo { - pub allowed_duplicate_crates: FxHashSet, - pub ignore_publish: bool, + allowed_duplicate_crates: &'static FxHashSet, + ignore_publish: bool, } impl_lint_pass!(Cargo => [ @@ -217,6 +218,15 @@ impl_lint_pass!(Cargo => [ LINT_GROUPS_PRIORITY, ]); +impl Cargo { + pub fn new(conf: &'static Conf) -> Self { + Self { + allowed_duplicate_crates: &conf.allowed_duplicate_crates, + ignore_publish: conf.cargo_ignore_publish, + } + } +} + impl LateLintPass<'_> for Cargo { fn check_crate(&mut self, cx: &LateContext<'_>) { static NO_DEPS_LINTS: &[&Lint] = &[ @@ -253,7 +263,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); + multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index e9f9084af07..773731113ca 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -24,6 +24,7 @@ mod utils; mod zero_ptr; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -722,9 +723,10 @@ pub struct Casts { } impl Casts { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1ec4b831a2c..0b1ab5411bf 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,6 +1,7 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; @@ -40,9 +41,10 @@ pub struct CheckedConversions { } impl CheckedConversions { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 60815f4f2af..5fa0522e4e5 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -39,10 +40,9 @@ pub struct CognitiveComplexity { } impl CognitiveComplexity { - #[must_use] - pub fn new(limit: u64) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - limit: LimitStack::new(limit), + limit: LimitStack::new(conf.cognitive_complexity_threshold), } } } diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index d896452be92..86e0368c4e4 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; @@ -11,6 +12,7 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -159,15 +161,13 @@ declare_clippy_lint! { } pub struct CopyAndPaste<'tcx> { - ignore_interior_mutability: Vec, interior_mut: InteriorMut<'tcx>, } -impl CopyAndPaste<'_> { - pub fn new(ignore_interior_mutability: Vec) -> Self { +impl<'tcx> CopyAndPaste<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - ignore_interior_mutability, - interior_mut: InteriorMut::default(), + interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability), } } } @@ -180,10 +180,6 @@ impl_lint_pass!(CopyAndPaste<'_> => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index b0590b0a71c..788c6f3ada2 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; @@ -33,7 +34,6 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } -#[derive(Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, /// Tracks the `dbg!` macro callsites that are already checked. @@ -45,9 +45,9 @@ pub struct DbgMacro { impl_lint_pass!(DbgMacro => [DBG_MACRO]); impl DbgMacro { - pub fn new(allow_dbg_in_tests: bool) -> Self { + pub fn new(conf: &'static Conf) -> Self { DbgMacro { - allow_dbg_in_tests, + allow_dbg_in_tests: conf.allow_dbg_in_tests, checked_dbg_call_site: FxHashSet::default(), prev_ctxt: SyntaxContext::root(), } diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 0c9ad5e8d00..f27f68e2cbc 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; @@ -60,9 +61,10 @@ pub struct DerivableImpls { } impl DerivableImpls { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - DerivableImpls { msrv } + pub fn new(conf: &'static Conf) -> Self { + DerivableImpls { + msrv: conf.msrv.clone(), + } } } diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 871f529da6c..b51d343132b 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -1,4 +1,5 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -9,6 +10,7 @@ use rustc_hir::{ Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, MacroKind, Span}; @@ -57,27 +59,24 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, seen: FxHashSet, - // Track the most recently seen node that can have a `derive` attribute. // Needed to use the correct lint level. derive_src: Option, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_macros), seen: FxHashSet::default(), derive_src: None, } } fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option) { - if self.conf_disallowed.is_empty() { + if self.disallowed.is_empty() { return; } @@ -86,11 +85,10 @@ impl DisallowedMacros { return; } - if let Some(&index) = self.disallowed.get(&mac.def_id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed macro `{}`", conf.path()); + if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) { + let msg = format!("use of a disallowed macro `{path}`"); let add_note = |diag: &mut Diag<'_, _>| { - if let Some(reason) = conf.reason() { + if let Some(reason) = reason { diag.note(reason); } }; @@ -116,15 +114,6 @@ impl DisallowedMacros { impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); impl LateLintPass<'_> for DisallowedMacros { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { self.check(cx, expr.span, None); // `$t + $t` can have the context of $t, check also the span of the binary operator diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 38fe687f7cc..5a01d76a2a6 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -1,9 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -55,17 +57,14 @@ declare_clippy_lint! { "use of a disallowed method call" } -#[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_methods), } } } @@ -73,15 +72,6 @@ impl DisallowedMethods { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (id, span) = match &expr.kind { ExprKind::Path(path) @@ -95,14 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - if let Some(&index) = self.disallowed.get(&id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&(path, reason)) = self.disallowed.get(&id) { + span_lint_and_then( + cx, + DISALLOWED_METHODS, + span, + format!("use of a disallowed method `{path}`"), + |diag| { + if let Some(reason) = reason { + diag.note(reason); + } + }, + ); } } } diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 58809604c37..f55b0cf1c50 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -1,9 +1,11 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -24,15 +26,14 @@ declare_clippy_lint! { "usage of a disallowed/placeholder name" } -#[derive(Clone, Debug)] pub struct DisallowedNames { - disallow: FxHashSet, + disallow: FxHashSet, } impl DisallowedNames { - pub fn new(disallowed_names: &[String]) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - disallow: disallowed_names.iter().cloned().collect(), + disallow: conf.disallowed_names.iter().map(|x| Symbol::intern(x)).collect(), } } } @@ -42,7 +43,7 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind - && self.disallow.contains(&ident.name.to_string()) + && self.disallow.contains(&ident.name) && !is_in_test(cx.tcx, pat.hir_id) { span_lint( diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 5ce11900adf..f79264e6b04 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; @@ -44,19 +45,20 @@ declare_clippy_lint! { "usage of non-allowed Unicode scripts" } -#[derive(Clone, Debug)] pub struct DisallowedScriptIdents { whitelist: FxHashSet